Index: clang/include/clang/Sema/Overload.h =================================================================== --- clang/include/clang/Sema/Overload.h +++ clang/include/clang/Sema/Overload.h @@ -539,6 +539,17 @@ /// sequence only represents the worst element conversion. unsigned StdInitializerListElement : 1; + /// Whether the target is really a constant array, and the sequence only + /// represents the worst element conversion. + unsigned ConstantArrayElement : 1; + + /// The number of elements the std::initalizer_list has less then the + /// number of elements in the array. A value of 0 means the same number of + /// elements. If the std::initializer_list has more elements than the array + /// the conversion sequence will be marked as a bad conversion and this + /// field won't be used. + llvm::APInt ConstantArraySizeDiff{}; + void setKind(Kind K) { destruct(); ConversionKind = K; @@ -568,13 +579,17 @@ }; ImplicitConversionSequence() - : ConversionKind(Uninitialized), StdInitializerListElement(false) { + : ConversionKind(Uninitialized), StdInitializerListElement(false), + ConstantArrayElement(false) { Standard.setAsIdentityConversion(); } ImplicitConversionSequence(const ImplicitConversionSequence &Other) : ConversionKind(Other.ConversionKind), - StdInitializerListElement(Other.StdInitializerListElement) { + StdInitializerListElement(Other.StdInitializerListElement), + ConstantArrayElement(Other.ConstantArrayElement), + ConstantArraySizeDiff(Other.ConstantArraySizeDiff) { + switch (ConversionKind) { case Uninitialized: break; case StandardConversion: Standard = Other.Standard; break; @@ -680,6 +695,16 @@ StdInitializerListElement = V; } + bool isConstantArrayElement() const { return ConstantArrayElement; } + void setConstantArraySizeDiff(llvm::APInt Value) { + ConstantArrayElement = true; + ConstantArraySizeDiff = Value; + } + llvm::APInt getConstantArraySizeDiff() const { + assert(ConstantArrayElement); + return ConstantArraySizeDiff; + } + /// Form an "implicit" conversion sequence from nullptr_t to bool, for a /// direct-initialization of a bool object from nullptr_t. static ImplicitConversionSequence getNullptrToBool(QualType SourceType, Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -3809,6 +3809,15 @@ if (!ICS1.isStdInitializerListElement() && ICS2.isStdInitializerListElement()) return ImplicitConversionSequence::Worse; + + if (ICS1.isConstantArrayElement() && ICS2.isConstantArrayElement()) { + llvm::APInt Diff1 = ICS1.getConstantArraySizeDiff(); + llvm::APInt Diff2 = ICS2.getConstantArraySizeDiff(); + if (Diff1.ult(Diff2)) + return ImplicitConversionSequence::Better; + if (Diff2.ult(Diff1)) + return ImplicitConversionSequence::Worse; + } } if (ICS1.isStandard()) @@ -5062,9 +5071,16 @@ // FIXME: We're missing a lot of these checks. bool toStdInitializerList = false; QualType X; - if (ToType->isArrayType()) + Optional ArraySizeDiff; + if (ToType->isArrayType()) { + // Has the initializer list exactly N elements or fewer than N elements? + if (const auto *CAT = S.getASTContext().getAsConstantArrayType(ToType)) { + if (CAT->getSize().ult(From->getNumInits())) + return Result; + ArraySizeDiff = CAT->getSize() - From->getNumInits(); + } X = S.Context.getAsArrayType(ToType)->getElementType(); - else + } else toStdInitializerList = S.isStdInitializerList(ToType, &X); if (!X.isNull()) { for (unsigned i = 0, e = From->getNumInits(); i < e; ++i) { @@ -5095,6 +5111,8 @@ } Result.setStdInitializerListElement(toStdInitializerList); + if (ArraySizeDiff) + Result.setConstantArraySizeDiff(*ArraySizeDiff); return Result; } Index: clang/test/SemaCXX/overload-call.cpp =================================================================== --- clang/test/SemaCXX/overload-call.cpp +++ clang/test/SemaCXX/overload-call.cpp @@ -688,3 +688,41 @@ f(pmf); } } + +#if __cplusplus >= 201103L +// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1307 +// DR1307 +// For review are we sure the example with array of unknown bounds is DR1307 and not P0388? P0388 is resolved in +// https://reviews.llvm.org/D87566 +namespace InitializerListToArray { +void f(int(&&)[2]); // expected-note {{candidate function not viable}} +void f(int(&&)[3]); // expected-note {{candidate function not viable}} +void f(int(&&)[4]); // expected-note {{candidate function not viable}} + +void g() { + f({1}); + f({1, 2}); + f({1, 2, 3}); + f({1, 2, 3, 4}); + f({1, 2, 3, 4, 5}); // expected-error {{no matching function for call to 'f'}} +} + +struct S { + S(); + S(double); +}; + +void h(S(&&)[2]); // expected-note {{candidate function not viable}} +void h(S(&&)[3]); // expected-note {{candidate function not viable}} +void h(S(&&)[4]); // expected-note {{candidate function not viable}} + +void i() { + h({1}); + h({1, 2}); + h({1, 2, 3}); + h({1, 2, 3, 4}); + h({1, 2, 3, 4, 5}); // expected-error {{no matching function for call to 'h'}} +} + +} // namespace InitializerListToArray +#endif