On 6/9/20 2:17 PM, Marek Polacek wrote:
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.

Would it work to handle this only in add_list_candidates?

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


Reply via email to