diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3200,6 +3200,8 @@ bool CanPerformAggregateInitializationForOverloadResolution( const InitializedEntity &Entity, InitListExpr *From); + bool IsStringInit(Expr *Init, const ArrayType *AT); + bool CanPerformCopyInitialization(const InitializedEntity &Entity, ExprResult Init); ExprResult PerformCopyInitialization(const InitializedEntity &Entity, diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -141,6 +141,10 @@ return IsStringInit(init, arrayType, Context); } +bool Sema::IsStringInit(Expr *Init, const ArrayType *AT) { + return ::IsStringInit(Init, AT, Context) == SIF_None; +} + /// Update the type of a string literal, including any surrounding parentheses, /// to match the type of the object which it is initializing. static void updateStringLiteralType(Expr *E, QualType Ty) { diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -4984,18 +4984,19 @@ InOverloadResolution, AllowObjCWritebackConversion); } - // FIXME: Check the other conditions here: array of character type, - // initializer is a string literal. - if (ToType->isArrayType()) { - InitializedEntity Entity = - InitializedEntity::InitializeParameter(S.Context, ToType, - /*Consumed=*/false); - if (S.CanPerformCopyInitialization(Entity, From)) { - Result.setStandard(); - Result.Standard.setAsIdentityConversion(); - Result.Standard.setFromType(ToType); - Result.Standard.setAllToTypes(ToType); - return Result; + + if (const auto *AT = S.Context.getAsArrayType(ToType)) { + if (S.IsStringInit(From->getInit(0), AT)) { + InitializedEntity Entity = + InitializedEntity::InitializeParameter(S.Context, ToType, + /*Consumed=*/false); + if (S.CanPerformCopyInitialization(Entity, From)) { + Result.setStandard(); + Result.Standard.setAsIdentityConversion(); + Result.Standard.setFromType(ToType); + Result.Standard.setAllToTypes(ToType); + return Result; + } } } } diff --git a/clang/test/CXX/drs/dr14xx.cpp b/clang/test/CXX/drs/dr14xx.cpp --- a/clang/test/CXX/drs/dr14xx.cpp +++ b/clang/test/CXX/drs/dr14xx.cpp @@ -334,6 +334,22 @@ X x; X x2{x}; + + void f1(int); // expected-note {{candidate function}} + void f1(std::initializer_list) = delete; // expected-note {{candidate function has been explicitly deleted}} + void g1() { f1({42}); } // expected-error {{call to deleted function 'f1'}} + + template + struct Pair { + Pair(T, U); + }; + struct String { + String(const char *); + }; + + void f2(Pair); // expected-note {{candidate function}} + void f2(std::initializer_list) = delete; // expected-note {{candidate function has been explicitly deleted}} + void g2() { f2({"foo", "bar"}); } // expected-error {{call to deleted function 'f2'}} } // dr_example namespace nonaggregate { @@ -379,6 +395,46 @@ 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 { + // When the array size is 4 the call will attempt to bind an lvalue to an + // rvalue and fail. Therefore #2 will be called. (rsmith will bring this + // issue to CWG) + void f(const char(&&)[4]); // expected-note 5 {{no known conversion}} + void f(const char(&&)[5]) = delete; // expected-note 2 {{candidate function has been explicitly deleted}} expected-note 3 {{no known conversion}} + void f(const wchar_t(&&)[4]); // expected-note 5 {{no known conversion}} + void f(const wchar_t(&&)[5]) = delete; // expected-note {{candidate function has been explicitly deleted}} expected-note 4 {{no known conversion}} +#if __cplusplus >= 202002L + void f2(const char8_t(&&)[4]); // expected-note {{no known conversion}} + void f2(const char8_t(&&)[5]) = delete; // expected-note {{candidate function has been explicitly deleted}} +#endif + void f(const char16_t(&&)[4]); // expected-note 5 {{no known conversion}} + void f(const char16_t(&&)[5]) = delete; // expected-note {{candidate function has been explicitly deleted}} expected-note 4 {{no known conversion}} + void f(const char32_t(&&)[4]); // expected-note 5 {{no known conversion}} + void f(const char32_t(&&)[5]) = delete; // expected-note {{candidate function has been explicitly deleted}} expected-note 4 {{no known conversion}} + void g() { + f({"abc"}); // expected-error {{call to deleted function 'f'}} + f({((("abc")))}); // expected-error {{call to deleted function 'f'}} + f({L"abc"}); // expected-error {{call to deleted function 'f'}} +#if __cplusplus >= 202002L + f2({u8"abc"}); // expected-error {{call to deleted function 'f2'}} +#endif + f({uR"(abc)"}); // expected-error {{call to deleted function 'f'}} + f({(UR"(abc)")}); // expected-error {{call to deleted function 'f'}} + } + } // namespace StringLiterals +#endif } // dr1467 namespace dr1490 { // dr1490: 3.7 c++11 diff --git a/clang/test/SemaObjCXX/overload.mm b/clang/test/SemaObjCXX/overload.mm --- a/clang/test/SemaObjCXX/overload.mm +++ b/clang/test/SemaObjCXX/overload.mm @@ -201,3 +201,17 @@ } } + +namespace StringLiterals { +void f(const char(&&)[5]); +void f(const wchar_t(&&)[5]); +void f(const char16_t(&&)[5]); +void f(const char32_t(&&)[5]); +void g() { + f({"abc"}); + f({(((@encode(int))))}); + f({L"abc"}); + f({uR"(abc)"}); + f({(UR"(abc)")}); +} +} // namespace StringLiterals