зеркало из https://github.com/microsoft/clang-1.git
Overloading for initializer list construction.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147156 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
62f13c9e9e
Коммит
cf15cef844
|
@ -643,8 +643,10 @@ public:
|
|||
FK_InitListBadDestinationType,
|
||||
/// \brief Overloading for a user-defined conversion failed.
|
||||
FK_UserConversionOverloadFailed,
|
||||
/// \brief Overloaded for initialization by constructor failed.
|
||||
/// \brief Overloading for initialization by constructor failed.
|
||||
FK_ConstructorOverloadFailed,
|
||||
/// \brief Overloading for list-initialization by constructor failed.
|
||||
FK_ListConstructorOverloadFailed,
|
||||
/// \brief Default-initialization of a 'const' object.
|
||||
FK_DefaultInitOfConst,
|
||||
/// \brief Initialization of an incomplete type.
|
||||
|
|
|
@ -2436,6 +2436,7 @@ bool InitializationSequence::isAmbiguous() const {
|
|||
case FK_ReferenceInitOverloadFailed:
|
||||
case FK_UserConversionOverloadFailed:
|
||||
case FK_ConstructorOverloadFailed:
|
||||
case FK_ListConstructorOverloadFailed:
|
||||
return FailedOverloadResult == OR_Ambiguous;
|
||||
}
|
||||
|
||||
|
@ -2849,8 +2850,8 @@ static bool TryListConstructionSpecialCases(Sema &S,
|
|||
Args, NumArgs, CandidateSet,
|
||||
/*SuppressUserConversions*/ false);
|
||||
Sequence.SetOverloadFailure(
|
||||
InitializationSequence::FK_ConstructorOverloadFailed,
|
||||
OR_Deleted);
|
||||
InitializationSequence::FK_ListConstructorOverloadFailed,
|
||||
OR_Deleted);
|
||||
} else
|
||||
Sequence.AddConstructorInitializationStep(DefaultConstructor,
|
||||
DefaultConstructor->getAccess(),
|
||||
|
@ -2961,8 +2962,9 @@ static void TryConstructorInitialization(Sema &S,
|
|||
OverloadCandidateSet::iterator Best;
|
||||
if (OverloadingResult Result
|
||||
= CandidateSet.BestViableFunction(S, DeclLoc, Best)) {
|
||||
Sequence.SetOverloadFailure(
|
||||
InitializationSequence::FK_ConstructorOverloadFailed,
|
||||
Sequence.SetOverloadFailure(FromInitList ?
|
||||
InitializationSequence::FK_ListConstructorOverloadFailed :
|
||||
InitializationSequence::FK_ConstructorOverloadFailed,
|
||||
Result);
|
||||
return;
|
||||
}
|
||||
|
@ -5428,12 +5430,20 @@ bool InitializationSequence::Diagnose(Sema &S,
|
|||
<< (DestType->isRecordType()) << DestType << Args[0]->getSourceRange();
|
||||
break;
|
||||
|
||||
case FK_ListConstructorOverloadFailed:
|
||||
case FK_ConstructorOverloadFailed: {
|
||||
SourceRange ArgsRange;
|
||||
if (NumArgs)
|
||||
ArgsRange = SourceRange(Args[0]->getLocStart(),
|
||||
Args[NumArgs - 1]->getLocEnd());
|
||||
|
||||
if (Failure == FK_ListConstructorOverloadFailed) {
|
||||
assert(NumArgs == 1 && "List construction from other than 1 argument.");
|
||||
InitListExpr *InitList = cast<InitListExpr>(Args[0]);
|
||||
Args = InitList->getInits();
|
||||
NumArgs = InitList->getNumInits();
|
||||
}
|
||||
|
||||
// FIXME: Using "DestType" for the entity we're printing is probably
|
||||
// bad.
|
||||
switch (FailedOverloadResult) {
|
||||
|
|
|
@ -824,6 +824,86 @@ bool Sema::isFunctionConsideredUnavailable(FunctionDecl *FD) {
|
|||
return FD->isUnavailable() && !cast<Decl>(CurContext)->isUnavailable();
|
||||
}
|
||||
|
||||
/// \brief Tries a user-defined conversion from From to ToType.
|
||||
///
|
||||
/// Produces an implicit conversion sequence for when a standard conversion
|
||||
/// is not an option. See TryImplicitConversion for more information.
|
||||
static ImplicitConversionSequence
|
||||
TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
|
||||
bool SuppressUserConversions,
|
||||
bool AllowExplicit,
|
||||
bool InOverloadResolution,
|
||||
bool CStyle,
|
||||
bool AllowObjCWritebackConversion) {
|
||||
ImplicitConversionSequence ICS;
|
||||
|
||||
if (SuppressUserConversions) {
|
||||
// We're not in the case above, so there is no conversion that
|
||||
// we can perform.
|
||||
ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
|
||||
return ICS;
|
||||
}
|
||||
|
||||
// Attempt user-defined conversion.
|
||||
OverloadCandidateSet Conversions(From->getExprLoc());
|
||||
OverloadingResult UserDefResult
|
||||
= IsUserDefinedConversion(S, From, ToType, ICS.UserDefined, Conversions,
|
||||
AllowExplicit);
|
||||
|
||||
if (UserDefResult == OR_Success) {
|
||||
ICS.setUserDefined();
|
||||
// C++ [over.ics.user]p4:
|
||||
// A conversion of an expression of class type to the same class
|
||||
// type is given Exact Match rank, and a conversion of an
|
||||
// expression of class type to a base class of that type is
|
||||
// given Conversion rank, in spite of the fact that a copy
|
||||
// constructor (i.e., a user-defined conversion function) is
|
||||
// called for those cases.
|
||||
if (CXXConstructorDecl *Constructor
|
||||
= dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) {
|
||||
QualType FromCanon
|
||||
= S.Context.getCanonicalType(From->getType().getUnqualifiedType());
|
||||
QualType ToCanon
|
||||
= S.Context.getCanonicalType(ToType).getUnqualifiedType();
|
||||
if (Constructor->isCopyConstructor() &&
|
||||
(FromCanon == ToCanon || S.IsDerivedFrom(FromCanon, ToCanon))) {
|
||||
// Turn this into a "standard" conversion sequence, so that it
|
||||
// gets ranked with standard conversion sequences.
|
||||
ICS.setStandard();
|
||||
ICS.Standard.setAsIdentityConversion();
|
||||
ICS.Standard.setFromType(From->getType());
|
||||
ICS.Standard.setAllToTypes(ToType);
|
||||
ICS.Standard.CopyConstructor = Constructor;
|
||||
if (ToCanon != FromCanon)
|
||||
ICS.Standard.Second = ICK_Derived_To_Base;
|
||||
}
|
||||
}
|
||||
|
||||
// C++ [over.best.ics]p4:
|
||||
// However, when considering the argument of a user-defined
|
||||
// conversion function that is a candidate by 13.3.1.3 when
|
||||
// invoked for the copying of the temporary in the second step
|
||||
// of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or
|
||||
// 13.3.1.6 in all cases, only standard conversion sequences and
|
||||
// ellipsis conversion sequences are allowed.
|
||||
if (SuppressUserConversions && ICS.isUserDefined()) {
|
||||
ICS.setBad(BadConversionSequence::suppressed_user, From, ToType);
|
||||
}
|
||||
} else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) {
|
||||
ICS.setAmbiguous();
|
||||
ICS.Ambiguous.setFromType(From->getType());
|
||||
ICS.Ambiguous.setToType(ToType);
|
||||
for (OverloadCandidateSet::iterator Cand = Conversions.begin();
|
||||
Cand != Conversions.end(); ++Cand)
|
||||
if (Cand->Viable)
|
||||
ICS.Ambiguous.addConversion(Cand->Function);
|
||||
} else {
|
||||
ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
|
||||
}
|
||||
|
||||
return ICS;
|
||||
}
|
||||
|
||||
/// TryImplicitConversion - Attempt to perform an implicit conversion
|
||||
/// from the given expression (Expr) to the given type (ToType). This
|
||||
/// function returns an implicit conversion sequence that can be used
|
||||
|
@ -899,71 +979,9 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
|
|||
return ICS;
|
||||
}
|
||||
|
||||
if (SuppressUserConversions) {
|
||||
// We're not in the case above, so there is no conversion that
|
||||
// we can perform.
|
||||
ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
|
||||
return ICS;
|
||||
}
|
||||
|
||||
// Attempt user-defined conversion.
|
||||
OverloadCandidateSet Conversions(From->getExprLoc());
|
||||
OverloadingResult UserDefResult
|
||||
= IsUserDefinedConversion(S, From, ToType, ICS.UserDefined, Conversions,
|
||||
AllowExplicit);
|
||||
|
||||
if (UserDefResult == OR_Success) {
|
||||
ICS.setUserDefined();
|
||||
// C++ [over.ics.user]p4:
|
||||
// A conversion of an expression of class type to the same class
|
||||
// type is given Exact Match rank, and a conversion of an
|
||||
// expression of class type to a base class of that type is
|
||||
// given Conversion rank, in spite of the fact that a copy
|
||||
// constructor (i.e., a user-defined conversion function) is
|
||||
// called for those cases.
|
||||
if (CXXConstructorDecl *Constructor
|
||||
= dyn_cast<CXXConstructorDecl>(ICS.UserDefined.ConversionFunction)) {
|
||||
QualType FromCanon
|
||||
= S.Context.getCanonicalType(From->getType().getUnqualifiedType());
|
||||
QualType ToCanon
|
||||
= S.Context.getCanonicalType(ToType).getUnqualifiedType();
|
||||
if (Constructor->isCopyConstructor() &&
|
||||
(FromCanon == ToCanon || S.IsDerivedFrom(FromCanon, ToCanon))) {
|
||||
// Turn this into a "standard" conversion sequence, so that it
|
||||
// gets ranked with standard conversion sequences.
|
||||
ICS.setStandard();
|
||||
ICS.Standard.setAsIdentityConversion();
|
||||
ICS.Standard.setFromType(From->getType());
|
||||
ICS.Standard.setAllToTypes(ToType);
|
||||
ICS.Standard.CopyConstructor = Constructor;
|
||||
if (ToCanon != FromCanon)
|
||||
ICS.Standard.Second = ICK_Derived_To_Base;
|
||||
}
|
||||
}
|
||||
|
||||
// C++ [over.best.ics]p4:
|
||||
// However, when considering the argument of a user-defined
|
||||
// conversion function that is a candidate by 13.3.1.3 when
|
||||
// invoked for the copying of the temporary in the second step
|
||||
// of a class copy-initialization, or by 13.3.1.4, 13.3.1.5, or
|
||||
// 13.3.1.6 in all cases, only standard conversion sequences and
|
||||
// ellipsis conversion sequences are allowed.
|
||||
if (SuppressUserConversions && ICS.isUserDefined()) {
|
||||
ICS.setBad(BadConversionSequence::suppressed_user, From, ToType);
|
||||
}
|
||||
} else if (UserDefResult == OR_Ambiguous && !SuppressUserConversions) {
|
||||
ICS.setAmbiguous();
|
||||
ICS.Ambiguous.setFromType(From->getType());
|
||||
ICS.Ambiguous.setToType(ToType);
|
||||
for (OverloadCandidateSet::iterator Cand = Conversions.begin();
|
||||
Cand != Conversions.end(); ++Cand)
|
||||
if (Cand->Viable)
|
||||
ICS.Ambiguous.addConversion(Cand->Function);
|
||||
} else {
|
||||
ICS.setBad(BadConversionSequence::no_conversion, From, ToType);
|
||||
}
|
||||
|
||||
return ICS;
|
||||
return TryUserDefinedConversion(S, From, ToType, SuppressUserConversions,
|
||||
AllowExplicit, InOverloadResolution, CStyle,
|
||||
AllowObjCWritebackConversion);
|
||||
}
|
||||
|
||||
ImplicitConversionSequence
|
||||
|
@ -2612,6 +2630,18 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
|
|||
// We're not going to find any constructors.
|
||||
} else if (CXXRecordDecl *ToRecordDecl
|
||||
= dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) {
|
||||
|
||||
Expr **Args = &From;
|
||||
unsigned NumArgs = 1;
|
||||
bool ListInitializing = false;
|
||||
// If we're list-initializing, we pass the individual elements as
|
||||
// arguments, not the entire list.
|
||||
if (InitListExpr *InitList = dyn_cast<InitListExpr>(From)) {
|
||||
Args = InitList->getInits();
|
||||
NumArgs = InitList->getNumInits();
|
||||
ListInitializing = true;
|
||||
}
|
||||
|
||||
DeclContext::lookup_iterator Con, ConEnd;
|
||||
for (llvm::tie(Con, ConEnd) = S.LookupConstructors(ToRecordDecl);
|
||||
Con != ConEnd; ++Con) {
|
||||
|
@ -2628,28 +2658,33 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
|
|||
else
|
||||
Constructor = cast<CXXConstructorDecl>(D);
|
||||
|
||||
if (!Constructor->isInvalidDecl() &&
|
||||
Constructor->isConvertingConstructor(AllowExplicit)) {
|
||||
bool Usable = !Constructor->isInvalidDecl();
|
||||
if (ListInitializing)
|
||||
Usable = Usable && (AllowExplicit || !Constructor->isExplicit());
|
||||
else
|
||||
Usable = Usable &&Constructor->isConvertingConstructor(AllowExplicit);
|
||||
if (Usable) {
|
||||
if (ConstructorTmpl)
|
||||
S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
|
||||
/*ExplicitArgs*/ 0,
|
||||
&From, 1, CandidateSet,
|
||||
Args, NumArgs, CandidateSet,
|
||||
/*SuppressUserConversions=*/
|
||||
!ConstructorsOnly);
|
||||
!ConstructorsOnly &&
|
||||
!ListInitializing);
|
||||
else
|
||||
// Allow one user-defined conversion when user specifies a
|
||||
// From->ToType conversion via an static cast (c-style, etc).
|
||||
S.AddOverloadCandidate(Constructor, FoundDecl,
|
||||
&From, 1, CandidateSet,
|
||||
Args, NumArgs, CandidateSet,
|
||||
/*SuppressUserConversions=*/
|
||||
!ConstructorsOnly);
|
||||
!ConstructorsOnly && !ListInitializing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enumerate conversion functions, if we're allowed to.
|
||||
if (ConstructorsOnly) {
|
||||
if (ConstructorsOnly || isa<InitListExpr>(From)) {
|
||||
} else if (S.RequireCompleteType(From->getLocStart(), From->getType(),
|
||||
S.PDiag(0) << From->getSourceRange())) {
|
||||
// No conversion functions from incomplete types.
|
||||
|
@ -2705,11 +2740,16 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
|
|||
// the argument of the constructor.
|
||||
//
|
||||
QualType ThisType = Constructor->getThisType(S.Context);
|
||||
if (Best->Conversions[0].isEllipsis())
|
||||
User.EllipsisConversion = true;
|
||||
else {
|
||||
User.Before = Best->Conversions[0].Standard;
|
||||
User.EllipsisConversion = false;
|
||||
if (isa<InitListExpr>(From)) {
|
||||
// Initializer lists don't have conversions as such.
|
||||
User.Before.setAsIdentityConversion();
|
||||
} else {
|
||||
if (Best->Conversions[0].isEllipsis())
|
||||
User.EllipsisConversion = true;
|
||||
else {
|
||||
User.Before = Best->Conversions[0].Standard;
|
||||
User.EllipsisConversion = false;
|
||||
}
|
||||
}
|
||||
User.HadMultipleCandidates = HadMultipleCandidates;
|
||||
User.ConversionFunction = Constructor;
|
||||
|
@ -3916,7 +3956,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
|
|||
// conversion sequence is the worst conversion necessary to convert an
|
||||
// element of the list to X.
|
||||
// FIXME: Recognize std::initializer_list.
|
||||
// FIXME: Arrays don't make sense until we can deal with references.
|
||||
// FIXME: Implement arrays.
|
||||
if (ToType->isArrayType())
|
||||
return Result;
|
||||
|
||||
|
@ -3926,9 +3966,15 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
|
|||
// conversion sequence is a user-defined conversion sequence. If multiple
|
||||
// constructors are viable but none is better than the others, the
|
||||
// implicit conversion sequence is a user-defined conversion sequence.
|
||||
// FIXME: Implement this.
|
||||
if (ToType->isRecordType() && !ToType->isAggregateType())
|
||||
if (ToType->isRecordType() && !ToType->isAggregateType()) {
|
||||
// This function can deal with initializer lists.
|
||||
Result = TryUserDefinedConversion(S, From, ToType, SuppressUserConversions,
|
||||
/*AllowExplicit=*/false,
|
||||
InOverloadResolution, /*CStyle=*/false,
|
||||
AllowObjCWritebackConversion);
|
||||
Result.setListInitializationSequence();
|
||||
return Result;
|
||||
}
|
||||
|
||||
// C++11 [over.ics.list]p4:
|
||||
// Otherwise, if the parameter has an aggregate type which can be
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
|
||||
|
||||
struct one { char c[1]; };
|
||||
struct two { char c[2]; };
|
||||
|
||||
namespace objects {
|
||||
|
||||
struct X1 { X1(int); };
|
||||
|
@ -45,8 +48,8 @@ namespace objects {
|
|||
void takes_C(C);
|
||||
takes_C({1, 1.0});
|
||||
|
||||
//C c;
|
||||
//c[{1, 1.0}]; needs overloading
|
||||
C c;
|
||||
c[{1, 1.0}];
|
||||
|
||||
return {1, 1.0};
|
||||
}
|
||||
|
@ -56,11 +59,23 @@ namespace objects {
|
|||
(void) new C{1, 1.0};
|
||||
}
|
||||
|
||||
struct B {
|
||||
B(C, int, C);
|
||||
struct B { // expected-note 2 {{candidate constructor}}
|
||||
B(C, int, C); // expected-note {{candidate constructor not viable: cannot convert initializer list argument to 'objects::C'}}
|
||||
};
|
||||
|
||||
void nested_init() {
|
||||
//B b{{1, 1.0}, 2, {3, 4}}; needs overloading
|
||||
B b1{{1, 1.0}, 2, {3, 4}};
|
||||
B b2{{1, 1.0, 4}, 2, {3, 4}}; // expected-error {{no matching constructor for initialization of 'objects::B'}}
|
||||
}
|
||||
|
||||
void overloaded_call() {
|
||||
one ov1(B); // expected-note {{not viable: cannot convert initializer list}}
|
||||
two ov1(C); // expected-note {{not viable: cannot convert initializer list}}
|
||||
|
||||
static_assert(sizeof(ov1({})) == sizeof(two), "bad overload");
|
||||
static_assert(sizeof(ov1({1, 2})) == sizeof(two), "bad overload");
|
||||
static_assert(sizeof(ov1({{1, 1.0}, 2, {3, 4}})) == sizeof(one), "bad overload");
|
||||
|
||||
ov1({1}); // expected-error {{no matching function}}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче