forked from OSchip/llvm-project
Employ DirectList initialized entities to properly sort through some initialization edge cases.
llvm-svn: 150342
This commit is contained in:
parent
34ca89afa8
commit
5a41f68fe2
|
@ -470,9 +470,13 @@ public:
|
|||
assert(Kind == SIK_Copy && "Only copy initialization has an '='");
|
||||
return Locations[1];
|
||||
}
|
||||
|
||||
|
||||
bool isCopyInit() const { return Kind == SIK_Copy; }
|
||||
|
||||
|
||||
/// \brief Retrieve whether this initialization allows the use of explicit
|
||||
/// constructors.
|
||||
bool AllowExplicit() const { return !isCopyInit(); }
|
||||
|
||||
/// \brief Retrieve the source range containing the locations of the open
|
||||
/// and closing parentheses for value and direct initializations.
|
||||
SourceRange getParenRange() const {
|
||||
|
|
|
@ -6143,9 +6143,12 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
|
|||
if (!VDecl->isInvalidDecl()) {
|
||||
InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl);
|
||||
InitializationKind Kind
|
||||
= DirectInit ? InitializationKind::CreateDirect(VDecl->getLocation(),
|
||||
Init->getLocStart(),
|
||||
Init->getLocEnd())
|
||||
= DirectInit ?
|
||||
CXXDirectInit ? InitializationKind::CreateDirect(VDecl->getLocation(),
|
||||
Init->getLocStart(),
|
||||
Init->getLocEnd())
|
||||
: InitializationKind::CreateDirectList(
|
||||
VDecl->getLocation())
|
||||
: InitializationKind::CreateCopy(VDecl->getLocation(),
|
||||
Init->getLocStart());
|
||||
|
||||
|
|
|
@ -2860,9 +2860,7 @@ static void TryConstructorInitialization(Sema &S,
|
|||
|
||||
// Determine whether we are allowed to call explicit constructors or
|
||||
// explicit conversion operators.
|
||||
bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct ||
|
||||
Kind.getKind() == InitializationKind::IK_Value ||
|
||||
Kind.getKind() == InitializationKind::IK_Default);
|
||||
bool AllowExplicit = Kind.AllowExplicit();
|
||||
bool CopyInitialization = Kind.getKind() == InitializationKind::IK_Copy;
|
||||
|
||||
// - Otherwise, if T is a class type, constructors are considered. The
|
||||
|
@ -3065,8 +3063,10 @@ static void TryListInitialization(Sema &S,
|
|||
if (DestType->isRecordType() && !DestType->isAggregateType()) {
|
||||
if (S.getLangOptions().CPlusPlus0x) {
|
||||
Expr *Arg = InitList;
|
||||
// A direct-initializer is not list-syntax, i.e. there's no special
|
||||
// treatment of "A a({1, 2});".
|
||||
TryConstructorInitialization(S, Entity, Kind, &Arg, 1, DestType,
|
||||
Sequence, /*InitListSyntax=*/true);
|
||||
Sequence, Kind.getKind() != InitializationKind::IK_Direct);
|
||||
} else
|
||||
Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType);
|
||||
return;
|
||||
|
@ -3074,7 +3074,7 @@ static void TryListInitialization(Sema &S,
|
|||
|
||||
InitListChecker CheckInitList(S, Entity, InitList,
|
||||
DestType, /*VerifyOnly=*/true,
|
||||
Kind.getKind() != InitializationKind::IK_Direct ||
|
||||
Kind.getKind() != InitializationKind::IK_DirectList ||
|
||||
!S.getLangOptions().CPlusPlus0x);
|
||||
if (CheckInitList.HadError()) {
|
||||
Sequence.SetFailed(InitializationSequence::FK_ListInitializationFailed);
|
||||
|
@ -3118,7 +3118,7 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
|
|||
|
||||
// Determine whether we are allowed to call explicit constructors or
|
||||
// explicit conversion operators.
|
||||
bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct;
|
||||
bool AllowExplicit = Kind.AllowExplicit();
|
||||
|
||||
const RecordType *T1RecordType = 0;
|
||||
if (AllowRValues && (T1RecordType = T1->getAs<RecordType>()) &&
|
||||
|
@ -3480,7 +3480,7 @@ static void TryReferenceInitializationCore(Sema &S,
|
|||
|
||||
// Determine whether we are allowed to call explicit constructors or
|
||||
// explicit conversion operators.
|
||||
bool AllowExplicit = (Kind.getKind() == InitializationKind::IK_Direct);
|
||||
bool AllowExplicit = Kind.AllowExplicit();
|
||||
|
||||
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(cv1T1);
|
||||
|
||||
|
@ -3643,7 +3643,7 @@ static void TryUserDefinedConversion(Sema &S,
|
|||
|
||||
// Determine whether we are allowed to call explicit constructors or
|
||||
// explicit conversion operators.
|
||||
bool AllowExplicit = Kind.getKind() == InitializationKind::IK_Direct;
|
||||
bool AllowExplicit = Kind.AllowExplicit();
|
||||
|
||||
if (const RecordType *DestRecordType = DestType->getAs<RecordType>()) {
|
||||
// The type we're converting to is a class type. Enumerate its constructors
|
||||
|
@ -5028,7 +5028,7 @@ InitializationSequence::Perform(Sema &S,
|
|||
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(Ty);
|
||||
InitListChecker PerformInitList(S, IsTemporary ? TempEntity : Entity,
|
||||
InitList, Ty, /*VerifyOnly=*/false,
|
||||
Kind.getKind() != InitializationKind::IK_Direct ||
|
||||
Kind.getKind() != InitializationKind::IK_DirectList ||
|
||||
!S.getLangOptions().CPlusPlus0x);
|
||||
if (PerformInitList.HadError())
|
||||
return ExprError();
|
||||
|
@ -5050,10 +5050,19 @@ InitializationSequence::Perform(Sema &S,
|
|||
}
|
||||
|
||||
case SK_ListConstructorCall: {
|
||||
// When an initializer list is passed for a parameter of type "reference
|
||||
// to object", we don't get an EK_Temporary entity, but instead an
|
||||
// EK_Parameter entity with reference type.
|
||||
// FIXME: This is a hack. Why is this necessary here, but not in other
|
||||
// places where implicit temporaries are created?
|
||||
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(
|
||||
Entity.getType().getNonReferenceType());
|
||||
bool UseTemporary = Entity.getType()->isReferenceType();
|
||||
InitListExpr *InitList = cast<InitListExpr>(CurInit.get());
|
||||
MultiExprArg Arg(InitList->getInits(), InitList->getNumInits());
|
||||
CurInit = PerformConstructorInitialization(S, Entity, Kind,
|
||||
move(Arg), *Step,
|
||||
CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity :
|
||||
Entity,
|
||||
Kind, move(Arg), *Step,
|
||||
ConstructorInitRequiresZeroInit);
|
||||
break;
|
||||
}
|
||||
|
@ -5549,7 +5558,7 @@ bool InitializationSequence::Diagnose(Sema &S,
|
|||
QualType DestType = Entity.getType();
|
||||
InitListChecker DiagnoseInitList(S, Entity, InitList,
|
||||
DestType, /*VerifyOnly=*/false,
|
||||
Kind.getKind() != InitializationKind::IK_Direct ||
|
||||
Kind.getKind() != InitializationKind::IK_DirectList ||
|
||||
!S.getLangOptions().CPlusPlus0x);
|
||||
assert(DiagnoseInitList.HadError() &&
|
||||
"Inconsistent init list check result.");
|
||||
|
|
|
@ -146,4 +146,33 @@ namespace objects {
|
|||
static_assert(sizeof(ov2({1})) == sizeof(one), "bad overload"); // list -> int ranks as identity
|
||||
static_assert(sizeof(ov2({1, 2, 3})) == sizeof(two), "bad overload"); // list -> F only viable
|
||||
}
|
||||
|
||||
struct G { // expected-note 2 {{not viable}}
|
||||
// This is not an initializer-list constructor.
|
||||
template<typename ...T>
|
||||
G(std::initializer_list<int>, T ...); // expected-note {{not viable}}
|
||||
};
|
||||
|
||||
struct H { // expected-note 2 {{not viable}}
|
||||
explicit H(int, int); // expected-note {{not viable}}
|
||||
H(int, void*); // expected-note {{not viable}}
|
||||
};
|
||||
|
||||
void edge_cases() {
|
||||
// invalid (the first phase only considers init-list ctors)
|
||||
// (for the second phase, no constructor is viable)
|
||||
G g1{1, 2, 3}; // expected-error {{no matching constructor}}
|
||||
|
||||
// valid (T deduced to <>).
|
||||
G g2({1, 2, 3});
|
||||
|
||||
// invalid
|
||||
H h1({1, 2}); // expected-error {{no matching constructor}}
|
||||
|
||||
// valid (by copy constructor).
|
||||
H h2({1, nullptr});
|
||||
|
||||
// valid
|
||||
H h3{1, 2};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,27 +49,4 @@ namespace litb {
|
|||
// invalid
|
||||
int const &b({0}); // expected-error {{}}
|
||||
|
||||
struct C { explicit C(int, int); C(int, long); };
|
||||
|
||||
// invalid
|
||||
C c({1, 2}); // expected-error {{}}
|
||||
|
||||
// valid (by copy constructor).
|
||||
C d({1, 2L});
|
||||
|
||||
// valid
|
||||
C e{1, 2};
|
||||
|
||||
struct B {
|
||||
template<typename ...T>
|
||||
B(std::initializer_list<int>, T ...);
|
||||
};
|
||||
|
||||
// invalid (the first phase only considers init-list ctors)
|
||||
// (for the second phase, no constructor is viable)
|
||||
B f{1, 2, 3};
|
||||
|
||||
// valid (T deduced to <>).
|
||||
B g({1, 2, 3});
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue