]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/26099 (support for type traits is not available)
authorPaolo Carlini <pcarlini@suse.de>
Fri, 30 Mar 2007 19:45:57 +0000 (19:45 +0000)
committerPaolo Carlini <paolo@gcc.gnu.org>
Fri, 30 Mar 2007 19:45:57 +0000 (19:45 +0000)
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:
gcc/ChangeLog
gcc/c-common.h
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-objcp-common.c
gcc/cp/cp-tree.def
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/lex.c
gcc/cp/method.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/cp/tree.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ext/has_nothrow_assign.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/has_nothrow_constructor.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/has_nothrow_copy.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/has_trivial_assign.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/has_trivial_constructor.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/has_trivial_copy.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/has_trivial_destructor.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/has_virtual_destructor.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/is_abstract.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/is_base_of.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/is_base_of_diagnostic.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/is_class.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/is_empty.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/is_enum.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/is_pod.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/is_polymorphic.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/is_union.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/crash43.C
gcc/testsuite/g++.dg/tree-ssa/pr22444.C
libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/allocator.h
libstdc++-v3/include/bits/cpp_type_traits.h
libstdc++-v3/include/bits/stl_tree.h
libstdc++-v3/include/bits/valarray_array.h

index f60049ff6abd0a8a62b2a725b93c1721a562e8bc..de93d5dd1bec8fdf10b9b4227a383f28da7cf47c 100644 (file)
@@ -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...
index b16a02d6b13b598b109ff77fb1e61eff6749db6e..b128e31a0085da7d0d57d4c9a43e313bbd58d209 100644 (file)
@@ -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,
 
index bf5e28c272ef805a92e8adc2a3d106f08a588930..4374e6b7db0a3818f785da12b2d7b2f11b0ec93e 100644 (file)
@@ -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.
index 22c9439aa1ad5bd72071b6be509eb72bf1813d0c..5e5bcbf895c40eb9aaf4215a7f78b13c50a9d2d2 100644 (file)
@@ -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,
index 7b1841e3fa74dd75991fcf199cab8e7ffec6552f..af8eb94cf4945e61d90ecbd410cc0c633aea4e22 100644 (file)
@@ -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 ();
     }
index a2a0c03b79a46936079599659c243e12064cafac..a0feb30e001cc154ae155396a56eeba5156601f4 100644 (file)
@@ -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
index 95945b33837dd7acbf522fc617b6f0e532cfa837..2d20246a24441e5c8e50d5d074f85fd6e88acf24 100644 (file)
@@ -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;
 };
 
 \f
@@ -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,
index 0315f01241d05bcde3a0e9b94910674095f667cb..833e7b8e43a31304a60240701cc53d9ce6997fb6 100644 (file)
@@ -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;
     }
 }
index 2f619be9645f710e9b4b685ff522f02f99449697..080a843df413bc8106e2f8f58e8cbd079d3458c4 100644 (file)
@@ -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 },
index 4dff5b9026aaea04d4164eae21beaf9ba7c39266..03078a3f017dfd805d54ebfe4e52c20135ad6ed1 100644 (file)
@@ -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_;
index dcd73f06ab510e44541e0ce6ccb075cb4e610146..4fc1a629d5c09d89efb25a27d77d28d8df1e144b 100644 (file)
@@ -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.
index 1e6c04408e22416f5bec7cbb2c262a027059b32d..f1e6b18ca24cb725679f07442f4576e271232889 100644 (file)
@@ -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
index e2603531e881e796aa3d6ae9bc18278ca8a8b5e2..bfb84ec5d5f83a16c1ef0edeb062b9a805e7b682 100644 (file)
@@ -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"
index 7fd6664a8c61a4ce5e0d9f371d5e9aab3d96bfc1..78a3520dd98b8c7f1e2ef192db31cdec2c2cf116 100644 (file)
@@ -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;
     }
index d01e5fab3a1b8d493e75776914825fd3a26003d7..ccdc99516348f919ce4d07ee446188efcd9c612d 100644 (file)
@@ -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
 
index 8693f9f12648f532806a653fe7b19430ff41fbd4..a1af0d59ca342188cd48fa194f83149f85ad7551 100644 (file)
@@ -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 (file)
index 0000000..f879082
--- /dev/null
@@ -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 (file)
index 0000000..04c2706
--- /dev/null
@@ -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 (file)
index 0000000..5ac727c
--- /dev/null
@@ -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 (file)
index 0000000..97bcbf2
--- /dev/null
@@ -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 (file)
index 0000000..cc74739
--- /dev/null
@@ -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 (file)
index 0000000..ca2eeec
--- /dev/null
@@ -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 (file)
index 0000000..719f05f
--- /dev/null
@@ -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 (file)
index 0000000..c263a94
--- /dev/null
@@ -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 (file)
index 0000000..919f928
--- /dev/null
@@ -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 (file)
index 0000000..52ccff1
--- /dev/null
@@ -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 (file)
index 0000000..8cb1ce3
--- /dev/null
@@ -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 (file)
index 0000000..6f0c8a5
--- /dev/null
@@ -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 (file)
index 0000000..86a0312
--- /dev/null
@@ -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 (file)
index 0000000..7dc061c
--- /dev/null
@@ -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 (file)
index 0000000..5c1f0cd
--- /dev/null
@@ -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 (file)
index 0000000..ded071b
--- /dev/null
@@ -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 (file)
index 0000000..acba0bb
--- /dev/null
@@ -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;
+}
index 1261c36505835f480ff5a6eb95c66ff7250c3697..cbb1221b355d0d1bcf5e6d1fd1c3f2d70caf130d 100644 (file)
@@ -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" }
 
index f37c7f6f12e9e4c77f1b785c928bdc06c7af9559..2cc84bb9d1efa887fbda52f9888897a76e27c80f 100644 (file)
@@ -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;
index 7483907ac0de54989ba3ca074e9ee0097d38abba..a6ab09b72fe06602871bdc1e91b953c24e40da9a 100644 (file)
@@ -1,3 +1,12 @@
+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
index 43939c14fa763e2adf7df131312c1d3a94d1c5c7..94f43ce23f32607c629cbdad596a4808f98a3cc0 100644 (file)
@@ -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&) { } };
 
index ed9a48a704a61e8c828f4b8ede8c1a66ea3f6479..f3c71ac1be5c66e68e3e3c9dc477519103da2ce7 100644 (file)
@@ -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.
   //
index 0bb653947185557d5ed92e7fd00e60ac8e8f53f9..e80afc808a3ab6425c439861fc63eba993c1cef4 100644 (file)
@@ -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;
index a40c880ba8d61c8e900c37e0a64b3b094c88af32..12a6b5fd4190757393b19b3a851f5e49dc513113 100644 (file)
@@ -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>]