aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp')
-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
12 files changed, 509 insertions, 8 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index bf5e28c..4374e6b 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 22c9439..5e5bcbf 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 7b1841e..af8eb94 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 a2a0c03..a0feb30 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 95945b3..2d20246 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 0315f01..833e7b8 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 2f619be..080a843 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 4dff5b9..03078a3 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 dcd73f0..4fc1a62 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 1e6c044..f1e6b18 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 e260353..bfb84ec 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 7fd6664..78a3520 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;
}