public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [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).