diff --git a/src/il.h b/src/il.h index 913487a57e..15a1cc54f0 100644 --- a/src/il.h +++ b/src/il.h @@ -2823,6 +2823,10 @@ typedef int a_conv_context_set; #define CCO_FORCE_DEPENDENCE ((a_conv_context_set)0x20000000) /* TRUE if overload resolution should treat the call as dependent in any case. */ +#define CCO_EXPLICIT_CONV_FUNCTIONS_RETURN_REF ((a_conv_context_set)0x40000000) + /* Used with CCO_ALLOW_EXPLICIT_CONV_FUNCTIONS to + restrict the explicit conversion functions allowed + to those that return a reference. */ /* diff --git a/src/overload.c b/src/overload.c index 62e5a4f2fe..e6c7b1a397 100644 --- a/src/overload.c +++ b/src/overload.c @@ -16401,7 +16401,10 @@ ultimate binding is to an rvalue reference . } /* if */ } else if (conv_context & CCO_ALLOW_EXPLICIT_CONV_FUNCTIONS) { /* We've been told specifically to allow explicit conversion - functions. */ + functions (possibly only those that return a reference). */ + if (conv_context & CCO_EXPLICIT_CONV_FUNCTIONS_RETURN_REF) { + require_reference_return = TRUE; + } /* if */ } else { goto reject_function; } /* if */ @@ -28193,6 +28196,32 @@ will be an lvalue instead of the usual prvalue. in reproducing the source when the cp_gen_be is used. */ rmake_lvalue_temp = TRUE; } /* if */ + if (is_direct_init && + (clang_version_is(any_version) || gnu_version_is(<90000) || + ms_version_is(<1929) || + (ms_version_is(any_version) && ms_permissive))) { + /* Core issue 2267 clarified that the temporary is copy-list- + initialized even when the reference is direct-list-initialized, + and so explicit conversion functions cannot be used to initialize + it. For example: + struct A { explicit operator int(); } a; + int &&r{a}; // Error. + Clang, g++ before version 9, and MSVC in permissive mode (and + before version 19.29 also in non-permissive mode) accept such + cases, though. */ + rconv_context |= CCO_ALLOW_EXPLICIT_CONV_FUNCTIONS; + } else if (is_direct_init && gnu_version_is(>= 140000)) { + /* g++ 14 and later bind the reference directly to the result of a + conversion function that returns a reference (a proposed resolution + of Core issue 1996), and that binding may use an explicit conversion + function: + struct B { explicit operator int&&(); }; + int &&r{B{}}; // Okay with g++ 14. + Approximate that by allowing such conversion functions for the + initialization of the temporary. */ + rconv_context |= CCO_ALLOW_EXPLICIT_CONV_FUNCTIONS | + CCO_EXPLICIT_CONV_FUNCTIONS_RETURN_REF; + } /* if */ /* The cost of a reference initialization in overload resolution is the cost of the underlying initialization of the temporary, so pass arg_match down to the next level. See below for class cases. */ @@ -28201,7 +28230,7 @@ will be an lvalue instead of the usual prvalue. /*is_direct_init=*/FALSE, /*check_narrowing=*/TRUE, /*warning_on_narrowing=*/FALSE, - rconv_context | CCO_ALLOW_EXPLICIT_CONV_FUNCTIONS, + rconv_context, /*fill_in_dtor=*/TRUE, /*force_temp=*/TRUE, rmake_lvalue_temp, diff --git a/src/pending_changes/gh-344-list-init-ref-explicit-conv.txt b/src/pending_changes/gh-344-list-init-ref-explicit-conv.txt new file mode 100644 index 0000000000..15ab8f7df8 --- /dev/null +++ b/src/pending_changes/gh-344-list-init-ref-explicit-conv.txt @@ -0,0 +1,36 @@ +[GH #344] +Explicit conversion functions and list-initialization of references + +When a reference is list-initialized from an element whose type is not +reference-related to the referenced type, a temporary is created and the +reference is bound to that temporary. The resolution of Core issue 2267 +clarified that this temporary is copy-list-initialized even when the reference +itself is direct-list-initialized, so explicit conversion functions cannot be +used to initialize it. The front end nevertheless accepted them, even for +copy-list-initialization (including when passing an argument). That is now +fixed. For example: + + struct A { explicit operator int() const; } a; + struct B { explicit operator int&&(); }; + void f(int&&); + int &&r1{a}; // Now an error. + int &&r2{B{}}; // Now an error. + int &&r3 = {a}; // Now an error in all modes. + void g() { + f({a}); // Now an error in all modes. + } + +The change for EDGcpfe/23402 (in version 6.2) implemented the resolution of +Core issue 2267 for initializations with parentheses (e.g., "int &&r(a);"), +but not for list-initializations. Those were still governed by the change for +EDGcpfe/21369 (in version 5.1), which allowed explicit conversion functions to +initialize the temporary in every list-initialization of a reference (to +accept cases like r2 above). That allowance is now limited to the emulation +modes described below. + +Because Clang, GCC before version 9, and Microsoft C++ in permissive mode +(and before version 19.29 also in non-permissive mode) accept the +direct-list-initialization cases, those are still accepted in the +corresponding emulation modes. GCC 14 and later accept them only when the +conversion function returns a reference (like r2 above), and so does the +front end when emulating those versions. diff --git a/tests/tests/edg/ccs/gnats21369.sft.cpp b/tests/tests/edg/ccs/gnats21369.sft.cpp index 5ef50897c7..dd1a740c8b 100644 --- a/tests/tests/edg/ccs/gnats21369.sft.cpp +++ b/tests/tests/edg/ccs/gnats21369.sft.cpp @@ -1,5 +1,5 @@ //type:cp -//options_all:--c++11 +//options_all:--c++11 --gnu=80000 struct A { explicit operator int() { return int{}; } diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.cxx2a-explicit-bool.rto/default.1.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.cxx2a-explicit-bool.rto/default.1.1.txt index ae52017175..2ab3156cf0 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.cxx2a-explicit-bool.rto/default.1.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.cxx2a-explicit-bool.rto/default.1.1.txt @@ -356,10 +356,22 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers int ai01 = {A()}; // expected-error {{no viable conversion}} ^ +"Test_name.c", line 258: error: no suitable conversion function from "conversion::A" to "const int" exists + const int& ai11 = {A()}; // expected-error {{no viable conversion}} + ^ + +"Test_name.c", line 259: error: no suitable conversion function from "conversion::A" to "int" exists + int&& ai31 = {A()}; // expected-error {{no viable conversion}} + ^ + "Test_name.c", line 260: error: no suitable conversion function from "conversion::A" to "int" exists int ai41 = {A_true}; // expected-error {{no viable conversion}} ^ +"Test_name.c", line 261: error: no suitable conversion function from "conversion::A" to "const int" exists + const int& ai51 = {A_true}; // expected-error {{no viable conversion}} + ^ + "Test_name.c", line 296: warning: 'explicit(bool)' is a C++20 feature explicit(enable_ifv::value, a>::value) ^ @@ -815,4 +827,4 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers explicit(1L) S(char, char, char); ^ -118 errors detected in the compilation of "Test_name.c". +121 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.cxx2a-explicit-bool.rto/default.2.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.cxx2a-explicit-bool.rto/default.2.1.txt index 61b48306c1..5a04cd0406 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.cxx2a-explicit-bool.rto/default.2.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.cxx2a-explicit-bool.rto/default.2.1.txt @@ -296,10 +296,22 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers int ai01 = {A()}; // expected-error {{no viable conversion}} ^ +"Test_name.c", line 258: error: no suitable conversion function from "conversion::A" to "const int" exists + const int& ai11 = {A()}; // expected-error {{no viable conversion}} + ^ + +"Test_name.c", line 259: error: no suitable conversion function from "conversion::A" to "int" exists + int&& ai31 = {A()}; // expected-error {{no viable conversion}} + ^ + "Test_name.c", line 260: error: no suitable conversion function from "conversion::A" to "int" exists int ai41 = {A_true}; // expected-error {{no viable conversion}} ^ +"Test_name.c", line 261: error: no suitable conversion function from "conversion::A" to "const int" exists + const int& ai51 = {A_true}; // expected-error {{no viable conversion}} + ^ + "Test_name.c", line 305: error: no suitable conversion function from "conversion2::A" to "int" exists int ai0 = A(); // expected-error {{no viable conversion}} ^ @@ -683,4 +695,4 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers explicit(ptr) S(long); // expected-error {{conversion from 'const int *' to 'bool' is not allowed in a converted constant expression}} ^ -121 errors detected in the compilation of "Test_name.c". +124 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.explicit.rto/default.1.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.explicit.rto/default.1.1.txt index 5b221f0012..129050d89d 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.explicit.rto/default.1.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.explicit.rto/default.1.1.txt @@ -123,6 +123,10 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers int copyList4 = {n}; // expected-error {{no viable conversion}} ^ +"Test_name.c", line 201: error: no suitable conversion function from "NotBool" to "const bool" exists + const bool ©List6 = {n}; // expected-error {{no viable conversion}} + ^ + "Test_name.c", line 203: error: no suitable conversion function from "NotBool" to "const int" exists const int ©List8 = {n}; // expected-error {{no viable conversion}} ^ @@ -171,4 +175,4 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers switch(EC){} ^ -30 errors detected in the compilation of "Test_name.c". +31 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/imported/clang/cpp/SemaCXX/.explicit.rto/default.2.1.txt b/tests/tests/imported/clang/cpp/SemaCXX/.explicit.rto/default.2.1.txt index ededac4caa..85aaecd1ed 100644 --- a/tests/tests/imported/clang/cpp/SemaCXX/.explicit.rto/default.2.1.txt +++ b/tests/tests/imported/clang/cpp/SemaCXX/.explicit.rto/default.2.1.txt @@ -131,6 +131,10 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers int copyList4 = {n}; // expected-error {{no viable conversion}} ^ +"Test_name.c", line 201: error: no suitable conversion function from "NotBool" to "const bool" exists + const bool ©List6 = {n}; // expected-error {{no viable conversion}} + ^ + "Test_name.c", line 203: error: no suitable conversion function from "NotBool" to "const int" exists const int ©List8 = {n}; // expected-error {{no viable conversion}} ^ @@ -171,4 +175,4 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers switch(EC){} ^ -31 errors detected in the compilation of "Test_name.c". +32 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/regressions/.gh-344.rto/default.1.1.txt b/tests/tests/regressions/.gh-344.rto/default.1.1.txt new file mode 100644 index 0000000000..4af83967bf --- /dev/null +++ b/tests/tests/regressions/.gh-344.rto/default.1.1.txt @@ -0,0 +1,34 @@ +fe_only -DTEST_NUMBER=1 --c++11 Test_name.c +"Test_name.c", line 21: error: no suitable conversion function from "E" to "int" exists + int &&r1{e}; + ^ + +"Test_name.c", line 22: error: no suitable conversion function from "E" to "const int" exists + const int &r2{e}; + ^ + +"Test_name.c", line 23: error: no suitable conversion function from "ER" to "int" exists + int &&r3{ER{}}; + ^ + +"Test_name.c", line 26: error: no suitable conversion function from "E" to "int" exists + int &&r4 = {e}; + ^ + +"Test_name.c", line 27: error: no suitable conversion function from "ER" to "int" exists + int &&r5 = {ER{}}; + ^ + +"Test_name.c", line 29: error: no suitable conversion function from "E" to "int" exists + h({e}); + ^ + +"Test_name.c", line 30: error: no suitable conversion function from "ER" to "int" exists + h({ER{}}); + ^ + +"Test_name.c", line 31: error: no suitable conversion function from "E" to "const int" exists + hc({e}); + ^ + +8 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/regressions/.gh-344.rto/default.2.1.txt b/tests/tests/regressions/.gh-344.rto/default.2.1.txt new file mode 100644 index 0000000000..7445d16ba2 --- /dev/null +++ b/tests/tests/regressions/.gh-344.rto/default.2.1.txt @@ -0,0 +1,34 @@ +fe_only -DTEST_NUMBER=2 --c++20 Test_name.c +"Test_name.c", line 21: error: no suitable conversion function from "E" to "int" exists + int &&r1{e}; + ^ + +"Test_name.c", line 22: error: no suitable conversion function from "E" to "const int" exists + const int &r2{e}; + ^ + +"Test_name.c", line 23: error: no suitable conversion function from "ER" to "int" exists + int &&r3{ER{}}; + ^ + +"Test_name.c", line 26: error: no suitable conversion function from "E" to "int" exists + int &&r4 = {e}; + ^ + +"Test_name.c", line 27: error: no suitable conversion function from "ER" to "int" exists + int &&r5 = {ER{}}; + ^ + +"Test_name.c", line 29: error: no suitable conversion function from "E" to "int" exists + h({e}); + ^ + +"Test_name.c", line 30: error: no suitable conversion function from "ER" to "int" exists + h({ER{}}); + ^ + +"Test_name.c", line 31: error: no suitable conversion function from "E" to "const int" exists + hc({e}); + ^ + +8 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/regressions/.gh-344.rto/default.3.1.txt b/tests/tests/regressions/.gh-344.rto/default.3.1.txt new file mode 100644 index 0000000000..b58196db91 --- /dev/null +++ b/tests/tests/regressions/.gh-344.rto/default.3.1.txt @@ -0,0 +1,22 @@ +fe_only -DTEST_NUMBER=3 --g++ --c++17 --gnu_version=80500 Test_name.c +"Test_name.c", line 26: error: no suitable conversion function from "E" to "int" exists + int &&r4 = {e}; + ^ + +"Test_name.c", line 27: error: no suitable conversion function from "ER" to "int" exists + int &&r5 = {ER{}}; + ^ + +"Test_name.c", line 29: error: no suitable conversion function from "E" to "int" exists + h({e}); + ^ + +"Test_name.c", line 30: error: no suitable conversion function from "ER" to "int" exists + h({ER{}}); + ^ + +"Test_name.c", line 31: error: no suitable conversion function from "E" to "const int" exists + hc({e}); + ^ + +5 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/regressions/.gh-344.rto/default.4.1.txt b/tests/tests/regressions/.gh-344.rto/default.4.1.txt new file mode 100644 index 0000000000..aefeafa873 --- /dev/null +++ b/tests/tests/regressions/.gh-344.rto/default.4.1.txt @@ -0,0 +1,34 @@ +fe_only -DTEST_NUMBER=4 --g++ --c++17 --gnu_version=130300 Test_name.c +"Test_name.c", line 21: error: no suitable conversion function from "E" to "int" exists + int &&r1{e}; + ^ + +"Test_name.c", line 22: error: no suitable conversion function from "E" to "const int" exists + const int &r2{e}; + ^ + +"Test_name.c", line 23: error: no suitable conversion function from "ER" to "int" exists + int &&r3{ER{}}; + ^ + +"Test_name.c", line 26: error: no suitable conversion function from "E" to "int" exists + int &&r4 = {e}; + ^ + +"Test_name.c", line 27: error: no suitable conversion function from "ER" to "int" exists + int &&r5 = {ER{}}; + ^ + +"Test_name.c", line 29: error: no suitable conversion function from "E" to "int" exists + h({e}); + ^ + +"Test_name.c", line 30: error: no suitable conversion function from "ER" to "int" exists + h({ER{}}); + ^ + +"Test_name.c", line 31: error: no suitable conversion function from "E" to "const int" exists + hc({e}); + ^ + +8 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/regressions/.gh-344.rto/default.5.1.txt b/tests/tests/regressions/.gh-344.rto/default.5.1.txt new file mode 100644 index 0000000000..48a8ab654f --- /dev/null +++ b/tests/tests/regressions/.gh-344.rto/default.5.1.txt @@ -0,0 +1,30 @@ +fe_only -DTEST_NUMBER=5 --g++ --c++17 --gnu_version=150200 Test_name.c +"Test_name.c", line 21: error: no suitable conversion function from "E" to "int" exists + int &&r1{e}; + ^ + +"Test_name.c", line 22: error: no suitable conversion function from "E" to "const int" exists + const int &r2{e}; + ^ + +"Test_name.c", line 26: error: no suitable conversion function from "E" to "int" exists + int &&r4 = {e}; + ^ + +"Test_name.c", line 27: error: no suitable conversion function from "ER" to "int" exists + int &&r5 = {ER{}}; + ^ + +"Test_name.c", line 29: error: no suitable conversion function from "E" to "int" exists + h({e}); + ^ + +"Test_name.c", line 30: error: no suitable conversion function from "ER" to "int" exists + h({ER{}}); + ^ + +"Test_name.c", line 31: error: no suitable conversion function from "E" to "const int" exists + hc({e}); + ^ + +7 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/regressions/.gh-344.rto/default.6.1.txt b/tests/tests/regressions/.gh-344.rto/default.6.1.txt new file mode 100644 index 0000000000..c5280f86ea --- /dev/null +++ b/tests/tests/regressions/.gh-344.rto/default.6.1.txt @@ -0,0 +1,22 @@ +fe_only -DTEST_NUMBER=6 --clang --c++17 --clang_version=180100 Test_name.c +"Test_name.c", line 26: error: no suitable conversion function from "E" to "int" exists + int &&r4 = {e}; + ^ + +"Test_name.c", line 27: error: no suitable conversion function from "ER" to "int" exists + int &&r5 = {ER{}}; + ^ + +"Test_name.c", line 29: error: no suitable conversion function from "E" to "int" exists + h({e}); + ^ + +"Test_name.c", line 30: error: no suitable conversion function from "ER" to "int" exists + h({ER{}}); + ^ + +"Test_name.c", line 31: error: no suitable conversion function from "E" to "const int" exists + hc({e}); + ^ + +5 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/regressions/.gh-344.rto/default.7.1.txt b/tests/tests/regressions/.gh-344.rto/default.7.1.txt new file mode 100644 index 0000000000..391349b502 --- /dev/null +++ b/tests/tests/regressions/.gh-344.rto/default.7.1.txt @@ -0,0 +1,22 @@ +fe_only -DTEST_NUMBER=7 --ms_c++17 --microsoft_version 1928 Test_name.c +"Test_name.c", line 26: error: no suitable conversion function from "E" to "int" exists + int &&r4 = {e}; + ^ + +"Test_name.c", line 27: error: no suitable conversion function from "ER" to "int" exists + int &&r5 = {ER{}}; + ^ + +"Test_name.c", line 29: error: no suitable conversion function from "E" to "int" exists + h({e}); + ^ + +"Test_name.c", line 30: error: no suitable conversion function from "ER" to "int" exists + h({ER{}}); + ^ + +"Test_name.c", line 31: error: no suitable conversion function from "E" to "const int" exists + hc({e}); + ^ + +5 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/regressions/.gh-344.rto/default.8.1.txt b/tests/tests/regressions/.gh-344.rto/default.8.1.txt new file mode 100644 index 0000000000..0ba180a498 --- /dev/null +++ b/tests/tests/regressions/.gh-344.rto/default.8.1.txt @@ -0,0 +1,22 @@ +fe_only -DTEST_NUMBER=8 --ms_c++17 --microsoft_version 1944 Test_name.c +"Test_name.c", line 26: error: no suitable conversion function from "E" to "int" exists + int &&r4 = {e}; + ^ + +"Test_name.c", line 27: error: no suitable conversion function from "ER" to "int" exists + int &&r5 = {ER{}}; + ^ + +"Test_name.c", line 29: error: no suitable conversion function from "E" to "int" exists + h({e}); + ^ + +"Test_name.c", line 30: error: no suitable conversion function from "ER" to "int" exists + h({ER{}}); + ^ + +"Test_name.c", line 31: error: no suitable conversion function from "E" to "const int" exists + hc({e}); + ^ + +5 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/regressions/.gh-344.rto/default.9.1.txt b/tests/tests/regressions/.gh-344.rto/default.9.1.txt new file mode 100644 index 0000000000..8096fd0a78 --- /dev/null +++ b/tests/tests/regressions/.gh-344.rto/default.9.1.txt @@ -0,0 +1,34 @@ +fe_only -DTEST_NUMBER=9 --ms_c++20 --microsoft_version 1944 Test_name.c +"Test_name.c", line 21: error: no suitable conversion function from "E" to "int" exists + int &&r1{e}; + ^ + +"Test_name.c", line 22: error: no suitable conversion function from "E" to "const int" exists + const int &r2{e}; + ^ + +"Test_name.c", line 23: error: no suitable conversion function from "ER" to "int" exists + int &&r3{ER{}}; + ^ + +"Test_name.c", line 26: error: no suitable conversion function from "E" to "int" exists + int &&r4 = {e}; + ^ + +"Test_name.c", line 27: error: no suitable conversion function from "ER" to "int" exists + int &&r5 = {ER{}}; + ^ + +"Test_name.c", line 29: error: no suitable conversion function from "E" to "int" exists + h({e}); + ^ + +"Test_name.c", line 30: error: no suitable conversion function from "ER" to "int" exists + h({ER{}}); + ^ + +"Test_name.c", line 31: error: no suitable conversion function from "E" to "const int" exists + hc({e}); + ^ + +8 errors detected in the compilation of "Test_name.c". diff --git a/tests/tests/regressions/gh-344.sft.cpp b/tests/tests/regressions/gh-344.sft.cpp new file mode 100644 index 0000000000..64552c58d1 --- /dev/null +++ b/tests/tests/regressions/gh-344.sft.cpp @@ -0,0 +1,36 @@ +//type:fn +//options:--c++11:--c++20:--g++ --c++17 --gnu_version=80500:--g++ --c++17 --gnu_version=130300:--g++ --c++17 --gnu_version=150200:--clang --c++17 --clang_version=180100:--ms_c++17 --microsoft_version 1928:--ms_c++17 --microsoft_version 1944:--ms_c++20 --microsoft_version 1944 +//remark:Explicit conversion functions and list-initialized reference temps + +// Core issue 2267: when a reference is list-initialized from an element whose +// type is not reference-related, the temporary is copy-list-initialized, so +// explicit conversion functions cannot be used even for direct-list- +// initialization. Clang, g++ before 9, and MSVC in permissive mode (the +// default before C++20) accept the direct-list-initialization cases anyway, +// and g++ 14 and later accept the one with a conversion function returning a +// reference, but no compiler accepts copy-list-initialization. + +struct E { explicit operator int() const; } e; +struct ER { explicit operator int&&(); }; +struct NE { operator int() const; } ne; + +void h(int &&); +void hc(const int &); + +// Direct-list-initialization: errors in strict mode only. +int &&r1{e}; +const int &r2{e}; +int &&r3{ER{}}; + +// Copy-list-initialization: always errors. +int &&r4 = {e}; +int &&r5 = {ER{}}; +void g() { + h({e}); + h({ER{}}); + hc({e}); +} + +// Non-explicit conversion: okay. +int &&r6{ne}; +void k() { h({ne}); }