c++: explicit ctor and list-initialization [PR109159]
When I implemented explicit(bool) in r9-3735, I added this code to add_template_candidate_real: + /* Now the explicit specifier might have been deduced; check if this + declaration is explicit. If it is and we're ignoring non-converting + constructors, don't add this function to the set of candidates. */ + if ((flags & LOOKUP_ONLYCONVERTING) && DECL_NONCONVERTING_P (fn)) + return NULL; but as this test demonstrates, that's incorrect when we're initializing from a {}: for list-initialization we consider explicit constructors and complain if one is chosen. PR c++/109159 gcc/cp/ChangeLog: * call.cc (add_template_candidate_real): Add explicit decls to the set of candidates when the initializer is a braced-init-list. libstdc++-v3/ChangeLog: * testsuite/20_util/pair/cons/explicit_construct.cc: Adjust dg-error. * testsuite/20_util/tuple/cons/explicit_construct.cc: Likewise. * testsuite/23_containers/span/explicit.cc: Likewise. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/explicit16.C: New test.
This commit is contained in:
parent
0a846340b9
commit
a226590fef
5 changed files with 57 additions and 37 deletions
|
@ -3612,7 +3612,9 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
|
|||
/* Now the explicit specifier might have been deduced; check if this
|
||||
declaration is explicit. If it is and we're ignoring non-converting
|
||||
constructors, don't add this function to the set of candidates. */
|
||||
if ((flags & LOOKUP_ONLYCONVERTING) && DECL_NONCONVERTING_P (fn))
|
||||
if (((flags & (LOOKUP_ONLYCONVERTING|LOOKUP_LIST_INIT_CTOR))
|
||||
== LOOKUP_ONLYCONVERTING)
|
||||
&& DECL_NONCONVERTING_P (fn))
|
||||
return NULL;
|
||||
|
||||
if (DECL_CONSTRUCTOR_P (fn) && nargs == 2)
|
||||
|
|
18
gcc/testsuite/g++.dg/cpp0x/explicit16.C
Normal file
18
gcc/testsuite/g++.dg/cpp0x/explicit16.C
Normal file
|
@ -0,0 +1,18 @@
|
|||
// PR c++/109159
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
struct A {
|
||||
A(float) {}
|
||||
template<class U>
|
||||
explicit A(U) {}
|
||||
};
|
||||
|
||||
void f(A t)
|
||||
{
|
||||
t = {1}; // { dg-error "explicit constructor" }
|
||||
t = 1;
|
||||
A a1{1};
|
||||
A a2 = {1}; // { dg-error "explicit constructor" }
|
||||
A a3 = 1;
|
||||
A a4(1);
|
||||
}
|
|
@ -37,7 +37,7 @@ struct ExplicitDefaultDefault
|
|||
|
||||
std::pair<int, int> f1() {return {1,2};}
|
||||
|
||||
std::pair<Explicit, Explicit> f2() {return {1,2};} // { dg-error "could not convert" }
|
||||
std::pair<Explicit, Explicit> f2() {return {1,2};} // { dg-error "explicit constructor" }
|
||||
|
||||
std::pair<long, long> f3() {return std::pair<int, int>{1,2};}
|
||||
|
||||
|
@ -52,7 +52,7 @@ std::pair<int, int> v0{1,2};
|
|||
|
||||
std::pair<Explicit, Explicit> v1{1,2};
|
||||
|
||||
std::pair<Explicit, Explicit> v2 = {1,2}; // { dg-error "could not convert" }
|
||||
std::pair<Explicit, Explicit> v2 = {1,2}; // { dg-error "explicit constructor" }
|
||||
|
||||
std::pair<Explicit, Explicit> v3{std::pair<int,int>{1,2}};
|
||||
|
||||
|
@ -99,7 +99,7 @@ void test_arg_passing()
|
|||
{
|
||||
f6(v0); // { dg-error "could not convert" }
|
||||
f6(v1);
|
||||
f6({1,2}); // { dg-error "could not convert" }
|
||||
f6({1,2}); // { dg-error "explicit constructor" }
|
||||
f6(std::pair<Explicit, Explicit>{});
|
||||
f6(std::pair<int, int>{}); // { dg-error "could not convert" }
|
||||
f7(v0);
|
||||
|
@ -130,6 +130,6 @@ std::pair<int*, ExplicitMoveOnly> v14{nullptr, MoveOnly{}};
|
|||
std::pair<ExplicitMoveOnly, int*> v15{MoveOnly{}, nullptr};
|
||||
|
||||
std::pair<int*, ExplicitMoveOnly> v16 =
|
||||
{nullptr, MoveOnly{}}; // { dg-error "could not convert" }
|
||||
{nullptr, MoveOnly{}}; // { dg-error "explicit constructor" }
|
||||
std::pair<ExplicitMoveOnly, int*> v17 =
|
||||
{MoveOnly{}, nullptr}; // { dg-error "could not convert" }
|
||||
{MoveOnly{}, nullptr}; // { dg-error "explicit constructor" }
|
||||
|
|
|
@ -45,11 +45,11 @@ std::tuple<int, int> f1b() {return {1,2};}
|
|||
std::tuple<int, int, int> f1c() {return {1,2,3};}
|
||||
|
||||
std::tuple<Explicit> f2_a()
|
||||
{return {1};} // { dg-error "could not convert" }
|
||||
{return {1};} // { dg-error "explicit constructor" }
|
||||
std::tuple<Explicit, Explicit> f2_b()
|
||||
{return {1,2};} // { dg-error "could not convert" }
|
||||
{return {1,2};} // { dg-error "explicit constructor" }
|
||||
std::tuple<Explicit, Explicit, Explicit> f2_c()
|
||||
{return {1,2,3};} // { dg-error "could not convert" }
|
||||
{return {1,2,3};} // { dg-error "explicit constructor" }
|
||||
|
||||
std::tuple<long> f3_a() {return std::tuple<int>{1};}
|
||||
std::tuple<long, long> f3_b() {return std::tuple<int, int>{1,2};}
|
||||
|
@ -73,22 +73,22 @@ std::tuple<long, long> f5_b() {return {1,2};}
|
|||
std::tuple<long, long, long> f5_c() {return {1,2,3};}
|
||||
|
||||
std::tuple<ExplicitDefault> f6_a()
|
||||
{return {};} // { dg-error "could not convert" }
|
||||
{return {};} // { dg-error "explicit constructor" }
|
||||
std::tuple<ExplicitDefault, ExplicitDefault> f6_b()
|
||||
{return {};} // { dg-error "could not convert" }
|
||||
{return {};} // { dg-error "explicit constructor" }
|
||||
std::tuple<ExplicitDefault, ExplicitDefault, ExplicitDefault> f6_c()
|
||||
{return {};} // { dg-error "could not convert" }
|
||||
{return {};} // { dg-error "explicit constructor" }
|
||||
std::tuple<ExplicitDefault, int> f6_d()
|
||||
{return {};} // { dg-error "could not convert" }
|
||||
{return {};} // { dg-error "explicit constructor" }
|
||||
|
||||
std::tuple<ExplicitDefaultDefault> f7_a()
|
||||
{return {};} // { dg-error "could not convert" }
|
||||
{return {};} // { dg-error "explicit constructor" }
|
||||
std::tuple<ExplicitDefaultDefault, ExplicitDefaultDefault> f7_b()
|
||||
{return {};} // { dg-error "could not convert" }
|
||||
{return {};} // { dg-error "explicit constructor" }
|
||||
std::tuple<ExplicitDefaultDefault,
|
||||
ExplicitDefaultDefault,
|
||||
ExplicitDefaultDefault> f7_c()
|
||||
{return {};} // { dg-error "could not convert" }
|
||||
{return {};} // { dg-error "explicit constructor" }
|
||||
|
||||
std::tuple<int, int> fp1() {return std::pair<int, int>{1,2}; }
|
||||
std::tuple<long, long> fp2() {return std::pair<int, int>{1,2}; }
|
||||
|
@ -103,9 +103,9 @@ std::tuple<Explicit> v1_a{1};
|
|||
std::tuple<Explicit, Explicit> v1_b{1,2};
|
||||
std::tuple<Explicit, Explicit, Explicit> v1_c{1,2,3};
|
||||
|
||||
std::tuple<Explicit> v2_a = {1}; // { dg-error "could not convert" }
|
||||
std::tuple<Explicit, Explicit> v2_b = {1,2}; // { dg-error "could not convert" }
|
||||
std::tuple<Explicit, Explicit, Explicit> v2_c = {1,2,3}; // { dg-error "could not convert" }
|
||||
std::tuple<Explicit> v2_a = {1}; // { dg-error "explicit constructor" }
|
||||
std::tuple<Explicit, Explicit> v2_b = {1,2}; // { dg-error "explicit constructor" }
|
||||
std::tuple<Explicit, Explicit, Explicit> v2_c = {1,2,3}; // { dg-error "explicit constructor" }
|
||||
|
||||
std::tuple<Explicit> v3_a{std::tuple<int>{1}};
|
||||
std::tuple<Explicit, Explicit> v3_b{std::tuple<int,int>{1,2}};
|
||||
|
@ -196,11 +196,11 @@ std::tuple<long, long, long>
|
|||
v31_c{std::allocator_arg, std::allocator<int>{}, 1,2,3};
|
||||
|
||||
std::tuple<Explicit> v32_a
|
||||
= {std::allocator_arg, std::allocator<int>{ }, 1}; // { dg-error "could not convert" }
|
||||
= {std::allocator_arg, std::allocator<int>{ }, 1}; // { dg-error "explicit constructor" }
|
||||
std::tuple<Explicit, Explicit> v32_b
|
||||
= {std::allocator_arg, std::allocator<int>{}, 1, 2}; // { dg-error "could not convert" }
|
||||
= {std::allocator_arg, std::allocator<int>{}, 1, 2}; // { dg-error "explicit constructor" }
|
||||
std::tuple<Explicit, Explicit, Explicit> v32_c
|
||||
= {std::allocator_arg, std::allocator<int>{}, 1,2,3}; // { dg-error "could not convert" }
|
||||
= {std::allocator_arg, std::allocator<int>{}, 1,2,3}; // { dg-error "explicit constructor" }
|
||||
|
||||
std::tuple<int, int> v33{std::allocator_arg, std::allocator<int>{},
|
||||
std::pair<int, int>{1, 2}};
|
||||
|
@ -218,7 +218,7 @@ std::tuple<long, long> v37 = {std::allocator_arg, std::allocator<int>{},
|
|||
std::pair<int, int>{1, 2}};
|
||||
|
||||
std::tuple<Explicit, Explicit> v38
|
||||
= {std::allocator_arg, std::allocator<int>{}, std::pair<int, int>{1, 2}}; // { dg-error "could not convert" }
|
||||
= {std::allocator_arg, std::allocator<int>{}, std::pair<int, int>{1, 2}}; // { dg-error "explicit constructor" }
|
||||
|
||||
std::tuple<int, int> v39{std::allocator_arg, std::allocator<int>{}, v20};
|
||||
|
||||
|
@ -232,18 +232,18 @@ std::tuple<int, int> v42 = {std::allocator_arg, std::allocator<int>{}, v20};
|
|||
std::tuple<long, long> v43 = {std::allocator_arg, std::allocator<int>{}, v20};
|
||||
|
||||
std::tuple<Explicit, Explicit> v44
|
||||
= {std::allocator_arg, std::allocator<int>{ }, v20}; // { dg-error "could not convert" }
|
||||
= {std::allocator_arg, std::allocator<int>{ }, v20}; // { dg-error "explicit constructor" }
|
||||
std::tuple<ExplicitDefault> v45_a{};
|
||||
std::tuple<ExplicitDefault, int> v45_b{};
|
||||
|
||||
std::tuple<ExplicitDefault> v46_a = {}; // { dg-error "could not convert" }
|
||||
std::tuple<ExplicitDefault, int> v46_b = {}; // { dg-error "could not convert" }
|
||||
std::tuple<ExplicitDefault> v46_a = {}; // { dg-error "explicit constructor" }
|
||||
std::tuple<ExplicitDefault, int> v46_b = {}; // { dg-error "explicit constructor" }
|
||||
|
||||
std::tuple<ExplicitDefaultDefault> v47_a{};
|
||||
std::tuple<ExplicitDefaultDefault, int> v47_b{};
|
||||
|
||||
std::tuple<ExplicitDefaultDefault> v48_a = {}; // { dg-error "could not convert" }
|
||||
std::tuple<ExplicitDefaultDefault, int> v48_b = { }; // { dg-error "could not convert" }
|
||||
std::tuple<ExplicitDefaultDefault> v48_a = {}; // { dg-error "explicit constructor" }
|
||||
std::tuple<ExplicitDefaultDefault, int> v48_b = { }; // { dg-error "explicit constructor" }
|
||||
|
||||
|
||||
struct DeletedCopy
|
||||
|
@ -295,9 +295,9 @@ void test_arg_passing()
|
|||
f8_b(v1_b);
|
||||
f8_c(v1_c);
|
||||
|
||||
f8_a({1}); // { dg-error "could not convert" }
|
||||
f8_b({1,2}); // { dg-error "could not convert" }
|
||||
f8_c({1,2,3}); // { dg-error "could not convert" }
|
||||
f8_a({1}); // { dg-error "explicit constructor" }
|
||||
f8_b({1,2}); // { dg-error "explicit constructor" }
|
||||
f8_c({1,2,3}); // { dg-error "explicit constructor" }
|
||||
|
||||
f8_a(std::tuple<Explicit>{});
|
||||
f8_b(std::tuple<Explicit, Explicit>{});
|
||||
|
@ -330,10 +330,10 @@ void test_arg_passing()
|
|||
f9_b(std::tuple<long, long>{});
|
||||
f9_c(std::tuple<long, long, long>{});
|
||||
|
||||
f10_a({}); // { dg-error "could not convert" }
|
||||
f10_b({}); // { dg-error "could not convert" }
|
||||
f11_a({}); // { dg-error "could not convert" }
|
||||
f11_b({}); // { dg-error "could not convert" }
|
||||
f10_a({}); // { dg-error "explicit constructor" }
|
||||
f10_b({}); // { dg-error "explicit constructor" }
|
||||
f11_a({}); // { dg-error "explicit constructor" }
|
||||
f11_b({}); // { dg-error "explicit constructor" }
|
||||
|
||||
f10_a(std::tuple<ExplicitDefault>{});
|
||||
f10_b(std::tuple<ExplicitDefault, int>{});
|
||||
|
|
|
@ -31,11 +31,11 @@ auto first = std::begin(r), last = std::end(r);
|
|||
|
||||
// span(It, size_type)
|
||||
std::span<int> s1 = {first, 2};
|
||||
std::span<int, 2> s2 = {first, 2}; // { dg-error "could not convert" }
|
||||
std::span<int, 2> s2 = {first, 2}; // { dg-error "explicit constructor" }
|
||||
|
||||
// span(It, End)
|
||||
std::span<int> s3 = {first, last};
|
||||
std::span<int, 2> s4 = {first, last}; // { dg-error "could not convert" }
|
||||
std::span<int, 2> s4 = {first, last}; // { dg-error "explicit constructor" }
|
||||
|
||||
// span(R&&)
|
||||
std::span<int> s5 = r;
|
||||
|
|
Loading…
Add table
Reference in a new issue