Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/il.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */


/*
Expand Down
33 changes: 31 additions & 2 deletions src/overload.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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. */
Expand All @@ -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,
Expand Down
36 changes: 36 additions & 0 deletions src/pending_changes/gh-344-list-init-ref-explicit-conv.txt
Original file line number Diff line number Diff line change
@@ -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
Comment thread
daveedvdv-nvidia marked this conversation as resolved.
Resolved
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.
2 changes: 1 addition & 1 deletion tests/tests/edg/ccs/gnats21369.sft.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//type:cp
//options_all:--c++11
//options_all:--c++11 --gnu=80000

struct A {
explicit operator int() { return int{}; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,10 +356,22 @@ fe_only -DTEST_NUMBER=1 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
int ai01 = {A<true>()}; // expected-error {{no viable conversion}}
^

"Test_name.c", line 258: error: no suitable conversion function from "conversion::A<true>" to "const int" exists
const int& ai11 = {A<true>()}; // expected-error {{no viable conversion}}
^

"Test_name.c", line 259: error: no suitable conversion function from "conversion::A<true>" to "int" exists
int&& ai31 = {A<true>()}; // expected-error {{no viable conversion}}
^

"Test_name.c", line 260: error: no suitable conversion function from "conversion::A<true>" 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<true>" 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<is_same<B, T2>::value, a>::value)
^
Expand Down Expand Up @@ -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".
Original file line number Diff line number Diff line change
Expand Up @@ -296,10 +296,22 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
int ai01 = {A<true>()}; // expected-error {{no viable conversion}}
^

"Test_name.c", line 258: error: no suitable conversion function from "conversion::A<true>" to "const int" exists
const int& ai11 = {A<true>()}; // expected-error {{no viable conversion}}
^

"Test_name.c", line 259: error: no suitable conversion function from "conversion::A<true>" to "int" exists
int&& ai31 = {A<true>()}; // expected-error {{no viable conversion}}
^

"Test_name.c", line 260: error: no suitable conversion function from "conversion::A<true>" 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<true>" 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<true>" to "int" exists
int ai0 = A<true>(); // expected-error {{no viable conversion}}
^
Expand Down Expand Up @@ -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".
Original file line number Diff line number Diff line change
Expand Up @@ -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 &copyList6 = {n}; // expected-error {{no viable conversion}}
^

"Test_name.c", line 203: error: no suitable conversion function from "NotBool" to "const int" exists
const int &copyList8 = {n}; // expected-error {{no viable conversion}}
^
Expand Down Expand Up @@ -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".
Original file line number Diff line number Diff line change
Expand Up @@ -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 &copyList6 = {n}; // expected-error {{no viable conversion}}
^

"Test_name.c", line 203: error: no suitable conversion function from "NotBool" to "const int" exists
const int &copyList8 = {n}; // expected-error {{no viable conversion}}
^
Expand Down Expand Up @@ -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".
34 changes: 34 additions & 0 deletions tests/tests/regressions/.gh-344.rto/default.1.1.txt
Original file line number Diff line number Diff line change
@@ -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".
34 changes: 34 additions & 0 deletions tests/tests/regressions/.gh-344.rto/default.2.1.txt
Original file line number Diff line number Diff line change
@@ -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".
22 changes: 22 additions & 0 deletions tests/tests/regressions/.gh-344.rto/default.3.1.txt
Original file line number Diff line number Diff line change
@@ -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".
34 changes: 34 additions & 0 deletions tests/tests/regressions/.gh-344.rto/default.4.1.txt
Original file line number Diff line number Diff line change
@@ -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".
30 changes: 30 additions & 0 deletions tests/tests/regressions/.gh-344.rto/default.5.1.txt
Original file line number Diff line number Diff line change
@@ -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".
22 changes: 22 additions & 0 deletions tests/tests/regressions/.gh-344.rto/default.6.1.txt
Original file line number Diff line number Diff line change
@@ -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".
Loading
Loading