public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] c++: Fixing the wording of () aggregate-init [PR92812]
@ 2020-07-20 23:28 Marek Polacek
  2020-07-21  9:53 ` Ville Voutilainen
  2020-07-29 23:21 ` Jason Merrill
  0 siblings, 2 replies; 10+ messages in thread
From: Marek Polacek @ 2020-07-20 23:28 UTC (permalink / raw)
  To: GCC Patches, Jason Merrill, Ville Voutilainen

P1975R0 tweaks the static_cast wording: it says that "An expression e can be
explicitly converted to a type T if [...] T is an aggregate type having a first
element x and there is an implicit conversion sequence from e to the type of
x."  This already works for classes, e.g.:

  struct Aggr { int x; int y; };
  Aggr a = static_cast<Aggr>(1);

albeit I noticed a -Wmissing-field-initializer warning which is unlikely to be
helpful in this context, as there's nothing like static_cast<Aggr>(1, 2)
to quash that warning.

However, the proposal also mentions "If T is ``array of unknown bound of U'',
this direct-initialization defines the type of the expression as U[1]" which
suggest that this should work for arrays (they're aggregates too, after all).
Ville, can you confirm that these

  int (&&r)[3] = static_cast<int[3]>(42);
  int (&&r2)[1] = static_cast<int[]>(42);

are supposed to work now?  There's no {} variant to check.  Thanks.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

gcc/cp/ChangeLog:

	PR c++/92812
	* typeck.c (build_static_cast_1): Add warning_sentinel for
	-Wmissing-field-initializer.

gcc/testsuite/ChangeLog:

	PR c++/92812
	* g++.dg/cpp2a/paren-init27.C: New test.
---
 gcc/cp/typeck.c                           |  3 +++
 gcc/testsuite/g++.dg/cpp2a/paren-init27.C | 24 +++++++++++++++++++++++
 2 files changed, 27 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init27.C

diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 589e014f855..062751a6379 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -7472,6 +7472,9 @@ build_static_cast_1 (location_t loc, tree type, tree expr, bool c_cast_p,
      static_cast of the form static_cast<T>(e) if the declaration T
      t(e);" is well-formed, for some invented temporary variable
      t.  */
+
+  /* In C++20, we don't want to warn about static_cast<Aggr>(1).  */
+  warning_sentinel w (warn_missing_field_initializers);
   result = perform_direct_initialization_if_possible (type, expr,
 						      c_cast_p, complain);
   if (result)
diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init27.C b/gcc/testsuite/g++.dg/cpp2a/paren-init27.C
new file mode 100644
index 00000000000..a856c7fd7be
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/paren-init27.C
@@ -0,0 +1,24 @@
+// PR c++/92812
+// P1975R0
+// { dg-do run { target c++20 } }
+// { dg-options "-Wall -Wextra" }
+
+struct Aggr { int x; int y; };
+struct Base { int i; Base(int i_) : i{i_} { } };
+struct BaseAggr : Base { };
+struct X { };
+struct AggrSDM { static X x; int i; int j; };
+
+int
+main ()
+{
+  Aggr a = static_cast<Aggr>(42);
+  if (a.x != 42 || a.y != 0)
+    __builtin_abort ();
+  BaseAggr b = static_cast<BaseAggr>(42);
+  if (b.i != 42)
+    __builtin_abort ();
+  AggrSDM s = static_cast<AggrSDM>(42);
+  if (s.i != 42 || s.j != 0)
+    __builtin_abort ();
+}

base-commit: 932fbc868ad429167a3d4d5625aa9d6dc0b4506b
-- 
2.26.2


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] c++: Fixing the wording of () aggregate-init [PR92812]
  2020-07-20 23:28 [PATCH] c++: Fixing the wording of () aggregate-init [PR92812] Marek Polacek
@ 2020-07-21  9:53 ` Ville Voutilainen
  2020-07-21 18:56   ` Marek Polacek
  2020-07-29 23:21 ` Jason Merrill
  1 sibling, 1 reply; 10+ messages in thread
From: Ville Voutilainen @ 2020-07-21  9:53 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jason Merrill

On Tue, 21 Jul 2020 at 02:28, Marek Polacek <polacek@redhat.com> wrote:
>
> P1975R0 tweaks the static_cast wording: it says that "An expression e can be
> explicitly converted to a type T if [...] T is an aggregate type having a first
> element x and there is an implicit conversion sequence from e to the type of
> x."  This already works for classes, e.g.:
>
>   struct Aggr { int x; int y; };
>   Aggr a = static_cast<Aggr>(1);
>
> albeit I noticed a -Wmissing-field-initializer warning which is unlikely to be
> helpful in this context, as there's nothing like static_cast<Aggr>(1, 2)
> to quash that warning.
>
> However, the proposal also mentions "If T is ``array of unknown bound of U'',
> this direct-initialization defines the type of the expression as U[1]" which
> suggest that this should work for arrays (they're aggregates too, after all).
> Ville, can you confirm that these
>
>   int (&&r)[3] = static_cast<int[3]>(42);
>   int (&&r2)[1] = static_cast<int[]>(42);
>
> are supposed to work now?  There's no {} variant to check.  Thanks.

I don't know what it means to cast something to an array; doesn't that create
an array prvalue? Is that a thing?

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] c++: Fixing the wording of () aggregate-init [PR92812]
  2020-07-21  9:53 ` Ville Voutilainen
@ 2020-07-21 18:56   ` Marek Polacek
  2020-07-21 19:03     ` Ville Voutilainen
  0 siblings, 1 reply; 10+ messages in thread
From: Marek Polacek @ 2020-07-21 18:56 UTC (permalink / raw)
  To: Ville Voutilainen; +Cc: GCC Patches, Jason Merrill

On Tue, Jul 21, 2020 at 12:53:03PM +0300, Ville Voutilainen wrote:
> On Tue, 21 Jul 2020 at 02:28, Marek Polacek <polacek@redhat.com> wrote:
> >
> > P1975R0 tweaks the static_cast wording: it says that "An expression e can be
> > explicitly converted to a type T if [...] T is an aggregate type having a first
> > element x and there is an implicit conversion sequence from e to the type of
> > x."  This already works for classes, e.g.:
> >
> >   struct Aggr { int x; int y; };
> >   Aggr a = static_cast<Aggr>(1);
> >
> > albeit I noticed a -Wmissing-field-initializer warning which is unlikely to be
> > helpful in this context, as there's nothing like static_cast<Aggr>(1, 2)
> > to quash that warning.
> >
> > However, the proposal also mentions "If T is ``array of unknown bound of U'',
> > this direct-initialization defines the type of the expression as U[1]" which
> > suggest that this should work for arrays (they're aggregates too, after all).
> > Ville, can you confirm that these
> >
> >   int (&&r)[3] = static_cast<int[3]>(42);
> >   int (&&r2)[1] = static_cast<int[]>(42);
> >
> > are supposed to work now?  There's no {} variant to check.  Thanks.
> 
> I don't know what it means to cast something to an array; doesn't that create
> an array prvalue? Is that a thing?

Yes, I imagined this would be similar to

using T = int[3];
int (&&r)[3] = T{1, 2, 3}; // binds to array prvalue, lifetime extended

but I'd like to avoid allowing code that isn't supposed to work.
We also might want to consider if we want to extend the lifetime of r/r2 in my
previous example (I think so; DRs 1299/1376).  Worth bothering CWG?

Marek


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] c++: Fixing the wording of () aggregate-init [PR92812]
  2020-07-21 18:56   ` Marek Polacek
@ 2020-07-21 19:03     ` Ville Voutilainen
  2020-07-21 19:38       ` Marek Polacek
  0 siblings, 1 reply; 10+ messages in thread
From: Ville Voutilainen @ 2020-07-21 19:03 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jason Merrill

On Tue, 21 Jul 2020 at 21:56, Marek Polacek <polacek@redhat.com> wrote:
>
> On Tue, Jul 21, 2020 at 12:53:03PM +0300, Ville Voutilainen wrote:
> > On Tue, 21 Jul 2020 at 02:28, Marek Polacek <polacek@redhat.com> wrote:
> > >
> > > P1975R0 tweaks the static_cast wording: it says that "An expression e can be
> > > explicitly converted to a type T if [...] T is an aggregate type having a first
> > > element x and there is an implicit conversion sequence from e to the type of
> > > x."  This already works for classes, e.g.:
> > >
> > >   struct Aggr { int x; int y; };
> > >   Aggr a = static_cast<Aggr>(1);
> > >
> > > albeit I noticed a -Wmissing-field-initializer warning which is unlikely to be
> > > helpful in this context, as there's nothing like static_cast<Aggr>(1, 2)
> > > to quash that warning.
> > >
> > > However, the proposal also mentions "If T is ``array of unknown bound of U'',
> > > this direct-initialization defines the type of the expression as U[1]" which
> > > suggest that this should work for arrays (they're aggregates too, after all).
> > > Ville, can you confirm that these
> > >
> > >   int (&&r)[3] = static_cast<int[3]>(42);
> > >   int (&&r2)[1] = static_cast<int[]>(42);
> > >
> > > are supposed to work now?  There's no {} variant to check.  Thanks.
> >
> > I don't know what it means to cast something to an array; doesn't that create
> > an array prvalue? Is that a thing?
>
> Yes, I imagined this would be similar to
>
> using T = int[3];
> int (&&r)[3] = T{1, 2, 3}; // binds to array prvalue, lifetime extended
>
> but I'd like to avoid allowing code that isn't supposed to work.

Okay. I think it's remotely reasonable that a static_cast<T>(42) would
work for an array, then.
And by a natural extension, that using the concrete type would also
work. That seems consistent,
but doesn't seem like it rises to the level of "an important part of
the design". Trafficking arrays
around in generic code is already hard, because they don't behave like
other things do, so the
answer to "was this supposed to work?" is pretty much "it wasn't
considered during the design phase".

> We also might want to consider if we want to extend the lifetime of r/r2 in my
> previous example (I think so; DRs 1299/1376).  Worth bothering CWG?

I think it's a good idea to bother CWG with both the above and the
lifetime extension.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] c++: Fixing the wording of () aggregate-init [PR92812]
  2020-07-21 19:03     ` Ville Voutilainen
@ 2020-07-21 19:38       ` Marek Polacek
  2020-07-21 19:52         ` Ville Voutilainen
  0 siblings, 1 reply; 10+ messages in thread
From: Marek Polacek @ 2020-07-21 19:38 UTC (permalink / raw)
  To: Ville Voutilainen; +Cc: GCC Patches

On Tue, Jul 21, 2020 at 10:03:37PM +0300, Ville Voutilainen via Gcc-patches wrote:
> On Tue, 21 Jul 2020 at 21:56, Marek Polacek <polacek@redhat.com> wrote:
> >
> > On Tue, Jul 21, 2020 at 12:53:03PM +0300, Ville Voutilainen wrote:
> > > On Tue, 21 Jul 2020 at 02:28, Marek Polacek <polacek@redhat.com> wrote:
> > > >
> > > > P1975R0 tweaks the static_cast wording: it says that "An expression e can be
> > > > explicitly converted to a type T if [...] T is an aggregate type having a first
> > > > element x and there is an implicit conversion sequence from e to the type of
> > > > x."  This already works for classes, e.g.:
> > > >
> > > >   struct Aggr { int x; int y; };
> > > >   Aggr a = static_cast<Aggr>(1);
> > > >
> > > > albeit I noticed a -Wmissing-field-initializer warning which is unlikely to be
> > > > helpful in this context, as there's nothing like static_cast<Aggr>(1, 2)
> > > > to quash that warning.
> > > >
> > > > However, the proposal also mentions "If T is ``array of unknown bound of U'',
> > > > this direct-initialization defines the type of the expression as U[1]" which
> > > > suggest that this should work for arrays (they're aggregates too, after all).
> > > > Ville, can you confirm that these
> > > >
> > > >   int (&&r)[3] = static_cast<int[3]>(42);
> > > >   int (&&r2)[1] = static_cast<int[]>(42);
> > > >
> > > > are supposed to work now?  There's no {} variant to check.  Thanks.
> > >
> > > I don't know what it means to cast something to an array; doesn't that create
> > > an array prvalue? Is that a thing?
> >
> > Yes, I imagined this would be similar to
> >
> > using T = int[3];
> > int (&&r)[3] = T{1, 2, 3}; // binds to array prvalue, lifetime extended
> >
> > but I'd like to avoid allowing code that isn't supposed to work.
> 
> Okay. I think it's remotely reasonable that a static_cast<T>(42) would
> work for an array, then.
> And by a natural extension, that using the concrete type would also
> work. That seems consistent,
> but doesn't seem like it rises to the level of "an important part of
> the design". Trafficking arrays
> around in generic code is already hard, because they don't behave like
> other things do, so the
> answer to "was this supposed to work?" is pretty much "it wasn't
> considered during the design phase".

Fair enough.

> > We also might want to consider if we want to extend the lifetime of r/r2 in my
> > previous example (I think so; DRs 1299/1376).  Worth bothering CWG?
> 
> I think it's a good idea to bother CWG with both the above and the
> lifetime extension.

I'll email core then.  Thanks for responding!

Jason, I think the patch still makes sense as-is; presumably we can follow up
with the controversial bits (arrays) later.

Marek


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] c++: Fixing the wording of () aggregate-init [PR92812]
  2020-07-21 19:38       ` Marek Polacek
@ 2020-07-21 19:52         ` Ville Voutilainen
  0 siblings, 0 replies; 10+ messages in thread
From: Ville Voutilainen @ 2020-07-21 19:52 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches

On Tue, 21 Jul 2020 at 22:39, Marek Polacek <polacek@redhat.com> wrote:
> > Okay. I think it's remotely reasonable that a static_cast<T>(42) would
> > work for an array, then.
> > And by a natural extension, that using the concrete type would also
> > work. That seems consistent,
> > but doesn't seem like it rises to the level of "an important part of
> > the design". Trafficking arrays
> > around in generic code is already hard, because they don't behave like
> > other things do, so the
> > answer to "was this supposed to work?" is pretty much "it wasn't
> > considered during the design phase".
>
> Fair enough.

Sorry. :)  None of the main driving-use-cases for allowing paren-init
of aggregates involved
arrays. They were to some extent expected to hitch a ride since they
are aggregates, but
otherwise they never received particular design-level lovin'. It
seemed plausible to
be able to paren-init a member array in a ctor-initializer.
Paren-initializing automatic storage
duration variables requires a typedef anyway. So the casting cases
have not been fully
fledged design-wise, and that's mostly just oversight. Or lack of
energy, if you wish.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] c++: Fixing the wording of () aggregate-init [PR92812]
  2020-07-20 23:28 [PATCH] c++: Fixing the wording of () aggregate-init [PR92812] Marek Polacek
  2020-07-21  9:53 ` Ville Voutilainen
@ 2020-07-29 23:21 ` Jason Merrill
  2020-07-31 17:24   ` Marek Polacek
  1 sibling, 1 reply; 10+ messages in thread
From: Jason Merrill @ 2020-07-29 23:21 UTC (permalink / raw)
  To: Marek Polacek, GCC Patches, Ville Voutilainen

On 7/20/20 7:28 PM, Marek Polacek wrote:
> P1975R0 tweaks the static_cast wording: it says that "An expression e can be
> explicitly converted to a type T if [...] T is an aggregate type having a first
> element x and there is an implicit conversion sequence from e to the type of
> x."  This already works for classes, e.g.:
> 
>    struct Aggr { int x; int y; };
>    Aggr a = static_cast<Aggr>(1);
> 
> albeit I noticed a -Wmissing-field-initializer warning which is unlikely to be
> helpful in this context, as there's nothing like static_cast<Aggr>(1, 2)
> to quash that warning.

You could write Aggr{1,2} instead?

This warning could be helpful if they didn't realize that what they were 
writing is initializing one element of an aggregate.

> However, the proposal also mentions "If T is ``array of unknown bound of U'',
> this direct-initialization defines the type of the expression as U[1]" which
> suggest that this should work for arrays (they're aggregates too, after all).
> Ville, can you confirm that these
> 
>    int (&&r)[3] = static_cast<int[3]>(42);
>    int (&&r2)[1] = static_cast<int[]>(42);
> 
> are supposed to work now?  There's no {} variant to check.  Thanks.

I'll review the discussion of this later.

> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> 
> gcc/cp/ChangeLog:
> 
> 	PR c++/92812
> 	* typeck.c (build_static_cast_1): Add warning_sentinel for
> 	-Wmissing-field-initializer.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/92812
> 	* g++.dg/cpp2a/paren-init27.C: New test.
> ---
>   gcc/cp/typeck.c                           |  3 +++
>   gcc/testsuite/g++.dg/cpp2a/paren-init27.C | 24 +++++++++++++++++++++++
>   2 files changed, 27 insertions(+)
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init27.C
> 
> diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
> index 589e014f855..062751a6379 100644
> --- a/gcc/cp/typeck.c
> +++ b/gcc/cp/typeck.c
> @@ -7472,6 +7472,9 @@ build_static_cast_1 (location_t loc, tree type, tree expr, bool c_cast_p,
>        static_cast of the form static_cast<T>(e) if the declaration T
>        t(e);" is well-formed, for some invented temporary variable
>        t.  */
> +
> +  /* In C++20, we don't want to warn about static_cast<Aggr>(1).  */
> +  warning_sentinel w (warn_missing_field_initializers);
>     result = perform_direct_initialization_if_possible (type, expr,
>   						      c_cast_p, complain);
>     if (result)
> diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init27.C b/gcc/testsuite/g++.dg/cpp2a/paren-init27.C
> new file mode 100644
> index 00000000000..a856c7fd7be
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/paren-init27.C
> @@ -0,0 +1,24 @@
> +// PR c++/92812
> +// P1975R0
> +// { dg-do run { target c++20 } }
> +// { dg-options "-Wall -Wextra" }
> +
> +struct Aggr { int x; int y; };
> +struct Base { int i; Base(int i_) : i{i_} { } };
> +struct BaseAggr : Base { };
> +struct X { };
> +struct AggrSDM { static X x; int i; int j; };
> +
> +int
> +main ()
> +{
> +  Aggr a = static_cast<Aggr>(42);
> +  if (a.x != 42 || a.y != 0)
> +    __builtin_abort ();
> +  BaseAggr b = static_cast<BaseAggr>(42);
> +  if (b.i != 42)
> +    __builtin_abort ();
> +  AggrSDM s = static_cast<AggrSDM>(42);
> +  if (s.i != 42 || s.j != 0)
> +    __builtin_abort ();
> +}
> 
> base-commit: 932fbc868ad429167a3d4d5625aa9d6dc0b4506b
> 


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] c++: Fixing the wording of () aggregate-init [PR92812]
  2020-07-29 23:21 ` Jason Merrill
