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
16 changes: 16 additions & 0 deletions src/Changes
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
Version 7.1
Comment thread
yronglin marked this conversation as resolved.

10/12/26 [GH #281]
Explicit conversion functions before parenthesized aggregate initialization

The front end could incorrectly attempt parenthesized aggregate initialization
instead of considering an explicit conversion function when directly
initializing an aggregate in C++20 mode. For example:

struct D { float x, y; };
struct S { explicit operator D() const; };
D d(S{}); // Previously an error in C++20 mode. Now okay.

That is now fixed. The rule allowing explicit conversion functions in this
context comes from Core issue 899 and applies in C++11 and later modes. The
failure occurred when C++20 parenthesized aggregate initialization was enabled.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following example is now accepted in C++11 mode:

int f(int &&);
int f(int *);

struct A {
  explicit operator int() const;
};

int i = f({A{}});

Seems to be related to EDGcpfe/21369. g++/clang don't accept this. Needs some more investigation, and should be mentioned in the Changes entry (if we want to keep that behaviour).


10/9/26 [GH #27]
Clearer diagnostic when auto is deduced from an incomplete type

Expand Down
7 changes: 6 additions & 1 deletion src/expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -30702,11 +30702,16 @@ parentheses do not themselves correspond to aggregate initialization).
an_arg_match_summary arg_match;
an_operand opnd;
clear_arg_match_summary(&arg_match);
/* When matching the first reference parameter of a copy constructor
called with one argument in a direct-initialization context, explicit
conversion functions are considered (N3092 [over.match.copy]/1,
Core issue 899). */
prep_list_initializer(arg_list, dest_type, /*is_direct_init=*/TRUE,
/*check_narrowing=*/FALSE,
/*warning_on_narrowing=*/FALSE,
CCO_CAST | CCO_FUNC_NOTATION_CAST |
CCO_EXPLICIT_CAST | CCO_DIRECT_INITIALIZATION,
CCO_EXPLICIT_CAST | CCO_DIRECT_INITIALIZATION |
CCO_ALLOW_EXPLICIT_CONV_FUNCTIONS,
/*fill_in_dtor=*/TRUE, /*force_temp=*/FALSE,
/*make_lvalue_temp=*/FALSE,
&opnd, (an_init_state*)NULL, &arg_match);
Expand Down
7 changes: 6 additions & 1 deletion src/overload.c
Original file line number Diff line number Diff line change
Expand Up @@ -27545,13 +27545,18 @@ will be an lvalue instead of the usual prvalue.
in this context. */
arg_match_err = TRUE;
} else {
/* For this tentative match, explicit conversion functions are only
considered for direct initialization. In particular, a temporary
created for a braced reference argument is copy-list-initialized. */
determine_arg_match_level(operand_of_arg_list_elem(icp),
(a_type_ptr)NULL,
dest_type,
(a_param_type_ptr)NULL,
/*param_type_is_deduced=*/FALSE,
try_user_conversions_in_ovl_res,
/*allow_expl_conv_funcs=*/FALSE,
is_direct_init &&
(conv_context &
CCO_ALLOW_EXPLICIT_CONV_FUNCTIONS) != 0,
arg_match);
} /* if */
} else {
Expand Down
1 change: 1 addition & 0 deletions tests/tests/changes/.GH281.rto/default.1.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=1 -tused --c++11 Test_name.c
1 change: 1 addition & 0 deletions tests/tests/changes/.GH281.rto/default.2.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=2 -tused --c++11 --gnu_version 160200 Test_name.c
1 change: 1 addition & 0 deletions tests/tests/changes/.GH281.rto/default.3.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=3 -tused --c++11 --clang_version 230100 Test_name.c
1 change: 1 addition & 0 deletions tests/tests/changes/.GH281.rto/default.4.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=4 -tused --c++20 Test_name.c
1 change: 1 addition & 0 deletions tests/tests/changes/.GH281.rto/default.5.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=5 -tused --c++20 --gnu_version 160200 Test_name.c
1 change: 1 addition & 0 deletions tests/tests/changes/.GH281.rto/default.6.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=6 -tused --c++20 --clang_version 230100 Test_name.c
1 change: 1 addition & 0 deletions tests/tests/changes/.GH281.rto/default.7.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=7 -tused --ms_c++20 --microsoft_version 1950 Test_name.c
8 changes: 8 additions & 0 deletions tests/tests/changes/GH281.sft.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//type:fp
Comment thread
yronglin marked this conversation as resolved.
//options:--c++11:--c++11 --gnu_version 160200:--c++11 --clang_version 230100:--c++20:--c++20 --gnu_version 160200:--c++20 --clang_version 230100:--ms_c++20 --microsoft_version 1950
//options_all:-tused
//remark:Explicit conversion functions before aggregate fallback [GH #281]

struct D { float x, y; };
struct S { explicit operator D() const; };
D d(S{}); // Error, now okay.
1 change: 1 addition & 0 deletions tests/tests/cwg/.cwg899.rto/default.1.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=1 -tused --c++11 Test_name.c
1 change: 1 addition & 0 deletions tests/tests/cwg/.cwg899.rto/default.2.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=2 -tused --c++11 --gnu_version 160200 Test_name.c
1 change: 1 addition & 0 deletions tests/tests/cwg/.cwg899.rto/default.3.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=3 -tused --c++11 --clang_version 230100 Test_name.c
1 change: 1 addition & 0 deletions tests/tests/cwg/.cwg899.rto/default.4.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=4 -tused --c++20 Test_name.c
1 change: 1 addition & 0 deletions tests/tests/cwg/.cwg899.rto/default.5.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=5 -tused --c++20 --gnu_version 160200 Test_name.c
1 change: 1 addition & 0 deletions tests/tests/cwg/.cwg899.rto/default.6.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=6 -tused --c++20 --clang_version 230100 Test_name.c
1 change: 1 addition & 0 deletions tests/tests/cwg/.cwg899.rto/default.7.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fe_only -DTEST_NUMBER=7 -tused --ms_c++20 --microsoft_version 1950 Test_name.c
10 changes: 10 additions & 0 deletions tests/tests/cwg/.cwg899b.rto/default.1.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
fe_only -DTEST_NUMBER=1 -tused --c++11 Test_name.c
"Test_name.c", line 13: error: no suitable conversion function from "A" to "int" exists
int i = a; // Error: copy-initialization.
^

"Test_name.c", line 14: error: no suitable user-defined conversion from "A" to "C" exists
C c = a; // Error: copy-initialization.
^

2 errors detected in the compilation of "Test_name.c".
10 changes: 10 additions & 0 deletions tests/tests/cwg/.cwg899b.rto/default.2.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
fe_only -DTEST_NUMBER=2 -tused --c++11 --gnu_version 160200 Test_name.c
"Test_name.c", line 13: error: no suitable conversion function from "A" to "int" exists
int i = a; // Error: copy-initialization.
^

"Test_name.c", line 14: error: no suitable user-defined conversion from "A" to "C" exists
C c = a; // Error: copy-initialization.
^

2 errors detected in the compilation of "Test_name.c".
10 changes: 10 additions & 0 deletions tests/tests/cwg/.cwg899b.rto/default.3.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
fe_only -DTEST_NUMBER=3 -tused --c++11 --clang_version 230100 Test_name.c
"Test_name.c", line 13: error: no suitable conversion function from "A" to "int" exists
int i = a; // Error: copy-initialization.
^

"Test_name.c", line 14: error: no suitable user-defined conversion from "A" to "C" exists
C c = a; // Error: copy-initialization.
^

2 errors detected in the compilation of "Test_name.c".
10 changes: 10 additions & 0 deletions tests/tests/cwg/.cwg899b.rto/default.4.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
fe_only -DTEST_NUMBER=4 -tused --c++20 Test_name.c
"Test_name.c", line 13: error: no suitable conversion function from "A" to "int" exists
int i = a; // Error: copy-initialization.
^

"Test_name.c", line 14: error: no suitable user-defined conversion from "A" to "C" exists
C c = a; // Error: copy-initialization.
^

2 errors detected in the compilation of "Test_name.c".
10 changes: 10 additions & 0 deletions tests/tests/cwg/.cwg899b.rto/default.5.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
fe_only -DTEST_NUMBER=5 -tused --c++20 --gnu_version 160200 Test_name.c
"Test_name.c", line 13: error: no suitable conversion function from "A" to "int" exists
int i = a; // Error: copy-initialization.
^

"Test_name.c", line 14: error: no suitable user-defined conversion from "A" to "C" exists
C c = a; // Error: copy-initialization.
^

2 errors detected in the compilation of "Test_name.c".
10 changes: 10 additions & 0 deletions tests/tests/cwg/.cwg899b.rto/default.6.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
fe_only -DTEST_NUMBER=6 -tused --c++20 --clang_version 230100 Test_name.c
"Test_name.c", line 13: error: no suitable conversion function from "A" to "int" exists
int i = a; // Error: copy-initialization.
^

"Test_name.c", line 14: error: no suitable user-defined conversion from "A" to "C" exists
C c = a; // Error: copy-initialization.
^

2 errors detected in the compilation of "Test_name.c".
10 changes: 10 additions & 0 deletions tests/tests/cwg/.cwg899b.rto/default.7.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
fe_only -DTEST_NUMBER=7 -tused --ms_c++20 --microsoft_version 1950 Test_name.c
"Test_name.c", line 13: error: no suitable conversion function from "A" to "int" exists
int i = a; // Error: copy-initialization.
^

"Test_name.c", line 14: error: no suitable user-defined conversion from "A" to "C" exists
C c = a; // Error: copy-initialization.
^

2 errors detected in the compilation of "Test_name.c".
20 changes: 20 additions & 0 deletions tests/tests/cwg/cwg899.sft.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//type:fp
//options:--c++11:--c++11 --gnu_version 160200:--c++11 --clang_version 230100:--c++20:--c++20 --gnu_version 160200:--c++20 --clang_version 230100:--ms_c++20 --microsoft_version 1950
//options_all:-tused
//remark:Core issue 899: Explicit conversion functions in direct class initialization

struct C { };
struct A {
explicit operator int() const;
explicit operator C() const;
};

struct B {
int i;
B(const A& a): i(a) { } // Okay.
};

void f(A a) {
int j(a); // Okay: direct-initialization.
C c2(a); // Okay: direct-initialization (Core issue 899).
}
15 changes: 15 additions & 0 deletions tests/tests/cwg/cwg899b.sft.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//type:fn
//options:--c++11:--c++11 --gnu_version 160200:--c++11 --clang_version 230100:--c++20:--c++20 --gnu_version 160200:--c++20 --clang_version 230100:--ms_c++20 --microsoft_version 1950
//options_all:-tused
//remark:Core issue 899: Explicit conversion functions in copy-initialization

struct C { };
struct A {
explicit operator int() const;
explicit operator C() const;
};

void f(A a) {
int i = a; // Error: copy-initialization.
C c = a; // Error: copy-initialization.
}
Original file line number Diff line number Diff line change
Expand Up @@ -476,14 +476,6 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
Y y2 = z; // expected-error {{no viable conversion}}
^

"Test_name.c", line 530: error: too many initializer values
Y y2b(z);
^

"Test_name.c", line 532: error: too many initializer values
Y y4 = Y(z);
^

"Test_name.c", line 540: error: no suitable user-defined conversion from "conversion3::Z<true>" to "const conversion3::Y" exists
const Y& y6 = z; // expected-error {{no viable conversion}}
^
Expand Down Expand Up @@ -683,4 +675,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".
119 errors detected in the compilation of "Test_name.c".
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,6 @@ fe_only -DTEST_NUMBER=2 --clang -tused -e 200 --no_wrap_diagnostics --clang_vers
Y y2 = z; // expected-error {{no viable conversion from 'Z' to 'Y'}}
^

"Test_name.c", line 90: error: too many initializer values
Y y2b(z);
^

"Test_name.c", line 92: error: too many initializer values
Y y4 = Y(z);
^

"Test_name.c", line 100: error: no suitable user-defined conversion from "Z" to "const Y" exists
const Y& y6 = z; // expected-error {{no viable conversion from 'Z' to 'const Y'}}
^
Expand Down Expand Up @@ -171,4 +163,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".
29 errors detected in the compilation of "Test_name.c".
24 changes: 24 additions & 0 deletions tests/tests/regressions/.gh-222.rto/default.1.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
fe_only -DTEST_NUMBER=1 -tused --c++11 Test_name.c
"Test_name.c", line 15: error: no instance of overloaded function "f" matches the argument list
argument types are: ({...})
int i = f({A{}}); // Error: cannot copy-list-initialize the temporary int.
^
"Test_name.c", line 7: note: function "f(int *)" does not match because argument #1 does not match parameter
int f(int*);
^
"Test_name.c", line 6: note: function "f(int &&)" does not match because argument #1 does not match parameter
int f(int&&);
^

"Test_name.c", line 16: error: no instance of overloaded function "g" matches the argument list
argument types are: ({...})
int j = g({A{}}); // Likewise for a const lvalue reference.
^
"Test_name.c", line 9: note: function "g(int *)" does not match because argument #1 does not match parameter
int g(int*);
^
"Test_name.c", line 8: note: function "g(const int &)" does not match because argument #1 does not match parameter
int g(const int&);
^

2 errors detected in the compilation of "Test_name.c".
24 changes: 24 additions & 0 deletions tests/tests/regressions/.gh-222.rto/default.2.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
fe_only -DTEST_NUMBER=2 -tused --c++11 --gnu_version 160200 Test_name.c
"Test_name.c", line 15: error: no instance of overloaded function "f" matches the argument list
argument types are: ({...})
int i = f({A{}}); // Error: cannot copy-list-initialize the temporary int.
^
"Test_name.c", line 7: note: function "f(int *)" does not match because argument #1 does not match parameter
int f(int*);
^
"Test_name.c", line 6: note: function "f(int &&)" does not match because argument #1 does not match parameter
int f(int&&);
^

"Test_name.c", line 16: error: no instance of overloaded function "g" matches the argument list
argument types are: ({...})
int j = g({A{}}); // Likewise for a const lvalue reference.
^
"Test_name.c", line 9: note: function "g(int *)" does not match because argument #1 does not match parameter
int g(int*);
^
"Test_name.c", line 8: note: function "g(const int &)" does not match because argument #1 does not match parameter
int g(const int&);
^

2 errors detected in the compilation of "Test_name.c".
24 changes: 24 additions & 0 deletions tests/tests/regressions/.gh-222.rto/default.3.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
fe_only -DTEST_NUMBER=3 -tused --c++11 --clang_version 230100 Test_name.c
"Test_name.c", line 15: error: no instance of overloaded function "f" matches the argument list
argument types are: ({...})
int i = f({A{}}); // Error: cannot copy-list-initialize the temporary int.
^
"Test_name.c", line 7: note: function "f(int *)" does not match because argument #1 does not match parameter
int f(int*);
^
"Test_name.c", line 6: note: function "f(int &&)" does not match because argument #1 does not match parameter
int f(int&&);
^

"Test_name.c", line 16: error: no instance of overloaded function "g" matches the argument list
argument types are: ({...})
int j = g({A{}}); // Likewise for a const lvalue reference.
^
"Test_name.c", line 9: note: function "g(int *)" does not match because argument #1 does not match parameter
int g(int*);
^
"Test_name.c", line 8: note: function "g(const int &)" does not match because argument #1 does not match parameter
int g(const int&);
^

2 errors detected in the compilation of "Test_name.c".
24 changes: 24 additions & 0 deletions tests/tests/regressions/.gh-222.rto/default.4.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
fe_only -DTEST_NUMBER=4 -tused --c++20 Test_name.c
"Test_name.c", line 15: error: no instance of overloaded function "f" matches the argument list
argument types are: ({...})
int i = f({A{}}); // Error: cannot copy-list-initialize the temporary int.
^
"Test_name.c", line 7: note: function "f(int *)" does not match because argument #1 does not match parameter
int f(int*);
^
"Test_name.c", line 6: note: function "f(int &&)" does not match because argument #1 does not match parameter
int f(int&&);
^

"Test_name.c", line 16: error: no instance of overloaded function "g" matches the argument list
argument types are: ({...})
int j = g({A{}}); // Likewise for a const lvalue reference.
^
"Test_name.c", line 9: note: function "g(int *)" does not match because argument #1 does not match parameter
int g(int*);
^
"Test_name.c", line 8: note: function "g(const int &)" does not match because argument #1 does not match parameter
int g(const int&);
^

2 errors detected in the compilation of "Test_name.c".
24 changes: 24 additions & 0 deletions tests/tests/regressions/.gh-222.rto/default.5.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
fe_only -DTEST_NUMBER=5 -tused --c++20 --gnu_version 160200 Test_name.c
"Test_name.c", line 15: error: no instance of overloaded function "f" matches the argument list
argument types are: ({...})
int i = f({A{}}); // Error: cannot copy-list-initialize the temporary int.
^
"Test_name.c", line 7: note: function "f(int *)" does not match because argument #1 does not match parameter
int f(int*);
^
"Test_name.c", line 6: note: function "f(int &&)" does not match because argument #1 does not match parameter
int f(int&&);
^

"Test_name.c", line 16: error: no instance of overloaded function "g" matches the argument list
argument types are: ({...})
int j = g({A{}}); // Likewise for a const lvalue reference.
^
"Test_name.c", line 9: note: function "g(int *)" does not match because argument #1 does not match parameter
int g(int*);
^
"Test_name.c", line 8: note: function "g(const int &)" does not match because argument #1 does not match parameter
int g(const int&);
^

2 errors detected in the compilation of "Test_name.c".
Loading