* [PATCH] c++: Don't allow designated initializers with non-aggregates [PR95369]
@ 2020-06-09 18:17 Marek Polacek
2020-06-11 19:51 ` Jason Merrill
0 siblings, 1 reply; 6+ messages in thread
From: Marek Polacek @ 2020-06-09 18:17 UTC (permalink / raw)
To: Jason Merrill, GCC Patches
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
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] c++: Don't allow designated initializers with non-aggregates [PR95369]
2020-06-09 18:17 [PATCH] c++: Don't allow designated initializers with non-aggregates [PR95369] Marek Polacek
@ 2020-06-11 19:51 ` Jason Merrill
2020-06-11 21:28 ` Marek Polacek
0 siblings, 1 reply; 6+ messages in thread
From: Jason Merrill @ 2020-06-11 19:51 UTC (permalink / raw)
To: Marek Polacek, GCC Patches
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
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] c++: Don't allow designated initializers with non-aggregates [PR95369]
2020-06-11 19:51 ` Jason Merrill
@ 2020-06-11 21:28 ` Marek Polacek
2020-06-11 22:15 ` Jason Merrill
0 siblings, 1 reply; 6+ messages in thread
From: Marek Polacek @ 2020-06-11 21:28 UTC (permalink / raw)
To: Jason Merrill; +Cc: GCC Patches
On Thu, Jun 11, 2020 at 03:51:29PM -0400, Jason Merrill wrote:
> 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?
'fraid not -- we don't call add_list_candidates at all when compiling
desig16.C.
Marek
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] c++: Don't allow designated initializers with non-aggregates [PR95369]
2020-06-11 21:28 ` Marek Polacek
@ 2020-06-11 22:15 ` Jason Merrill
2020-06-15 20:56 ` [PATCH v2] " Marek Polacek
0 siblings, 1 reply; 6+ messages in thread
From: Jason Merrill @ 2020-06-11 22:15 UTC (permalink / raw)
To: Marek Polacek; +Cc: GCC Patches
On 6/11/20 5:28 PM, Marek Polacek wrote:
> On Thu, Jun 11, 2020 at 03:51:29PM -0400, Jason Merrill wrote:
>> 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?
>
> 'fraid not -- we don't call add_list_candidates at all when compiling
> desig16.C.
Hmm, why not? What is turning the CONSTRUCTOR into an argument vec?
Jason
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] c++: Don't allow designated initializers with non-aggregates [PR95369]
2020-06-11 22:15 ` Jason Merrill
@ 2020-06-15 20:56 ` Marek Polacek
2020-06-16 16:03 ` Jason Merrill
0 siblings, 1 reply; 6+ messages in thread
From: Marek Polacek @ 2020-06-15 20:56 UTC (permalink / raw)
To: Jason Merrill; +Cc: GCC Patches
On Thu, Jun 11, 2020 at 06:15:26PM -0400, Jason Merrill via Gcc-patches wrote:
> On 6/11/20 5:28 PM, Marek Polacek wrote:
> > On Thu, Jun 11, 2020 at 03:51:29PM -0400, Jason Merrill wrote:
> > > 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?
> >
> > 'fraid not -- we don't call add_list_candidates at all when compiling
> > desig16.C.
>
> Hmm, why not? What is turning the CONSTRUCTOR into an argument vec?
Nevermind, I must've glossed over a local patch. This better patch
implements your suggestion. I still changed implicit_conversion_error
to give a better diagnostic but that should be fine. Thanks,
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
-- >8 --
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 | 13 +++++++++++++
gcc/testsuite/g++.dg/cpp2a/desig11.C | 2 +-
gcc/testsuite/g++.dg/cpp2a/desig16.C | 28 ++++++++++++++++++++++++++++
3 files changed, 42 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 b99959f76f9..1a54e9f4440 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -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);
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..3edb68d24a4
--- /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|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" }
+}
base-commit: c7bac01ab41f019a66bc07fc704752f436707eb8
--
Marek Polacek • Red Hat, Inc. • 300 A St, Boston, MA
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v2] c++: Don't allow designated initializers with non-aggregates [PR95369]
2020-06-15 20:56 ` [PATCH v2] " Marek Polacek
@ 2020-06-16 16:03 ` Jason Merrill
0 siblings, 0 replies; 6+ messages in thread
From: Jason Merrill @ 2020-06-16 16:03 UTC (permalink / raw)
To: Marek Polacek; +Cc: GCC Patches
On 6/15/20 4:56 PM, Marek Polacek wrote:
> On Thu, Jun 11, 2020 at 06:15:26PM -0400, Jason Merrill via Gcc-patches wrote:
>> On 6/11/20 5:28 PM, Marek Polacek wrote:
>>> On Thu, Jun 11, 2020 at 03:51:29PM -0400, Jason Merrill wrote:
>>>> 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?
>>>
>>> 'fraid not -- we don't call add_list_candidates at all when compiling
>>> desig16.C.
>>
>> Hmm, why not? What is turning the CONSTRUCTOR into an argument vec?
>
> Nevermind, I must've glossed over a local patch. This better patch
> implements your suggestion. I still changed implicit_conversion_error
> to give a better diagnostic but that should be fine. Thanks,
>
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
OK, thanks.
> -- >8 --
> 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 | 13 +++++++++++++
> gcc/testsuite/g++.dg/cpp2a/desig11.C | 2 +-
> gcc/testsuite/g++.dg/cpp2a/desig16.C | 28 ++++++++++++++++++++++++++++
> 3 files changed, 42 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 b99959f76f9..1a54e9f4440 100644
> --- a/gcc/cp/call.c
> +++ b/gcc/cp/call.c
> @@ -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);
> 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..3edb68d24a4
> --- /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|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" }
> +}
>
> base-commit: c7bac01ab41f019a66bc07fc704752f436707eb8
>
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2020-06-16 16:04 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-09 18:17 [PATCH] c++: Don't allow designated initializers with non-aggregates [PR95369] Marek Polacek
2020-06-11 19:51 ` Jason Merrill
2020-06-11 21:28 ` Marek Polacek
2020-06-11 22:15 ` Jason Merrill
2020-06-15 20:56 ` [PATCH v2] " Marek Polacek
2020-06-16 16:03 ` Jason Merrill
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).