@ 2020-07-31 17:24   ` Marek Polacek
  0 siblings, 0 replies; 10+ messages in thread
From: Marek Polacek @ 2020-07-31 17:24 UTC (permalink / raw)
  To: Jason Merrill; +Cc: GCC Patches

On Wed, Jul 29, 2020 at 07:21:46PM -0400, Jason Merrill via Gcc-patches wrote:
> On 7/20/20 7:28 PM, Marek Polacek wrote:
> > P1975R0 tweaks the static_cast wording: it says that "An expression e can be
> > explicitly converted to a type T if [...] T is an aggregate type having a first
> > element x and there is an implicit conversion sequence from e to the type of
> > x."  This already works for classes, e.g.:
> > 
> >    struct Aggr { int x; int y; };
> >    Aggr a = static_cast<Aggr>(1);
> > 
> > albeit I noticed a -Wmissing-field-initializer warning which is unlikely to be
> > helpful in this context, as there's nothing like static_cast<Aggr>(1, 2)
> > to quash that warning.
> 
> You could write Aggr{1,2} instead?
> 
> This warning could be helpful if they didn't realize that what they were
> writing is initializing one element of an aggregate.

Ok, I can drop it.  Though explicit cast usually suppress warnings like that.

> > However, the proposal also mentions "If T is ``array of unknown bound of U'',
> > this direct-initialization defines the type of the expression as U[1]" which
> > suggest that this should work for arrays (they're aggregates too, after all).
> > Ville, can you confirm that these
> > 
> >    int (&&r)[3] = static_cast<int[3]>(42);
> >    int (&&r2)[1] = static_cast<int[]>(42);
> > 
> > are supposed to work now?  There's no {} variant to check.  Thanks.
> 
> I'll review the discussion of this later.

It's become clear that the array cases are supposed to work, so I think
let's drop this patch and I'll post a new patch when I get the array cases
working.

Thanks,
Marek


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] c++: Fixing the wording of () aggregate-init [PR92812]
  2020-08-11 23:34 Marek Polacek
@ 2020-08-12 20:10 ` Jason Merrill
  0 siblings, 0 replies; 10+ messages in thread
