Created attachment 43181 [details] default_ctor_regression_for_default_value_ctor_argument Unlike C++14, C++17 isn't using default ctor of a type T when it's braced initialized, i.e. {}, and used as argument for a ctor of a type that has a default argument for the same type T. The following code struct S { S(int i = 42); }; void f() { S( {} ); } produces this assembly to g++ --std=c++14 lea rax, [rbp-1] mov esi, 0 mov rdi, rax call S::S(int) and this one for g++ --std=c++17 lea rax, [rbp-1] mov esi, 42 mov rdi, rax call S::S(int) that also works for any user-defined type, such as struct T { T(int i = 10); }; struct S { S(T i = T(42)); }; void f() { S( {} ); } S's ctor is called with 42 instead of 10 for C++17. but C++14 judges it ambiguous and doesn't even compile it. Note that if I change S( {} ) to S( T{} ), it works as expected. The code attached which resembles the first code shown produces the following output: $ g++ --std=c++17 ub.cc -o ub; ./ub 42 $ g++ --std=c++14 ub.cc -o ub; ./ub 0 Please find code for output above attached.
another interesting example which shows the bug: https://godbolt.org/g/nMdPBF
This changed with r240889 aka P0135 refinement, but whether it is intentional and why, or a bug, I'll defer to the C++ folks.
Link to P0135: http://wg21.link/p0135
I don't think P0135 should cause S( {} ) to mean S( S{} ) so I agree that the C++17 behaviour is wrong.
GCC 7.3 is being released, adjusting target milestone.
struct S { S(int i = 42); // (1) }; void f() { S( {} ); // (2) } So if I understand this right, (2) is a copy-list-initialization which is supposed to initialize the constructor's parameter in (1), i.e. an integer to 0, as if we wrote int i = {} (copy-list-initialization), not the type S. But the latter is what's happening in C++17 and that is wrong.
Actually this might be just a missing TARGET_EXPR_DIRECT_INIT_P check in build_special_member_call: --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -8824,7 +8824,8 @@ build_special_member_call (tree instance, tree name, vec<tree, va_gc> **args, arg = perform_implicit_conversion_flags (class_type, arg, sub_complain, flags); - if ((TREE_CODE (arg) == TARGET_EXPR + if (((TREE_CODE (arg) == TARGET_EXPR + && TARGET_EXPR_DIRECT_INIT_P (arg)) || TREE_CODE (arg) == CONSTRUCTOR) && (same_type_ignoring_top_level_qualifiers_p (class_type, TREE_TYPE (arg))))
Author: jason Date: Fri Mar 16 14:35:47 2018 New Revision: 258594 URL: https://gcc.gnu.org/viewcvs?rev=258594&root=gcc&view=rev Log: PR c++/83937 - wrong C++17 handling of init-list ctor argument. * call.c (build_special_member_call): Don't convert an init-list argument directly to the class type. Added: trunk/gcc/testsuite/g++.dg/cpp0x/initlist-ctor2.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/call.c
(In reply to Jason Merrill from comment #8) > Author: jason > Date: Fri Mar 16 14:35:47 2018 > New Revision: 258594 > > URL: https://gcc.gnu.org/viewcvs?rev=258594&root=gcc&view=rev > Log: > PR c++/83937 - wrong C++17 handling of init-list ctor argument. > > * call.c (build_special_member_call): Don't convert an init-list > argument directly to the class type. > > Added: > trunk/gcc/testsuite/g++.dg/cpp0x/initlist-ctor2.C > Modified: > trunk/gcc/cp/ChangeLog > trunk/gcc/cp/call.c Did this fix it?
Yes but only on trunk, it's also a regression on gcc-7-branch.
Fixed in GCC 8.