Employ DirectList initialized entities to properly sort through some initialization edge cases.

llvm-svn: 150342
This commit is contained in:
Sebastian Redl 2012-02-12 16:37:24 +00:00
parent 34ca89afa8
commit 5a41f68fe2
5 changed files with 62 additions and 40 deletions

View File

@ -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 {

View File

@ -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());

View File

@ -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.");

View File

@ -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};
}
}

View File

@ -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});
}