From dea93fc60d293b08d137f08d9129de6f4fc772db Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 18 Jan 2019 15:35:57 -0500 Subject: [PATCH] PR c++/88875 - error with explicit list constructor. In my patch for CWG issue 2267, I changed reference_binding to clear CONSTRUCTOR_IS_DIRECT_INIT on the argument init-list. But that breaks if there's another candidate for which CONSTRUCTOR_IS_DIRECT_INIT is correct. So instead, let's encode in the conversion that we want to override the flag. * call.c (reference_binding): Don't modify EXPR. Set need_temporary_p on the ck_user conversion for a temporary. (convert_like_real): Check it. From-SVN: r268085 --- gcc/cp/ChangeLog | 7 +++++++ gcc/cp/call.c | 11 +++++++--- .../g++.dg/cpp0x/initlist-explicit2.C | 20 +++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist-explicit2.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d224b72c0bb..4292930daf3 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2019-01-18 Jason Merrill + + PR c++/88875 - error with explicit list constructor. + * call.c (reference_binding): Don't modify EXPR. Set + need_temporary_p on the ck_user conversion for a temporary. + (convert_like_real): Check it. + 2019-01-18 H.J. Lu PR c/51628 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 499894b353f..16c3706cc5c 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -94,7 +94,7 @@ struct conversion { BOOL_BITFIELD bad_p : 1; /* If KIND is ck_ref_bind ck_base_conv, true to indicate that a temporary should be created to hold the result of the - conversion. If KIND is ck_ambig, true if the context is + conversion. If KIND is ck_ambig or ck_user, true means force copy-initialization. */ BOOL_BITFIELD need_temporary_p : 1; /* If KIND is ck_ptr or ck_pmem, true to indicate that a conversion @@ -1560,6 +1560,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags, from = TREE_TYPE (expr); } + bool copy_list_init = false; if (expr && BRACE_ENCLOSED_INITIALIZER_P (expr)) { maybe_warn_cpp0x (CPP0X_INITIALIZER_LISTS); @@ -1582,7 +1583,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags, /* Otherwise, if T is a reference type, a prvalue temporary of the type referenced by T is copy-list-initialized, and the reference is bound to that temporary. */ - CONSTRUCTOR_IS_DIRECT_INIT (expr) = false; + copy_list_init = true; skip:; } @@ -1770,6 +1771,10 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags, if (conv->user_conv_p) { + if (copy_list_init) + /* Remember this was copy-list-initialization. */ + conv->need_temporary_p = true; + /* If initializing the temporary used a conversion function, recalculate the second conversion sequence. */ for (conversion *t = conv; t; t = next_conversion (t)) @@ -6941,7 +6946,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, if (DECL_NONCONVERTING_P (convfn) && DECL_CONSTRUCTOR_P (convfn) && BRACE_ENCLOSED_INITIALIZER_P (expr) /* Unless this is for direct-list-initialization. */ - && !CONSTRUCTOR_IS_DIRECT_INIT (expr) + && (!CONSTRUCTOR_IS_DIRECT_INIT (expr) || convs->need_temporary_p) /* And in C++98 a default constructor can't be explicit. */ && cxx_dialect >= cxx11) { diff --git a/gcc/testsuite/g++.dg/cpp0x/initlist-explicit2.C b/gcc/testsuite/g++.dg/cpp0x/initlist-explicit2.C new file mode 100644 index 00000000000..26a63bf2aa7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/initlist-explicit2.C @@ -0,0 +1,20 @@ +// PR c++/88875 +// { dg-do compile { target c++11 } } + +#include + +struct X { + X(); + explicit X(const std::initializer_list& init); +}; + +struct Y +{ + X x { 1, 2 }; // error + + Y (int) + : x {1, 2} // ok + { + } + +};