public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r12-2991] c++: aggregate CTAD and brace elision [PR101344]
@ 2021-08-18 12:39 Patrick Palka
  0 siblings, 0 replies; only message in thread
From: Patrick Palka @ 2021-08-18 12:39 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:be4a4fb516688d7cfe28a80a4aa333f4ecf0b518

commit r12-2991-gbe4a4fb516688d7cfe28a80a4aa333f4ecf0b518
Author: Patrick Palka <ppalka@redhat.com>
Date:   Wed Aug 18 08:37:45 2021 -0400

    c++: aggregate CTAD and brace elision [PR101344]
    
    Here the problem is ultimately that collect_ctor_idx_types always
    recurses into an eligible sub-CONSTRUCTOR regardless of whether the
    corresponding pair of braces was elided in the original initializer.
    This causes us to reject some completely-braced forms of aggregate
    CTAD as in the first testcase below, because collect_ctor_idx_types
    effectively assumes that the original initializer is always minimally
    braced (and so the aggregate deduction candidate is given a function
    type that's incompatible with the original completely-braced initializer).
    
    In order to fix this, collect_ctor_idx_types needs to somehow know the
    shape of the original initializer when iterating over the reshaped
    initializer.  To that end this patch makes reshape_init flag sub-ctors
    that were built to undo brace elision in the original ctor, so that
    collect_ctor_idx_types that determine whether to recurse into a sub-ctor
    by simply inspecting this flag.
    
    This happens to also fix PR101820, which is about aggregate CTAD using
    designated initializers, for much the same reasons.
    
    A curious case is the "intermediately-braced" initialization of 'e3'
    (which we reject) in the first testcase below.  It seems to me we're
    behaving as specified here (according to [over.match.class.deduct]/1)
    because the initializer element x_1={1, 2, 3, 4} corresponds to the
    subobject e_1=E::t, hence the type T_1 of the first function parameter
    of the aggregate deduction candidate is T(&&)[2][2], but T can't be
    deduced from x_1 using this parameter type (as opposed to say T(&&)[4]).
    
            PR c++/101344
            PR c++/101820
    
    gcc/cp/ChangeLog:
    
            * cp-tree.h (CONSTRUCTOR_BRACES_ELIDED_P): Define.
            * decl.c (reshape_init_r): Set it.
            * pt.c (collect_ctor_idx_types): Recurse into a sub-CONSTRUCTOR
            iff CONSTRUCTOR_BRACES_ELIDED_P.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp2a/class-deduction-aggr11.C: New test.
            * g++.dg/cpp2a/class-deduction-aggr12.C: New test.

Diff:
---
 gcc/cp/cp-tree.h                                   |  6 +++++
 gcc/cp/decl.c                                      | 18 +++++++++++---
 gcc/cp/pt.c                                        |  7 +-----
 .../g++.dg/cpp2a/class-deduction-aggr11.C          | 29 ++++++++++++++++++++++
 .../g++.dg/cpp2a/class-deduction-aggr12.C          | 15 +++++++++++
 5 files changed, 65 insertions(+), 10 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 14e2db26f77..7ba02bed0fb 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 32d07babf43..3414cbdc876 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 0c1496693e2..020a4bf2f6d 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 00000000000..c4806de56af
--- /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 00000000000..ebe73c1d817
--- /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


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-08-18 12:39 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-18 12:39 [gcc r12-2991] c++: aggregate CTAD and brace elision [PR101344] Patrick Palka

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).