forked from OSchip/llvm-project
Basic overloading support for std::initializer_list.
llvm-svn: 148350
This commit is contained in:
parent
c1839b1b09
commit
10f0fc04a8
|
@ -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<X> 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,
|
||||
|
|
|
@ -58,3 +58,32 @@ void function_call() {
|
|||
void g(std::initializer_list<B>);
|
||||
g({ {1, 2}, {2, 3}, {} });
|
||||
}
|
||||
|
||||
struct C {
|
||||
C(int);
|
||||
};
|
||||
|
||||
struct D {
|
||||
D();
|
||||
operator int();
|
||||
operator C();
|
||||
};
|
||||
|
||||
void overloaded_call() {
|
||||
one overloaded(std::initializer_list<int>);
|
||||
two overloaded(std::initializer_list<B>);
|
||||
|
||||
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<A>); // expected-note {{candidate}}
|
||||
void ambiguous(std::initializer_list<B>); // expected-note {{candidate}}
|
||||
ambiguous({ {1, 2}, {2, 3}, {3, 4} }); // expected-error {{ambiguous}}
|
||||
|
||||
one ov2(std::initializer_list<int>); // expected-note {{candidate}}
|
||||
two ov2(std::initializer_list<C>); // 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}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue