From dd5d5481bebf401a855eb362fa5ffc2101ba06f2 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 30 Sep 2014 13:13:10 -0400 Subject: [PATCH] c-common.h (enum rid): Add RID_IS_TRIVIALLY_ASSIGNABLE and RID_IS_TRIVIALLY_CONSTRUCTIBLE. c-family/ * c-common.h (enum rid): Add RID_IS_TRIVIALLY_ASSIGNABLE and RID_IS_TRIVIALLY_CONSTRUCTIBLE. * c-common.c (c_common_reswords): Add __is_trivially_copyable. cp/ * cp-tree.h (cp_trait_kind): Add CPTK_IS_TRIVIALLY_ASSIGNABLE and CPTK_IS_TRIVIALLY_CONSTRUCTIBLE. * cxx-pretty-print.c (pp_cxx_trait_expression): Likewise. * parser.c (cp_parser_primary_expression): Likewise. (cp_parser_trait_expr): Likewise. Handle variadic trait. * semantics.c (trait_expr_value): Likewise. (finish_trait_expr): Likewise. (check_trait_type): Handle variadic trait. Return bool. * method.c (build_stub_object): Add rvalue reference here. (locate_fn_flags): Not here. (check_nontriv, assignable_expr, constructible_expr): New. (is_trivially_xible): New. From-SVN: r215738 --- gcc/c-family/ChangeLog | 4 + gcc/c-family/c-common.c | 2 + gcc/c-family/c-common.h | 1 + gcc/cp/ChangeLog | 13 ++ gcc/cp/cp-tree.h | 3 + gcc/cp/cxx-pretty-print.c | 6 + gcc/cp/method.c | 111 +++++++++++++++++- gcc/cp/parser.c | 22 ++++ gcc/cp/semantics.c | 33 ++++-- .../g++.dg/ext/is_trivially_constructible1.C | 35 ++++++ 10 files changed, 221 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 8c44b18a859..b3a71312ad6 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,5 +1,9 @@ 2014-09-30 Jason Merrill + * c-common.h (enum rid): Add RID_IS_TRIVIALLY_ASSIGNABLE and + RID_IS_TRIVIALLY_CONSTRUCTIBLE. + * c-common.c (c_common_reswords): Add __is_trivially_copyable. + * c-common.h (enum rid): Add RID_IS_TRIVIALLY_COPYABLE. * c-common.c (c_common_reswords): Add __is_trivially_copyable. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 482dd449611..b16d030ae2b 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -480,6 +480,8 @@ const struct c_common_resword c_common_reswords[] = { "__is_polymorphic", RID_IS_POLYMORPHIC, D_CXXONLY }, { "__is_standard_layout", RID_IS_STD_LAYOUT, D_CXXONLY }, { "__is_trivial", RID_IS_TRIVIAL, D_CXXONLY }, + { "__is_trivially_assignable", RID_IS_TRIVIALLY_ASSIGNABLE, D_CXXONLY }, + { "__is_trivially_constructible", RID_IS_TRIVIALLY_CONSTRUCTIBLE, D_CXXONLY }, { "__is_trivially_copyable", RID_IS_TRIVIALLY_COPYABLE, D_CXXONLY }, { "__is_union", RID_IS_UNION, D_CXXONLY }, { "__label__", RID_LABEL, 0 }, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index b7e3385ab7a..1e3477f7058 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -143,6 +143,7 @@ enum rid RID_IS_FINAL, RID_IS_LITERAL_TYPE, RID_IS_POD, RID_IS_POLYMORPHIC, RID_IS_STD_LAYOUT, RID_IS_TRIVIAL, + RID_IS_TRIVIALLY_ASSIGNABLE, RID_IS_TRIVIALLY_CONSTRUCTIBLE, RID_IS_TRIVIALLY_COPYABLE, RID_IS_UNION, RID_UNDERLYING_TYPE, diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d44d67a3875..2fedd372a48 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,18 @@ 2014-09-30 Jason Merrill + * cp-tree.h (cp_trait_kind): Add CPTK_IS_TRIVIALLY_ASSIGNABLE and + CPTK_IS_TRIVIALLY_CONSTRUCTIBLE. + * cxx-pretty-print.c (pp_cxx_trait_expression): Likewise. + * parser.c (cp_parser_primary_expression): Likewise. + (cp_parser_trait_expr): Likewise. Handle variadic trait. + * semantics.c (trait_expr_value): Likewise. + (finish_trait_expr): Likewise. + (check_trait_type): Handle variadic trait. Return bool. + * method.c (build_stub_object): Add rvalue reference here. + (locate_fn_flags): Not here. + (check_nontriv, assignable_expr, constructible_expr): New. + (is_trivially_xible): New. + * cp-tree.h (cp_trait_kind): Add CPTK_IS_TRIVIALLY_COPYABLE. * cxx-pretty-print.c (pp_cxx_trait_expression): Likewise. * parser.c (cp_parser_primary_expression): Likewise. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8e5c3b7909f..b2b9063a365 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -653,6 +653,8 @@ typedef enum cp_trait_kind CPTK_IS_POLYMORPHIC, CPTK_IS_STD_LAYOUT, CPTK_IS_TRIVIAL, + CPTK_IS_TRIVIALLY_ASSIGNABLE, + CPTK_IS_TRIVIALLY_CONSTRUCTIBLE, CPTK_IS_TRIVIALLY_COPYABLE, CPTK_IS_UNION, CPTK_UNDERLYING_TYPE @@ -5521,6 +5523,7 @@ extern tree make_thunk (tree, bool, tree, tree); extern void finish_thunk (tree); extern void use_thunk (tree, bool); extern bool trivial_fn_p (tree); +extern bool is_trivially_xible (enum tree_code, tree, tree); extern tree get_defaulted_eh_spec (tree); extern tree unevaluated_noexcept_spec (void); extern void after_nsdmi_defaulted_late_checks (tree); diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index 7b2d7fd205b..67e84c0a240 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -2393,6 +2393,12 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t) case CPTK_IS_TRIVIAL: pp_cxx_ws_string (pp, "__is_trivial"); break; + case CPTK_IS_TRIVIALLY_ASSIGNABLE: + pp_cxx_ws_string (pp, "__is_trivially_assignable"); + break; + case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE: + pp_cxx_ws_string (pp, "__is_trivially_constructible"); + break; case CPTK_IS_TRIVIALLY_COPYABLE: pp_cxx_ws_string (pp, "__is_trivially_copyable"); break; diff --git a/gcc/cp/method.c b/gcc/cp/method.c index b427d65d642..9a2bd0f1055 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -852,6 +852,8 @@ build_stub_type (tree type, int quals, bool rvalue) static tree build_stub_object (tree reftype) { + if (TREE_CODE (reftype) != REFERENCE_TYPE) + reftype = cp_build_reference_type (reftype, /*rval*/true); tree stub = build1 (CONVERT_EXPR, reftype, integer_one_node); return convert_from_reference (stub); } @@ -889,8 +891,6 @@ locate_fn_flags (tree type, tree name, tree argtype, int flags, elt = TREE_CHAIN (elt)) { tree type = TREE_VALUE (elt); - if (TREE_CODE (type) != REFERENCE_TYPE) - type = cp_build_reference_type (type, /*rval*/true); tree arg = build_stub_object (type); vec_safe_push (args, arg); } @@ -1001,6 +1001,113 @@ get_inherited_ctor (tree ctor) return fn; } +/* walk_tree helper function for is_trivially_xible. If *TP is a call, + return it if it calls something other than a trivial special member + function. */ + +static tree +check_nontriv (tree *tp, int *, void *) +{ + tree fn; + if (TREE_CODE (*tp) == CALL_EXPR) + fn = CALL_EXPR_FN (*tp); + else if (TREE_CODE (*tp) == AGGR_INIT_EXPR) + fn = AGGR_INIT_EXPR_FN (*tp); + else + return NULL_TREE; + + if (TREE_CODE (fn) == ADDR_EXPR) + fn = TREE_OPERAND (fn, 0); + + if (TREE_CODE (fn) != FUNCTION_DECL + || !trivial_fn_p (fn)) + return fn; + return NULL_TREE; +} + +/* Return declval() = declval() treated as an unevaluated operand. */ + +static tree +assignable_expr (tree to, tree from) +{ + ++cp_unevaluated_operand; + to = build_stub_object (to); + from = build_stub_object (from); + tree r = cp_build_modify_expr (to, NOP_EXPR, from, tf_none); + --cp_unevaluated_operand; + return r; +} + +/* The predicate condition for a template specialization + is_constructible shall be satisfied if and only if the + following variable definition would be well-formed for some invented + variable t: T t(create()...); + + Return something equivalent in well-formedness and triviality. */ + +static tree +constructible_expr (tree to, tree from) +{ + tree expr; + if (CLASS_TYPE_P (to)) + { + tree ctype = to; + vec *args = NULL; + if (TREE_CODE (to) != REFERENCE_TYPE) + to = cp_build_reference_type (to, /*rval*/false); + tree ob = build_stub_object (to); + for (; from; from = TREE_CHAIN (from)) + vec_safe_push (args, build_stub_object (TREE_VALUE (from))); + expr = build_special_member_call (ob, complete_ctor_identifier, &args, + ctype, LOOKUP_NORMAL, tf_none); + if (expr == error_mark_node) + return error_mark_node; + /* The current state of the standard vis-a-vis LWG 2116 is that + is_*constructible involves destruction as well. */ + if (type_build_dtor_call (ctype)) + { + tree dtor = build_special_member_call (ob, complete_dtor_identifier, + NULL, ctype, LOOKUP_NORMAL, + tf_none); + if (dtor == error_mark_node) + return error_mark_node; + if (!TYPE_HAS_TRIVIAL_DESTRUCTOR (ctype)) + expr = build2 (COMPOUND_EXPR, void_type_node, expr, dtor); + } + } + else + { + if (TREE_CHAIN (from)) + return error_mark_node; // too many initializers + from = build_stub_object (TREE_VALUE (from)); + expr = perform_direct_initialization_if_possible (to, from, + /*cast*/false, + tf_none); + } + return expr; +} + +/* Returns true iff TO is trivially assignable (if CODE is MODIFY_EXPR) or + constructible (otherwise) from FROM, which is a single type for + assignment or a list of types for construction. */ + +bool +is_trivially_xible (enum tree_code code, tree to, tree from) +{ + tree expr; + if (code == MODIFY_EXPR) + expr = assignable_expr (to, from); + else if (from && TREE_CHAIN (from)) + return false; // only 0- and 1-argument ctors can be trivial + else + expr = constructible_expr (to, from); + + if (expr == error_mark_node) + return false; + tree nt = cp_walk_tree_without_duplicates (&expr, check_nontriv, NULL); + return !nt; +} + /* Subroutine of synthesized_method_walk. Update SPEC_P, TRIVIAL_P and DELETED_P or give an error message MSG with argument ARG. */ diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b1feef52b93..e4aaf53fa6c 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -4490,6 +4490,8 @@ cp_parser_primary_expression (cp_parser *parser, case RID_IS_POLYMORPHIC: case RID_IS_STD_LAYOUT: case RID_IS_TRIVIAL: + case RID_IS_TRIVIALLY_ASSIGNABLE: + case RID_IS_TRIVIALLY_CONSTRUCTIBLE: case RID_IS_TRIVIALLY_COPYABLE: case RID_IS_UNION: return cp_parser_trait_expr (parser, token->keyword); @@ -8664,6 +8666,7 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) cp_trait_kind kind; tree type1, type2 = NULL_TREE; bool binary = false; + bool variadic = false; switch (keyword) { @@ -8725,6 +8728,14 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) case RID_IS_TRIVIAL: kind = CPTK_IS_TRIVIAL; break; + case RID_IS_TRIVIALLY_ASSIGNABLE: + kind = CPTK_IS_TRIVIALLY_ASSIGNABLE; + binary = true; + break; + case RID_IS_TRIVIALLY_CONSTRUCTIBLE: + kind = CPTK_IS_TRIVIALLY_CONSTRUCTIBLE; + variadic = true; + break; case RID_IS_TRIVIALLY_COPYABLE: kind = CPTK_IS_TRIVIALLY_COPYABLE; break; @@ -8763,6 +8774,17 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) if (type2 == error_mark_node) return error_mark_node; } + else if (variadic) + { + while (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + { + cp_lexer_consume_token (parser->lexer); + tree elt = cp_parser_type_id (parser); + if (elt == error_mark_node) + return error_mark_node; + type2 = tree_cons (NULL_TREE, elt, type2); + } + } cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 9bcc6d73c78..756982667b1 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -7379,6 +7379,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) case CPTK_IS_TRIVIAL: return (trivial_type_p (type1)); + case CPTK_IS_TRIVIALLY_ASSIGNABLE: + return is_trivially_xible (MODIFY_EXPR, type1, type2); + + case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE: + return is_trivially_xible (INIT_EXPR, type1, type2); + case CPTK_IS_TRIVIALLY_COPYABLE: return (trivially_copyable_p (type1)); @@ -7392,19 +7398,26 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2) } /* If TYPE is an array of unknown bound, or (possibly cv-qualified) - void, or a complete type, returns it, otherwise NULL_TREE. */ + void, or a complete type, returns true, otherwise false. */ -static tree +static bool check_trait_type (tree type) { + if (type == NULL_TREE) + return true; + + if (TREE_CODE (type) == TREE_LIST) + return (check_trait_type (TREE_VALUE (type)) + && check_trait_type (TREE_CHAIN (type))); + if (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type) && COMPLETE_TYPE_P (TREE_TYPE (type))) - return type; + return true; if (VOID_TYPE_P (type)) - return type; + return true; - return complete_type_or_else (strip_array_types (type), NULL_TREE); + return !!complete_type_or_else (strip_array_types (type), NULL_TREE); } /* Process a trait expression. */ @@ -7413,8 +7426,7 @@ tree finish_trait_expr (cp_trait_kind kind, tree type1, tree type2) { if (type1 == error_mark_node - || ((kind == CPTK_IS_BASE_OF) - && type2 == error_mark_node)) + || type2 == error_mark_node) return error_mark_node; if (processing_template_decl) @@ -7450,6 +7462,13 @@ finish_trait_expr (cp_trait_kind kind, tree type1, tree type2) return error_mark_node; break; + case CPTK_IS_TRIVIALLY_ASSIGNABLE: + case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE: + if (!check_trait_type (type1) + || !check_trait_type (type2)) + return error_mark_node; + break; + case CPTK_IS_BASE_OF: if (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2) && !same_type_ignoring_top_level_qualifiers_p (type1, type2) diff --git a/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C b/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C new file mode 100644 index 00000000000..f558538694c --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_trivially_constructible1.C @@ -0,0 +1,35 @@ +// { dg-do compile { target c++11 } } + +struct A { }; +struct B { B(); operator int(); }; +struct C { + C() = default; + C(const C&); + C(C&&) = default; + C& operator=(C&&); + C& operator= (const C&) = default; +}; +struct D { ~D() {} }; + +#define SA(X) static_assert((X),#X) + +SA(__is_trivially_constructible(A)); +SA(__is_trivially_constructible(A,A)); +SA(!__is_trivially_constructible(B)); +SA(__is_trivially_constructible(B,B)); + +SA(!__is_trivially_constructible(A,B)); +SA(!__is_trivially_constructible(B,A)); + +SA(__is_trivially_constructible(C)); +SA(__is_trivially_constructible(C,C)); +SA(!__is_trivially_constructible(C,C&)); +SA(__is_trivially_assignable(C,C&)); +SA(!__is_trivially_assignable(C,C)); +SA(!__is_trivially_assignable(C,C&&)); + +SA(__is_trivially_constructible(int,int)); +SA(__is_trivially_constructible(int,double)); +SA(!__is_trivially_constructible(int,B)); + +SA(!__is_trivially_constructible(D));