aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/cp-tree.h6
-rw-r--r--gcc/cp/decl.c18
-rw-r--r--gcc/cp/pt.c7
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr11.C29
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr12.C15
5 files changed, 65 insertions, 10 deletions
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 14e2db2..7ba02be 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4503,6 +4503,12 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter)
#define CONSTRUCTOR_IS_PAREN_INIT(NODE) \
(CONSTRUCTOR_CHECK(NODE)->base.private_flag)
+/* True if reshape_init built this CONSTRUCTOR to undo the brace elision
+ of another CONSTRUCTOR. This flag is used during C++20 aggregate
+ CTAD. */
+#define CONSTRUCTOR_BRACES_ELIDED_P(NODE) \
+ (CONSTRUCTOR_CHECK (NODE)->base.protected_flag)
+
/* True if NODE represents a conversion for direct-initialization in a
template. Set by perform_implicit_conversion_flags. */
#define IMPLICIT_CONV_EXPR_DIRECT_INIT(NODE) \
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 32d07ba..3414cbd 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6657,7 +6657,8 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p,
/* A non-aggregate type is always initialized with a single
initializer. */
if (!CP_AGGREGATE_TYPE_P (type)
- /* As is an array with dependent bound. */
+ /* As is an array with dependent bound, which we can see
+ during C++20 aggregate CTAD. */
|| (cxx_dialect >= cxx20
&& TREE_CODE (type) == ARRAY_TYPE
&& uses_template_parms (TYPE_DOMAIN (type))))
@@ -6774,6 +6775,7 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p,
initializer already, and there is not a CONSTRUCTOR, it means that there
is a missing set of braces (that is, we are processing the case for
which reshape_init exists). */
+ bool braces_elided_p = false;
if (!first_initializer_p)
{
if (TREE_CODE (stripped_init) == CONSTRUCTOR)
@@ -6809,17 +6811,25 @@ reshape_init_r (tree type, reshape_iter *d, tree first_initializer_p,
warning (OPT_Wmissing_braces,
"missing braces around initializer for %qT",
type);
+ braces_elided_p = true;
}
/* Dispatch to specialized routines. */
+ tree new_init;
if (CLASS_TYPE_P (type))
- return reshape_init_class (type, d, first_initializer_p, complain);
+ new_init = reshape_init_class (type, d, first_initializer_p, complain);
else if (TREE_CODE (type) == ARRAY_TYPE)
- return reshape_init_array (type, d, first_initializer_p, complain);
+ new_init = reshape_init_array (type, d, first_initializer_p, complain);
else if (VECTOR_TYPE_P (type))
- return reshape_init_vector (type, d, complain);
+ new_init = reshape_init_vector (type, d, complain);
else
gcc_unreachable();
+
+ if (braces_elided_p
+ && TREE_CODE (new_init) == CONSTRUCTOR)
+ CONSTRUCTOR_BRACES_ELIDED_P (new_init) = true;
+
+ return new_init;
}
/* Undo the brace-elision allowed by [dcl.init.aggr] in a
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 0c14966..020a4bf 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -28837,12 +28837,7 @@ collect_ctor_idx_types (tree ctor, tree list, tree elt = NULL_TREE)
{
tree ftype = elt ? elt : TREE_TYPE (idx);
if (BRACE_ENCLOSED_INITIALIZER_P (val)
- && CONSTRUCTOR_NELTS (val)
- /* As in reshape_init_r, a non-aggregate or array-of-dependent-bound
- type gets a single initializer. */
- && CP_AGGREGATE_TYPE_P (ftype)
- && !(TREE_CODE (ftype) == ARRAY_TYPE
- && uses_template_parms (TYPE_DOMAIN (ftype))))
+ && CONSTRUCTOR_BRACES_ELIDED_P (val))
{
tree subelt = NULL_TREE;
if (TREE_CODE (ftype) == ARRAY_TYPE)
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr11.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr11.C
new file mode 100644
index 0000000..c4806de
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr11.C
@@ -0,0 +1,29 @@
+// PR c++/101344
+// { dg-do compile { target c++20 } }
+
+template<class T=void>
+struct A { int m; int t[2]; };
+
+A a1{1, {2, 3}}; // previously rejected
+A a2{1, 2, 3};
+
+struct B { int x, y; };
+
+template<class T=void>
+struct C { int m; struct { int x, y; } t; };
+
+A b1{1, {2, 3}}; // previously rejected
+A b2{1, 2, 3};
+
+template<class T>
+struct D { T t[2]; };
+
+D d1{1, 2};
+D d2{{1, 2}}; // previously rejected
+
+template<class T>
+struct E { T t[2][2]; };
+
+E e1{1, 2, 3, 4};
+E e2{{{1, 2}, {3, 4}}}; // previously rejected
+E e3{{1, 2, 3, 4}}; // { dg-error "deduction|no match" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr12.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr12.C
new file mode 100644
index 0000000..ebe73c1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr12.C
@@ -0,0 +1,15 @@
+// PR c++/101820
+// { dg-do compile { target c++20 } }
+
+struct Inner { int i = 0; };
+
+template <typename T = void>
+struct Outer { Inner s{}; };
+
+Outer o1{ .s = {} }; // works
+Outer o2{ .s = Inner{ .i = 1} }; // works
+Outer o3{ .s = { .i = 1} }; // does not
+
+Outer o4{ .s{} }; // works
+Outer o5{ .s{Inner{ .i = 1} } }; // works
+Outer o6{ .s{ .i = 1} }; // does not