2014-09-30 Jason Merrill <jason@redhat.com>
+ * 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.
{ "__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 },
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,
2014-09-30 Jason Merrill <jason@redhat.com>
+ * 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.
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
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);
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;
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);
}
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);
}
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<T>() = declval<U>() 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<T, Args...> shall be satisfied if and only if the
+ following variable definition would be well-formed for some invented
+ variable t: T t(create<Args>()...);
+
+ 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<tree, va_gc> *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. */
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);
cp_trait_kind kind;
tree type1, type2 = NULL_TREE;
bool binary = false;
+ bool variadic = false;
switch (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;
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);
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));
}
/* 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. */
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)
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)
--- /dev/null
+// { 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));