Re: C++ PATCH for c++/89214 - ICE when initializing aggregates with bases

2019-04-09 Thread Andreas Schwab
On Apr 08 2019, Marek Polacek  wrote:

> Thanks, committed.  Andreas -- I hope the failure is fixed now.

Yes, all tests of aggr-base[89].C are passing.

Andreas.

-- 
Andreas Schwab, SUSE Labs, sch...@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."


Re: C++ PATCH for c++/89214 - ICE when initializing aggregates with bases

2019-04-08 Thread Marek Polacek
On Mon, Apr 08, 2019 at 03:24:13PM -0400, Jason Merrill wrote:
> On 4/1/19 11:23 AM, Marek Polacek wrote:
> > On Mon, Apr 01, 2019 at 10:15:11AM +0200, Andreas Schwab wrote:
> > > On Mär 28 2019, Marek Polacek  wrote:
> > > 
> > > > Andreas, could you please find out why we're not hitting this code in
> > > > digest_init_r:
> > > > 
> > > > 1210   tree elt = CONSTRUCTOR_ELT (stripped_init, 0)->value;
> > > > 1211   if (reference_related_p (type, TREE_TYPE (elt)))
> > > 
> > > This is never executed if flag_checking is false, of course.
> > 
> > It's certainly wrong for a warning to depend on flag_checking, so this
> > patch corrects it, and I hope will fix the ia64 problem as well.
> > 
> > Bootstrapped/regtested on x86_64-linux, ok for trunk?
> > 
> > 2019-04-01  Marek Polacek  
> > 
> > * typeck2.c (digest_init_r): Don't condition the object slicing warning
> > on flag_checking.
> 
> OK.

Thanks, committed.  Andreas -- I hope the failure is fixed now.

Marek


Re: C++ PATCH for c++/89214 - ICE when initializing aggregates with bases

2019-04-08 Thread Jason Merrill

On 4/1/19 11:23 AM, Marek Polacek wrote:

On Mon, Apr 01, 2019 at 10:15:11AM +0200, Andreas Schwab wrote:

On Mär 28 2019, Marek Polacek  wrote:


Andreas, could you please find out why we're not hitting this code in
digest_init_r:

1210   tree elt = CONSTRUCTOR_ELT (stripped_init, 0)->value;
1211   if (reference_related_p (type, TREE_TYPE (elt)))


This is never executed if flag_checking is false, of course.


It's certainly wrong for a warning to depend on flag_checking, so this
patch corrects it, and I hope will fix the ia64 problem as well.

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

2019-04-01  Marek Polacek  

* typeck2.c (digest_init_r): Don't condition the object slicing warning
on flag_checking.


OK.

Jason



Re: C++ PATCH for c++/89214 - ICE when initializing aggregates with bases

2019-04-08 Thread Marek Polacek
Any comments?

