gcc 4.8.0 20120930 (experimental) with the compiler flags -Wall -pedantic -std=c++11 accepts the following copy-list-initialization of a class type with an explicit default constructor: //------------------------- struct S { explicit S(int = 0) {} }; S s = {}; //------------------------- This code should be ill-formed, because it is ruled out by [over.match.list], in particular by the unconditional wording: "In copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed."
confirmed, not a regression
It's not clear to me that [over.match.list] applies to this initialization, since the value-initialization bullet is separate from the bullet that cross-references [over.match.list]. And in fact there's code in convert_like_real specifically to avoid this diagnostic because of this difference, and it's tested for in initlist40.C. I'm not opposed to this behavior, but I think it would be a language change.
(In reply to comment #2) > I'm not opposed to this behavior, but I think it would be a language change. Thanks Jason. I just see now http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1518 Unless I'm mistaken, this is actually the relevant issue. I suggest to defer this issue and mark it with CWG 1518. I'm not sure how this would be best done, so leave it to the administrators of this list.
Ah, good point. I think we decided in Portland to go with the behavior you expect; all that's left is the drafting (which is also for me to do). Thanks.
Author: jason Date: Sun Mar 17 02:36:08 2013 New Revision: 196732 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=196732 Log: DR 1518 PR c++/54835 * call.c (convert_like_real): Check for explicit constructors even for value-initialization. Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/call.c trunk/gcc/testsuite/g++.dg/cpp0x/initlist40.C
Ah, good point. I think we decided in Portland to go with the behavior you expect; all that's left is the drafting (which is also for me to do). Thanks. Fixed for 4.9.
x
*** Bug 58399 has been marked as a duplicate of this bug. ***
I believe that the resolution of DR 1630 clarifies that value-initialization can invoke an explicit constructor even in copy-list-initialization context, so I should revert my change for this PR.
(In reply to Jason Merrill from comment #9) > I believe that the resolution of DR 1630 clarifies that value-initialization > can invoke an explicit constructor even in copy-list-initialization context, > so I should revert my change for this PR. I read DR 1630 again and cannot follow that conclusion - could you clarify? It still says "For copy-initialization, the candidate functions are all the converting constructors (12.3.1 [class.conv.ctor]) of that class" and the issue example uses an explicit default constructor.
Author: jason Date: Wed May 6 02:07:34 2015 New Revision: 222836 URL: https://gcc.gnu.org/viewcvs?rev=222836&root=gcc&view=rev Log: DR 1518 DR 1630 PR c++/54835 PR c++/60417 * call.c (convert_like_real): Check value-initialization before explicit. * typeck2.c (process_init_constructor_record): Don't set CONSTRUCTOR_IS_DIRECT_INIT. (process_init_constructor_array): Likewise. * init.c (build_vec_init): Likewise. Added: trunk/gcc/testsuite/g++.dg/cpp0x/initlist-dr1518.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/call.c trunk/gcc/cp/init.c trunk/gcc/cp/typeck2.c trunk/gcc/testsuite/g++.dg/cpp0x/initlist40.C
(In reply to Daniel Krügler from comment #10) > I read DR 1630 again and cannot follow that conclusion - could you clarify? > It still says "For copy-initialization, the candidate functions are all the > converting constructors (12.3.1 [class.conv.ctor]) of that class" and the > issue example uses an explicit default constructor. Yes, but the previous sentence now says "For direct-initialization or default-initialization, the candidate functions are all the constructors of the class of the object being initialized." This is default-initialization by way of value-initialization, so I think this sentence takes priority over the one you quote.
*** Bug 66537 has been marked as a duplicate of this bug. ***
Suspended pending resolution of DR 1518.
Author: jason Date: Sat Oct 24 02:58:10 2015 New Revision: 229283 URL: https://gcc.gnu.org/viewcvs?rev=229283&root=gcc&view=rev Log: DR 1518 DR 1630 PR c++/54835 PR c++/60417 * call.c (convert_like_real): Value-initialization can't use explicit constructors in C++11 and up. Added: trunk/gcc/testsuite/g++.dg/cpp0x/explicit10.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/call.c trunk/gcc/testsuite/g++.dg/cpp0x/initlist40.C trunk/gcc/testsuite/g++.dg/init/explicit1.C trunk/gcc/testsuite/g++.dg/init/explicit2.C
Since the last meeting it has been suggested that this effect of DR 1630 was unintended, and the testcase should be ill-formed. So I've changed it back.
Jason, should this be FIXED instead of SUSPENDED?
Can the bug be marked as resolved?
Note that this bug report was marked as suspended based on the resolution of CWG 1518 (and the related DR 1630) in June 2015, but the resolution of both these issue were since changed. Citing 1518: > Additional note, October, 2015: > > It has been suggested that **the resolution of issue 1630 went too** > far in allowing use of explicit constructors for default initialization, > and that default initialization should be considered to model copy > initialization instead. The resolution of this issue would provide an > opportunity to adjust that. P0398R0 [1] describes the final resolution to CWG 1518, after which the following example is arguably well-formed: struct tag_t { explicit constexpr tag_t() = default; // #3 }; struct S { constexpr S() {} constexpr S(S const&) {} S& operator=(S const&) { return *this; } S& operator=(tag_t) { return *this; } // #1 }; int main() { S s{}; s = {}; // #2: GCC error: ambiguous overload for 'operator=' } as (at least from C++17) #1 is not a viable overload for the assignment at #2, as tag_t is not an aggregate and copy-list-init from empty braces will not consider the ctor #3 as it is explicit. The example above is rejected by GCC (various versions) for both C++17 and C++20, whereas Clang and MSVC both accepts it (curiosly Clang accepts it also for C++11 for C++14, which may be wrong as tag_t is an aggregate for these case, but I'm unsure, as we are covering a lot of CWG/LWG/DR confusion for this issue). --- [1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0398r0.html
Un-suspending based on the previous comment.
(In reply to David Friberg from comment #19) > > P0398R0 [1] describes the final resolution to CWG 1518, after which the > following example is arguably well-formed: > It's not. Explicitness of a constructor is not considered when forming implicit conversion sequences from a braced-init-list, and therefore the assignment is ambiguous because {} can convert to either S or tag_t, even though the latter is ill-formed if actually used.
(In reply to TC from comment #21) > (In reply to David Friberg from comment #19) > > > > P0398R0 [1] describes the final resolution to CWG 1518, after which the > > following example is arguably well-formed: > > > > It's not. Explicitness of a constructor is not considered when forming > implicit conversion sequences from a braced-init-list, and therefore the > assignment is ambiguous because {} can convert to either S or tag_t, even > though the latter is ill-formed if actually used. TC, thanks for the clarification. Just to be sure I'm not missing something, I was under the impression that the [**emphasis**] > For direct-initialization or default-initialization > **that is not in the context of copy-initialization**, > the candidate functions are all the constructors of > the class of the object being initialized. part of [over.match.ctor]/1 [1], which was added in P0398R0, intended to remove non-converting (explicit) constructors from overload resolution in this context, particularly resolving the issue shown in the original example of LWG issue 251 [2]: > That turns out to be very unfortunate, consider the following: > > #include <memory> > #include <array> > > void f(std::array<int, 1>, int) {} // #1 > void f(std::allocator_arg_t, int) {} // #2 > > int main() > { > f({}, 666); // #3 > } > > The call at #3 is ambiguous. after which the call at #3 in the LWG example above is no longer ambiguous (afaict). I may be missing some subtlety here, but does my example above not fall into the same category as this one? [1] https://timsong-cpp.github.io/cppwp/n4861/over.match.ctor#1 [2] https://cplusplus.github.io/LWG/issue2510