From: Sebastian Redl Date: Tue, 17 Jan 2012 22:49:48 +0000 (+0000) Subject: Basic overloading support for std::initializer_list. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fe5922809ec906390769a2cf0a765f395fa0c599;p=clang Basic overloading support for std::initializer_list. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148350 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index d14bf904df..e39735e256 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -3953,15 +3953,42 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, Result.setBad(BadConversionSequence::no_conversion, From, ToType); Result.setListInitializationSequence(); + // We need a complete type for what follows. Incomplete types can bever be + // initialized from init lists. + if (S.RequireCompleteType(From->getLocStart(), ToType, S.PDiag())) + return Result; + // C++11 [over.ics.list]p2: // If the parameter type is std::initializer_list or "array of X" and // all the elements can be implicitly converted to X, the implicit // conversion sequence is the worst conversion necessary to convert an // element of the list to X. - // FIXME: Recognize std::initializer_list. - // FIXME: Implement arrays. + QualType X; if (ToType->isArrayType()) + X = S.Context.getBaseElementType(ToType); + else + (void)S.isStdInitializerList(ToType, &X); + if (!X.isNull()) { + for (unsigned i = 0, e = From->getNumInits(); i < e; ++i) { + Expr *Init = From->getInit(i); + ImplicitConversionSequence ICS = + TryCopyInitialization(S, Init, X, SuppressUserConversions, + InOverloadResolution, + AllowObjCWritebackConversion); + // If a single element isn't convertible, fail. + if (ICS.isBad()) { + Result = ICS; + break; + } + // Otherwise, look for the worst conversion. + if (Result.isBad() || + CompareImplicitConversionSequences(S, ICS, Result) == + ImplicitConversionSequence::Worse) + Result = ICS; + } + Result.setListInitializationSequence(); return Result; + } // C++11 [over.ics.list]p3: // Otherwise, if the parameter is a non-aggregate class X and overload @@ -4078,7 +4105,6 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, // - if the initializer list has one element, the implicit conversion // sequence is the one required to convert the element to the // parameter type. - // FIXME: Catch narrowing here? unsigned NumInits = From->getNumInits(); if (NumInits == 1) Result = TryCopyInitialization(S, From->getInit(0), ToType, diff --git a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp index fc0df68575..87e7e8462b 100644 --- a/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp +++ b/test/SemaCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -58,3 +58,32 @@ void function_call() { void g(std::initializer_list); g({ {1, 2}, {2, 3}, {} }); } + +struct C { + C(int); +}; + +struct D { + D(); + operator int(); + operator C(); +}; + +void overloaded_call() { + one overloaded(std::initializer_list); + two overloaded(std::initializer_list); + + static_assert(sizeof(overloaded({1, 2, 3})) == sizeof(one), "bad overload"); + static_assert(sizeof(overloaded({ {1, 2}, {2, 3}, {} })) == sizeof(two), "bad overload"); + + void ambiguous(std::initializer_list); // expected-note {{candidate}} + void ambiguous(std::initializer_list); // expected-note {{candidate}} + ambiguous({ {1, 2}, {2, 3}, {3, 4} }); // expected-error {{ambiguous}} + + one ov2(std::initializer_list); // expected-note {{candidate}} + two ov2(std::initializer_list); // expected-note {{candidate}} + // Worst sequence to int is identity, whereas to C it's user-defined. + static_assert(sizeof(ov2({1, 2, 3})) == sizeof(one), "bad overload"); + // But here, user-defined is worst in both cases. + ov2({1, 2, D()}); // expected-error {{ambiguous}} +}