From: Jason Merrill @ 2020-08-12 20:10 UTC (permalink / raw)
  To: Marek Polacek, GCC Patches

On 8/11/20 7:34 PM, Marek Polacek wrote:
> P1975R0 tweaks the static_cast wording: it says that "An expression e can be
> explicitly converted to a type T if [...] T is an aggregate type having a first
> element x and there is an implicit conversion sequence from e to the type of
> x."  This already works for classes, e.g.:
> 
>    struct Aggr { int x; int y; };
>    Aggr a = static_cast<Aggr>(1);
> 
> for which we create TARGET_EXPR <D.2111, {.x=1}>.
> 
> The proposal also mentions "If T is ``array of unknown bound of U'',
> this direct-initialization defines the type of the expression as U[1]" which
> suggest that this should work for arrays (they're aggregates too, after all):
> 
>    int (&&r)[3] = static_cast<int[3]>(42);
>    int (&&r2)[1] = static_cast<int[]>(42);
> 
> So I handled that specifically in build_static_cast_1: wrap the
> expression in { } and initialize from that.  For the 'r' case above
> this creates TARGET_EXPR <D.2083, {42}>.
> 
> There are multiple things in play, as usual, so the tests test brace
> elision, narrowing, explicit constructors, and lifetime extension too.
> I think it's in line with what we discussed on the core reflector.
> 
> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

OK.

> gcc/cp/ChangeLog:
> 
> 	PR c++/92812
> 	* typeck.c (build_static_cast_1): Implement P1975R0 by allowing
> 	static_cast to aggregate type.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR c++/92812
> 	* g++.dg/cpp2a/paren-init27.C: New test.
> 	* g++.dg/cpp2a/paren-init28.C: New test.
> 	* g++.dg/cpp2a/paren-init29.C: New test.
> 	* g++.dg/cpp2a/paren-init30.C: New test.
> 	* g++.dg/cpp2a/paren-init31.C: New test.
> 	* g++.dg/cpp2a/paren-init32.C: New test.
> ---
>   gcc/cp/typeck.c                           | 14 +++++++++++++
>   gcc/testsuite/g++.dg/cpp2a/paren-init27.C | 24 +++++++++++++++++++++++
>   gcc/testsuite/g++.dg/cpp2a/paren-init28.C | 15 ++++++++++++++
>   gcc/testsuite/g++.dg/cpp2a/paren-init29.C | 15 ++++++++++++++
>   gcc/testsuite/g++.dg/cpp2a/paren-init30.C | 23 ++++++++++++++++++++++
>   gcc/testsuite/g++.dg/cpp2a/paren-init31.C | 10 ++++++++++
>   gcc/testsuite/g++.dg/cpp2a/paren-init32.C | 21 ++++++++++++++++++++
>   7 files changed, 122 insertions(+)
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init27.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init28.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init29.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init30.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init31.C
>   create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init32.C
> 
> diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
> index a557f3439a8..9166156a5d5 100644
> --- a/gcc/cp/typeck.c
> +++ b/gcc/cp/typeck.c
> @@ -7480,6 +7480,20 @@ build_static_cast_1 (location_t loc, tree type, tree expr, bool c_cast_p,
>        t.  */
>     result = perform_direct_initialization_if_possible (type, expr,
>   						      c_cast_p, complain);
> +  /* P1975 allows static_cast<Aggr>(42), as well as static_cast<T[5]>(42),
> +     which initialize the first element of the aggregate.  We need to handle
> +     the array case specifically.  */
> +  if (result == NULL_TREE
> +      && cxx_dialect >= cxx20
> +      && TREE_CODE (type) == ARRAY_TYPE)
> +    {
> +      /* Create { EXPR } and perform direct-initialization from it.  */
> +      tree e = build_constructor_single (init_list_type_node, NULL_TREE, expr);
> +      CONSTRUCTOR_IS_DIRECT_INIT (e) = true;
> +      CONSTRUCTOR_IS_PAREN_INIT (e) = true;
> +      result = perform_direct_initialization_if_possible (type, e, c_cast_p,
> +							  complain);
> +    }
>     if (result)
>       {
>         if (processing_template_decl)
> diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init27.C b/gcc/testsuite/g++.dg/cpp2a/paren-init27.C
> new file mode 100644
> index 00000000000..0b8cbe33b69
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/paren-init27.C
> @@ -0,0 +1,24 @@
> +// PR c++/92812
> +// P1975R0
> +// { dg-do run { target c++20 } }
> +// { dg-options "-Wall -Wextra" }
> +
> +struct Aggr { int x; int y; };
> +struct Base { int i; Base(int i_) : i{i_} { } };
> +struct BaseAggr : Base { };
> +struct X { };
> +struct AggrSDM { static X x; int i; int j; };
> +
> +int
> +main ()
> +{
> +  Aggr a = static_cast<Aggr>(42); // { dg-warning "missing initializer" }
> +  if (a.x != 42 || a.y != 0)
> +    __builtin_abort ();
> +  BaseAggr b = static_cast<BaseAggr>(42);
> +  if (b.i != 42)
> +    __builtin_abort ();
> +  AggrSDM s = static_cast<AggrSDM>(42); // { dg-warning "missing initializer" }
> +  if (s.i != 42 || s.j != 0)
> +    __builtin_abort ();
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init28.C b/gcc/testsuite/g++.dg/cpp2a/paren-init28.C
> new file mode 100644
> index 00000000000..8c57dc8e155
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/paren-init28.C
> @@ -0,0 +1,15 @@
> +// PR c++/92812
> +// P1975R0
> +// { dg-do compile { target c++20 } }
> +
> +// In both cases the reference declarations lifetime-extend the array
> +// temporary.
> +int (&&r)[3] = static_cast<int[3]>(42);
> +int (&&r2)[1] = static_cast<int[]>(42);
> +
> +// Make sure we've lifetime-extended.
> +// { dg-final { scan-assembler "_ZGR1r_" } }
> +// { dg-final { scan-assembler "_ZGR2r2_" } }
> +
> +// Narrowing is probably OK here.
> +int (&&r3)[1] = static_cast<int[1]>(1.3);
> diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init29.C b/gcc/testsuite/g++.dg/cpp2a/paren-init29.C
> new file mode 100644
> index 00000000000..c39cd8cc0d0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/paren-init29.C
> @@ -0,0 +1,15 @@
> +// PR c++/92812
> +// P1975R0
> +// { dg-do run { target c++20 } }
> +
> +int (&&r)[3] = static_cast<int[3]>(42);
> +int (&&r2)[1] = static_cast<int[]>(42);
> +
> +int
> +main ()
> +{
> +  if (r[0] != 42 || r[1] != 0 || r[2] != 0)
> +    __builtin_abort ();
> +  if (r2[0] != 42 || sizeof (r2) != sizeof (int))
> +    __builtin_abort ();
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init30.C b/gcc/testsuite/g++.dg/cpp2a/paren-init30.C
> new file mode 100644
> index 00000000000..6b2e86f00f4
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/paren-init30.C
> @@ -0,0 +1,23 @@
> +// PR c++/92812
> +// P1975R0
> +// { dg-do compile { target c++20 } }
> +
> +struct S1 {
> +  int i;
> +  int j;
> +};
> +
> +struct S2 {
> +  S1 s[4];
> +};
> +
> +struct S3 {
> +  S2 s2;
> +};
> +
> +void
> +f ()
> +{
> +  // Brace elision not allowed.
> +  auto s3 = static_cast<S3>(1); // { dg-error "could not convert" }
> +}
> diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init31.C b/gcc/testsuite/g++.dg/cpp2a/paren-init31.C
> new file mode 100644
> index 00000000000..3600c4993a5
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/paren-init31.C
> @@ -0,0 +1,10 @@
> +// PR c++/92812
> +// P1975R0
> +// { dg-do compile { target c++20 } }
> +// Test we don't lifetime-extend the int temporary.
> +
> +struct A { const int &r; };
> +A a(42);
> +auto a2 = static_cast<A>(42);
> +
> +// { dg-final { scan-assembler-not "_ZGR" } }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init32.C b/gcc/testsuite/g++.dg/cpp2a/paren-init32.C
> new file mode 100644
> index 00000000000..bf7833ebd5b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/paren-init32.C
> @@ -0,0 +1,21 @@
> +// PR c++/92812
> +// P1975R0
> +// { dg-do compile { target c++20 } }
> +
> +struct A { int i; };
> +struct A2 { int i; A2(int); };
> +struct A3 { int i; explicit A3(int); };
> +
> +struct X { A a; };
> +auto x = static_cast<X>(42); // { dg-error "could not convert" }
> +
> +struct X2 { A2 a; };
> +auto x2 = static_cast<X2>(42);
> +
> +struct X3 { A3 a; };
> +// Aggregate-initialization copy-initializes, so the explicit ctor
> +// isn't considered.
> +auto x3 = static_cast<X3>(42); // { dg-error "could not convert" }
> +
> +struct NonAggr { int i; virtual void foo (); };
> +auto x4 = static_cast<NonAggr>(42); // { dg-error "no matching" }
> 
> base-commit: ebd203778cc56df61cc3434fa01e77b4bae26362
> 


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH] c++: Fixing the wording of () aggregate-init [PR92812]
@ 2020-08-11 23:34 Marek Polacek
  2020-08-12 20:10 ` Jason Merrill
  0 siblings, 1 reply; 10+ messages in thread
From: Marek Polacek @ 2020-08-11 23:34 UTC (permalink / raw)
  To: GCC Patches, Jason Merrill

P1975R0 tweaks the static_cast wording: it says that "An expression e can be
explicitly converted to a type T if [...] T is an aggregate type having a first
element x and there is an implicit conversion sequence from e to the type of
x."  This already works for classes, e.g.:

  struct Aggr { int x; int y; };
  Aggr a = static_cast<Aggr>(1);

for which we create TARGET_EXPR <D.2111, {.x=1}>.

The proposal also mentions "If T is ``array of unknown bound of U'',
this direct-initialization defines the type of the expression as U[1]" which
suggest that this should work for arrays (they're aggregates too, after all):

  int (&&r)[3] = static_cast<int[3]>(42);
  int (&&r2)[1] = static_cast<int[]>(42);

So I handled that specifically in build_static_cast_1: wrap the
expression in { } and initialize from that.  For the 'r' case above
this creates TARGET_EXPR <D.2083, {42}>.

There are multiple things in play, as usual, so the tests test brace
elision, narrowing, explicit constructors, and lifetime extension too.
I think it's in line with what we discussed on the core reflector.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

gcc/cp/ChangeLog:

	PR c++/92812
	* typeck.c (build_static_cast_1): Implement P1975R0 by allowing
	static_cast to aggregate type.

gcc/testsuite/ChangeLog:

	PR c++/92812
	* g++.dg/cpp2a/paren-init27.C: New test.
	* g++.dg/cpp2a/paren-init28.C: New test.
	* g++.dg/cpp2a/paren-init29.C: New test.
	* g++.dg/cpp2a/paren-init30.C: New test.
	* g++.dg/cpp2a/paren-init31.C: New test.
	* g++.dg/cpp2a/paren-init32.C: New test.
---
 gcc/cp/typeck.c                           | 14 +++++++++++++
 gcc/testsuite/g++.dg/cpp2a/paren-init27.C | 24 +++++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp2a/paren-init28.C | 15 ++++++++++++++
 gcc/testsuite/g++.dg/cpp2a/paren-init29.C | 15 ++++++++++++++
 gcc/testsuite/g++.dg/cpp2a/paren-init30.C | 23 ++++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp2a/paren-init31.C | 10 ++++++++++
 gcc/testsuite/g++.dg/cpp2a/paren-init32.C | 21 ++++++++++++++++++++
 7 files changed, 122 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init27.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init28.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init29.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init30.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init31.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/paren-init32.C

diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index a557f3439a8..9166156a5d5 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -7480,6 +7480,20 @@ build_static_cast_1 (location_t loc, tree type, tree expr, bool c_cast_p,
      t.  */
   result = perform_direct_initialization_if_possible (type, expr,
 						      c_cast_p, complain);
+  /* P1975 allows static_cast<Aggr>(42), as well as static_cast<T[5]>(42),
+     which initialize the first element of the aggregate.  We need to handle
+     the array case specifically.  */
+  if (result == NULL_TREE
+      && cxx_dialect >= cxx20
+      && TREE_CODE (type) == ARRAY_TYPE)
+    {
+      /* Create { EXPR } and perform direct-initialization from it.  */
+      tree e = build_constructor_single (init_list_type_node, NULL_TREE, expr);
+      CONSTRUCTOR_IS_DIRECT_INIT (e) = true;
+      CONSTRUCTOR_IS_PAREN_INIT (e) = true;
+      result = perform_direct_initialization_if_possible (type, e, c_cast_p,
+							  complain);
+    }
   if (result)
     {
       if (processing_template_decl)
diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init27.C b/gcc/testsuite/g++.dg/cpp2a/paren-init27.C
new file mode 100644
index 00000000000..0b8cbe33b69
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/paren-init27.C
@@ -0,0 +1,24 @@
+// PR c++/92812
+// P1975R0
+// { dg-do run { target c++20 } }
+// { dg-options "-Wall -Wextra" }
+
+struct Aggr { int x; int y; };
+struct Base { int i; Base(int i_) : i{i_} { } };
+struct BaseAggr : Base { };
+struct X { };
+struct AggrSDM { static X x; int i; int j; };
+
+int
+main ()
+{
+  Aggr a = static_cast<Aggr>(42); // { dg-warning "missing initializer" }
+  if (a.x != 42 || a.y != 0)
+    __builtin_abort ();
+  BaseAggr b = static_cast<BaseAggr>(42);
+  if (b.i != 42)
+    __builtin_abort ();
+  AggrSDM s = static_cast<AggrSDM>(42); // { dg-warning "missing initializer" }
+  if (s.i != 42 || s.j != 0)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init28.C b/gcc/testsuite/g++.dg/cpp2a/paren-init28.C
new file mode 100644
index 00000000000..8c57dc8e155
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/paren-init28.C
@@ -0,0 +1,15 @@
+// PR c++/92812
+// P1975R0
+// { dg-do compile { target c++20 } }
+
+// In both cases the reference declarations lifetime-extend the array
+// temporary.
+int (&&r)[3] = static_cast<int[3]>(42);
+int (&&r2)[1] = static_cast<int[]>(42);
+
+// Make sure we've lifetime-extended.
+// { dg-final { scan-assembler "_ZGR1r_" } }
+// { dg-final { scan-assembler "_ZGR2r2_" } }
+
+// Narrowing is probably OK here.
+int (&&r3)[1] = static_cast<int[1]>(1.3);
diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init29.C b/gcc/testsuite/g++.dg/cpp2a/paren-init29.C
new file mode 100644
index 00000000000..c39cd8cc0d0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/paren-init29.C
@@ -0,0 +1,15 @@
+// PR c++/92812
+// P1975R0
+// { dg-do run { target c++20 } }
+
+int (&&r)[3] = static_cast<int[3]>(42);
+int (&&r2)[1] = static_cast<int[]>(42);
+
+int
+main ()
+{
+  if (r[0] != 42 || r[1] != 0 || r[2] != 0)
+    __builtin_abort ();
+  if (r2[0] != 42 || sizeof (r2) != sizeof (int))
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init30.C b/gcc/testsuite/g++.dg/cpp2a/paren-init30.C
new file mode 100644
index 00000000000..6b2e86f00f4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/paren-init30.C
@@ -0,0 +1,23 @@
+// PR c++/92812
+// P1975R0
+// { dg-do compile { target c++20 } }
+
+struct S1 {
+  int i;
+  int j;
+};
+
+struct S2 {
+  S1 s[4];
+};
+
+struct S3 {
+  S2 s2;
+};
+
+void
+f ()
+{
+  // Brace elision not allowed.
+  auto s3 = static_cast<S3>(1); // { dg-error "could not convert" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init31.C b/gcc/testsuite/g++.dg/cpp2a/paren-init31.C
new file mode 100644
index 00000000000..3600c4993a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/paren-init31.C
@@ -0,0 +1,10 @@
+// PR c++/92812
+// P1975R0
+// { dg-do compile { target c++20 } }
+// Test we don't lifetime-extend the int temporary.
+
+struct A { const int &r; };
+A a(42);
+auto a2 = static_cast<A>(42);
+
+// { dg-final { scan-assembler-not "_ZGR" } }
diff --git a/gcc/testsuite/g++.dg/cpp2a/paren-init32.C b/gcc/testsuite/g++.dg/cpp2a/paren-init32.C
new file mode 100644
index 00000000000..bf7833ebd5b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/paren-init32.C
@@ -0,0 +1,21 @@
+// PR c++/92812
+// P1975R0
+// { dg-do compile { target c++20 } }
+
+struct A { int i; };
+struct A2 { int i; A2(int); };
+struct A3 { int i; explicit A3(int); };
+
+struct X { A a; };
+auto x = static_cast<X>(42); // { dg-error "could not convert" }
+
+struct X2 { A2 a; };
+auto x2 = static_cast<X2>(42);
+
+struct X3 { A3 a; };
+// Aggregate-initialization copy-initializes, so the explicit ctor
+// isn't considered.
+auto x3 = static_cast<X3>(42); // { dg-error "could not convert" }
+
+struct NonAggr { int i; virtual void foo (); };
+auto x4 = static_cast<NonAggr>(42); // { dg-error "no matching" }

base-commit: ebd203778cc56df61cc3434fa01e77b4bae26362
-- 
2.26.2


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2020-08-12 20:10 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-20 23:28 [PATCH] c++: Fixing the wording of () aggregate-init [PR92812] Marek Polacek
2020-07-21  9:53 ` Ville Voutilainen
2020-07-21 18:56   ` Marek Polacek
2020-07-21 19:03     ` Ville Voutilainen
2020-07-21 19:38       ` Marek Polacek
2020-07-21 19:52         ` Ville Voutilainen
2020-07-29 23:21 ` Jason Merrill
2020-07-31 17:24   ` Marek Polacek
2020-08-11 23:34 Marek Polacek
2020-08-12 20:10 ` 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).