c++: Don't allow designated initializers with non-aggregates [PR95369]
authorMarek Polacek <polacek@redhat.com>
Mon, 15 Jun 2020 19:31:32 +0000 (15:31 -0400)
committerMarek Polacek <polacek@redhat.com>
Tue, 16 Jun 2020 17:19:44 +0000 (13:19 -0400)
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.

There are multiple contexts where we can use designated initializers:
function-like casts, member list initializers, NTTP, etc.  I've adjusted
add_list_candidates and implicit_conversion_error in order to to detect
this case.

gcc/cp/ChangeLog:

PR c++/95369
* call.c (add_list_candidates): Return if a designated initializer
is used with a non-aggregate.
(implicit_conversion_error): Give an error for the case above.

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
gcc/testsuite/g++.dg/cpp2a/desig11.C
gcc/testsuite/g++.dg/cpp2a/desig16.C [new file with mode: 0644]

index b55dc83f0e7caec48a8add9fe5c8c014a460e8f2..1d95bd2d07bed5826772fcb9f4fb94355f445bf1 100644 (file)
@@ -3952,6 +3952,14 @@ add_list_candidates (tree fns, tree first_arg,
       if (any_strictly_viable (*candidates))
        return;
     }
+  else if (CONSTRUCTOR_IS_DESIGNATED_INIT (init_list)
+          && !CP_AGGREGATE_TYPE_P (totype))
+    {
+      if (complain & tf_error)
+       error ("designated initializers cannot be used with a "
+              "non-aggregate type %qT", totype);
+      return;
+    }
 
   /* Expand the CONSTRUCTOR into a new argument vec.  */
   vec<tree, va_gc> *new_args;
@@ -4301,6 +4309,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);
index d6895a7be56ec866ad2a2d6fd007d40caf34786d..a189fff2059632a94671a4c7907e686f00ee8eca 100644 (file)
@@ -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 (file)
index 0000000..3edb68d
--- /dev/null
@@ -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|no matching function" }
+};
+
+S
+f()
+{
+  X<{.a = 1, .b = 2}> x; // { dg-error "designated initializers" }
+  S s{ .a = 1, .b = 2 }; // { dg-error "designated initializers|no matching function" }
+  S s2 = { .a = 1, .b = 2 }; // { dg-error "designated initializers" }
+  S s3 = S{ .a = 1, .b = 2 }; // { dg-error "designated initializers|no matching function" }
+  g({.a = 1, .b = 2}); // { dg-error "designated initializers" }
+  g(S{.a = 1, .b = 2}); // { dg-error "designated initializers|no matching function" }
+  return {.a = 1, .b = 2}; // { dg-error "designated initializers" }
+}