summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaolo Carlini <pcarlini@suse.de>2007-03-30 19:45:57 +0000
committerPaolo Carlini <paolo@gcc.gnu.org>2007-03-30 19:45:57 +0000
commitcb68ec50055e516ac270a043f772935561b01968 (patch)
tree63250c95176e6d94178beae6b2735b398dfbfec1
parentc7a0240aa55b4f7a2d11d33bd12af7a40f42aa55 (diff)
downloadgcc-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
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/c-common.h11
-rw-r--r--gcc/cp/ChangeLog32
-rw-r--r--gcc/cp/class.c4
-rw-r--r--gcc/cp/cp-objcp-common.c3
-rw-r--r--gcc/cp/cp-tree.def5
-rw-r--r--gcc/cp/cp-tree.h65
-rw-r--r--gcc/cp/decl.c1
-rw-r--r--gcc/cp/lex.c17
-rw-r--r--gcc/cp/method.c9
-rw-r--r--gcc/cp/parser.c148
-rw-r--r--gcc/cp/pt.c21
-rw-r--r--gcc/cp/semantics.c206
-rw-r--r--gcc/cp/tree.c6
-rw-r--r--gcc/doc/extend.texi119
-rw-r--r--gcc/testsuite/ChangeLog23
-rw-r--r--gcc/testsuite/g++.dg/ext/has_nothrow_assign.C152
-rw-r--r--gcc/testsuite/g++.dg/ext/has_nothrow_constructor.C106
-rw-r--r--gcc/testsuite/g++.dg/ext/has_nothrow_copy.C140
-rw-r--r--gcc/testsuite/g++.dg/ext/has_trivial_assign.C106
-rw-r--r--gcc/testsuite/g++.dg/ext/has_trivial_constructor.C98
-rw-r--r--gcc/testsuite/g++.dg/ext/has_trivial_copy.C105
-rw-r--r--gcc/testsuite/g++.dg/ext/has_trivial_destructor.C86
-rw-r--r--gcc/testsuite/g++.dg/ext/has_virtual_destructor.C89
-rw-r--r--gcc/testsuite/g++.dg/ext/is_abstract.C89
-rw-r--r--gcc/testsuite/g++.dg/ext/is_base_of.C94
-rw-r--r--gcc/testsuite/g++.dg/ext/is_base_of_diagnostic.C15
-rw-r--r--gcc/testsuite/g++.dg/ext/is_class.C76
-rw-r--r--gcc/testsuite/g++.dg/ext/is_empty.C78
-rw-r--r--gcc/testsuite/g++.dg/ext/is_enum.C73
-rw-r--r--gcc/testsuite/g++.dg/ext/is_pod.C75
-rw-r--r--gcc/testsuite/g++.dg/ext/is_polymorphic.C83
-rw-r--r--gcc/testsuite/g++.dg/ext/is_union.C76
-rw-r--r--gcc/testsuite/g++.dg/template/crash43.C2
-rw-r--r--gcc/testsuite/g++.dg/tree-ssa/pr22444.C4
-rw-r--r--libstdc++-v3/ChangeLog9
-rw-r--r--libstdc++-v3/include/bits/allocator.h4
-rw-r--r--libstdc++-v3/include/bits/cpp_type_traits.h47
-rw-r--r--libstdc++-v3/include/bits/stl_tree.h2
-rw-r--r--libstdc++-v3/include/bits/valarray_array.h16
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>]