Mordante created this revision. Mordante added reviewers: lvoufo, rsmith. Mordante added a project: clang. Mordante requested review of this revision.
The function `TryListConversion` didn't properly validate the following part of the standard: Otherwise, if the parameter type is a character array [... ] and the initializer list has a single element that is an appropriately-typed string literal (8.5.2 [dcl.init.string]), the implicit conversion sequence is the identity conversion. This caused the following call to `f()` to be ambiguous. void f(int(&&)[1]); void f(unsigned(&&)[1]); void g(unsigned i) { f({i}); } This issue only occurrs when the initializer list had one element. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D87561 Files: clang/lib/Sema/SemaOverload.cpp clang/test/CXX/drs/dr14xx.cpp Index: clang/test/CXX/drs/dr14xx.cpp =================================================================== --- clang/test/CXX/drs/dr14xx.cpp +++ clang/test/CXX/drs/dr14xx.cpp @@ -334,6 +334,22 @@ X x; X x2{x}; + + void f1(int); + void f1(std::initializer_list<long>); + void g1() { f1({42}); } + + template <class T, class U> + struct Pair { + Pair(T, U); + }; + struct String { + String(const char *); + }; + + void f2(Pair<const char *, const char *>); + void f2(std::initializer_list<String>); + void g2() { f2({"foo", "bar"}); } } // dr_example namespace nonaggregate { @@ -379,6 +395,31 @@ struct Value { Value(Pair); Value(TwoPairs); }; void f() { Value{{{1,2},{3,4}}}; } } + namespace NonAmbiguous { + // The original implementation made this case ambigious due to the special + // handling of one element initialization lists. + void f(int(&&)[1]); + void f(unsigned(&&)[1]); + + void g(unsigned i) { + f({i}); + } + } // namespace NonAmbiguous + +#if __cplusplus >= 201103L + namespace StringLiterals { + void f(const char[4]); + void f(const wchar_t[4]); + void f(const char16_t[4]); + void f(const char32_t[4]); + void g() { + f({"abc"}); // expected-warning {{braces around scalar initializer}} + f({L"abc"}); // expected-warning {{braces around scalar initializer}} + f({uR"(abc)"}); // expected-warning {{braces around scalar initializer}} + f({UR"(abc)"}); // expected-warning {{braces around scalar initializer}} + } + } // namespace StringLiterals +#endif } // dr1467 namespace dr1490 { // dr1490: 3.7 c++11 Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -4984,12 +4984,12 @@ InOverloadResolution, AllowObjCWritebackConversion); } - // FIXME: Check the other conditions here: array of character type, - // initializer is a string literal. - if (ToType->isArrayType()) { + + if (ToType->isArrayType() && ToType->isCharType() && + isa<StringLiteral>(From->getInit(0))) { InitializedEntity Entity = - InitializedEntity::InitializeParameter(S.Context, ToType, - /*Consumed=*/false); + InitializedEntity::InitializeParameter(S.Context, ToType, + /*Consumed=*/false); if (S.CanPerformCopyInitialization(Entity, From)) { Result.setStandard(); Result.Standard.setAsIdentityConversion();
Index: clang/test/CXX/drs/dr14xx.cpp =================================================================== --- clang/test/CXX/drs/dr14xx.cpp +++ clang/test/CXX/drs/dr14xx.cpp @@ -334,6 +334,22 @@ X x; X x2{x}; + + void f1(int); + void f1(std::initializer_list<long>); + void g1() { f1({42}); } + + template <class T, class U> + struct Pair { + Pair(T, U); + }; + struct String { + String(const char *); + }; + + void f2(Pair<const char *, const char *>); + void f2(std::initializer_list<String>); + void g2() { f2({"foo", "bar"}); } } // dr_example namespace nonaggregate { @@ -379,6 +395,31 @@ struct Value { Value(Pair); Value(TwoPairs); }; void f() { Value{{{1,2},{3,4}}}; } } + namespace NonAmbiguous { + // The original implementation made this case ambigious due to the special + // handling of one element initialization lists. + void f(int(&&)[1]); + void f(unsigned(&&)[1]); + + void g(unsigned i) { + f({i}); + } + } // namespace NonAmbiguous + +#if __cplusplus >= 201103L + namespace StringLiterals { + void f(const char[4]); + void f(const wchar_t[4]); + void f(const char16_t[4]); + void f(const char32_t[4]); + void g() { + f({"abc"}); // expected-warning {{braces around scalar initializer}} + f({L"abc"}); // expected-warning {{braces around scalar initializer}} + f({uR"(abc)"}); // expected-warning {{braces around scalar initializer}} + f({UR"(abc)"}); // expected-warning {{braces around scalar initializer}} + } + } // namespace StringLiterals +#endif } // dr1467 namespace dr1490 { // dr1490: 3.7 c++11 Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -4984,12 +4984,12 @@ InOverloadResolution, AllowObjCWritebackConversion); } - // FIXME: Check the other conditions here: array of character type, - // initializer is a string literal. - if (ToType->isArrayType()) { + + if (ToType->isArrayType() && ToType->isCharType() && + isa<StringLiteral>(From->getInit(0))) { InitializedEntity Entity = - InitializedEntity::InitializeParameter(S.Context, ToType, - /*Consumed=*/false); + InitializedEntity::InitializeParameter(S.Context, ToType, + /*Consumed=*/false); if (S.CanPerformCopyInitialization(Entity, From)) { Result.setStandard(); Result.Standard.setAsIdentityConversion();
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits