OK.
On Thu, Sep 20, 2018 at 4:49 PM, Marek Polacek <pola...@redhat.com> wrote: > On Thu, Sep 20, 2018 at 12:20:08PM -0400, Jason Merrill wrote: >> On Thu, Sep 20, 2018 at 11:53 AM, Marek Polacek <pola...@redhat.com> wrote: >> > On Thu, Sep 20, 2018 at 11:25:38AM -0400, Jason Merrill wrote: >> >> On Wed, Sep 19, 2018 at 9:50 PM, Marek Polacek <pola...@redhat.com> wrote: >> >> > Aaaand this addresses >> >> > <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87150#c11>, >> >> > as I promised earlier. I hope I got it right. >> >> > >> >> > Bootstrapped/regtested on x86_64-linux, ok for trunk? >> >> > >> >> > 2018-09-19 Marek Polacek <pola...@redhat.com> >> >> > >> >> > PR c++/87109 - wrong ctor with maybe-rvalue semantics. >> >> > * call.c (build_user_type_conversion_1): Refine the maybe-rvalue >> >> > check to only return if we're converting from a base class. >> >> > >> >> > * g++.dg/cpp0x/ref-qual19.C: Adjust the expected results. >> >> > * g++.dg/cpp0x/ref-qual20.C: New test. >> >> > >> >> > diff --git gcc/cp/call.c gcc/cp/call.c >> >> > index ddf0ed044a0..4bbd77b9cef 100644 >> >> > --- gcc/cp/call.c >> >> > +++ gcc/cp/call.c >> >> > @@ -4034,9 +4034,13 @@ build_user_type_conversion_1 (tree totype, tree >> >> > expr, int flags, >> >> > conv->bad_p = true; >> >> > >> >> > /* We're performing the maybe-rvalue overload resolution and >> >> > - a conversion function is in play. This isn't going to work >> >> > - because we would not end up with a suitable constructor. */ >> >> > - if ((flags & LOOKUP_PREFER_RVALUE) && !DECL_CONSTRUCTOR_P (cand->fn)) >> >> > + a conversion function is in play. If we're converting from >> >> > + a base class to a derived class, reject the conversion. */ >> >> > + if ((flags & LOOKUP_PREFER_RVALUE) >> >> > + && !DECL_CONSTRUCTOR_P (cand->fn) >> >> > + && CLASS_TYPE_P (fromtype) >> >> > + && CLASS_TYPE_P (totype) >> >> > + && DERIVED_FROM_P (fromtype, totype)) >> >> >> >> Here fromtype is the type we're converting from, and what we want to >> >> reject is converting the return value of the conversion op to a base >> >> class. CLASS_TYPE_P (fromtype) will always be true, since it has a >> >> conversion op. And I think we also want to handle the case of totype >> >> being a reference. >> > >> > I think I totally misunderstood what this was about. It's actually about >> > this case >> > >> > struct Y { int y; }; >> > struct X : public Y { int x; }; >> > >> > struct A { >> > operator X(); >> > }; >> > >> > Y >> > fn (A a) >> > { >> > return a; >> > } >> > >> > where we want to avoid slicing of X when converting X to Y, yes? >> >> Yes. > > Got it. So I think the following is the real fix then: > > Bootstrapped/regtested on x86_64-linux, ok for trunk? > > 2018-09-20 Marek Polacek <pola...@redhat.com> > > PR c++/87109 - wrong ctor with maybe-rvalue semantics. > * call.c (build_user_type_conversion_1): Refine the maybe-rvalue > check to only return if we're converting the return value to a base > class. > > * g++.dg/cpp0x/ref-qual19.C: Adjust the expected results. > * g++.dg/cpp0x/ref-qual20.C: New test. > > diff --git gcc/cp/call.c gcc/cp/call.c > index ddf0ed044a0..b2ca667c8b4 100644 > --- gcc/cp/call.c > +++ gcc/cp/call.c > @@ -4034,10 +4034,12 @@ build_user_type_conversion_1 (tree totype, tree expr, > int flags, > conv->bad_p = true; > > /* We're performing the maybe-rvalue overload resolution and > - a conversion function is in play. This isn't going to work > - because we would not end up with a suitable constructor. */ > + a conversion function is in play. Reject converting the return > + value of the conversion function to a base class. */ > if ((flags & LOOKUP_PREFER_RVALUE) && !DECL_CONSTRUCTOR_P (cand->fn)) > - return NULL; > + for (conversion *t = cand->second_conv; t; t = next_conversion (t)) > + if (t->kind == ck_base) > + return NULL; > > /* Remember that this was a list-initialization. */ > if (flags & LOOKUP_NO_NARROWING) > diff --git gcc/testsuite/g++.dg/cpp0x/ref-qual19.C > gcc/testsuite/g++.dg/cpp0x/ref-qual19.C > index 8494b83e5b0..50f92977c49 100644 > --- gcc/testsuite/g++.dg/cpp0x/ref-qual19.C > +++ gcc/testsuite/g++.dg/cpp0x/ref-qual19.C > @@ -85,13 +85,13 @@ int > main () > { > C c1 = f (A()); > - if (c1.i != 1) > + if (c1.i != 2) > __builtin_abort (); > C c2 = f2 (A()); > if (c2.i != 2) > __builtin_abort (); > C c3 = f3 (); > - if (c3.i != 1) > + if (c3.i != 2) > __builtin_abort (); > C c4 = f4 (); > if (c4.i != 2) > @@ -100,13 +100,13 @@ main () > if (c5.i != 2) > __builtin_abort (); > D c6 = f6 (B()); > - if (c6.i != 3) > + if (c6.i != 4) > __builtin_abort (); > D c7 = f7 (B()); > if (c7.i != 4) > __builtin_abort (); > D c8 = f8 (); > - if (c8.i != 3) > + if (c8.i != 4) > __builtin_abort (); > D c9 = f9 (); > if (c9.i != 4) > diff --git gcc/testsuite/g++.dg/cpp0x/ref-qual20.C > gcc/testsuite/g++.dg/cpp0x/ref-qual20.C > index e69de29bb2d..c8bd43643af 100644 > --- gcc/testsuite/g++.dg/cpp0x/ref-qual20.C > +++ gcc/testsuite/g++.dg/cpp0x/ref-qual20.C > @@ -0,0 +1,70 @@ > +// PR c++/87109 > +// { dg-do run { target c++11 } } > + > +#include <utility> > + > +struct Y { > + int y; > + Y(int y_) : y(y_) { } > +}; > +struct X : public Y { > + int x; > + X(int x_, int y_) : x(x_), Y(y_) { } > +}; > + > +struct A { > + operator X() & { return { 0, 2 }; } > + operator X() && { return { 0, -1 }; } > +}; > + > +Y > +f (A a) > +{ > + return a; > +} > + > +Y > +f2 (A a) > +{ > + return std::move (a); > +} > + > +Y > +f3 () > +{ > + A a; > + return a; > +} > + > +Y > +f4 () > +{ > + A a; > + return std::move (a); > +} > + > +Y > +f5 () > +{ > + return A(); > +} > + > +int > +main () > +{ > + Y y1 = f (A()); > + if (y1.y != 2) > + __builtin_abort (); > + Y y2 = f2 (A()); > + if (y2.y != -1) > + __builtin_abort (); > + Y y3 = f3 (); > + if (y3.y != 2) > + __builtin_abort (); > + Y y4 = f4 (); > + if (y4.y != -1) > + __builtin_abort (); > + Y y5 = f5 (); > + if (y5.y != -1) > + __builtin_abort (); > +}