On Mon, Apr 01, 2019 at 11:23:29AM -0400, Marek Polacek wrote:
> On Mon, Apr 01, 2019 at 10:15:11AM +0200, Andreas Schwab wrote:
> > On Mär 28 2019, Marek Polacek  wrote:
> > 
> > > Andreas, could you please find out why we're not hitting this code in
> > > digest_init_r:
> > >
> > > 1210   tree elt = CONSTRUCTOR_ELT (stripped_init, 0)->value;
> > > 1211   if (reference_related_p (type, TREE_TYPE (elt)))
> > 
> > This is never executed if flag_checking is false, of course.
> 
> It's certainly wrong for a warning to depend on flag_checking, so this
> patch corrects it, and I hope will fix the ia64 problem as well.
> 
> Bootstrapped/regtested on x86_64-linux, ok for trunk?
> 
> 2019-04-01  Marek Polacek  
> 
>   * typeck2.c (digest_init_r): Don't condition the object slicing warning
>   on flag_checking.
> 
> diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c
> index fa98b1cb8b5..55b84f043f4 100644
> --- gcc/cp/typeck2.c
> +++ gcc/cp/typeck2.c
> @@ -1200,8 +1200,7 @@ digest_init_r (tree type, tree init, int nested, int 
> flags,
>/* "If T is a class type and the initializer list has a single
>   element of type cv U, where U is T or a class derived from T,
>   the object is initialized from that element."  */
> -  if (flag_checking
> -  && cxx_dialect >= cxx11
> +  if (cxx_dialect >= cxx11
>&& BRACE_ENCLOSED_INITIALIZER_P (stripped_init)
>&& CONSTRUCTOR_NELTS (stripped_init) == 1
>&& ((CLASS_TYPE_P (type) && !CLASSTYPE_NON_AGGREGATE (type))
> @@ -1228,7 +1227,7 @@ digest_init_r (tree type, tree init, int nested, int 
> flags,
> "results in object slicing", TREE_TYPE (field)))
>   inform (loc, "remove %<{ }%> around initializer");
>   }
> -   else
> +   else if (flag_checking)
>   /* We should have fixed this in reshape_init.  */
>   gcc_unreachable ();
>   }

Marek


Re: C++ PATCH for c++/89214 - ICE when initializing aggregates with bases

2019-04-01 Thread Marek Polacek
On Mon, Apr 01, 2019 at 10:15:11AM +0200, Andreas Schwab wrote:
> On Mär 28 2019, Marek Polacek  wrote:
> 
> > Andreas, could you please find out why we're not hitting this code in
> > digest_init_r:
> >
> > 1210   tree elt = CONSTRUCTOR_ELT (stripped_init, 0)->value;
> > 1211   if (reference_related_p (type, TREE_TYPE (elt)))
> 
> This is never executed if flag_checking is false, of course.

It's certainly wrong for a warning to depend on flag_checking, so this
patch corrects it, and I hope will fix the ia64 problem as well.

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

2019-04-01  Marek Polacek  

* typeck2.c (digest_init_r): Don't condition the object slicing warning
on flag_checking.

diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c
index fa98b1cb8b5..55b84f043f4 100644
--- gcc/cp/typeck2.c
+++ gcc/cp/typeck2.c
@@ -1200,8 +1200,7 @@ digest_init_r (tree type, tree init, int nested, int 
flags,
   /* "If T is a class type and the initializer list has a single
  element of type cv U, where U is T or a class derived from T,
  the object is initialized from that element."  */
-  if (flag_checking
-  && cxx_dialect >= cxx11
+  if (cxx_dialect >= cxx11
   && BRACE_ENCLOSED_INITIALIZER_P (stripped_init)
   && CONSTRUCTOR_NELTS (stripped_init) == 1
   && ((CLASS_TYPE_P (type) && !CLASSTYPE_NON_AGGREGATE (type))
@@ -1228,7 +1227,7 @@ digest_init_r (tree type, tree init, int nested, int 
flags,
  "results in object slicing", TREE_TYPE (field)))
inform (loc, "remove %<{ }%> around initializer");
}
- else
+ else if (flag_checking)
/* We should have fixed this in reshape_init.  */
gcc_unreachable ();
}


Re: C++ PATCH for c++/89214 - ICE when initializing aggregates with bases

2019-04-01 Thread Andreas Schwab
On Mär 28 2019, Marek Polacek  wrote:

> Andreas, could you please find out why we're not hitting this code in
> digest_init_r:
>
> 1210   tree elt = CONSTRUCTOR_ELT (stripped_init, 0)->value;
> 1211   if (reference_related_p (type, TREE_TYPE (elt)))

This is never executed if flag_checking is false, of course.

Andreas.

-- 
Andreas Schwab, SUSE Labs, sch...@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."


Re: C++ PATCH for c++/89214 - ICE when initializing aggregates with bases

2019-03-28 Thread Marek Polacek
On Thu, Mar 28, 2019 at 01:30:46PM -0400, Jason Merrill wrote:
> On 3/26/19 11:06 AM, Marek Polacek wrote:
> > On Tue, Mar 26, 2019 at 12:34:03PM +0100, Andreas Schwab wrote:
> > > I don't see any of the warnings in the tests on ia64.
> > > 
> > > FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 33)
> > > FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 34)
> > > FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 35)
> > > FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 45)
> > > FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 46)
> > > FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 47)
> > > PASS: g++.dg/cpp1z/aggr-base8.C  -std=c++17 (test for excess errors)
> > > 
> > > FAIL: g++.dg/cpp1z/aggr-base9.C  -std=c++17  (test for warnings, line 22)
> > > FAIL: g++.dg/cpp1z/aggr-base9.C  -std=c++17  (test for warnings, line 23)
> > > FAIL: g++.dg/cpp1z/aggr-base9.C  -std=c++17  (test for warnings, line 31)
> > > FAIL: g++.dg/cpp1z/aggr-base9.C  -std=c++17  (test for warnings, line 32)
> > > PASS: g++.dg/cpp1z/aggr-base9.C  -std=c++17 (test for excess errors)
> > 
> > I don't have access to an ia64 box -- I see none on Compile Farm.  But if
> > it doesn't ICE, can we just add ! { target ia64-*-* } to the dg-warnings?
> 
> Hmm, this behavior shouldn't be dependent on the target.

True.  But I can't reproduce the missing warning on e.g. ppc64.

Andreas, could you please find out why we're not hitting this code in
digest_init_r:

