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
This commit is contained in:
Jason Merrill 2014-09-30 13:13:10 -04:00 committed by Jason Merrill
parent b752325e94
commit dd5d5481be
10 changed files with 221 additions and 9 deletions

View File

@ -1,5 +1,9 @@
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.

View File

@ -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 },

View File

@ -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,

View File

@ -1,5 +1,18 @@
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.

View File

@ -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);

View File

@ -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;

View File

@ -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<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. */

View File

@ -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);

View File

@ -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)

View File

@ -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));