diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index feef15689fafd8..179da2ac26d77e 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -3346,10 +3346,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType, bool Usable = !Info.Constructor->isInvalidDecl() && S.isInitListConstructor(Info.Constructor); if (Usable) { - // If the first argument is (a reference to) the target type, - // suppress conversions. - bool SuppressUserConversions = isFirstArgumentCompatibleWithType( - S.Context, Info.Constructor, ToType); + bool SuppressUserConversions = false; if (Info.ConstructorTmpl) S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl, /*ExplicitArgs*/ nullptr, From, @@ -3473,14 +3470,18 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, /*AllowExplicit*/ true); if (Usable) { bool SuppressUserConversions = !ConstructorsOnly; + // C++20 [over.best.ics.general]/4.5: + // if the target is the first parameter of a constructor [of class + // X] and the constructor [...] is a candidate by [...] the second + // phase of [over.match.list] when the initializer list has exactly + // one element that is itself an initializer list, [...] and the + // conversion is to X or reference to cv X, user-defined conversion + // sequences are not cnosidered. if (SuppressUserConversions && ListInitializing) { - SuppressUserConversions = false; - if (NumArgs == 1) { - // If the first argument is (a reference to) the target type, - // suppress conversions. - SuppressUserConversions = isFirstArgumentCompatibleWithType( - S.Context, Info.Constructor, ToType); - } + SuppressUserConversions = + NumArgs == 1 && isa(Args[0]) && + isFirstArgumentCompatibleWithType(S.Context, Info.Constructor, + ToType); } if (Info.ConstructorTmpl) S.AddTemplateOverloadCandidate( diff --git a/clang/test/CXX/drs/dr14xx.cpp b/clang/test/CXX/drs/dr14xx.cpp index 866f2fe0bf85a6..70bf1ea70e38ea 100644 --- a/clang/test/CXX/drs/dr14xx.cpp +++ b/clang/test/CXX/drs/dr14xx.cpp @@ -296,6 +296,9 @@ namespace std { } // std namespace dr1467 { // dr1467: 3.7 c++11 + // Note that the change to [over.best.ics] was partially undone by DR2076; + // the resulting rule is tested with the tests for that change. + // List-initialization of aggregate from same-type object namespace basic0 { @@ -419,7 +422,7 @@ namespace dr1467 { // dr1467: 3.7 c++11 void f() { Value{{{1,2},{3,4}}}; } } namespace NonAmbiguous { - // The original implementation made this case ambigious due to the special + // The original implementation made this case ambiguous due to the special // handling of one element initialization lists. void f(int(&&)[1]); void f(unsigned(&&)[1]); diff --git a/clang/test/CXX/drs/dr20xx.cpp b/clang/test/CXX/drs/dr20xx.cpp index 56cc1161a00c8c..9a0c772973eca7 100644 --- a/clang/test/CXX/drs/dr20xx.cpp +++ b/clang/test/CXX/drs/dr20xx.cpp @@ -49,6 +49,47 @@ namespace dr2026 { // dr2026: 11 } } +namespace dr2076 { // dr2076: 13 +#if __cplusplus >= 201103L + namespace std_example { + struct A { A(int); }; + struct B { B(A); }; + B b{{0}}; + + struct Params { int a; int b; }; + struct Foo { + Foo(Params); + }; + Foo foo{{1, 2}}; + } + + struct string_view { + string_view(int); // not an aggregate + }; + struct string { + string(int); // not an aggregate + operator string_view() const; + }; + + void foo(const string &); // expected-note {{cannot convert initializer list}} + void bar(string_view); // expected-note 2{{cannot convert initializer list}} + + void func(const string &arg) { + // An argument in one set of braces is subject to user-defined conversions; + // an argument in two sets of braces is not, but an identity conversion is + // still OK. + foo(arg); + foo({arg}); + foo({{arg}}); + foo({{{arg}}}); // expected-error {{no matching function}} + bar(arg); + bar({arg}); + bar({{arg}}); // expected-error {{no matching function}} + bar({{{arg}}}); // expected-error {{no matching function}} + } +#endif +} + namespace dr2082 { // dr2082: 11 void test1(int x, int = sizeof(x)); // ok #if __cplusplus >= 201103L