diff options
author | Paolo Carlini <pcarlini@suse.de> | 2007-03-30 19:45:57 +0000 |
---|---|---|
committer | Paolo Carlini <paolo@gcc.gnu.org> | 2007-03-30 19:45:57 +0000 |
commit | cb68ec50055e516ac270a043f772935561b01968 (patch) | |
tree | 63250c95176e6d94178beae6b2735b398dfbfec1 | |
parent | c7a0240aa55b4f7a2d11d33bd12af7a40f42aa55 (diff) | |
download | gcc-cb68ec50055e516ac270a043f772935561b01968.tar.gz |
re PR c++/26099 (support for type traits is not available)
gcc/
2007-03-30 Paolo Carlini <pcarlini@suse.de>
PR c++/26099
* c-common.h (enum rid): Add RID_HAS_NOTHROW_ASSIGN,
RID_HAS_NOTHROW_CONSTRUCTOR, RID_HAS_NOTHROW_COPY,
RID_HAS_TRIVIAL_ASSIGN, RID_HAS_TRIVIAL_CONSTRUCTOR,
RID_HAS_TRIVIAL_COPY, RID_HAS_TRIVIAL_DESTRUCTOR,
RID_HAS_VIRTUAL_DESTRUCTOR, RID_IS_ABSTRACT, RID_IS_BASE_OF,
RID_IS_CONVERTIBLE_TO, RID_IS_CLASS, RID_IS_EMPTY, RID_IS_ENUM,
RID_IS_POD, RID_IS_POLYMORPHIC, RID_IS_UNION, as
C++ extensions.
* doc/extend.texi (Extensions to the C++ Language): Add Type Traits.
gcc/cp/
2007-03-30 Paolo Carlini <pcarlini@suse.de>
PR c++/26099
* cp-tree.h (enum cp_trait_kind, struct tree_trait_expr,
TRAIT_EXPR_TYPE1, TRAIT_EXPR_TYPE2, TRAIT_EXPR_KIND): Add.
(enum cp_tree_node_structure_enum, union lang_tree_node): Update.
(CLASS_TYPE_NON_UNION_P): Add.
(struct lang_type_class): Add has_complex_dflt.
(TYPE_HAS_COMPLEX_DFLT, TYPE_HAS_TRIVIAL_DFLT): Add.
(locate_copy, locate_ctor, locate_dtor, finish_trait_expr): Declare.
* cp-tree.def: Add TRAIT_EXPR.
* cp-objcp-common.c (cp_tree_size): Add TRAIT_EXPR case.
* lex.c (struct resword): Add __has_nothrow_assign,
__has_nothrow_constructor, __has_nothrow_copy, __has_trivial_assign,
__has_trivial_constructor, __has_trivial_copy,
__has_trivial_destructor, __has_virtual_destructor, __is_abstract,
__is_base_of, __is_class, __is_convertible_to, __is_empty, __is_enum,
__is_pod, __is_polymorphic, __is_union.
* parser.c (cp_parser_primary_expression): Deal with the new RIDs.
(cp_parser_trait_expr): New.
* semantics.c (finish_trait_expr, trait_expr_value
classtype_has_nothrow_copy_or_assign_p): New.
* method.c (locate_copy, locate_ctor, locate_dtor): Do not define
as static.
* decl.c (cp_tree_node_structure): Add TRAIT_EXPR.
* class.c (check_bases, check_field_decl, check_bases_and_members):
Deal with TYPE_HAS_COMPLEX_DFLT (t) too.
* pt.c (uses_template_parms, tsubst_copy_and_build,
value_dependent_expression_p, type_dependent_expression_p): Deal with
TRAIT_EXPR.
* tree.c (cp_walk_subtrees): Deal with TRAIT_EXPR.
gcc/testsuite/
2007-03-30 Paolo Carlini <pcarlini@suse.de>
PR c++/26099
* g++.dg/ext/is_base_of.C: New.
* g++.dg/ext/has_virtual_destructor.C: New.
* g++.dg/ext/is_polymorphic.C: New.
* g++.dg/ext/is_base_of_diagnostic.C: New.
* g++.dg/ext/is_enum.C: New.
* g++.dg/ext/has_nothrow_assign.C: New.
* g++.dg/ext/has_nothrow_constructor.C: New.
* g++.dg/ext/is_empty.C: New.
* g++.dg/ext/has_trivial_copy.C: New.
* g++.dg/ext/has_trivial_assign.C: New.
* g++.dg/ext/is_abstract.C: New.
* g++.dg/ext/is_pod.C: New.
* g++.dg/ext/has_nothrow_copy.C: New.
* g++.dg/ext/is_class.C: New.
* g++.dg/ext/has_trivial_constructor.C: New.
* g++.dg/ext/is_union.C: New.
* g++.dg/ext/has_trivial_destructor.C: New.
* g++.dg/tree-ssa/pr22444.C: Adjust, avoid __is_pod.
* g++.dg/template/crash43.C: Likewise.
libstdc++-v3/
2007-03-30 Paolo Carlini <pcarlini@suse.de>
PR c++/26099
* include/bits/cpp_type_traits.h (struct __is_pod, struct __is_empty):
Remove.
* include/bits/valarray_array.h: Adjust.
* include/bits/allocator.h: Likewise.
* include/bits/stl_tree.h: Likewise.
From-SVN: r123366
40 files changed, 2240 insertions, 68 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f60049ff6ab..de93d5dd1be 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2007-03-30 Paolo Carlini <pcarlini@suse.de> + + PR c++/26099 + * c-common.h (enum rid): Add RID_HAS_NOTHROW_ASSIGN, + RID_HAS_NOTHROW_CONSTRUCTOR, RID_HAS_NOTHROW_COPY, + RID_HAS_TRIVIAL_ASSIGN, RID_HAS_TRIVIAL_CONSTRUCTOR, + RID_HAS_TRIVIAL_COPY, RID_HAS_TRIVIAL_DESTRUCTOR, + RID_HAS_VIRTUAL_DESTRUCTOR, RID_IS_ABSTRACT, RID_IS_BASE_OF, + RID_IS_CONVERTIBLE_TO, RID_IS_CLASS, RID_IS_EMPTY, RID_IS_ENUM, + RID_IS_POD, RID_IS_POLYMORPHIC, RID_IS_UNION, as + C++ extensions. + * doc/extend.texi (Extensions to the C++ Language): Add Type Traits. + 2007-03-30 Steven Bosscher <steven@gcc.gnu.org> * regmove.c: Move all of pass_stack_adjustments from here... diff --git a/gcc/c-common.h b/gcc/c-common.h index b16a02d6b13..b128e31a008 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -90,6 +90,17 @@ enum rid /* casts */ RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST, + /* C++ extensions */ + RID_HAS_NOTHROW_ASSIGN, RID_HAS_NOTHROW_CONSTRUCTOR, + RID_HAS_NOTHROW_COPY, RID_HAS_TRIVIAL_ASSIGN, + RID_HAS_TRIVIAL_CONSTRUCTOR, RID_HAS_TRIVIAL_COPY, + RID_HAS_TRIVIAL_DESTRUCTOR, RID_HAS_VIRTUAL_DESTRUCTOR, + RID_IS_ABSTRACT, RID_IS_BASE_OF, + RID_IS_CONVERTIBLE_TO, RID_IS_CLASS, + RID_IS_EMPTY, RID_IS_ENUM, + RID_IS_POD, RID_IS_POLYMORPHIC, + RID_IS_UNION, + /* C++0x */ RID_STATIC_ASSERT, diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index bf5e28c272e..4374e6b7db0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,35 @@ +2007-03-30 Paolo Carlini <pcarlini@suse.de> + + PR c++/26099 + * cp-tree.h (enum cp_trait_kind, struct tree_trait_expr, + TRAIT_EXPR_TYPE1, TRAIT_EXPR_TYPE2, TRAIT_EXPR_KIND): Add. + (enum cp_tree_node_structure_enum, union lang_tree_node): Update. + (CLASS_TYPE_NON_UNION_P): Add. + (struct lang_type_class): Add has_complex_dflt. + (TYPE_HAS_COMPLEX_DFLT, TYPE_HAS_TRIVIAL_DFLT): Add. + (locate_copy, locate_ctor, locate_dtor, finish_trait_expr): Declare. + * cp-tree.def: Add TRAIT_EXPR. + * cp-objcp-common.c (cp_tree_size): Add TRAIT_EXPR case. + * lex.c (struct resword): Add __has_nothrow_assign, + __has_nothrow_constructor, __has_nothrow_copy, __has_trivial_assign, + __has_trivial_constructor, __has_trivial_copy, + __has_trivial_destructor, __has_virtual_destructor, __is_abstract, + __is_base_of, __is_class, __is_convertible_to, __is_empty, __is_enum, + __is_pod, __is_polymorphic, __is_union. + * parser.c (cp_parser_primary_expression): Deal with the new RIDs. + (cp_parser_trait_expr): New. + * semantics.c (finish_trait_expr, trait_expr_value + classtype_has_nothrow_copy_or_assign_p): New. + * method.c (locate_copy, locate_ctor, locate_dtor): Do not define + as static. + * decl.c (cp_tree_node_structure): Add TRAIT_EXPR. + * class.c (check_bases, check_field_decl, check_bases_and_members): + Deal with TYPE_HAS_COMPLEX_DFLT (t) too. + * pt.c (uses_template_parms, tsubst_copy_and_build, + value_dependent_expression_p, type_dependent_expression_p): Deal with + TRAIT_EXPR. + * tree.c (cp_walk_subtrees): Deal with TRAIT_EXPR. + 2007-03-29 Richard Guenther <rguenther@suse.de> * tree.c (cp_walk_subtrees): Do not set input_location. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 22c9439aa1a..5e5bcbf895c 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -1270,6 +1270,7 @@ check_bases (tree t, TYPE_POLYMORPHIC_P (t) |= TYPE_POLYMORPHIC_P (basetype); CLASSTYPE_CONTAINS_EMPTY_CLASS_P (t) |= CLASSTYPE_CONTAINS_EMPTY_CLASS_P (basetype); + TYPE_HAS_COMPLEX_DFLT (t) |= TYPE_HAS_COMPLEX_DFLT (basetype); } } @@ -2753,6 +2754,7 @@ check_field_decl (tree field, |= TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type); TYPE_HAS_COMPLEX_ASSIGN_REF (t) |= TYPE_HAS_COMPLEX_ASSIGN_REF (type); TYPE_HAS_COMPLEX_INIT_REF (t) |= TYPE_HAS_COMPLEX_INIT_REF (type); + TYPE_HAS_COMPLEX_DFLT (t) |= TYPE_HAS_COMPLEX_DFLT (type); } if (!TYPE_HAS_CONST_INIT_REF (type)) @@ -4113,6 +4115,8 @@ check_bases_and_members (tree t) || TYPE_HAS_ASSIGN_REF (t)); TYPE_HAS_COMPLEX_ASSIGN_REF (t) |= TYPE_HAS_ASSIGN_REF (t) || TYPE_CONTAINS_VPTR_P (t); + TYPE_HAS_COMPLEX_DFLT (t) + |= (TYPE_HAS_DEFAULT_CONSTRUCTOR (t) || TYPE_CONTAINS_VPTR_P (t)); /* Synthesize any needed methods. */ add_implicitly_declared_members (t, diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index 7b1841e3fa7..af8eb94cf49 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -135,6 +135,9 @@ cp_tree_size (enum tree_code code) case ARGUMENT_PACK_SELECT: return sizeof (struct tree_argument_pack_select); + case TRAIT_EXPR: + return sizeof (struct tree_trait_expr); + default: gcc_unreachable (); } diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index a2a0c03b79a..a0feb30e001 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -422,6 +422,11 @@ DEFTREECODE (EXPR_PACK_EXPANSION, "expr_pack_expansion", tcc_expression, 1) index is a machine integer. */ DEFTREECODE (ARGUMENT_PACK_SELECT, "argument_pack_select", tcc_exceptional, 0) +/** C++ extensions. */ + +/* Represents a trait expression during template expansion. */ +DEFTREECODE (TRAIT_EXPR, "trait_expr", tcc_exceptional, 0) + /* Local variables: mode:c diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 95945b33837..2d20246a244 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -478,6 +478,48 @@ struct tree_argument_pack_select GTY (()) int index; }; +/* The different kinds of traits that we encounter. */ + +typedef enum cp_trait_kind +{ + CPTK_HAS_NOTHROW_ASSIGN, + CPTK_HAS_NOTHROW_CONSTRUCTOR, + CPTK_HAS_NOTHROW_COPY, + CPTK_HAS_TRIVIAL_ASSIGN, + CPTK_HAS_TRIVIAL_CONSTRUCTOR, + CPTK_HAS_TRIVIAL_COPY, + CPTK_HAS_TRIVIAL_DESTRUCTOR, + CPTK_HAS_VIRTUAL_DESTRUCTOR, + CPTK_IS_ABSTRACT, + CPTK_IS_BASE_OF, + CPTK_IS_CLASS, + CPTK_IS_CONVERTIBLE_TO, + CPTK_IS_EMPTY, + CPTK_IS_ENUM, + CPTK_IS_POD, + CPTK_IS_POLYMORPHIC, + CPTK_IS_UNION +} cp_trait_kind; + +/* The types that we are processing. */ +#define TRAIT_EXPR_TYPE1(NODE) \ + (((struct tree_trait_expr *)TRAIT_EXPR_CHECK (NODE))->type1) + +#define TRAIT_EXPR_TYPE2(NODE) \ + (((struct tree_trait_expr *)TRAIT_EXPR_CHECK (NODE))->type2) + +/* The specific trait that we are processing. */ +#define TRAIT_EXPR_KIND(NODE) \ + (((struct tree_trait_expr *)TRAIT_EXPR_CHECK (NODE))->kind) + +struct tree_trait_expr GTY (()) +{ + struct tree_common common; + tree type1; + tree type2; + enum cp_trait_kind kind; +}; + enum cp_tree_node_structure_enum { TS_CP_GENERIC, TS_CP_IDENTIFIER, @@ -491,6 +533,7 @@ enum cp_tree_node_structure_enum { TS_CP_DEFAULT_ARG, TS_CP_STATIC_ASSERT, TS_CP_ARGUMENT_PACK_SELECT, + TS_CP_TRAIT_EXPR, LAST_TS_CP_ENUM }; @@ -511,6 +554,8 @@ union lang_tree_node GTY((desc ("cp_tree_node_structure (&%h)"), static_assertion; struct tree_argument_pack_select GTY ((tag ("TS_CP_ARGUMENT_PACK_SELECT"))) argument_pack_select; + struct tree_trait_expr GTY ((tag ("TS_CP_TRAIT_EXPR"))) + trait_expression; }; @@ -936,6 +981,10 @@ enum languages { lang_c, lang_cplusplus, lang_java }; #define CLASS_TYPE_P(T) \ (IS_AGGR_TYPE_CODE (TREE_CODE (T)) && TYPE_LANG_FLAG_5 (T)) +/* Nonzero if T is a class type but not an union. */ +#define NON_UNION_CLASS_TYPE_P(T) \ + (CLASS_TYPE_P (T) && TREE_CODE (T) != UNION_TYPE) + /* Keep these checks in ascending code order. */ #define IS_AGGR_TYPE_CODE(T) \ ((T) == RECORD_TYPE || (T) == UNION_TYPE) @@ -1093,6 +1142,7 @@ struct lang_type_class GTY(()) unsigned has_complex_init_ref : 1; unsigned has_complex_assign_ref : 1; unsigned non_aggregate : 1; + unsigned has_complex_dflt : 1; /* When adding a flag here, consider whether or not it ought to apply to a template instance if it applies to the template. If @@ -1101,7 +1151,7 @@ struct lang_type_class GTY(()) /* There are some bits left to fill out a 32-bit word. Keep track of this by updating the size of this bitfield whenever you add or remove a flag. */ - unsigned dummy : 12; + unsigned dummy : 11; tree primary_base; VEC(tree_pair_s,gc) *vcall_indices; @@ -2682,8 +2732,13 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) /* Nonzero if there is a user-defined X::op=(x&) for this class. */ #define TYPE_HAS_COMPLEX_ASSIGN_REF(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_complex_assign_ref) + +/* Nonzero if there is a user-defined X::X(x&) for this class. */ #define TYPE_HAS_COMPLEX_INIT_REF(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_complex_init_ref) +/* Nonzero if there is a user-defined default constructor for this class. */ +#define TYPE_HAS_COMPLEX_DFLT(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_complex_dflt) + /* Nonzero if TYPE has a trivial destructor. From [class.dtor]: A destructor is trivial if it is an implicitly declared @@ -2705,6 +2760,10 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define TYPE_HAS_NONTRIVIAL_DESTRUCTOR(NODE) \ (TYPE_LANG_FLAG_4 (NODE)) +/* Nonzero for class type means that the default constructor is trivial. */ +#define TYPE_HAS_TRIVIAL_DFLT(NODE) \ + (TYPE_HAS_DEFAULT_CONSTRUCTOR (NODE) && ! TYPE_HAS_COMPLEX_DFLT (NODE)) + /* Nonzero for class type means that copy initialization of this type can use a bitwise copy. */ #define TYPE_HAS_TRIVIAL_INIT_REF(NODE) \ @@ -4280,6 +4339,9 @@ extern tree lazily_declare_fn (special_function_kind, extern tree skip_artificial_parms_for (tree, tree); extern int num_artificial_parms_for (tree); extern tree make_alias_for (tree, tree); +extern tree locate_copy (tree, void *); +extern tree locate_ctor (tree, void *); +extern tree locate_dtor (tree, void *); /* In optimize.c */ extern bool maybe_clone_body (tree); @@ -4557,6 +4619,7 @@ extern bool cxx_omp_privatize_by_reference (tree); extern tree baselink_for_fns (tree); extern void finish_static_assert (tree, tree, location_t, bool); +extern tree finish_trait_expr (enum cp_trait_kind, tree, tree); /* in tree.c */ extern void lang_check_failed (const char *, int, diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 0315f01241d..833e7b8e43a 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -11739,6 +11739,7 @@ cp_tree_node_structure (union lang_tree_node * t) case BASELINK: return TS_CP_BASELINK; case STATIC_ASSERT: return TS_CP_STATIC_ASSERT; case ARGUMENT_PACK_SELECT: return TS_CP_ARGUMENT_PACK_SELECT; + case TRAIT_EXPR: return TS_CP_TRAIT_EXPR; default: return TS_CP_GENERIC; } } diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index 2f619be9645..080a843df41 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -199,6 +199,23 @@ static const struct resword reswords[] = { "__const__", RID_CONST, 0 }, { "__extension__", RID_EXTENSION, 0 }, { "__func__", RID_C99_FUNCTION_NAME, 0 }, + { "__has_nothrow_assign", RID_HAS_NOTHROW_ASSIGN, 0 }, + { "__has_nothrow_constructor", RID_HAS_NOTHROW_CONSTRUCTOR, 0 }, + { "__has_nothrow_copy", RID_HAS_NOTHROW_COPY, 0 }, + { "__has_trivial_assign", RID_HAS_TRIVIAL_ASSIGN, 0 }, + { "__has_trivial_constructor", RID_HAS_TRIVIAL_CONSTRUCTOR, 0 }, + { "__has_trivial_copy", RID_HAS_TRIVIAL_COPY, 0 }, + { "__has_trivial_destructor", RID_HAS_TRIVIAL_DESTRUCTOR, 0 }, + { "__has_virtual_destructor", RID_HAS_VIRTUAL_DESTRUCTOR, 0 }, + { "__is_abstract", RID_IS_ABSTRACT, 0 }, + { "__is_base_of", RID_IS_BASE_OF, 0 }, + { "__is_class", RID_IS_CLASS, 0 }, + { "__is_convertible_to", RID_IS_CONVERTIBLE_TO, 0 }, + { "__is_empty", RID_IS_EMPTY, 0 }, + { "__is_enum", RID_IS_ENUM, 0 }, + { "__is_pod", RID_IS_POD, 0 }, + { "__is_polymorphic", RID_IS_POLYMORPHIC, 0 }, + { "__is_union", RID_IS_UNION, 0 }, { "__imag", RID_IMAGPART, 0 }, { "__imag__", RID_IMAGPART, 0 }, { "__inline", RID_INLINE, 0 }, diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 4dff5b9026a..03078a3f017 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -61,9 +61,6 @@ static tree thunk_adjust (tree, bool, HOST_WIDE_INT, tree); static void do_build_assign_ref (tree); static void do_build_copy_constructor (tree); static tree synthesize_exception_spec (tree, tree (*) (tree, void *), void *); -static tree locate_dtor (tree, void *); -static tree locate_ctor (tree, void *); -static tree locate_copy (tree, void *); static tree make_alias_for_thunk (tree); /* Called once to initialize method.c. */ @@ -868,7 +865,7 @@ synthesize_exception_spec (tree type, tree (*extractor) (tree, void*), /* Locate the dtor of TYPE. */ -static tree +tree locate_dtor (tree type, void *client ATTRIBUTE_UNUSED) { return CLASSTYPE_DESTRUCTORS (type); @@ -876,7 +873,7 @@ locate_dtor (tree type, void *client ATTRIBUTE_UNUSED) /* Locate the default ctor of TYPE. */ -static tree +tree locate_ctor (tree type, void *client ATTRIBUTE_UNUSED) { tree fns; @@ -912,7 +909,7 @@ struct copy_data points to a COPY_DATA holding the name (NULL for the ctor) and desired qualifiers of the source operand. */ -static tree +tree locate_copy (tree type, void *client_) { struct copy_data *client = (struct copy_data *)client_; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index dcd73f06ab5..4fc1a629d5c 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1897,6 +1897,8 @@ static void cp_parser_late_parsing_default_args (cp_parser *, tree); static tree cp_parser_sizeof_operand (cp_parser *, enum rid); +static tree cp_parser_trait_expr + (cp_parser *, enum rid); static bool cp_parser_declares_only_class_p (cp_parser *); static void cp_parser_set_storage_class @@ -2959,6 +2961,25 @@ cp_parser_translation_unit (cp_parser* parser) __builtin_va_arg ( assignment-expression , type-id ) __builtin_offsetof ( type-id , offsetof-expression ) + C++ Extensions: + __has_nothrow_assign ( type-id ) + __has_nothrow_constructor ( type-id ) + __has_nothrow_copy ( type-id ) + __has_trivial_assign ( type-id ) + __has_trivial_constructor ( type-id ) + __has_trivial_copy ( type-id ) + __has_trivial_destructor ( type-id ) + __has_virtual_destructor ( type-id ) + __is_abstract ( type-id ) + __is_base_of ( type-id , type-id ) + __is_class ( type-id ) + __is_convertible_to ( type-id , type-id ) + __is_empty ( type-id ) + __is_enum ( type-id ) + __is_pod ( type-id ) + __is_polymorphic ( type-id ) + __is_union ( type-id ) + Objective-C++ Extension: primary-expression: @@ -3201,7 +3222,26 @@ cp_parser_primary_expression (cp_parser *parser, case RID_OFFSETOF: return cp_parser_builtin_offsetof (parser); - /* Objective-C++ expressions. */ + case RID_HAS_NOTHROW_ASSIGN: + case RID_HAS_NOTHROW_CONSTRUCTOR: + case RID_HAS_NOTHROW_COPY: + case RID_HAS_TRIVIAL_ASSIGN: + case RID_HAS_TRIVIAL_CONSTRUCTOR: + case RID_HAS_TRIVIAL_COPY: + case RID_HAS_TRIVIAL_DESTRUCTOR: + case RID_HAS_VIRTUAL_DESTRUCTOR: + case RID_IS_ABSTRACT: + case RID_IS_BASE_OF: + case RID_IS_CLASS: + case RID_IS_CONVERTIBLE_TO: + case RID_IS_EMPTY: + case RID_IS_ENUM: + case RID_IS_POD: + case RID_IS_POLYMORPHIC: + case RID_IS_UNION: + return cp_parser_trait_expr (parser, token->keyword); + + /* Objective-C++ expressions. */ case RID_AT_ENCODE: case RID_AT_PROTOCOL: case RID_AT_SELECTOR: @@ -6309,6 +6349,112 @@ cp_parser_builtin_offsetof (cp_parser *parser) return expr; } +/* Parse a trait expression. */ + +static tree +cp_parser_trait_expr (cp_parser* parser, enum rid keyword) +{ + cp_trait_kind kind; + tree type1, type2 = NULL_TREE; + bool binary = false; + cp_decl_specifier_seq decl_specs; + + switch (keyword) + { + case RID_HAS_NOTHROW_ASSIGN: + kind = CPTK_HAS_NOTHROW_ASSIGN; + break; + case RID_HAS_NOTHROW_CONSTRUCTOR: + kind = CPTK_HAS_NOTHROW_CONSTRUCTOR; + break; + case RID_HAS_NOTHROW_COPY: + kind = CPTK_HAS_NOTHROW_COPY; + break; + case RID_HAS_TRIVIAL_ASSIGN: + kind = CPTK_HAS_TRIVIAL_ASSIGN; + break; + case RID_HAS_TRIVIAL_CONSTRUCTOR: + kind = CPTK_HAS_TRIVIAL_CONSTRUCTOR; + break; + case RID_HAS_TRIVIAL_COPY: + kind = CPTK_HAS_TRIVIAL_COPY; + break; + case RID_HAS_TRIVIAL_DESTRUCTOR: + kind = CPTK_HAS_TRIVIAL_DESTRUCTOR; + break; + case RID_HAS_VIRTUAL_DESTRUCTOR: + kind = CPTK_HAS_VIRTUAL_DESTRUCTOR; + break; + case RID_IS_ABSTRACT: + kind = CPTK_IS_ABSTRACT; + break; + case RID_IS_BASE_OF: + kind = CPTK_IS_BASE_OF; + binary = true; + break; + case RID_IS_CLASS: + kind = CPTK_IS_CLASS; + break; + case RID_IS_CONVERTIBLE_TO: + kind = CPTK_IS_CONVERTIBLE_TO; + binary = true; + break; + case RID_IS_EMPTY: + kind = CPTK_IS_EMPTY; + break; + case RID_IS_ENUM: + kind = CPTK_IS_ENUM; + break; + case RID_IS_POD: + kind = CPTK_IS_POD; + break; + case RID_IS_POLYMORPHIC: + kind = CPTK_IS_POLYMORPHIC; + break; + case RID_IS_UNION: + kind = CPTK_IS_UNION; + break; + default: + gcc_unreachable (); + } + + /* Consume the token. */ + cp_lexer_consume_token (parser->lexer); + + cp_parser_require (parser, CPP_OPEN_PAREN, "`('"); + + type1 = cp_parser_type_id (parser); + + /* Build a trivial decl-specifier-seq. */ + clear_decl_specs (&decl_specs); + decl_specs.type = type1; + + /* Call grokdeclarator to figure out what type this is. */ + type1 = grokdeclarator (NULL, &decl_specs, TYPENAME, + /*initialized=*/0, /*attrlist=*/NULL); + + if (binary) + { + cp_parser_require (parser, CPP_COMMA, "`,'"); + + type2 = cp_parser_type_id (parser); + + /* Build a trivial decl-specifier-seq. */ + clear_decl_specs (&decl_specs); + decl_specs.type = type2; + + /* Call grokdeclarator to figure out what type this is. */ + type2 = grokdeclarator (NULL, &decl_specs, TYPENAME, + /*initialized=*/0, /*attrlist=*/NULL); + } + + cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); + + /* Complete the trait expr, which may mean either processing the + static assert now or saving it for template instantiation. */ + return finish_trait_expr (kind, type1, type2); +} + /* Statements [gram.stmt.stmt] */ /* Parse a statement. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 1e6c04408e2..f1e6b18ca24 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -5818,6 +5818,7 @@ uses_template_parms (tree t) || TREE_CODE (t) == OVERLOAD || TREE_CODE (t) == BASELINK || TREE_CODE (t) == IDENTIFIER_NODE + || TREE_CODE (t) == TRAIT_EXPR || CONSTANT_CLASS_P (t)) dependent_p = (type_dependent_expression_p (t) || value_dependent_expression_p (t)); @@ -10703,6 +10704,18 @@ tsubst_copy_and_build (tree t, case OFFSETOF_EXPR: return finish_offsetof (RECUR (TREE_OPERAND (t, 0))); + case TRAIT_EXPR: + { + tree type1 = tsubst_copy (TRAIT_EXPR_TYPE1 (t), args, + complain, in_decl); + + tree type2 = TRAIT_EXPR_TYPE2 (t); + if (type2) + type2 = tsubst_copy (type2, args, complain, in_decl); + + return finish_trait_expr (TRAIT_EXPR_KIND (t), type1, type2); + } + case STMT_EXPR: { tree old_stmt_expr = cur_stmt_expr; @@ -14912,6 +14925,13 @@ value_dependent_expression_p (tree expression) return false; } + case TRAIT_EXPR: + { + tree type2 = TRAIT_EXPR_TYPE2 (expression); + return (dependent_type_p (TRAIT_EXPR_TYPE1 (expression)) + || (type2 ? dependent_type_p (type2) : false)); + } + default: /* A constant expression is value-dependent if any subexpression is value-dependent. */ @@ -14975,6 +14995,7 @@ type_dependent_expression_p (tree expression) if (TREE_CODE (expression) == PSEUDO_DTOR_EXPR || TREE_CODE (expression) == SIZEOF_EXPR || TREE_CODE (expression) == ALIGNOF_EXPR + || TREE_CODE (expression) == TRAIT_EXPR || TREE_CODE (expression) == TYPEID_EXPR || TREE_CODE (expression) == DELETE_EXPR || TREE_CODE (expression) == VEC_DELETE_EXPR diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index e2603531e88..bfb84ec5d5f 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -4007,4 +4007,210 @@ finish_static_assert (tree condition, tree message, location_t location, } } +/* Called from trait_expr_value to evaluate either __has_nothrow_copy or + __has_nothrow_assign, depending on copy_p. */ + +static bool +classtype_has_nothrow_copy_or_assign_p (tree type, bool copy_p) +{ + if ((copy_p && TYPE_HAS_INIT_REF (type)) + || (!copy_p && TYPE_HAS_ASSIGN_REF (type))) + { + bool const_p = false; + tree t; + + struct copy_data + { + tree name; + int quals; + } data; + + data.name = copy_p ? NULL_TREE : ansi_assopname (NOP_EXPR); + + data.quals = TYPE_QUAL_CONST; + t = locate_copy (type, &data); + if (t) + { + const_p = true; + if (!TREE_NOTHROW (t)) + return false; + } + + if (copy_p || !CP_TYPE_CONST_P (type)) + { + data.quals = TYPE_UNQUALIFIED; + t = locate_copy (type, &data); + if (t && !TREE_NOTHROW (t)) + return false; + + data.quals = TYPE_QUAL_VOLATILE; + t = locate_copy (type, &data); + if (t && !TREE_NOTHROW (t)) + return false; + } + + data.quals = (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE); + t = locate_copy (type, &data); + if (t) + { + const_p = true; + if (!TREE_NOTHROW (t)) + return false; + } + + if (!copy_p && CP_TYPE_CONST_P (type) && !const_p) + return false; + } + else + return false; + + return true; +} + +/* Actually evaluates the trait. */ + +static bool +trait_expr_value (cp_trait_kind kind, tree type1, tree type2) +{ + enum tree_code type_code1; + tree t; + + type_code1 = TREE_CODE (type1); + + switch (kind) + { + case CPTK_HAS_NOTHROW_ASSIGN: + return (trait_expr_value (CPTK_HAS_TRIVIAL_ASSIGN, type1, type2) + || (CLASS_TYPE_P (type1) + && classtype_has_nothrow_copy_or_assign_p (type1, false))); + + case CPTK_HAS_TRIVIAL_ASSIGN: + return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE + && (pod_type_p (type1) + || (CLASS_TYPE_P (type1) + && TYPE_HAS_TRIVIAL_ASSIGN_REF (type1)))); + + case CPTK_HAS_NOTHROW_CONSTRUCTOR: + type1 = strip_array_types (type1); + return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2) + || (CLASS_TYPE_P (type1) + && (t = locate_ctor (type1, NULL)) && TREE_NOTHROW (t))); + + case CPTK_HAS_TRIVIAL_CONSTRUCTOR: + type1 = strip_array_types (type1); + return (pod_type_p (type1) + || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1))); + + case CPTK_HAS_NOTHROW_COPY: + return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2) + || (CLASS_TYPE_P (type1) + && classtype_has_nothrow_copy_or_assign_p (type1, true))); + + case CPTK_HAS_TRIVIAL_COPY: + return (pod_type_p (type1) || type_code1 == REFERENCE_TYPE + || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_INIT_REF (type1))); + + case CPTK_HAS_TRIVIAL_DESTRUCTOR: + type1 = strip_array_types (type1); + return (pod_type_p (type1) + || (CLASS_TYPE_P (type1) + && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1))); + + case CPTK_HAS_VIRTUAL_DESTRUCTOR: + return (CLASS_TYPE_P (type1) + && (t = locate_dtor (type1, NULL)) && DECL_VIRTUAL_P (t)); + + case CPTK_IS_ABSTRACT: + return (CLASS_TYPE_P (type1) && CLASSTYPE_PURE_VIRTUALS (type1)); + + case CPTK_IS_BASE_OF: + return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2) + && DERIVED_FROM_P (type1, type2)); + + case CPTK_IS_CLASS: + return (NON_UNION_CLASS_TYPE_P (type1)); + + case CPTK_IS_CONVERTIBLE_TO: + /* TODO */ + return false; + + case CPTK_IS_EMPTY: + return (NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1)); + + case CPTK_IS_ENUM: + return (type_code1 == ENUMERAL_TYPE); + + case CPTK_IS_POD: + return (pod_type_p (type1)); + + case CPTK_IS_POLYMORPHIC: + return (CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1)); + + case CPTK_IS_UNION: + return (type_code1 == UNION_TYPE); + + default: + gcc_unreachable (); + return false; + } +} + +/* Process a trait expression. */ + +tree +finish_trait_expr (cp_trait_kind kind, tree type1, tree type2) +{ + gcc_assert (kind == CPTK_HAS_NOTHROW_ASSIGN + || kind == CPTK_HAS_NOTHROW_CONSTRUCTOR + || kind == CPTK_HAS_NOTHROW_COPY + || kind == CPTK_HAS_TRIVIAL_ASSIGN + || kind == CPTK_HAS_TRIVIAL_CONSTRUCTOR + || kind == CPTK_HAS_TRIVIAL_COPY + || kind == CPTK_HAS_TRIVIAL_DESTRUCTOR + || kind == CPTK_HAS_VIRTUAL_DESTRUCTOR + || kind == CPTK_IS_ABSTRACT + || kind == CPTK_IS_BASE_OF + || kind == CPTK_IS_CLASS + || kind == CPTK_IS_CONVERTIBLE_TO + || kind == CPTK_IS_EMPTY + || kind == CPTK_IS_ENUM + || kind == CPTK_IS_POD + || kind == CPTK_IS_POLYMORPHIC + || kind == CPTK_IS_UNION); + + if (kind == CPTK_IS_CONVERTIBLE_TO) + { + sorry ("__is_convertible_to"); + return error_mark_node; + } + + if (type1 == error_mark_node + || ((kind == CPTK_IS_BASE_OF || kind == CPTK_IS_CONVERTIBLE_TO) + && type2 == error_mark_node)) + return error_mark_node; + + if (processing_template_decl) + { + tree trait_expr = make_node (TRAIT_EXPR); + TREE_TYPE (trait_expr) = boolean_type_node; + TRAIT_EXPR_TYPE1 (trait_expr) = type1; + TRAIT_EXPR_TYPE2 (trait_expr) = type2; + TRAIT_EXPR_KIND (trait_expr) = kind; + return trait_expr; + } + + /* The only required diagnostic. */ + if (kind == CPTK_IS_BASE_OF + && NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2) + && !same_type_ignoring_top_level_qualifiers_p (type1, type2) + && !COMPLETE_TYPE_P (complete_type (type2))) + { + error ("incomplete type %qT not allowed", type2); + return error_mark_node; + } + + return (trait_expr_value (kind, type1, type2) + ? boolean_true_node : boolean_false_node); +} + #include "gt-cp-semantics.h" diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 7fd6664a8c6..78a3520dd98 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -2293,6 +2293,12 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func, *walk_subtrees_p = 0; break; + case TRAIT_EXPR: + WALK_SUBTREE (TRAIT_EXPR_TYPE1 (*tp)); + WALK_SUBTREE (TRAIT_EXPR_TYPE2 (*tp)); + *walk_subtrees_p = 0; + break; + default: return NULL_TREE; } diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index d01e5fab3a1..ccdc9951634 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -10675,6 +10675,7 @@ Predefined Macros,cpp,The GNU C Preprocessor}). method denoted by a @samp{->*} or @samp{.*} expression. * C++ Attributes:: Variable, function, and type attributes for C++ only. * Namespace Association:: Strong using-directives for namespace association. +* Type Traits:: Compiler support for type traits * Java Exceptions:: Tweaking exception handling to work with Java. * Deprecated Features:: Things will disappear from g++. * Backwards Compatibility:: Compatibilities with earlier definitions of C++. @@ -11232,6 +11233,124 @@ int main() @} @end smallexample +@node Type Traits +@section Type Traits + +The C++ front-end implements syntactic extensions that allow to +determine at compile time various characteristics of a type (or of a +pair of types). + +@table @code +@item __has_nothrow_assign (type) +If @code{__has_trivial_assign (type)} is true then the trait is true, else if +@code{type} is a cv class or union type with copy assignment operators that +are known not to throw an exception then the trait is true, else it is false. +If @code{type} is const qualified, any copy assignment operator must +be both known not to throw an exception, and const qualified, for the +trait to be true. Requires: @code{type} shall be a complete type, an +array type of unknown bound, or is a @code{void} type. + +@item __has_nothrow_copy (type) +If @code{__has_trivial_copy (type)} is true then the trait is true, else if +@code{type} is a cv class or union type with copy constructors that +are known not to throw an exception then the trait is true, else it is false. +Requires: @code{type} shall be a complete type, an array type of +unknown bound, or is a @code{void} type. + +@item __has_nothrow_constructor (type) +If @code{__has_trivial_constructor (type)} is true then the trait is +true, else if @code{type} is a cv class or union type (or array +thereof) with a default constructor that is known not to throw an +exception then the trait is true, else it is false. Requires: +@code{type} shall be a complete type, an array type of unknown bound, +or is a @code{void} type. + +@item __has_trivial_assign (type) +If @code{type} is const qualified or is a reference type then the trait is +false. Otherwise if @code{__is_pod (type)} is true then the trait is +true, else if @code{type} is a cv class or union type with a trivial +copy assignment ([class.copy]) then the trait is true, else it is +false. Requires: @code{type} shall be a complete type, an array type +of unknown bound, or is a @code{void} type. + +@item __has_trivial_copy (type) +If @code{__is_pod (type)} is true or @code{type} is a reference type +then the trait is true, else if @code{type} is a cv class or union type +with a trivial copy constructor ([class.copy]) then the trait +is true, else it is false. Requires: @code{type} shall be a complete +type, an array type of unknown bound, or is a @code{void} type. + +@item __has_trivial_constructor (type) +If @code{__is_pod (type)} is true then the trait is true, else if +@code{type} is a cv class or union type (or array thereof) with a +trivial default constructor ([class.ctor]) then the trait is true, +else it is false. Requires: @code{type} shall be a complete type, an +array type of unknown bound, or is a @code{void} type. + +@item __has_trivial_destructor (type) +If @code{__is_pod (type)} is true or @code{type} is a reference type then +the trait is true, else if @code{type} is a cv class or union type (or +array thereof) with a trivial destructor ([class.dtor]) then the trait +is true, else it is false. Requires: @code{type} shall be a complete +type, an array type of unknown bound, or is a @code{void} type. + +@item __has_virtual_destructor (type) +If @code{type} is a class type with a virtual destructor +([class.dtor]) then the trait is true, else it is false. Requires: +@code{type} shall be a complete type, an array type of unknown bound, +or is a @code{void} type. + +@item __is_abstract (type) +If @code{type} is an abstract class ([class.abstract]) then the trait +is true, else it is false. Requires: @code{type} shall be a complete +type, an array type of unknown bound, or is a @code{void} type. + +@item __is_base_of (base_type, derived_type) +If @code{base_type} is a base class of @code{derived_type} +([class.derived]) then the trait is true, otherwise it is false. +Top-level cv qualifications of @code{base_type} and +@code{derived_type} are ignored. For the purposes of this trait, a +class type is considered is own base. Requires: if @code{__is_class +(base_type)} and @code{__is_class (derived_type)} are true and +@code{base_type} and @code{derived_type} are not the same type +(disregarding cv-qualifiers), @code{derived_type} shall be a complete +type. Diagnostic is produced if this requirement is not met. + +@item __is_class (type) +If @code{type} is a cv class type, and not a union type +([basic.compound]) the the trait is true, else it is false. + +@item __is_empty (type) +If @code{__is_class (type)} is false then the trait is false. +Otherwise @code{type} is considered empty if and only if: @code{type} +has no non-static data members, or all non-static data members, if +any, are bit-fields of lenght 0, and @code{type} has no virtual +members, and @code{type} has no virtual base classes, and @code{type} +has no base classes @code{base_type} for which +@code{__is_empty (base_type)} is false. Requires: @code{type} shall +be a complete type, an array type of unknown bound, or is a +@code{void} type. + +@item __is_enum (type) +If @code{type} is a cv enumeration type ([basic.compound]) the the trait is +true, else it is false. + +@item __is_pod (type) +If @code{type} is a cv POD type ([basic.types]) then the trait is true, +else it is false. Requires: @code{type} shall be a complete type, +an array type of unknown bound, or is a @code{void} type. + +@item __is_polymorphic (type) +If @code{type} is a polymorphic class ([class.virtual]) then the trait +is true, else it is false. Requires: @code{type} shall be a complete +type, an array type of unknown bound, or is a @code{void} type. + +@item __is_union (type) +If @code{type} is a cv union type ([basic.compound]) the the trait is +true, else it is false. + +@end table + @node Java Exceptions @section Java Exceptions diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 8693f9f1264..a1af0d59ca3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,26 @@ +2007-03-30 Paolo Carlini <pcarlini@suse.de> + + PR c++/26099 + * g++.dg/ext/is_base_of.C: New. + * g++.dg/ext/has_virtual_destructor.C: New. + * g++.dg/ext/is_polymorphic.C: New. + * g++.dg/ext/is_base_of_diagnostic.C: New. + * g++.dg/ext/is_enum.C: New. + * g++.dg/ext/has_nothrow_assign.C: New. + * g++.dg/ext/has_nothrow_constructor.C: New. + * g++.dg/ext/is_empty.C: New. + * g++.dg/ext/has_trivial_copy.C: New. + * g++.dg/ext/has_trivial_assign.C: New. + * g++.dg/ext/is_abstract.C: New. + * g++.dg/ext/is_pod.C: New. + * g++.dg/ext/has_nothrow_copy.C: New. + * g++.dg/ext/is_class.C: New. + * g++.dg/ext/has_trivial_constructor.C: New. + * g++.dg/ext/is_union.C: New. + * g++.dg/ext/has_trivial_destructor.C: New. + * g++.dg/tree-ssa/pr22444.C: Adjust, avoid __is_pod. + * g++.dg/template/crash43.C: Likewise. + 2007-03-29 Dirk Mueller <dmueller@suse.de> * g++.dg/warn/pedantic2.C: New testcase. diff --git a/gcc/testsuite/g++.dg/ext/has_nothrow_assign.C b/gcc/testsuite/g++.dg/ext/has_nothrow_assign.C new file mode 100644 index 00000000000..f8790825351 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/has_nothrow_assign.C @@ -0,0 +1,152 @@ +// { dg-do "run" } +#include <cassert> + +struct A +{ + double a; + double b; +}; + +struct B +{ + A a; +}; + +struct C +: public A { }; + +struct D +{ + D& operator=(const D&) throw() { return *this; } +}; + +struct E +{ + E& operator=(const E&) throw(int) { return *this; } +}; + +struct E1 +{ + E1& operator=(const E1&) throw(int) { throw int(); return *this; } +}; + +struct F +{ + F() throw(int) { } +}; + +struct G +{ + G() throw(int) { throw int(); } +}; + +struct H +{ + H& operator=(H&) throw(int) { return *this; } +}; + +struct H1 +{ + H1& operator=(H1&) throw(int) { throw int(); return *this; } +}; + +struct I +{ + I& operator=(I&) throw(int) { return *this; } + I& operator=(const I&) throw() { return *this; } +}; + +struct I1 +{ + I1& operator=(I1&) throw(int) { throw int(); return *this; } + I1& operator=(const I1&) throw() { return *this; } +}; + +struct J +{ + J& operator=(J&) throw() { return *this; } + J& operator=(const J&) throw() { return *this; } + J& operator=(volatile J&) throw() { return *this; } + J& operator=(const volatile J&) throw() { return *this; } +}; + +struct K +{ + K& operator=(K&) throw() { return *this; } +}; + +struct L +{ + L& operator=(const L&) throw() { return *this; } +}; + +template<typename T> + bool + f() + { return __has_nothrow_assign(T); } + +template<typename T> + class My + { + public: + bool + f() + { return !!__has_nothrow_assign(T); } + }; + +template<typename T> + class My2 + { + public: + static const bool trait = __has_nothrow_assign(T); + }; + +template<typename T> + const bool My2<T>::trait; + +template<typename T, bool b = __has_nothrow_assign(T)> + struct My3_help + { static const bool trait = b; }; + +template<typename T, bool b> + const bool My3_help<T, b>::trait; + +template<typename T> + class My3 + { + public: + bool + f() + { return My3_help<T>::trait; } + }; + +#define PTEST(T) (__has_nothrow_assign(T) && f<T>() \ + && My<T>().f() && My2<T>::trait && My3<T>().f()) + +#define NTEST(T) (!__has_nothrow_assign(T) && !f<T>() \ + && !My<T>().f() && !My2<T>::trait && !My3<T>().f()) + +int main() +{ + assert (PTEST (int)); + assert (NTEST (int (int))); + assert (NTEST (void)); + assert (PTEST (A)); + assert (PTEST (B)); + assert (PTEST (C)); + assert (NTEST (C[])); + assert (PTEST (D)); + assert (PTEST (E)); + assert (NTEST (E1)); + assert (PTEST (F)); + assert (PTEST (G)); + assert (PTEST (H)); + assert (NTEST (H1)); + assert (PTEST (I)); + assert (NTEST (I1)); + assert (PTEST (J)); + assert (NTEST (const K)); + assert (PTEST (const L)); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/has_nothrow_constructor.C b/gcc/testsuite/g++.dg/ext/has_nothrow_constructor.C new file mode 100644 index 00000000000..04c2706dad6 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/has_nothrow_constructor.C @@ -0,0 +1,106 @@ +// { dg-do "run" } +#include <cassert> + +struct A +{ + double a; + double b; +}; + +struct B +{ + A a; +}; + +struct C +: public A { }; + +struct D +{ + D() throw() { } +}; + +struct E +{ + E() throw(int) { } +}; + +struct E1 +{ + E1() throw(int) { throw int(); } +}; + +struct F +{ + F(const F&) throw() { } +}; + +struct G +{ + G(const G&) throw(int) { throw int(); } +}; + +template<typename T> + bool + f() + { return __has_nothrow_constructor(T); } + +template<typename T> + class My + { + public: + bool + f() + { return !!__has_nothrow_constructor(T); } + }; + +template<typename T> + class My2 + { + public: + static const bool trait = __has_nothrow_constructor(T); + }; + +template<typename T> + const bool My2<T>::trait; + + +template<typename T, bool b = __has_nothrow_constructor(T)> + struct My3_help + { static const bool trait = b; }; + +template<typename T, bool b> + const bool My3_help<T, b>::trait; + +template<typename T> + class My3 + { + public: + bool + f() + { return My3_help<T>::trait; } + }; + +#define PTEST(T) (__has_nothrow_constructor(T) && f<T>() \ + && My<T>().f() && My2<T>::trait && My3<T>().f()) + +#define NTEST(T) (!__has_nothrow_constructor(T) && !f<T>() \ + && !My<T>().f() && !My2<T>::trait && !My3<T>().f()) + +int main() +{ + assert (PTEST (int)); + assert (NTEST (int (int))); + assert (NTEST (void)); + assert (PTEST (A)); + assert (PTEST (B)); + assert (PTEST (C)); + assert (PTEST (C[])); + assert (PTEST (D)); + assert (PTEST (E)); + assert (NTEST (E1)); + assert (NTEST (F)); + assert (NTEST (G)); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/has_nothrow_copy.C b/gcc/testsuite/g++.dg/ext/has_nothrow_copy.C new file mode 100644 index 00000000000..5ac727c3353 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/has_nothrow_copy.C @@ -0,0 +1,140 @@ +// { dg-do "run" } +#include <cassert> + +struct A +{ + double a; + double b; +}; + +struct B +{ + A a; +}; + +struct C +: public A { }; + +struct D +{ + D(const D&) throw() { } +}; + +struct E +{ + E(const E&) throw(int) { } +}; + +struct E1 +{ + E1(const E1&) throw(int) { throw int(); } +}; + +struct F +{ + F() throw() { } +}; + +struct G +{ + G() throw(int) { throw int(); } +}; + +struct H +{ + H(H&) throw(int) { } +}; + +struct H1 +{ + H1(H1&) throw(int) { throw int(); } +}; + +struct I +{ + I(I&) throw(int) { } + I(const I&) throw() { } +}; + +struct I1 +{ + I1(I1&) throw(int) { throw int(); } + I1(const I1&) throw() { } +}; + +struct J +{ + J(J&) throw() { } + J(const J&) throw() { } + J(volatile J&) throw() { } + J(const volatile J&) throw() { } +}; + +template<typename T> + bool + f() + { return __has_nothrow_copy(T); } + +template<typename T> + class My + { + public: + bool + f() + { return !!__has_nothrow_copy(T); } + }; + +template<typename T> + class My2 + { + public: + static const bool trait = __has_nothrow_copy(T); + }; + +template<typename T> + const bool My2<T>::trait; + +template<typename T, bool b = __has_nothrow_copy(T)> + struct My3_help + { static const bool trait = b; }; + +template<typename T, bool b> + const bool My3_help<T, b>::trait; + +template<typename T> + class My3 + { + public: + bool + f() + { return My3_help<T>::trait; } + }; + +#define PTEST(T) (__has_nothrow_copy(T) && f<T>() \ + && My<T>().f() && My2<T>::trait && My3<T>().f()) + +#define NTEST(T) (!__has_nothrow_copy(T) && !f<T>() \ + && !My<T>().f() && !My2<T>::trait && !My3<T>().f()) + +int main() +{ + assert (PTEST (int)); + assert (NTEST (int (int))); + assert (NTEST (void)); + assert (PTEST (A)); + assert (PTEST (B)); + assert (PTEST (C)); + assert (NTEST (C[])); + assert (PTEST (D)); + assert (PTEST (E)); + assert (NTEST (E1)); + assert (PTEST (F)); + assert (PTEST (G)); + assert (PTEST (H)); + assert (NTEST (H1)); + assert (PTEST (I)); + assert (NTEST (I1)); + assert (PTEST (J)); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/has_trivial_assign.C b/gcc/testsuite/g++.dg/ext/has_trivial_assign.C new file mode 100644 index 00000000000..97bcbf23997 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/has_trivial_assign.C @@ -0,0 +1,106 @@ +// { dg-do "run" } +#include <cassert> + +struct A +{ + double a; + double b; +}; + +union U +{ + double a; + double b; +}; + +struct B +{ + B& operator=(const B&) { return *this;} +}; + +struct C +{ + virtual int f() { return 1; } +}; + +struct D +: public B { }; + +struct E +: public A { }; + +struct F +{ + A a; +}; + +struct G +{ + B b; +}; + +template<typename T> + bool + f() + { return __has_trivial_assign(T); } + +template<typename T> + class My + { + public: + bool + f() + { return !!__has_trivial_assign(T); } + }; + +template<typename T> + class My2 + { + public: + static const bool trait = __has_trivial_assign(T); + }; + +template<typename T> + const bool My2<T>::trait; + +template<typename T, bool b = __has_trivial_assign(T)> + struct My3_help + { static const bool trait = b; }; + +template<typename T, bool b> + const bool My3_help<T, b>::trait; + +template<typename T> + class My3 + { + public: + bool + f() + { return My3_help<T>::trait; } + }; + +#define PTEST(T) (__has_trivial_assign(T) && f<T>() \ + && My<T>().f() && My2<T>::trait && My3<T>().f()) + +#define NTEST(T) (!__has_trivial_assign(T) && !f<T>() \ + && !My<T>().f() && !My2<T>::trait && !My3<T>().f()) + +int main() +{ + assert (PTEST (int)); + assert (NTEST (int (int))); + assert (NTEST (void)); + assert (PTEST (A)); + assert (PTEST (U)); + assert (NTEST (B)); + assert (NTEST (C)); + assert (NTEST (D)); + assert (PTEST (E)); + assert (NTEST (E[])); + assert (PTEST (F)); + assert (NTEST (G)); + assert (NTEST (const A)); + assert (NTEST (A&)); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/has_trivial_constructor.C b/gcc/testsuite/g++.dg/ext/has_trivial_constructor.C new file mode 100644 index 00000000000..cc747391b32 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/has_trivial_constructor.C @@ -0,0 +1,98 @@ +// { dg-do "run" } +#include <cassert> + +struct A +{ + double a; + double b; +}; + +union U +{ + double a; + double b; +}; + +struct B +{ + B() { } +}; + +struct C +: public B { }; + +struct D +: public A { }; + +struct E +{ + A a; +}; + +struct F +{ + B b; +}; + +template<typename T> + bool + f() + { return __has_trivial_constructor(T); } + +template<typename T> + class My + { + public: + bool + f() + { return !!__has_trivial_constructor(T); } + }; + +template<typename T> + class My2 + { + public: + static const bool trait = __has_trivial_constructor(T); + }; + +template<typename T> + const bool My2<T>::trait; + +template<typename T, bool b = __has_trivial_constructor(T)> + struct My3_help + { static const bool trait = b; }; + +template<typename T, bool b> + const bool My3_help<T, b>::trait; + +template<typename T> + class My3 + { + public: + bool + f() + { return My3_help<T>::trait; } + }; + +#define PTEST(T) (__has_trivial_constructor(T) && f<T>() \ + && My<T>().f() && My2<T>::trait && My3<T>().f()) + +#define NTEST(T) (!__has_trivial_constructor(T) && !f<T>() \ + && !My<T>().f() && !My2<T>::trait && !My3<T>().f()) + +int main() +{ + assert (PTEST (int)); + assert (NTEST (int (int))); + assert (NTEST (void)); + assert (PTEST (A)); + assert (PTEST (U)); + assert (NTEST (B)); + assert (NTEST (C)); + assert (PTEST (D)); + assert (PTEST (D[])); + assert (PTEST (E)); + assert (NTEST (F)); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/has_trivial_copy.C b/gcc/testsuite/g++.dg/ext/has_trivial_copy.C new file mode 100644 index 00000000000..ca2eeec4bdb --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/has_trivial_copy.C @@ -0,0 +1,105 @@ +// { dg-do "run" } +#include <cassert> + +struct A +{ + double a; + double b; +}; + +union U +{ + double a; + double b; +}; + +struct B +{ + B(const B&) { } +}; + +struct C +{ + virtual int f() { return 1; } +}; + +struct D +: public B { }; + +struct E +: public A { }; + +struct F +{ + A a; +}; + +struct G +{ + B b; +}; + +template<typename T> + bool + f() + { return __has_trivial_copy(T); } + +template<typename T> + class My + { + public: + bool + f() + { return !!__has_trivial_copy(T); } + }; + +template<typename T> + class My2 + { + public: + static const bool trait = __has_trivial_copy(T); + }; + +template<typename T> + const bool My2<T>::trait; + +template<typename T, bool b = __has_trivial_copy(T)> + struct My3_help + { static const bool trait = b; }; + +template<typename T, bool b> + const bool My3_help<T, b>::trait; + +template<typename T> + class My3 + { + public: + bool + f() + { return My3_help<T>::trait; } + }; + +#define PTEST(T) (__has_trivial_copy(T) && f<T>() \ + && My<T>().f() && My2<T>::trait && My3<T>().f()) + +#define NTEST(T) (!__has_trivial_copy(T) && !f<T>() \ + && !My<T>().f() && !My2<T>::trait && !My3<T>().f()) + +int main() +{ + assert (PTEST (int)); + assert (NTEST (int (int))); + assert (NTEST (void)); + assert (PTEST (A)); + assert (PTEST (U)); + assert (NTEST (B)); + assert (NTEST (C)); + assert (NTEST (D)); + assert (PTEST (E)); + assert (NTEST (E[])); + assert (PTEST (F)); + assert (NTEST (G)); + assert (PTEST (B&)); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/has_trivial_destructor.C b/gcc/testsuite/g++.dg/ext/has_trivial_destructor.C new file mode 100644 index 00000000000..719f05fd7a5 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/has_trivial_destructor.C @@ -0,0 +1,86 @@ +// { dg-do "run" } +#include <cassert> + +struct A +{ + double a; + double b; +}; + +union U +{ + double a; + double b; +}; + +struct B +{ + ~B() { } +}; + +struct C +: public B { }; + +struct D +: public A { }; + +template<typename T> + bool + f() + { return __has_trivial_destructor(T); } + +template<typename T> + class My + { + public: + bool + f() + { return !!__has_trivial_destructor(T); } + }; + +template<typename T> + class My2 + { + public: + static const bool trait = __has_trivial_destructor(T); + }; + +template<typename T> + const bool My2<T>::trait; + +template<typename T, bool b = __has_trivial_destructor(T)> + struct My3_help + { static const bool trait = b; }; + +template<typename T, bool b> + const bool My3_help<T, b>::trait; + +template<typename T> + class My3 + { + public: + bool + f() + { return My3_help<T>::trait; } + }; + +#define PTEST(T) (__has_trivial_destructor(T) && f<T>() \ + && My<T>().f() && My2<T>::trait && My3<T>().f()) + +#define NTEST(T) (!__has_trivial_destructor(T) && !f<T>() \ + && !My<T>().f() && !My2<T>::trait && !My3<T>().f()) + +int main() +{ + assert (PTEST (int)); + assert (NTEST (int (int))); + assert (NTEST (void)); + assert (PTEST (A)); + assert (PTEST (U)); + assert (NTEST (B)); + assert (NTEST (C)); + assert (PTEST (D)); + assert (PTEST (D[])); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/has_virtual_destructor.C b/gcc/testsuite/g++.dg/ext/has_virtual_destructor.C new file mode 100644 index 00000000000..c263a94fd04 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/has_virtual_destructor.C @@ -0,0 +1,89 @@ +// { dg-do "run" } +#include <cassert> +#include <exception> + +struct A +{ + double a; + double b; +}; + +union U +{ + double a; + double b; +}; + +class B +{ + virtual ~B() { } +}; + +class C +: public B { }; + +class D +{ + ~D() { } +}; + +template<typename T> + bool + f() + { return __has_virtual_destructor(T); } + +template<typename T> + class My + { + public: + bool + f() + { return !!__has_virtual_destructor(T); } + }; + +template<typename T> + class My2 + { + public: + static const bool trait = __has_virtual_destructor(T); + }; + +template<typename T> + const bool My2<T>::trait; + +template<typename T, bool b = __has_virtual_destructor(T)> + struct My3_help + { static const bool trait = b; }; + +template<typename T, bool b> + const bool My3_help<T, b>::trait; + +template<typename T> + class My3 + { + public: + bool + f() + { return My3_help<T>::trait; } + }; + +#define PTEST(T) (__has_virtual_destructor(T) && f<T>() \ + && My<T>().f() && My2<T>::trait && My3<T>().f()) + +#define NTEST(T) (!__has_virtual_destructor(T) && !f<T>() \ + && !My<T>().f() && !My2<T>::trait && !My3<T>().f()) + +int main() +{ + assert (NTEST (int)); + assert (NTEST (void)); + assert (PTEST (std::exception)); + assert (NTEST (A)); + assert (NTEST (U)); + assert (PTEST (B)); + assert (PTEST (C)); + assert (NTEST (C[])); + assert (NTEST (D)); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/is_abstract.C b/gcc/testsuite/g++.dg/ext/is_abstract.C new file mode 100644 index 00000000000..919f928fd9a --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_abstract.C @@ -0,0 +1,89 @@ +// { dg-do "run" } +#include <cassert> + +struct A +{ + double a; + double b; +}; + +union U +{ + double a; + double b; +}; + +class B +{ + B(); +}; + +class C +{ + virtual void rotate(int) = 0; +}; + +class D +{ + virtual void rotate(int) { } +}; + +template<typename T> + bool + f() + { return __is_abstract(T); } + +template<typename T> + class My + { + public: + bool + f() + { return !!__is_abstract(T); } + }; + +template<typename T> + class My2 + { + public: + static const bool trait = __is_abstract(T); + }; + +template<typename T> + const bool My2<T>::trait; + +template<typename T, bool b = __is_abstract(T)> + struct My3_help + { static const bool trait = b; }; + +template<typename T, bool b> + const bool My3_help<T, b>::trait; + +template<typename T> + class My3 + { + public: + bool + f() + { return My3_help<T>::trait; } + }; + +#define PTEST(T) (__is_abstract(T) && f<T>() \ + && My<T>().f() && My2<T>::trait && My3<T>().f()) + +#define NTEST(T) (!__is_abstract(T) && !f<T>() \ + && !My<T>().f() && !My2<T>::trait && !My3<T>().f()) + +int main() +{ + assert (NTEST (int)); + assert (NTEST (void)); + assert (NTEST (A)); + assert (NTEST (U)); + assert (NTEST (B)); + assert (NTEST (B[])); + assert (PTEST (C)); + assert (NTEST (D)); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/is_base_of.C b/gcc/testsuite/g++.dg/ext/is_base_of.C new file mode 100644 index 00000000000..52ccff10009 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_base_of.C @@ -0,0 +1,94 @@ +// { dg-do "run" } +#include <cassert> + +class A1 +{ + double a; + double b; +}; + +class A2 +{ + double a; + double b; +}; + +class B +: private A1 { }; + +class C +: private A1, private A2 { }; + +union U +{ + double a; + double b; +}; + +template<typename T, typename U> + bool + f() + { return __is_base_of(T, U); } + +template<typename T, typename U> + class My + { + public: + bool + f() + { return !!__is_base_of(T, U); } + }; + +template<typename T, typename U> + class My2 + { + public: + static const bool trait = __is_base_of(T, U); + }; + +template<typename T, typename U> + const bool My2<T, U>::trait; + +template<typename T, typename U, bool b = __is_base_of(T, U)> + struct My3_help + { static const bool trait = b; }; + +template<typename T, typename U, bool b> + const bool My3_help<T, U, b>::trait; + +template<typename T, typename U> + class My3 + { + public: + bool + f() + { return My3_help<T, U>::trait; } + }; + +#define PTEST(T, U) (__is_base_of(T, U) && f<T, U>() \ + && My<T, U>().f() && My2<T, U>::trait && My3<T, U>().f()) + +#define NTEST(T, U) (!__is_base_of(T, U) && !f<T, U>() \ + && !My<T, U>().f() && !My2<T, U>::trait && !My3<T, U>().f()) + +int main() +{ + assert (NTEST (int, A1)); + assert (NTEST (A1, void)); + assert (PTEST (A1, A1)); + assert (NTEST (A1*, A1*)); + assert (NTEST (A1&, A1&)); + assert (PTEST (A1, B)); + assert (NTEST (B, A1)); + assert (PTEST (A1, C)); + assert (PTEST (A2, C)); + assert (NTEST (C, A1)); + assert (PTEST (A1, const B)); + assert (NTEST (const B, A1)); + assert (PTEST (A1, volatile C)); + assert (PTEST (volatile A2, const C)); + assert (NTEST (const volatile C, A1)); + assert (NTEST (U, U)); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/is_base_of_diagnostic.C b/gcc/testsuite/g++.dg/ext/is_base_of_diagnostic.C new file mode 100644 index 00000000000..8cb1ce38f63 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_base_of_diagnostic.C @@ -0,0 +1,15 @@ +class A +{ }; + +class B; + +union C +{ }; + +union D; + +void f() +{ + __is_base_of(A, B); // { dg-error "incomplete type" } + __is_base_of(C, D); +} diff --git a/gcc/testsuite/g++.dg/ext/is_class.C b/gcc/testsuite/g++.dg/ext/is_class.C new file mode 100644 index 00000000000..6f0c8a5ba5b --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_class.C @@ -0,0 +1,76 @@ +// { dg-do "run" } +#include <cassert> + +struct A +{ + double a; + double b; +}; + +class B +{ + B() { } +}; + +union U +{ + double a; + double b; +}; + +template<typename T> + bool + f() + { return __is_class(T); } + +template<typename T> + class My + { + public: + bool + f() + { return !!__is_class(T); } + }; + +template<typename T> + class My2 + { + public: + static const bool trait = __is_class(T); + }; + +template<typename T> + const bool My2<T>::trait; + +template<typename T, bool b = __is_class(T)> + struct My3_help + { static const bool trait = b; }; + +template<typename T, bool b> + const bool My3_help<T, b>::trait; + +template<typename T> + class My3 + { + public: + bool + f() + { return My3_help<T>::trait; } + }; + +#define PTEST(T) (__is_class(T) && f<T>() \ + && My<T>().f() && My2<T>::trait && My3<T>().f()) + +#define NTEST(T) (!__is_class(T) && !f<T>() \ + && !My<T>().f() && !My2<T>::trait && !My3<T>().f()) + +int main() +{ + assert (NTEST (int)); + assert (NTEST (void)); + assert (PTEST (A)); + assert (PTEST (B)); + assert (NTEST (U)); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/is_empty.C b/gcc/testsuite/g++.dg/ext/is_empty.C new file mode 100644 index 00000000000..86a0312c258 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_empty.C @@ -0,0 +1,78 @@ +// { dg-do "run" } +#include <cassert> + +struct A +{ + double a; + double b; +}; + +struct B +{ + virtual ~B() { } +}; + +class C +{ }; + +union U +{ }; + +template<typename T> + bool + f() + { return __is_empty(T); } + +template<typename T> + class My + { + public: + bool + f() + { return !!__is_empty(T); } + }; + +template<typename T> + class My2 + { + public: + static const bool trait = __is_empty(T); + }; + +template<typename T> + const bool My2<T>::trait; + +template<typename T, bool b = __is_empty(T)> + struct My3_help + { static const bool trait = b; }; + +template<typename T, bool b> + const bool My3_help<T, b>::trait; + +template<typename T> + class My3 + { + public: + bool + f() + { return My3_help<T>::trait; } + }; + +#define PTEST(T) (__is_empty(T) && f<T>() \ + && My<T>().f() && My2<T>::trait && My3<T>().f()) + +#define NTEST(T) (!__is_empty(T) && !f<T>() \ + && !My<T>().f() && !My2<T>::trait && !My3<T>().f()) + +int main() +{ + assert (NTEST (int)); + assert (NTEST (void)); + assert (NTEST (A)); + assert (NTEST (B)); + assert (PTEST (C)); + assert (NTEST (C[])); + assert (NTEST (U)); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/is_enum.C b/gcc/testsuite/g++.dg/ext/is_enum.C new file mode 100644 index 00000000000..7dc061cec76 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_enum.C @@ -0,0 +1,73 @@ +// { dg-do "run" } +#include <cassert> + +struct A +{ + double a; + double b; +}; + +class B +{ }; + +enum E +{ + e0 +}; + +template<typename T> + bool + f() + { return __is_enum(T); } + +template<typename T> + class My + { + public: + bool + f() + { return !!__is_enum(T); } + }; + +template<typename T> + class My2 + { + public: + static const bool trait = __is_enum(T); + }; + +template<typename T> + const bool My2<T>::trait; + +template<typename T, bool b = __is_enum(T)> + struct My3_help + { static const bool trait = b; }; + +template<typename T, bool b> + const bool My3_help<T, b>::trait; + +template<typename T> + class My3 + { + public: + bool + f() + { return My3_help<T>::trait; } + }; + +#define PTEST(T) (__is_enum(T) && f<T>() \ + && My<T>().f() && My2<T>::trait && My3<T>().f()) + +#define NTEST(T) (!__is_enum(T) && !f<T>() \ + && !My<T>().f() && !My2<T>::trait && !My3<T>().f()) + +int main() +{ + assert (NTEST (int)); + assert (NTEST (void)); + assert (NTEST (A)); + assert (NTEST (B)); + assert (PTEST (E)); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/is_pod.C b/gcc/testsuite/g++.dg/ext/is_pod.C new file mode 100644 index 00000000000..5c1f0cd3bcd --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_pod.C @@ -0,0 +1,75 @@ +// { dg-do "run" } +#include <cassert> + +struct A +{ + double a; + double b; +}; + +struct B +{ + B() { } +}; + +struct C +: public A { }; + +template<typename T> + bool + f() + { return __is_pod(T); } + +template<typename T> + class My + { + public: + bool + f() + { return !!__is_pod(T); } + }; + +template<typename T> + class My2 + { + public: + static const bool trait = __is_pod(T); + }; + +template<typename T> + const bool My2<T>::trait; + +template<typename T, bool b = __is_pod(T)> + struct My3_help + { static const bool trait = b; }; + +template<typename T, bool b> + const bool My3_help<T, b>::trait; + +template<typename T> + class My3 + { + public: + bool + f() + { return My3_help<T>::trait; } + }; + +#define PTEST(T) (__is_pod(T) && f<T>() \ + && My<T>().f() && My2<T>::trait && My3<T>().f()) + +#define NTEST(T) (!__is_pod(T) && !f<T>() \ + && !My<T>().f() && !My2<T>::trait && !My3<T>().f()) + +int main() +{ + assert (PTEST (int)); + assert (NTEST (void)); + assert (PTEST (A)); + assert (PTEST (A[])); + assert (NTEST (B)); + assert (NTEST (C)); + assert (NTEST (C[])); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/is_polymorphic.C b/gcc/testsuite/g++.dg/ext/is_polymorphic.C new file mode 100644 index 00000000000..ded071b1d02 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_polymorphic.C @@ -0,0 +1,83 @@ +// { dg-do "run" } +#include <cassert> +#include <exception> + +struct A +{ + double a; + double b; +}; + +class B +{ + virtual void rotate(int) { } +}; + +class C +: public B { }; + +union U +{ + double a; + double b; +}; + +template<typename T> + bool + f() + { return __is_polymorphic(T); } + +template<typename T> + class My + { + public: + bool + f() + { return !!__is_polymorphic(T); } + }; + +template<typename T> + class My2 + { + public: + static const bool trait = __is_polymorphic(T); + }; + +template<typename T> + const bool My2<T>::trait; + +template<typename T, bool b = __is_polymorphic(T)> + struct My3_help + { static const bool trait = b; }; + +template<typename T, bool b> + const bool My3_help<T, b>::trait; + +template<typename T> + class My3 + { + public: + bool + f() + { return My3_help<T>::trait; } + }; + +#define PTEST(T) (__is_polymorphic(T) && f<T>() \ + && My<T>().f() && My2<T>::trait && My3<T>().f()) + +#define NTEST(T) (!__is_polymorphic(T) && !f<T>() \ + && !My<T>().f() && !My2<T>::trait && !My3<T>().f()) + +int main() +{ + assert (NTEST (int)); + assert (NTEST (void)); + assert (PTEST (std::exception)); + assert (NTEST (A)); + assert (PTEST (B)); + assert (PTEST (C)); + assert (NTEST (C[])); + assert (NTEST (U)); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/ext/is_union.C b/gcc/testsuite/g++.dg/ext/is_union.C new file mode 100644 index 00000000000..acba0bb60f2 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_union.C @@ -0,0 +1,76 @@ +// { dg-do "run" } +#include <cassert> + +struct A +{ + double a; + double b; +}; + +class B +{ + B() { } +}; + +union U +{ + double a; + double b; +}; + +template<typename T> + bool + f() + { return __is_union(T); } + +template<typename T> + class My + { + public: + bool + f() + { return !!__is_union(T); } + }; + +template<typename T> + class My2 + { + public: + static const bool trait = __is_union(T); + }; + +template<typename T> + const bool My2<T>::trait; + +template<typename T, bool b = __is_union(T)> + struct My3_help + { static const bool trait = b; }; + +template<typename T, bool b> + const bool My3_help<T, b>::trait; + +template<typename T> + class My3 + { + public: + bool + f() + { return My3_help<T>::trait; } + }; + +#define PTEST(T) (__is_union(T) && f<T>() \ + && My<T>().f() && My2<T>::trait && My3<T>().f()) + +#define NTEST(T) (!__is_union(T) && !f<T>() \ + && !My<T>().f() && !My2<T>::trait && !My3<T>().f()) + +int main() +{ + assert (NTEST (int)); + assert (NTEST (void)); + assert (NTEST (A)); + assert (NTEST (B)); + assert (PTEST (U)); + + return 0; +} diff --git a/gcc/testsuite/g++.dg/template/crash43.C b/gcc/testsuite/g++.dg/template/crash43.C index 1261c365058..cbb1221b355 100644 --- a/gcc/testsuite/g++.dg/template/crash43.C +++ b/gcc/testsuite/g++.dg/template/crash43.C @@ -2,7 +2,7 @@ extern "C" { template<typename _Tp> // { dg-error "C" } - struct __is_pod { + struct ___is_pod { enum { __value = (sizeof(__gnu_internal::__test_type<_Tp>(0)))}; // { dg-error "declared|expected" } diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr22444.C b/gcc/testsuite/g++.dg/tree-ssa/pr22444.C index f37c7f6f12e..2cc84bb9d1e 100644 --- a/gcc/testsuite/g++.dg/tree-ssa/pr22444.C +++ b/gcc/testsuite/g++.dg/tree-ssa/pr22444.C @@ -22,7 +22,7 @@ namespace __gnu_internal } namespace std { - template<typename _Tp> struct __is_pod + template<typename _Tp> struct ___is_pod { enum { __value = (sizeof(__gnu_internal::__test_type<_Tp>(0))!= sizeof(__gnu_internal::__one)) }; }; @@ -111,7 +111,7 @@ namespace std typedef _Val value_type; typedef value_type* pointer; typedef _Rb_tree_node* _Link_type; - template<typename _Key_compare, bool _Is_pod_comparator = std::__is_pod<_Key_compare>::__value> struct _Rb_tree_impl + template<typename _Key_compare, bool _Is_pod_comparator = std::___is_pod<_Key_compare>::__value> struct _Rb_tree_impl : _Node_allocator { _Rb_tree_node_base _M_header; diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 7483907ac0d..a6ab09b72fe 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,14 @@ 2007-03-30 Paolo Carlini <pcarlini@suse.de> + PR c++/26099 + * include/bits/cpp_type_traits.h (struct __is_pod, struct __is_empty): + Remove. + * include/bits/valarray_array.h: Adjust. + * include/bits/allocator.h: Likewise. + * include/bits/stl_tree.h: Likewise. + +2007-03-30 Paolo Carlini <pcarlini@suse.de> + PR libstdc++/31401 * include/bits/basic_string.tcc (find(const _CharT*, size_type, size_type)): Avoid unsigned overflow. diff --git a/libstdc++-v3/include/bits/allocator.h b/libstdc++-v3/include/bits/allocator.h index 43939c14fa7..94f43ce23f3 100644 --- a/libstdc++-v3/include/bits/allocator.h +++ b/libstdc++-v3/include/bits/allocator.h @@ -1,6 +1,6 @@ // Allocators -*- C++ -*- -// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 +// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 // Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free @@ -132,7 +132,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std) #undef __glibcxx_base_allocator // To implement Option 3 of DR 431. - template<typename _Alloc, bool = std::__is_empty<_Alloc>::__value> + template<typename _Alloc, bool = __is_empty(_Alloc)> struct __alloc_swap { static void _S_do_it(_Alloc&, _Alloc&) { } }; diff --git a/libstdc++-v3/include/bits/cpp_type_traits.h b/libstdc++-v3/include/bits/cpp_type_traits.h index ed9a48a704a..f3c71ac1be5 100644 --- a/libstdc++-v3/include/bits/cpp_type_traits.h +++ b/libstdc++-v3/include/bits/cpp_type_traits.h @@ -1,6 +1,6 @@ // The -*- C++ -*- type traits classes for internal use in libstdc++ -// Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 +// Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 // Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free @@ -80,20 +80,6 @@ _GLIBCXX_END_NAMESPACE _GLIBCXX_BEGIN_NAMESPACE(std) -namespace __detail -{ - // NB: g++ can not compile these if declared within the class - // __is_pod itself. - typedef char __one; - typedef char __two[2]; - - template<typename _Tp> - __one __test_type(int _Tp::*); - template<typename _Tp> - __two& __test_type(...); -} // namespace __detail - - struct __true_type { }; struct __false_type { }; @@ -341,37 +327,6 @@ namespace __detail : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> > { }; - // For the immediate use, the following is a good approximation. - template<typename _Tp> - struct __is_pod - { - enum - { - __value = (sizeof(__detail::__test_type<_Tp>(0)) - != sizeof(__detail::__one)) - }; - }; - - // - // A stripped-down version of std::tr1::is_empty - // - template<typename _Tp> - struct __is_empty - { - private: - template<typename> - struct __first { }; - template<typename _Up> - struct __second - : public _Up { }; - - public: - enum - { - __value = sizeof(__first<_Tp>) == sizeof(__second<_Tp>) - }; - }; - // // For use in std::copy and std::find overloads for streambuf iterators. // diff --git a/libstdc++-v3/include/bits/stl_tree.h b/libstdc++-v3/include/bits/stl_tree.h index 0bb65394718..e80afc808a3 100644 --- a/libstdc++-v3/include/bits/stl_tree.h +++ b/libstdc++-v3/include/bits/stl_tree.h @@ -393,7 +393,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std) protected: template<typename _Key_compare, - bool _Is_pod_comparator = std::__is_pod<_Key_compare>::__value> + bool _Is_pod_comparator = __is_pod(_Key_compare)> struct _Rb_tree_impl : public _Node_allocator { _Key_compare _M_key_compare; diff --git a/libstdc++-v3/include/bits/valarray_array.h b/libstdc++-v3/include/bits/valarray_array.h index a40c880ba8d..12a6b5fd419 100644 --- a/libstdc++-v3/include/bits/valarray_array.h +++ b/libstdc++-v3/include/bits/valarray_array.h @@ -1,6 +1,6 @@ // The template and inlines for the -*- C++ -*- internal _Array helper class. -// Copyright (C) 1997, 1998, 1999, 2000, 2003, 2004, 2005, 2006 +// Copyright (C) 1997, 1998, 1999, 2000, 2003, 2004, 2005, 2006, 2007 // Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free @@ -98,7 +98,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std) inline void __valarray_default_construct(_Tp* __restrict__ __b, _Tp* __restrict__ __e) { - _Array_default_ctor<_Tp, __is_pod<_Tp>::__value>::_S_do_it(__b, __e); + _Array_default_ctor<_Tp, __is_pod(_Tp)>::_S_do_it(__b, __e); } // Turn a raw-memory into an array of _Tp filled with __t @@ -133,7 +133,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std) __valarray_fill_construct(_Tp* __restrict__ __b, _Tp* __restrict__ __e, const _Tp __t) { - _Array_init_ctor<_Tp, __is_pod<_Tp>::__value>::_S_do_it(__b, __e, __t); + _Array_init_ctor<_Tp, __is_pod(_Tp)>::_S_do_it(__b, __e, __t); } // @@ -169,7 +169,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std) const _Tp* __restrict__ __e, _Tp* __restrict__ __o) { - _Array_copy_ctor<_Tp, __is_pod<_Tp>::__value>::_S_do_it(__b, __e, __o); + _Array_copy_ctor<_Tp, __is_pod(_Tp)>::_S_do_it(__b, __e, __o); } // copy-construct raw array [__o, *) from strided array __a[<__n : __s>] @@ -178,7 +178,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std) __valarray_copy_construct (const _Tp* __restrict__ __a, size_t __n, size_t __s, _Tp* __restrict__ __o) { - if (__is_pod<_Tp>::__value) + if (__is_pod(_Tp)) while (__n--) { *__o++ = *__a; @@ -199,7 +199,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std) const size_t* __restrict__ __i, _Tp* __restrict__ __o, size_t __n) { - if (__is_pod<_Tp>::__value) + if (__is_pod(_Tp)) while (__n--) *__o++ = __a[*__i++]; else @@ -212,7 +212,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std) inline void __valarray_destroy_elements(_Tp* __restrict__ __b, _Tp* __restrict__ __e) { - if (!__is_pod<_Tp>::__value) + if (!__is_pod(_Tp)) while (__b != __e) { __b->~_Tp(); @@ -276,7 +276,7 @@ _GLIBCXX_BEGIN_NAMESPACE(std) __valarray_copy(const _Tp* __restrict__ __a, size_t __n, _Tp* __restrict__ __b) { - _Array_copier<_Tp, __is_pod<_Tp>::__value>::_S_do_it(__a, __n, __b); + _Array_copier<_Tp, __is_pod(_Tp)>::_S_do_it(__a, __n, __b); } // Copy strided array __a[<__n : __s>] in plain __b[<__n>] |