On Thu, Mar 21, 2019 at 04:13:29PM -0400, Jason Merrill wrote: > On 3/16/19 4:53 PM, Marek Polacek wrote: > > Here we have code like > > > > struct X { operator const int(); }; > > int&& rri = X(); > > > > which I think is invalid, because [dcl.init.ref] says that if types T1 and > > T2 > > are reference-related, no qualifiers can be dropped, and if the reference > > is an > > rvalue reference, the initializer expression can't be an lvalue. And here > > the > > result of the conversion is "const int", so the "const" would be dropped. A > > similar ill-formed test from the standard is > > > > struct X { operator int&(); }; > > int&& rri = X(); > > > > where the result of the conversion is an lvalue of related type. All the > > compilers I've tried actually accept the first test, but I think that's > > wrong. > > I don't think it is. g++ and clang++ reject the first test if you change > int to a class type, but prvalues of scalar type have no cv-qualifiers, so > the result of the conversion is a prvalue of type int, which is a perfectly > good initializer for int&&. > > This is OK for the same reason: > > int&& r = (const int)42;
Oop, this is embarassing, sorry. So I guess we're not handling the (5.3.2) case in [dcl.init.ref] properly: "If the converted initializer is a prvalue, its type T4 is adjusted to type “cv1 T4” ([conv.qual]) and the temporary materialization conversion ([conv.rval]) is applied. Marek