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