1210   tree elt = CONSTRUCTOR_ELT (stripped_init, 0)->value;
1211   if (reference_related_p (type, TREE_TYPE (elt)))

or if we are, is the reference_related_p condition not true?

Marek


Re: C++ PATCH for c++/89214 - ICE when initializing aggregates with bases

2019-03-28 Thread Jason Merrill

On 3/26/19 11:06 AM, Marek Polacek wrote:

On Tue, Mar 26, 2019 at 12:34:03PM +0100, Andreas Schwab wrote:

I don't see any of the warnings in the tests on ia64.

FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 33)
FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 34)
FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 35)
FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 45)
FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 46)
FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 47)
PASS: g++.dg/cpp1z/aggr-base8.C  -std=c++17 (test for excess errors)

FAIL: g++.dg/cpp1z/aggr-base9.C  -std=c++17  (test for warnings, line 22)
FAIL: g++.dg/cpp1z/aggr-base9.C  -std=c++17  (test for warnings, line 23)
FAIL: g++.dg/cpp1z/aggr-base9.C  -std=c++17  (test for warnings, line 31)
FAIL: g++.dg/cpp1z/aggr-base9.C  -std=c++17  (test for warnings, line 32)
PASS: g++.dg/cpp1z/aggr-base9.C  -std=c++17 (test for excess errors)


I don't have access to an ia64 box -- I see none on Compile Farm.  But if
it doesn't ICE, can we just add ! { target ia64-*-* } to the dg-warnings?


Hmm, this behavior shouldn't be dependent on the target.

Jason


Re: C++ PATCH for c++/89214 - ICE when initializing aggregates with bases

2019-03-26 Thread Marek Polacek
On Tue, Mar 26, 2019 at 12:34:03PM +0100, Andreas Schwab wrote:
> I don't see any of the warnings in the tests on ia64.
> 
> FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 33)
> FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 34)
> FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 35)
> FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 45)
> FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 46)
> FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 47)
> PASS: g++.dg/cpp1z/aggr-base8.C  -std=c++17 (test for excess errors)
> 
> FAIL: g++.dg/cpp1z/aggr-base9.C  -std=c++17  (test for warnings, line 22)
> FAIL: g++.dg/cpp1z/aggr-base9.C  -std=c++17  (test for warnings, line 23)
> FAIL: g++.dg/cpp1z/aggr-base9.C  -std=c++17  (test for warnings, line 31)
> FAIL: g++.dg/cpp1z/aggr-base9.C  -std=c++17  (test for warnings, line 32)
> PASS: g++.dg/cpp1z/aggr-base9.C  -std=c++17 (test for excess errors)

I don't have access to an ia64 box -- I see none on Compile Farm.  But if
it doesn't ICE, can we just add ! { target ia64-*-* } to the dg-warnings?

Marek


Re: C++ PATCH for c++/89214 - ICE when initializing aggregates with bases

2019-03-26 Thread Andreas Schwab
I don't see any of the warnings in the tests on ia64.

FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 33)
FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 34)
FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 35)
FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 45)
FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 46)
FAIL: g++.dg/cpp1z/aggr-base8.C  -std=c++17  (test for warnings, line 47)
PASS: g++.dg/cpp1z/aggr-base8.C  -std=c++17 (test for excess errors)

FAIL: g++.dg/cpp1z/aggr-base9.C  -std=c++17  (test for warnings, line 22)
FAIL: g++.dg/cpp1z/aggr-base9.C  -std=c++17  (test for warnings, line 23)
FAIL: g++.dg/cpp1z/aggr-base9.C  -std=c++17  (test for warnings, line 31)
FAIL: g++.dg/cpp1z/aggr-base9.C  -std=c++17  (test for warnings, line 32)
PASS: g++.dg/cpp1z/aggr-base9.C  -std=c++17 (test for excess errors)

Andreas.

-- 
Andreas Schwab, SUSE Labs, sch...@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."


Re: C++ PATCH for c++/89214 - ICE when initializing aggregates with bases

2019-03-25 Thread Jason Merrill

On 3/25/19 12:02 PM, Marek Polacek wrote:

On Fri, Mar 22, 2019 at 04:20:43PM -0400, Jason Merrill wrote:

On 3/22/19 4:12 PM, Jason Merrill wrote:

On 3/22/19 2:14 PM, Marek Polacek wrote:

On Fri, Mar 22, 2019 at 10:48:32AM -0400, Jason Merrill wrote:



