On 09/30/2014 06:48 PM, Ville Voutilainen wrote:
Ville asked for help with the necessary compiler intrinsics for the is_trivially_*
>>C++11 library traits. The first patch cleans up a few oddities I noticed with
the
Great. I think this can be as well marked as PR c++/26099.
There's also PR c++/63362.
The intrinsics still fail to support certain variadic cases, such as
template <class T, class... Args> void bar() {
static_assert(__is_trivially_constructible(T, Args...), "");
}
Here are two more patches: the first fixes trivial_fn_p for a defaulted
default constructor overloaded with a template default constructor, and
the second fixes the variadic case above.
commit 68a53de3f12b1d2adacf39d59836a558cc257759
Author: Jason Merrill <ja...@redhat.com>
Date: Tue Sep 30 17:24:13 2014 -0400
PR c++/63362
* class.c (type_has_non_user_provided_default_constructor): Rename
from type_has_user_provided_default_constructor, reverse sense.
(default_init_uninitialized_part, explain_non_literal_class): Adjust.
(check_bases_and_members): Set TYPE_HAS_COMPLEX_DFLT.
* call.c (build_new_method_call_1): Adjust.
* cp-tree.h: Adjust.
* decl.c (grok_special_member_properties): Don't set
TYPE_HAS_COMPLEX_DFLT.
* init.c (build_value_init_noctor): Don't use
type_has_user_provided_default_constructor.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 8f1b91a..3c8b338 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -7941,7 +7941,7 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
&& TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype)
/* For a user-provided default constructor, use the normal
mechanisms so that protected access works. */
- && !type_has_user_provided_default_constructor (basetype)
+ && type_has_non_user_provided_default_constructor (basetype)
&& !processing_template_decl)
init = build_value_init (basetype, complain);
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index acf5768..12ac30a 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4937,21 +4937,25 @@ type_has_user_provided_constructor (tree t)
return false;
}
-/* Returns true iff class T has a user-provided default constructor. */
+/* Returns true iff class T has a non-user-provided (i.e. implicitly
+ declared or explicitly defaulted in the class body) default
+ constructor. */
bool
-type_has_user_provided_default_constructor (tree t)
+type_has_non_user_provided_default_constructor (tree t)
{
tree fns;
- if (!TYPE_HAS_USER_CONSTRUCTOR (t))
+ if (!TYPE_HAS_DEFAULT_CONSTRUCTOR (t))
return false;
+ if (CLASSTYPE_LAZY_DEFAULT_CTOR (t))
+ return true;
for (fns = CLASSTYPE_CONSTRUCTORS (t); fns; fns = OVL_NEXT (fns))
{
tree fn = OVL_CURRENT (fns);
if (TREE_CODE (fn) == FUNCTION_DECL
- && user_provided_p (fn)
+ && !user_provided_p (fn)
&& sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (fn)))
return true;
}
@@ -5009,7 +5013,7 @@ default_init_uninitialized_part (tree type)
type = strip_array_types (type);
if (!CLASS_TYPE_P (type))
return type;
- if (type_has_user_provided_default_constructor (type))
+ if (!type_has_non_user_provided_default_constructor (type))
return NULL_TREE;
for (binfo = TYPE_BINFO (type), i = 0;
BINFO_BASE_ITERATE (binfo, i, t); ++i)
@@ -5383,8 +5387,7 @@ explain_non_literal_class (tree t)
inform (0, " %q+T is not an aggregate, does not have a trivial "
"default constructor, and has no constexpr constructor that "
"is not a copy or move constructor", t);
- if (TYPE_HAS_DEFAULT_CONSTRUCTOR (t)
- && !type_has_user_provided_default_constructor (t))
+ if (type_has_non_user_provided_default_constructor (t))
{
/* Note that we can't simply call locate_ctor because when the
constructor is deleted it just returns NULL_TREE. */
@@ -5528,6 +5531,13 @@ check_bases_and_members (tree t)
TYPE_HAS_COMPLEX_MOVE_ASSIGN (t) |= TYPE_CONTAINS_VPTR_P (t);
TYPE_HAS_COMPLEX_DFLT (t) |= TYPE_CONTAINS_VPTR_P (t);
+ /* If the only explicitly declared default constructor is user-provided,
+ set TYPE_HAS_COMPLEX_DFLT. */
+ if (!TYPE_HAS_COMPLEX_DFLT (t)
+ && TYPE_HAS_DEFAULT_CONSTRUCTOR (t)
+ && !type_has_non_user_provided_default_constructor (t))
+ TYPE_HAS_COMPLEX_DFLT (t) = true;
+
/* Warn if a public base of a polymorphic type has an accessible
non-virtual destructor. It is only now that we know the class is
polymorphic. Although a polymorphic base will have a already
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index b2b9063..14ec837 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3484,7 +3484,7 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
/* Nonzero if there is a non-trivial X::X(X&&) for this class. */
#define TYPE_HAS_COMPLEX_MOVE_CTOR(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->has_complex_move_ctor)
-/* Nonzero if there is a non-trivial default constructor for this class. */
+/* Nonzero if there is no trivial 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]:
@@ -5195,7 +5195,7 @@ extern bool type_has_user_nondefault_constructor (tree);
extern tree in_class_defaulted_default_constructor (tree);
extern bool user_provided_p (tree);
extern bool type_has_user_provided_constructor (tree);
-extern bool type_has_user_provided_default_constructor (tree);
+extern bool type_has_non_user_provided_default_constructor (tree);
extern bool vbase_has_user_provided_move_assign (tree);
extern tree default_init_uninitialized_part (tree);
extern bool trivial_default_constructor_is_constexpr (tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index d26a432..7856dd8 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -11476,11 +11476,7 @@ grok_special_member_properties (tree decl)
TYPE_HAS_CONST_COPY_CTOR (class_type) = 1;
}
else if (sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (decl)))
- {
- TYPE_HAS_DEFAULT_CONSTRUCTOR (class_type) = 1;
- if (user_provided_p (decl))
- TYPE_HAS_COMPLEX_DFLT (class_type) = 1;
- }
+ TYPE_HAS_DEFAULT_CONSTRUCTOR (class_type) = 1;
else if (move_fn_p (decl) && user_provided_p (decl))
TYPE_HAS_COMPLEX_MOVE_CTOR (class_type) = 1;
else if (is_list_ctor (decl))
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index f0ca9b9..6851fe9 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -343,13 +343,17 @@ build_value_init (tree type, tsubst_flags_t complain)
if (CLASS_TYPE_P (type)
&& type_build_ctor_call (type))
{
- tree ctor = build_aggr_init_expr
- (type,
+ tree ctor =
build_special_member_call (NULL_TREE, complete_ctor_identifier,
NULL, type, LOOKUP_NORMAL,
- complain));
- if (ctor == error_mark_node
- || type_has_user_provided_default_constructor (type))
+ complain);
+ if (ctor == error_mark_node)
+ return ctor;
+ tree fn = NULL_TREE;
+ if (TREE_CODE (ctor) == CALL_EXPR)
+ fn = get_callee_fndecl (ctor);
+ ctor = build_aggr_init_expr (type, ctor);
+ if (fn && user_provided_p (fn))
return ctor;
else if (TYPE_HAS_COMPLEX_DFLT (type))
{
diff --git a/gcc/testsuite/g++.dg/ext/is_trivially_constructible2.C b/gcc/testsuite/g++.dg/ext/is_trivially_constructible2.C
new file mode 100644
index 0000000..4e0a657
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_trivially_constructible2.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++11 } }
+
+struct X {
+ X() = default;
+ template<class... U> X(U...);
+};
+
+struct Y {
+ template<class... U> Y(U...);
+};
+
+#define SA(X) static_assert((X),#X)
+
+SA(__is_trivially_constructible(X));
+SA(!__is_trivially_constructible(Y));
commit 591e70a3906af599160ec59287f20ed20b8082ca
Author: Jason Merrill <ja...@redhat.com>
Date: Wed Oct 1 13:00:49 2014 -0400
PR c++/63362
* method.c (constructible_expr): Handle value-init of non-class.
* parser.c (cp_parser_trait_expr): Allow pack expansion.
* pt.c (tsubst_copy_and_build): Handle pack expansion.
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 9a2bd0f..8828986 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -1077,7 +1077,9 @@ constructible_expr (tree to, tree from)
}
else
{
- if (TREE_CHAIN (from))
+ if (from == NULL_TREE)
+ return build_value_init (to, tf_none);
+ 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,
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index e4aaf53..01b2fad 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -8780,6 +8780,11 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
{
cp_lexer_consume_token (parser->lexer);
tree elt = cp_parser_type_id (parser);
+ if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+ {
+ cp_lexer_consume_token (parser->lexer);
+ elt = make_pack_expansion (elt);
+ }
if (elt == error_mark_node)
return error_mark_node;
type2 = tree_cons (NULL_TREE, elt, type2);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9dd61f3..f03e74c 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -15487,7 +15487,9 @@ tsubst_copy_and_build (tree t,
complain, in_decl);
tree type2 = TRAIT_EXPR_TYPE2 (t);
- if (type2)
+ if (type2 && TREE_CODE (type2) == TREE_LIST)
+ type2 = RECUR (type2);
+ else if (type2)
type2 = tsubst (type2, args, complain, in_decl);
RETURN (finish_trait_expr (TRAIT_EXPR_KIND (t), type1, type2));
diff --git a/gcc/testsuite/g++.dg/ext/is_trivially_constructible3.C b/gcc/testsuite/g++.dg/ext/is_trivially_constructible3.C
new file mode 100644
index 0000000..02a678a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_trivially_constructible3.C
@@ -0,0 +1,8 @@
+// { dg-do compile { target c++11 } }
+
+template <class T, class... Args> void bar() {
+ static_assert(__is_trivially_constructible(T, Args...), "");
+}
+
+template void bar<int>();
+template void bar<int,int>();