Another part of 95369 is that we accept designated initializers with
non-aggregate types.  That seems to be wrong since they're part of
aggregate initialization.  clang/icc also reject it.

(Un)fortunately there are multiple contexts where we can use designated
initializers: function-like casts, member list initializers, NTTP, etc.
So I've adjusted multiple places in the compiler in order to to detect
this case and to provide a nice diagnostic, instead of an ugly raft of
errors.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

gcc/cp/ChangeLog:

        PR c++/95369
        * call.c (implicit_conversion): Return NULL if a designated
        initializer is used with a non-aggregate.
        (implicit_conversion_error): Give an error for the case above.
        * decl.c (check_initializer): Likewise.
        * init.c (build_aggr_init): Likewise.
        * semantics.c (finish_compound_literal): Likewise.

gcc/testsuite/ChangeLog:

        PR c++/95369
        * g++.dg/cpp2a/desig11.C: Adjust dg-error.
        * g++.dg/cpp2a/desig16.C: New test.
---
 gcc/cp/call.c                        | 11 +++++++++++
 gcc/cp/decl.c                        |  9 +++++++++
 gcc/cp/init.c                        | 10 ++++++++++
 gcc/cp/semantics.c                   |  7 +++++++
 gcc/testsuite/g++.dg/cpp2a/desig11.C |  2 +-
 gcc/testsuite/g++.dg/cpp2a/desig16.C | 28 ++++++++++++++++++++++++++++
 6 files changed, 66 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/desig16.C

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 3c97b9846e2..346fb850f84 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -2020,6 +2020,12 @@ implicit_conversion (tree to, tree from, tree expr, bool 
c_cast_p,
       if (is_std_init_list (to) && !CONSTRUCTOR_IS_DESIGNATED_INIT (expr))
        return build_list_conv (to, expr, flags, complain);
 
+      /* Designated initializers can only be used to initialize an aggregate
+        because they're part of aggregate initialization.  Return NULL here,
+        implicit_conversion_error will issue an actual error.  */
+      if (CONSTRUCTOR_IS_DESIGNATED_INIT (expr) && !CP_AGGREGATE_TYPE_P (to))
+       return NULL;
+
       /* As an extension, allow list-initialization of _Complex.  */
       if (TREE_CODE (to) == COMPLEX_TYPE
          && !CONSTRUCTOR_IS_DESIGNATED_INIT (expr))
@@ -4301,6 +4307,11 @@ implicit_conversion_error (location_t loc, tree type, 
tree expr)
     instantiate_type (type, expr, complain);
   else if (invalid_nonstatic_memfn_p (loc, expr, complain))
     /* We gave an error.  */;
+  else if (BRACE_ENCLOSED_INITIALIZER_P (expr)
+          && CONSTRUCTOR_IS_DESIGNATED_INIT (expr)
+          && !CP_AGGREGATE_TYPE_P (type))
+    error_at (loc, "designated initializers cannot be used with a "
+             "non-aggregate type %qT", type);
   else
     {
       range_label_for_type_mismatch label (TREE_TYPE (expr), type);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index b8bd09b37e6..577643a1523 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -6668,6 +6668,15 @@ check_initializer (tree decl, tree init, int flags, 
vec<tree, va_gc> **cleanups)
              return NULL_TREE;
            }
        }
+      else if (CONSTRUCTOR_IS_DESIGNATED_INIT (init)
+              && !CP_AGGREGATE_TYPE_P (type))
+       {
+         error_at (cp_expr_loc_or_loc (init, DECL_SOURCE_LOCATION (decl)),
+                   "designated initializers cannot be used with a "
+                   "non-aggregate type %qT", type);
+         TREE_TYPE (decl) = error_mark_node;
+         return NULL_TREE;
+       }
     }
 
   if (TREE_CODE (decl) == CONST_DECL)
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index ef4b3c4dc3c..de261cfe7a6 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -1802,6 +1802,16 @@ build_aggr_init (tree exp, tree init, int flags, 
tsubst_flags_t complain)
        TREE_TYPE (init) = itype;
       return stmt_expr;
     }
+  else if (init
+          && BRACE_ENCLOSED_INITIALIZER_P (init)
+          && CONSTRUCTOR_IS_DESIGNATED_INIT (init)
+          && !CP_AGGREGATE_TYPE_P (type))
+    {
+      if (complain & tf_error)
+       error_at (init_loc, "designated initializers cannot be used with a "
+                 "non-aggregate type %qT", type);
+      return error_mark_node;
+    }
 
   if (init && init != void_type_node
       && TREE_CODE (init) != TREE_LIST
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 64587c791c6..f25c4ec7110 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2933,6 +2933,13 @@ finish_compound_literal (tree type, tree 
compound_literal,
 
   if (TYPE_NON_AGGREGATE_CLASS (type))
     {
+      if (CONSTRUCTOR_IS_DESIGNATED_INIT (compound_literal))
+       {
+         if (complain & tf_error)
+           error ("designated initializers cannot be used with a "
+                  "non-aggregate type %qT", type);
+         return error_mark_node;
+       }
       /* Trying to deal with a CONSTRUCTOR instead of a TREE_LIST
         everywhere that deals with function arguments would be a pain, so
         just wrap it in a TREE_LIST.  The parser set a flag so we know
diff --git a/gcc/testsuite/g++.dg/cpp2a/desig11.C 
b/gcc/testsuite/g++.dg/cpp2a/desig11.C
index d6895a7be56..a189fff2059 100644
--- a/gcc/testsuite/g++.dg/cpp2a/desig11.C
+++ b/gcc/testsuite/g++.dg/cpp2a/desig11.C
@@ -11,4 +11,4 @@ int bar (_Complex int);                       // { dg-message 
"initializing argument 1 of" }
 int y = bar ({.real = 0, .imag = 1});  // { dg-error "cannot convert" }
 
 int baz (std::initializer_list<int>);
-int z = baz ({.one = 1, .two = 2, .three = 3});        // { dg-error "could 
not convert" }
+int z = baz ({.one = 1, .two = 2, .three = 3});        // { dg-error 
"designated initializers" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/desig16.C 
b/gcc/testsuite/g++.dg/cpp2a/desig16.C
new file mode 100644
index 00000000000..580115d985e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/desig16.C
@@ -0,0 +1,28 @@
+// PR c++/95369
+// { dg-do compile { target c++20 } }
+
+struct S {
+  unsigned a;
+  unsigned b;
+  constexpr S(unsigned _a, unsigned _b) noexcept: a{_a}, b{_b} { }
+};
+
+template<S s> struct X { };
+void g(S);
+
+struct Z {
+  S s;
+  Z() : s{.a = 1, .b = 2} { } // { dg-error "designated initializers" }
+};
+
+S
+f()
+{
+  X<{.a = 1, .b = 2}> x; // { dg-error "designated initializers" }
+  S s{ .a = 1, .b = 2 }; // { dg-error "designated initializers" }
+  S s2 = { .a = 1, .b = 2 }; // { dg-error "designated initializers" }
+  S s3 = S{ .a = 1, .b = 2 }; // { dg-error "designated initializers" }
+  g({.a = 1, .b = 2}); // { dg-error "designated initializers" }
+  g(S{.a = 1, .b = 2}); // { dg-error "designated initializers" }
+  return {.a = 1, .b = 2}; // { dg-error "designated initializers" }
+}

base-commit: ec34277611416aacdfdf3b8469b8e6ed43f623e6
-- 
Marek Polacek • Red Hat, Inc. • 300 A St, Boston, MA

Reply via email to