GCC 4.7.0 accepts the following code in C++0x mode: template<class T> T&& create(); template<class T, class Arg> void test() { T t(create<Arg>()); (void) t; } template<class T> struct To { explicit operator T(); }; int main() { test<int&, To<int&>>(); // a Well-formed test<int&&, To<int&&>>(); // b Well-formed } This code should be ill-formed because of the *explicit* conversion to a reference type. The semantics of this program is described in 8.5.3 [dcl.init.ref] p. 5 (referring to WD N3242). In case of (a) we first inter into bullet 1 ("If the reference is an lvalue reference"). Sub-bullet 1 does not apply, then we have to inspect sub-bullet 2: "has a class type (i.e., T2 is a class type), where T1 is not reference-related to T2, and can be implicitly converted to an lvalue of type “cv3 T3,” where “cv1 T1” is reference-compatible with “cv3 T3”106 (this conversion is selected by enumerating the applicable conversion functions (13.3.1.6) and choosing the best one through overload resolution (13.3))," This *seems* to fit, except that there is no *implicit* conversion possible here, so we cannot enter this rule. For (a) bullet 2 does not apply and we must fail immediately. For (b) we ignore bullet 1, but step into bullet 2 because of the rvalue-reference. Again, sub-bullet 1 does not apply, only sub-bullet 2 comes near: "has a class type (i.e., T2 is a class type), where T1 is not reference-related to T2, and can be implicitly converted to an xvalue, class prvalue, or function lvalue of type “cv3 T3”, where “cv1 T1” is reference-compatible with “cv3 T3”," Again, we have *no* implicit conversion, but now we need to try the last sub-bullet 3: "Otherwise, a temporary of type “cv1 T1” is created and initialized from the initializer expression using the rules for a non-reference copy-initialization (8.5). [..]" The semantics of a non-reference copy-initialization forbids the consideration of the explicit conversion function, thus, we should fail again.
This seems to me like a wording issue, not a compiler bug. The use of "implicitly" in 8.5.3 should have been adjusted when explicit conversion operators went in; this should be reported as a core DR.
(In reply to comment #1) I agree, I just recognize that 13.3.1.6 [over.match.ref] p. 1 b. 1 is written to support this: "The conversion functions of S and its base classes are considered, except that for copy-initialization, only the non-explicit conversion functions are considered. Those that are not hidden within S and yield type “lvalue reference to cv2 T2” (when 8.5.3 requires an lvalue result) or “cv2 T2” or “rvalue reference to cv2 T2” (when 8.5.3 requires an rvalue result), where “cv1 T” is reference-compatible (8.5.3) with “cv2 T2”, are candidate functions." IMO the core language should strike the reference to "implicit conversions" in 8.5.3.
Agreed. The wording in the standard should be fixed.
It would be nice to have a DR # for this. In any case, if in practice the compiler is already Ok, we can probably close it, right?
Added DR 1287 reference. I'm inclined to leave the bug suspended until that issue is resolved.
Ok, thanks.
Oh, by the way, the status is <ready>.
This is now in C++14. Time to add the testcase and close the bug.
(In reply to Paolo Carlini from comment #8) > This is now in C++14. Time to add the testcase and close the bug. I agree.
Author: paolo Date: Fri Mar 20 17:06:18 2015 New Revision: 221537 URL: https://gcc.gnu.org/viewcvs?rev=221537&root=gcc&view=rev Log: 2015-03-20 Paolo Carlini <paolo.carlini@oracle.com> PR c++/48453 * g++.dg/cpp0x/pr48453.C: New. Added: trunk/gcc/testsuite/g++.dg/cpp0x/pr48453.C Modified: trunk/gcc/testsuite/ChangeLog
Done.