Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -3188,6 +3188,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, Index: clang/lib/Sema/SemaInit.cpp =================================================================== --- clang/lib/Sema/SemaInit.cpp +++ clang/lib/Sema/SemaInit.cpp @@ -3112,6 +3112,10 @@ return !Check.HadError(); } +bool Sema::IsStringInit(Expr *Init, const ArrayType *AT) { + return ::IsStringInit(Init, AT, Context) == SIF_None; +} + /// Check that the given Index expression is a valid array designator /// value. This is essentially just a wrapper around /// VerifyIntegerConstantExpression that also checks for negative values Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -4984,20 +4984,20 @@ 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; + } } - } } // C++14 [over.ics.list]p2: Otherwise, if the parameter type [...] (below). 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); + void g1() { f1({42}); } + + template + struct Pair { + Pair(T, U); + }; + struct String { + String(const char *); + }; + + void f2(Pair); + void f2(std::initializer_list); + void g2() { f2({"foo", "bar"}); } } // dr_example namespace nonaggregate { @@ -379,6 +395,43 @@ 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 char(&&)[5]); + void f(const wchar_t(&&)[4]); + void f(const wchar_t(&&)[5]); +#if __cplusplus >= 202002L + void f(const char8_t(&&)[4]); + void f(const char8_t(&&)[5]); +#endif + void f(const char16_t(&&)[4]); + void f(const char16_t(&&)[5]); + void f(const char32_t(&&)[4]); + void f(const char32_t(&&)[5]); + void g() { + f({"abc"}); + f({((("abc")))}); + f({L"abc"}); +#if __cplusplus >= 202002L + f({u8"abc"}); +#endif + f({uR"(abc)"}); + f({(UR"(abc)")}); + } + } // namespace StringLiterals +#endif } // dr1467 namespace dr1490 { // dr1490: 3.7 c++11 Index: clang/test/SemaCXX/overload-array-size.cpp =================================================================== --- /dev/null +++ clang/test/SemaCXX/overload-array-size.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -ast-dump | FileCheck %s + +// When the array size is 4 the call will attempt to bind an lvalue to an +// rvalue and fail. Therfore #2 will be called. (rsmith will bring this issue +// to CWG) +void f(const char(&&)[4]); // #1 +void f(const char(&&)[5]); // #2 +void g() { + f({"abc"}); + // CHECK: ExprWithCleanups {{.*}} 'void' + // CHECK-NEXT: CallExpr + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'void (*)(const char (&&)[5])' +} Index: clang/test/SemaObjCXX/overload.mm =================================================================== --- clang/test/SemaObjCXX/overload.mm +++ 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