Bug 83937 - [7 Regression] C++17 binds braced init of a type T to default arg of a ctor instead of using T's own default ctor
Summary: [7 Regression] C++17 binds braced init of a type T to default arg of a ctor i...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 7.2.1
: P2 normal
Target Milestone: 8.0
Assignee: Jason Merrill
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2018-01-18 23:16 UTC by Raphael S. Carvalho
Modified: 2019-11-14 10:59 UTC (History)
7 users (show)

See Also:
Host:
Target:
Build:
Known to work: 8.0
Known to fail: 7.5.0
Last reconfirmed: 2018-01-19 00:00:00


Attachments
default_ctor_regression_for_default_value_ctor_argument (126 bytes, text/x-csrc)
2018-01-18 23:16 UTC, Raphael S. Carvalho
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Raphael S. Carvalho 2018-01-18 23:16:49 UTC
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.
Comment 1 Raphael S. Carvalho 2018-01-19 03:14:31 UTC
another interesting example which shows the bug: https://godbolt.org/g/nMdPBF
Comment 2 Jakub Jelinek 2018-01-19 08:19:03 UTC
This changed with r240889 aka P0135 refinement, but whether it is intentional and why, or a bug, I'll defer to the C++ folks.
Comment 3 Jakub Jelinek 2018-01-19 08:20:06 UTC
Link to P0135: http://wg21.link/p0135
Comment 4 Jonathan Wakely 2018-01-19 10:59:50 UTC
I don't think P0135 should cause S( {} ) to mean S( S{} ) so I agree that the C++17 behaviour is wrong.
Comment 5 Richard Biener 2018-01-25 08:21:46 UTC
GCC 7.3 is being released, adjusting target milestone.
Comment 6 Marek Polacek 2018-01-26 09:59:48 UTC
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.
Comment 7 Marek Polacek 2018-01-29 23:43:08 UTC
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))))
Comment 8 Jason Merrill 2018-03-16 14:36:19 UTC
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
Comment 9 Eric Gallager 2018-03-22 19:26:26 UTC
(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?
Comment 10 Jonathan Wakely 2018-03-23 11:49:32 UTC
Yes but only on trunk, it's also a regression on gcc-7-branch.
Comment 11 Richard Biener 2019-11-14 10:59:08 UTC
Fixed in GCC 8.