+  B b10 = {{B{42}}};
+  B b11 = {{B{{42;
+  B b12 = {{B{{{42};


These look ill-formed to me: too many braces around the B value.

Looks like the original testcase had the same problem.  So I
think this is
ice-on-invalid.


Are you sure?  clang/icc/gcc8/msvc compile it.  I thought this was a
case of
aggregate initialization, where we have a nested braced-init-list:
http://eel.is/c++draft/dcl.init.aggr#4.2
"If an initializer is itself an initializer list, the element is
list-initialized, which will result in a recursive application of
the rules in
this subclause if the element is an aggregate."


Yes.  Since the first element of the outer init-list is also an
init-list, we initialize the first element of D from the inner
init-list.  The first element of D is the B base, so we're initializing
a B from {D{42}}.

Ah, and D is derived from B, so the B base is copy-initialized from the
(B base subobject of) the D temporary.  So that's why it's different for
a base class.


So originally, when calling reshape_init, we have

   {{ TARGET_EXPR<> }} of type D

we recurse on it -- it's a class so we call reshape_init_class.
Then we call
reshape_init_r on a field D.2070 for the base (type B), the ctor is
{ TARGET_EXPR<> }.
Here we elide the braces, so we return just the TARGET_EXPR as a
field_init
for D.2070, but then we're back in reshape_init_class and append the
TARGET_EXPR to new_init constructor:
5969   CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_init),
field, field_init);
so we end up with the undesirable form.


I don't think it's undesirable; the temporary initializes the base, not
the complete object.  It seems that the assert in digest_init_r is wrong
for C++17.

It seems a bit questionable that adding a layer of braces silently
causes slicing; I'll raise this with the committee.


Thanks for that.


I think let's warn instead of aborting if the first element of the aggregate
is a base class.


Okay.  I guess we might raise it to an error later, if it becomes invalid.

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

2019-03-25  Marek Polacek  

PR c++/89214 - ICE when initializing aggregates with bases.
* typeck2.c (digest_init_r): Warn about object slicing instead of
crashing.


OK.

Jason



Re: C++ PATCH for c++/89214 - ICE when initializing aggregates with bases

2019-03-25 Thread Marek Polacek
On Fri, Mar 22, 2019 at 04:20:43PM -0400, Jason Merrill wrote:
> On 3/22/19 4:12 PM, Jason Merrill wrote:
> > On 3/22/19 2:14 PM, Marek Polacek wrote:
> > > On Fri, Mar 22, 2019 at 10:48:32AM -0400, Jason Merrill wrote:
> > 
> > > > > > +  B b10 = {{B{42}}};
> > > > > > +  B b11 = {{B{{42;
> > > > > > +  B b12 = {{B{{{42};
> > > > 
> > > > These look ill-formed to me: too many braces around the B value.
> > > > 
> > > > Looks like the original testcase had the same problem.  So I
> > > > think this is
> > > > ice-on-invalid.
> > > 
> > > Are you sure?  clang/icc/gcc8/msvc compile it.  I thought this was a
> > > case of
> > > aggregate initialization, where we have a nested braced-init-list:
> > > http://eel.is/c++draft/dcl.init.aggr#4.2
> > > "If an initializer is itself an initializer list, the element is
> > > list-initialized, which will result in a recursive application of
> > > the rules in
> > > this subclause if the element is an aggregate."
> > 
> > Yes.  Since the first element of the outer init-list is also an
> > init-list, we initialize the first element of D from the inner
> > init-list.  The first element of D is the B base, so we're initializing
> > a B from {D{42}}.
> > 
> > Ah, and D is derived from B, so the B base is copy-initialized from the
> > (B base subobject of) the D temporary.  So that's why it's different for
> > a base class.
> > 
> > > So originally, when calling reshape_init, we have
> > > 
> > >   {{ TARGET_EXPR<> }} of type D
> > > 
> > > we recurse on it -- it's a class so we call reshape_init_class. 
> > > Then we call
> > > reshape_init_r on a field D.2070 for the base (type B), the ctor is
> > > { TARGET_EXPR<> }.
> > > Here we elide the braces, so we return just the TARGET_EXPR as a
> > > field_init
> > > for D.2070, but then we're back in reshape_init_class and append the
> > > TARGET_EXPR to new_init constructor:
> > > 5969   CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_init),
> > > field, field_init);
> > > so we end up with the undesirable form.
> > 
> > I don't think it's undesirable; the temporary initializes the base, not
> > the complete object.  It seems that the assert in digest_init_r is wrong
> > for C++17.
> > 
> > It seems a bit questionable that adding a layer of braces silently
> > causes slicing; I'll raise this with the committee.

Thanks for that.

> I think let's warn instead of aborting if the first element of the aggregate
> is a base class.

Okay.  I guess we might raise it to an error later, if it becomes invalid.

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

2019-03-25  Marek Polacek  

PR c++/89214 - ICE when initializing aggregates with bases.
* typeck2.c (digest_init_r): Warn about object slicing instead of
crashing.

* g++.dg/cpp1z/aggr-base8.C: New test.
* g++.dg/cpp1z/aggr-base9.C: New test.

diff --git gcc/cp/typeck2.c gcc/cp/typeck2.c
index e50d6ed83c3..7f242ba93da 100644
--- gcc/cp/typeck2.c
+++ gcc/cp/typeck2.c
@@ -1209,8 +1209,29 @@ digest_init_r (tree type, tree init, int nested, int 
flags,
 {
   tree elt = CONSTRUCTOR_ELT (stripped_init, 0)->value;
   if (reference_related_p (type, TREE_TYPE (elt)))
-   /* We should have fixed this in reshape_init.  */
-   gcc_unreachable ();
+   {
+ /* In C++17, aggregates can have bases, thus participate in
+aggregate initialization.  In the following case:
+
+  struct B { int c; };
+  struct D : B { };
+  D d{{D{{42;
+
+   there's an extra set of braces, so the D temporary initializes
+   the first element of d, which is the B base subobject.  The base
+   of type B is copy-initialized from the D temporary, causing
+   object slicing.  */
+ tree field = next_initializable_field (TYPE_FIELDS (type));
+ if (field && DECL_FIELD_IS_BASE (field))
+   {
+ if (warning_at (loc, 0, "initializing a base class of type %qT "
+ "results in object slicing", TREE_TYPE (field)))
+   inform (loc, "remove %<{ }%> around initializer");
+   }
+ else
+   /* We should have fixed this in reshape_init.  */
+   gcc_unreachable ();
+   }
 }
 
   if (BRACE_ENCLOSED_INITIALIZER_P (stripped_init)
diff --git gcc/testsuite/g++.dg/cpp1z/aggr-base8.C 
gcc/testsuite/g++.dg/cpp1z/aggr-base8.C
new file mode 100644
index 000..8b495a80cb3
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp1z/aggr-base8.C
@@ -0,0 +1,48 @@
+// PR c++/89214
+// { dg-do compile { target c++17 } }
+
+struct A
+{
+  A (int);
+};
+
+struct BB
+{
+  A a;
+};
+
+struct B : BB
+{
+};
+
+void
+foo ()
+{
+  B b1 = {42};
+  B b2 = {{42}};
+  B b3 = {{{42}}};
+
+  B b4 = B{42};
+  B b5 = B{{42}};
+  B b6 = B{{{42}}};
+
+  B b7 = {B{42}};
+  B b8 = {B{{42}}};
+  B b9 = {B{{{42;
+
+  B b10 = {{B{42}}}; // { dg-warning "initializing a base class of type .BB. 
results in 

Re: C++ PATCH for c++/89214 - ICE when initializing aggregates with bases

2019-03-22 Thread Jason Merrill

On 3/22/19 4:12 PM, Jason Merrill wrote:

On 3/22/19 2:14 PM, Marek Polacek wrote:

On Fri, Mar 22, 2019 at 10:48:32AM -0400, Jason Merrill wrote:



+  B b10 = {{B{42}}};
+  B b11 = {{B{{42;
+  B b12 = {{B{{{42};


These look ill-formed to me: too many braces around the B value.

Looks like the original testcase had the same problem.  So I think 
this is

ice-on-invalid.


Are you sure?  clang/icc/gcc8/msvc compile it.  I thought this was a 
case of

aggregate initialization, where we have a nested braced-init-list:
http://eel.is/c++draft/dcl.init.aggr#4.2
"If an initializer is itself an initializer list, the element is
list-initialized, which will result in a recursive application of the 
rules in

this subclause if the element is an aggregate."


Yes.  Since the first element of the outer init-list is also an 
init-list, we initialize the first element of D from the inner 
init-list.  The first element of D is the B base, so we're initializing 
a B from {D{42}}.


Ah, and D is derived from B, so the B base is copy-initialized from the 
(B base subobject of) the D temporary.  So that's why it's different for 
a base class.



So originally, when calling reshape_init, we have

  {{ TARGET_EXPR<> }} of type D

we recurse on it -- it's a class so we call reshape_init_class.  Then 
we call
reshape_init_r on a field D.2070 for the base (type B), the ctor is { 
TARGET_EXPR<> }.
Here we elide the braces, so we return just the TARGET_EXPR as a 
field_init

for D.2070, but then we're back in reshape_init_class and append the
TARGET_EXPR to new_init constructor:
5969   CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_init), field, 
field_init);

so we end up with the undesirable form.


I don't think it's undesirable; the temporary initializes the base, not 
the complete object.  It seems that the assert in digest_init_r is wrong 
for C++17.


It seems a bit questionable that adding a layer of braces silently 
causes slicing; I'll raise this with the committee.


I think let's warn instead of aborting if the first element of the 
aggregate is a base class.


Jason


Re: C++ PATCH for c++/89214 - ICE when initializing aggregates with bases

2019-03-22 Thread Jason Merrill

On 3/22/19 2:14 PM, Marek Polacek wrote:

On Fri, Mar 22, 2019 at 10:48:32AM -0400, Jason Merrill wrote:



+  B b10 = {{B{42}}};
+  B b11 = {{B{{42;
+  B b12 = {{B{{{42};


These look ill-formed to me: too many braces around the B value.

Looks like the original testcase had the same problem.  So I think this is
ice-on-invalid.


Are you sure?  clang/icc/gcc8/msvc compile it.  I thought this was a case of
aggregate initialization, where we have a nested braced-init-list:
http://eel.is/c++draft/dcl.init.aggr#4.2
"If an initializer is itself an initializer list, the element is
list-initialized, which will result in a recursive application of the rules in
this subclause if the element is an aggregate."


Yes.  Since the first element of the outer init-list is also an 
init-list, we initialize the first element of D from the inner 
init-list.  The first element of D is the B base, so we're initializing 
a B from {D{42}}.


Ah, and D is derived from B, so the B base is copy-initialized from the 
(B base subobject of) the D temporary.  So that's why it's different for 
a base class.



So originally, when calling reshape_init, we have

  {{ TARGET_EXPR<> }} of type D

we recurse on it -- it's a class so we call reshape_init_class.  Then we call
reshape_init_r on a field D.2070 for the base (type B), the ctor is { 
TARGET_EXPR<> }.
Here we elide the braces, so we return just the TARGET_EXPR as a field_init
for D.2070, but then we're back in reshape_init_class and append the
TARGET_EXPR to new_init constructor:
5969   CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_init), field, 
field_init);
so we end up with the undesirable form.


I don't think it's undesirable; the temporary initializes the base, not 
the complete object.  It seems that the assert in digest_init_r is wrong 
for C++17.


It seems a bit questionable that adding a layer of braces silently 
causes slicing; I'll raise this with the committee.


Jason


Re: C++ PATCH for c++/89214 - ICE when initializing aggregates with bases

2019-03-22 Thread Marek Polacek
On Fri, Mar 22, 2019 at 10:48:32AM -0400, Jason Merrill wrote:
> On 3/21/19 4:51 PM, Marek Polacek wrote:
> > This is a crash in digest_init_r -- we encounter
> > 
> >/* "If T is a class type and the initializer list has a single
> >   element of type cv U, where U is T or a class derived from T,
> >   the object is initialized from that element."  */
> >if (flag_checking
> >&& cxx_dialect >= cxx11
> >&& BRACE_ENCLOSED_INITIALIZER_P (stripped_init)
> >&& CONSTRUCTOR_NELTS (stripped_init) == 1
> >&& ((CLASS_TYPE_P (type) && !CLASSTYPE_NON_AGGREGATE (type))
> >|| VECTOR_TYPE_P (type)))
> >  {
> >tree elt = CONSTRUCTOR_ELT (stripped_init, 0)->value;
> >if (reference_related_p (type, TREE_TYPE (elt)))
> >  /* We should have fixed this in reshape_init.  */
> >  gcc_unreachable ();
> >  }
> > 
> > As the comment suggests, we have code to fix this up in reshape_init_r:
> > 
> >/* "If T is a class type and the initializer list has a single element of
> >   type cv U, where U is T or a class derived from T, the object is
> >   initialized from that element."  Even if T is an aggregate.  */
> >if (cxx_dialect >= cxx11 && (CLASS_TYPE_P (type) || VECTOR_TYPE_P (type))
> >&& first_initializer_p
> >&& d->end - d->cur == 1
> >&& reference_related_p (type, TREE_TYPE (init)))
> >  {
> >d->cur++;
> >return init;
> >  }
> > 
> > but in this case this didn't work, because reshape_init_class always creates
> > a fresh CONSTRUCTOR.
> 
> But we hit that code before reshape_init_class, why didn't it work?

So originally, when calling reshape_init, we have

  {{ TARGET_EXPR<> }} of type D

we recurse on it -- it's a class so we call reshape_init_class.  Then we call
reshape_init_r on a field D.2070 for the base (type B), the ctor is { 
TARGET_EXPR<> }.
Here we elide the braces, so we return just the TARGET_EXPR as a field_init
for D.2070, but then we're back in reshape_init_class and append the
TARGET_EXPR to new_init constructor:
5969   CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (new_init), field, 
field_init);
so we end up with the undesirable form.  Hence my thinking we should handle
this at the end of reshape_init_class.

Let me know if this exaplanation isn't sufficient.

> > As of C++17, aggregates can have bases
> 
> Does it matter whether BB is a base or a member?
 
Yes, I couldn't trigger an ICE if it's a member rather than a base.

> > > +  B b10 = {{B{42}}};
> > > +  B b11 = {{B{{42;
> > > +  B b12 = {{B{{{42};
> 
> These look ill-formed to me: too many braces around the B value.
> 
> Looks like the original testcase had the same problem.  So I think this is
> ice-on-invalid.

Are you sure?  clang/icc/gcc8/msvc compile it.  I thought this was a case of
aggregate initialization, where we have a nested braced-init-list:
http://eel.is/c++draft/dcl.init.aggr#4.2
"If an initializer is itself an initializer list, the element is
list-initialized, which will result in a recursive application of the rules in
this subclause if the element is an aggregate."

I also noticed that since r269045 we accept

struct B { int c; };
struct D : B { };
D d = {{{42}}};

whereas before it was rejected with an error.  I dropped these cases from my
test as it's unrelated to this PR.

Marek


Re: C++ PATCH for c++/89214 - ICE when initializing aggregates with bases

2019-03-22 Thread Jason Merrill

On 3/21/19 4:51 PM, Marek Polacek wrote:

This is a crash in digest_init_r -- we encounter

   /* "If T is a class type and the initializer list has a single
  element of type cv U, where U is T or a class derived from T,
  the object is initialized from that element."  */
   if (flag_checking
   && cxx_dialect >= cxx11
   && BRACE_ENCLOSED_INITIALIZER_P (stripped_init)
   && CONSTRUCTOR_NELTS (stripped_init) == 1
   && ((CLASS_TYPE_P (type) && !CLASSTYPE_NON_AGGREGATE (type))
   || VECTOR_TYPE_P (type)))
 {
   tree elt = CONSTRUCTOR_ELT (stripped_init, 0)->value;
   if (reference_related_p (type, TREE_TYPE (elt)))
 /* We should have fixed this in reshape_init.  */
 gcc_unreachable ();
 }

As the comment suggests, we have code to fix this up in reshape_init_r:

   /* "If T is a class type and the initializer list has a single element of
  type cv U, where U is T or a class derived from T, the object is
  initialized from that element."  Even if T is an aggregate.  */
   if (cxx_dialect >= cxx11 && (CLASS_TYPE_P (type) || VECTOR_TYPE_P (type))
   && first_initializer_p
   && d->end - d->cur == 1
   && reference_related_p (type, TREE_TYPE (init)))
 {
   d->cur++;
   return init;
 }

but in this case this didn't work, because reshape_init_class always creates
a fresh CONSTRUCTOR.


But we hit that code before reshape_init_class, why didn't it work?


As of C++17, aggregates can have bases


Does it matter whether BB is a base or a member?


+  B b10 = {{B{42}}};
+  B b11 = {{B{{42;
+  B b12 = {{B{{{42};


These look ill-formed to me: too many braces around the B value.

Looks like the original testcase had the same problem.  So I think this 
is ice-on-invalid.


Jason


C++ PATCH for c++/89214 - ICE when initializing aggregates with bases

2019-03-21 Thread Marek Polacek
This is a crash in digest_init_r -- we encounter

  /* "If T is a class type and the initializer list has a single
 element of type cv U, where U is T or a class derived from T,
 the object is initialized from that element."  */
  if (flag_checking
  && cxx_dialect >= cxx11
  && BRACE_ENCLOSED_INITIALIZER_P (stripped_init)
  && CONSTRUCTOR_NELTS (stripped_init) == 1
  && ((CLASS_TYPE_P (type) && !CLASSTYPE_NON_AGGREGATE (type))
  || VECTOR_TYPE_P (type)))
{
  tree elt = CONSTRUCTOR_ELT (stripped_init, 0)->value;
  if (reference_related_p (type, TREE_TYPE (elt)))
/* We should have fixed this in reshape_init.  */
gcc_unreachable ();
}

As the comment suggests, we have code to fix this up in reshape_init_r:

  /* "If T is a class type and the initializer list has a single element of
 type cv U, where U is T or a class derived from T, the object is
 initialized from that element."  Even if T is an aggregate.  */
  if (cxx_dialect >= cxx11 && (CLASS_TYPE_P (type) || VECTOR_TYPE_P (type))
  && first_initializer_p
  && d->end - d->cur == 1
  && reference_related_p (type, TREE_TYPE (init)))
{
  d->cur++;
  return init; 
}

but in this case this didn't work, because reshape_init_class always creates
a fresh CONSTRUCTOR.  As of C++17, aggregates can have bases, so we called
reshape_init_class on the initializer for the public base, and returned a
constructor whose single element was of a reference-related type.  We can
check for this case and fix it up, as in the below.

I came up with testcases that test both cases of "where U is T *or* a class
derived from T".

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

2019-03-21  Marek Polacek  

PR c++/89214 - ICE when initializing aggregates with bases.
* decl.c (reshape_init_class): Adjust commentary.  If the initializer
list has a single element of the same or derived type, return the
element itself, not wrapped in a constructor.

* g++.dg/cpp1z/aggr-base8.C: New test.
* g++.dg/cpp1z/aggr-base9.C: New test.

diff --git gcc/cp/decl.c gcc/cp/decl.c
index c8435e29491..817e33e40d2 100644
--- gcc/cp/decl.c
+++ gcc/cp/decl.c
@@ -5873,7 +5873,7 @@ reshape_init_vector (tree type, reshape_iter *d, 
tsubst_flags_t complain)
 }
 
 /* Subroutine of reshape_init_r, processes the initializers for classes
-   or union. Parameters are the same of reshape_init_r.  */
+   or union.  Parameters are the same of reshape_init_r.  */
 
 static tree
 reshape_init_class (tree type, reshape_iter *d, bool first_initializer_p,
@@ -5884,7 +5884,8 @@ reshape_init_class (tree type, reshape_iter *d, bool 
first_initializer_p,
 
   gcc_assert (CLASS_TYPE_P (type));
 
-  /* The initializer for a class is always a CONSTRUCTOR.  */
+  /* The initializer for a class is always a CONSTRUCTOR.  Unless it
+ has a single element of the same or derived type, see below.  */
   new_init = build_constructor (init_list_type_node, NULL);
   field = next_initializable_field (TYPE_FIELDS (type));
 
@@ -5978,6 +5979,19 @@ reshape_init_class (tree type, reshape_iter *d, bool 
first_initializer_p,
   field = next_initializable_field (DECL_CHAIN (field));
 }
 
+  /* "If T is a class type and the initializer list has a single
+ element of type cv U, where U is T or a class derived from T,
+ the object is initialized from that element."  But this function
+ always builds up a new CONSTRUCTOR, so undo that here.  */
+  if (cxx_dialect >= cxx11
+  && BRACE_ENCLOSED_INITIALIZER_P (new_init)
+  && CONSTRUCTOR_NELTS (new_init) == 1)
+{
+  tree elt = CONSTRUCTOR_ELT (new_init, 0)->value;
+  if (reference_related_p (type, TREE_TYPE (elt)))
+   return elt;
+}
+
   return new_init;
 }
 
diff --git gcc/testsuite/g++.dg/cpp1z/aggr-base8.C 
gcc/testsuite/g++.dg/cpp1z/aggr-base8.C
new file mode 100644
index 000..10cff027c39
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp1z/aggr-base8.C
@@ -0,0 +1,48 @@
+// PR c++/89214
+// { dg-do compile { target c++17 } }
+
+struct A
+{
+  A (int);
+};
+
+struct BB
+{
+  A a;
+};
+
+struct B : BB
+{
+};
+
+void
+foo ()
+{
+  B b1 = {42};
+  B b2 = {{42}};
+  B b3 = {{{42}}};
+
+  B b4 = B{42};
+  B b5 = B{{42}};
+  B b6 = B{{{42}}};
+
+  B b7 = {B{42}};
+  B b8 = {B{{42}}};
+  B b9 = {B{{{42;
+
+  B b10 = {{B{42}}};
+  B b11 = {{B{{42;
+  B b12 = {{B{{{42};
+
+  B bb1{42};
+  B bb2{{42}};
+  B bb3{{{42}}};
+
+  B bb7{B{42}};
+  B bb8{B{{42}}};
+  B bb9{B{{{42;
+
+  B bb10{{B{42}}};
+  B bb11{{B{{42;
+  B bb12{{B{{{42};
+}
diff --git gcc/testsuite/g++.dg/cpp1z/aggr-base9.C 
gcc/testsuite/g++.dg/cpp1z/aggr-base9.C
new file mode 100644
index 000..a3fa747efa4
--- /dev/null
+++ gcc/testsuite/g++.dg/cpp1z/aggr-base9.C
@@ -0,0 +1,40 @@
+// PR c++/89214
+// { dg-do compile { target c++17 } }
+
+struct B {
+  int c;
+};
+
+struct D : B { };
+
+void
+foo ()
+{
+  D d1 =