Track the difference between

-- a constructor list initialization that unpacked an initializer list into
    constructor arguments and
 -- a list initialization that created as std::initializer_list and passed it
    as the first argument to a constructor

in the AST. Use this flag while instantiating templates to provide the right
semantics for the resulting initialization.

llvm-svn: 213224
This commit is contained in:
Richard Smith 2014-07-17 05:12:35 +00:00
parent 68c89c2480
commit f8adcdc436
12 changed files with 82 additions and 35 deletions

View File

@ -1077,6 +1077,7 @@ private:
bool Elidable : 1;
bool HadMultipleCandidates : 1;
bool ListInitialization : 1;
bool StdInitListInitialization : 1;
bool ZeroInitialization : 1;
unsigned ConstructKind : 2;
Stmt **Args;
@ -1088,6 +1089,7 @@ protected:
ArrayRef<Expr *> Args,
bool HadMultipleCandidates,
bool ListInitialization,
bool StdInitListInitialization,
bool ZeroInitialization,
ConstructionKind ConstructKind,
SourceRange ParenOrBraceRange);
@ -1114,6 +1116,7 @@ public:
ArrayRef<Expr *> Args,
bool HadMultipleCandidates,
bool ListInitialization,
bool StdInitListInitialization,
bool ZeroInitialization,
ConstructionKind ConstructKind,
SourceRange ParenOrBraceRange);
@ -1137,6 +1140,13 @@ public:
bool isListInitialization() const { return ListInitialization; }
void setListInitialization(bool V) { ListInitialization = V; }
/// \brief Whether this constructor call was written as list-initialization,
/// but was interpreted as forming a std::initializer_list<T> from the list
/// and passing that as a single constructor argument.
/// See C++11 [over.match.list]p1 bullet 1.
bool isStdInitListInitialization() const { return StdInitListInitialization; }
void setStdInitListInitialization(bool V) { StdInitListInitialization = V; }
/// \brief Whether this construction first requires
/// zero-initialization before the initializer is called.
bool requiresZeroInitialization() const { return ZeroInitialization; }
@ -1272,6 +1282,7 @@ public:
SourceRange ParenOrBraceRange,
bool HadMultipleCandidates,
bool ListInitialization,
bool StdInitListInitialization,
bool ZeroInitialization);
explicit CXXTemporaryObjectExpr(EmptyShell Empty)
: CXXConstructExpr(CXXTemporaryObjectExprClass, Empty), Type() { }

View File

@ -671,8 +671,6 @@ public:
SK_ConversionSequenceNoNarrowing,
/// \brief Perform list-initialization without a constructor.
SK_ListInitialization,
/// \brief Perform list-initialization with an initializer list constructor.
SK_ListConstructorCall,
/// \brief Unwrap the single-element initializer list for a reference.
SK_UnwrapInitList,
/// \brief Rewrap the single-element initializer list for a reference.
@ -705,6 +703,9 @@ public:
SK_ProduceObjCObject,
/// \brief Construct a std::initializer_list from an initializer list.
SK_StdInitializerList,
/// \brief Perform initialization via a constructor taking a single
/// std::initializer_list argument.
SK_StdInitializerListConstructorCall,
/// \brief Initialize an OpenCL sampler from an integer.
SK_OCLSamplerInit,
/// \brief Passing zero to a function where OpenCL event_t is expected.

View File

@ -3858,16 +3858,18 @@ public:
BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor, MultiExprArg Exprs,
bool HadMultipleCandidates, bool IsListInitialization,
bool IsStdInitListInitialization,
bool RequiresZeroInit, unsigned ConstructKind,
SourceRange ParenRange);
// FIXME: Can re remove this and have the above BuildCXXConstructExpr check if
// FIXME: Can we remove this and have the above BuildCXXConstructExpr check if
// the constructor can be elidable?
ExprResult
BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
CXXConstructorDecl *Constructor, bool Elidable,
MultiExprArg Exprs, bool HadMultipleCandidates,
bool IsListInitialization, bool RequiresZeroInit,
bool IsListInitialization,
bool IsStdInitListInitialization, bool RequiresZeroInit,
unsigned ConstructKind, SourceRange ParenRange);
/// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating

View File

@ -806,13 +806,16 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(const ASTContext &C,
SourceRange ParenOrBraceRange,
bool HadMultipleCandidates,
bool ListInitialization,
bool StdInitListInitialization,
bool ZeroInitialization)
: CXXConstructExpr(C, CXXTemporaryObjectExprClass,
Type->getType().getNonReferenceType(),
Type->getTypeLoc().getBeginLoc(),
Cons, false, Args,
HadMultipleCandidates,
ListInitialization, ZeroInitialization,
ListInitialization,
StdInitListInitialization,
ZeroInitialization,
CXXConstructExpr::CK_Complete, ParenOrBraceRange),
Type(Type) {
}
@ -834,12 +837,14 @@ CXXConstructExpr *CXXConstructExpr::Create(const ASTContext &C, QualType T,
ArrayRef<Expr*> Args,
bool HadMultipleCandidates,
bool ListInitialization,
bool StdInitListInitialization,
bool ZeroInitialization,
ConstructionKind ConstructKind,
SourceRange ParenOrBraceRange) {
return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D,
Elidable, Args,
HadMultipleCandidates, ListInitialization,
StdInitListInitialization,
ZeroInitialization, ConstructKind,
ParenOrBraceRange);
}
@ -850,6 +855,7 @@ CXXConstructExpr::CXXConstructExpr(const ASTContext &C, StmtClass SC,
ArrayRef<Expr*> args,
bool HadMultipleCandidates,
bool ListInitialization,
bool StdInitListInitialization,
bool ZeroInitialization,
ConstructionKind ConstructKind,
SourceRange ParenOrBraceRange)
@ -861,6 +867,7 @@ CXXConstructExpr::CXXConstructExpr(const ASTContext &C, StmtClass SC,
NumArgs(args.size()),
Elidable(elidable), HadMultipleCandidates(HadMultipleCandidates),
ListInitialization(ListInitialization),
StdInitListInitialization(StdInitListInitialization),
ZeroInitialization(ZeroInitialization),
ConstructKind(ConstructKind), Args(nullptr)
{

View File

@ -3021,6 +3021,7 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction(
ConstructorArgs,
CXXConstExpr->hadMultipleCandidates(),
CXXConstExpr->isListInitialization(),
CXXConstExpr->isStdInitListInitialization(),
CXXConstExpr->requiresZeroInitialization(),
CXXConstExpr->getConstructionKind(),
SourceRange());

View File

@ -10709,6 +10709,7 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
MultiExprArg ExprArgs,
bool HadMultipleCandidates,
bool IsListInitialization,
bool IsStdInitListInitialization,
bool RequiresZeroInit,
unsigned ConstructKind,
SourceRange ParenRange) {
@ -10732,7 +10733,8 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
Elidable, ExprArgs, HadMultipleCandidates,
IsListInitialization, RequiresZeroInit,
IsListInitialization,
IsStdInitListInitialization, RequiresZeroInit,
ConstructKind, ParenRange);
}
@ -10744,13 +10746,15 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
MultiExprArg ExprArgs,
bool HadMultipleCandidates,
bool IsListInitialization,
bool IsStdInitListInitialization,
bool RequiresZeroInit,
unsigned ConstructKind,
SourceRange ParenRange) {
MarkFunctionReferenced(ConstructLoc, Constructor);
return CXXConstructExpr::Create(
Context, DeclInitType, ConstructLoc, Constructor, Elidable, ExprArgs,
HadMultipleCandidates, IsListInitialization, RequiresZeroInit,
HadMultipleCandidates, IsListInitialization, IsStdInitListInitialization,
RequiresZeroInit,
static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind),
ParenRange);
}

View File

@ -2560,10 +2560,10 @@ static ExprResult BuildCXXCastArgument(Sema &S,
InitializedEntity::InitializeTemporary(Ty),
Constructor->getAccess());
ExprResult Result
= S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method),
ExprResult Result = S.BuildCXXConstructExpr(
CastLoc, Ty, cast<CXXConstructorDecl>(Method),
ConstructorArgs, HadMultipleCandidates,
/*ListInit*/ false, /*ZeroInit*/ false,
/*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete, SourceRange());
if (Result.isInvalid())
return ExprError();
@ -2709,20 +2709,17 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
From, /*FIXME:ConstructLoc*/SourceLocation(),
ConstructorArgs))
return ExprError();
return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
ToType, SCS.CopyConstructor,
ConstructorArgs,
/*HadMultipleCandidates*/ false,
/*ListInit*/ false, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
return BuildCXXConstructExpr(
/*FIXME:ConstructLoc*/ SourceLocation(), ToType, SCS.CopyConstructor,
ConstructorArgs, /*HadMultipleCandidates*/ false,
/*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete, SourceRange());
}
return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
ToType, SCS.CopyConstructor,
return BuildCXXConstructExpr(
/*FIXME:ConstructLoc*/ SourceLocation(), ToType, SCS.CopyConstructor,
From, /*HadMultipleCandidates*/ false,
/*ListInit*/ false, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
/*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete, SourceRange());
}
// Resolve overloaded function references.

View File

@ -2760,7 +2760,6 @@ void InitializationSequence::Step::Destroy() {
case SK_QualificationConversionLValue:
case SK_LValueToRValue:
case SK_ListInitialization:
case SK_ListConstructorCall:
case SK_UnwrapInitList:
case SK_RewrapInitList:
case SK_ConstructorInitialization:
@ -2775,6 +2774,7 @@ void InitializationSequence::Step::Destroy() {
case SK_PassByIndirectRestore:
case SK_ProduceObjCObject:
case SK_StdInitializerList:
case SK_StdInitializerListConstructorCall:
case SK_OCLSamplerInit:
case SK_OCLZeroEvent:
break;
@ -2945,7 +2945,7 @@ InitializationSequence
bool HadMultipleCandidates,
bool FromInitList, bool AsInitList) {
Step S;
S.Kind = FromInitList ? AsInitList ? SK_ListConstructorCall
S.Kind = FromInitList ? AsInitList ? SK_StdInitializerListConstructorCall
: SK_ConstructorInitializationFromList
: SK_ConstructorInitialization;
S.Type = T;
@ -5148,6 +5148,7 @@ static ExprResult CopyObject(Sema &S,
ConstructorArgs,
HadMultipleCandidates,
/*ListInit*/ false,
/*StdInitListInit*/ false,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
@ -5269,6 +5270,7 @@ PerformConstructorInitialization(Sema &S,
const InitializationSequence::Step& Step,
bool &ConstructorInitRequiresZeroInit,
bool IsListInitialization,
bool IsStdInitListInitialization,
SourceLocation LBraceLoc,
SourceLocation RBraceLoc) {
unsigned NumArgs = Args.size();
@ -5330,7 +5332,7 @@ PerformConstructorInitialization(Sema &S,
CurInit = new (S.Context) CXXTemporaryObjectExpr(
S.Context, Constructor, TSInfo, ConstructorArgs, ParenOrBraceRange,
HadMultipleCandidates, IsListInitialization,
ConstructorInitRequiresZeroInit);
IsStdInitListInitialization, ConstructorInitRequiresZeroInit);
} else {
CXXConstructExpr::ConstructionKind ConstructKind =
CXXConstructExpr::CK_Complete;
@ -5359,6 +5361,7 @@ PerformConstructorInitialization(Sema &S,
ConstructorArgs,
HadMultipleCandidates,
IsListInitialization,
IsStdInitListInitialization,
ConstructorInitRequiresZeroInit,
ConstructKind,
ParenOrBraceRange);
@ -5368,6 +5371,7 @@ PerformConstructorInitialization(Sema &S,
ConstructorArgs,
HadMultipleCandidates,
IsListInitialization,
IsStdInitListInitialization,
ConstructorInitRequiresZeroInit,
ConstructKind,
ParenOrBraceRange);
@ -5784,7 +5788,7 @@ InitializationSequence::Perform(Sema &S,
case SK_ConstructorInitialization:
case SK_ConstructorInitializationFromList:
case SK_ListConstructorCall:
case SK_StdInitializerListConstructorCall:
case SK_ZeroInitialization:
break;
}
@ -5959,6 +5963,7 @@ InitializationSequence::Perform(Sema &S,
ConstructorArgs,
HadMultipleCandidates,
/*ListInit*/ false,
/*StdInitListInit*/ false,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
@ -6132,6 +6137,7 @@ InitializationSequence::Perform(Sema &S,
Kind, Arg, *Step,
ConstructorInitRequiresZeroInit,
/*IsListInitialization*/true,
/*IsStdInitListInit*/false,
InitList->getLBraceLoc(),
InitList->getRBraceLoc());
break;
@ -6154,7 +6160,7 @@ InitializationSequence::Perform(Sema &S,
}
case SK_ConstructorInitialization:
case SK_ListConstructorCall: {
case SK_StdInitializerListConstructorCall: {
// 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.
@ -6164,10 +6170,13 @@ InitializationSequence::Perform(Sema &S,
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(
Entity.getType().getNonReferenceType());
bool UseTemporary = Entity.getType()->isReferenceType();
bool IsStdInitListInit =
Step->Kind == SK_StdInitializerListConstructorCall;
CurInit = PerformConstructorInitialization(
S, UseTemporary ? TempEntity : Entity, Kind, Args, *Step,
ConstructorInitRequiresZeroInit,
/*IsListInitialization*/Step->Kind == SK_ListConstructorCall,
/*IsListInitialization*/IsStdInitListInit,
/*IsStdInitListInitialization*/IsStdInitListInit,
/*LBraceLoc*/SourceLocation(),
/*RBraceLoc*/SourceLocation());
break;
@ -7030,10 +7039,6 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "list initialization via constructor";
break;
case SK_ListConstructorCall:
OS << "list initialization via initializer list constructor";
break;
case SK_ZeroInitialization:
OS << "zero initialization";
break;
@ -7074,6 +7079,10 @@ void InitializationSequence::dump(raw_ostream &OS) const {
OS << "std::initializer_list from initializer list";
break;
case SK_StdInitializerListConstructorCall:
OS << "list initialization from std::initializer_list";
break;
case SK_OCLSamplerInit:
OS << "OpenCL sampler_t from integer constant";
break;

View File

@ -2375,6 +2375,7 @@ public:
MultiExprArg Args,
bool HadMultipleCandidates,
bool ListInitialization,
bool StdInitListInitialization,
bool RequiresZeroInit,
CXXConstructExpr::ConstructionKind ConstructKind,
SourceRange ParenRange) {
@ -2387,6 +2388,7 @@ public:
ConvertedArgs,
HadMultipleCandidates,
ListInitialization,
StdInitListInitialization,
RequiresZeroInit, ConstructKind,
ParenRange);
}
@ -2877,6 +2879,11 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
if (!Construct || isa<CXXTemporaryObjectExpr>(Construct))
return getDerived().TransformExpr(Init);
// If the initialization implicitly converted an initializer list to a
// std::initializer_list object, unwrap the std::initializer_list too.
if (Construct && Construct->isStdInitListInitialization())
return TransformInitializer(Construct->getArg(0), CXXDirectInit);
SmallVector<Expr*, 8> NewArgs;
bool ArgChanged = false;
if (getDerived().TransformExprs(Construct->getArgs(), Construct->getNumArgs(),
@ -8571,6 +8578,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
Args,
E->hadMultipleCandidates(),
E->isListInitialization(),
E->isStdInitListInitialization(),
E->requiresZeroInitialization(),
E->getConstructionKind(),
E->getParenOrBraceRange());

View File

@ -1196,6 +1196,7 @@ void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
E->setElidable(Record[Idx++]);
E->setHadMultipleCandidates(Record[Idx++]);
E->setListInitialization(Record[Idx++]);
E->setStdInitListInitialization(Record[Idx++]);
E->setRequiresZeroInitialization(Record[Idx++]);
E->setConstructionKind((CXXConstructExpr::ConstructionKind)Record[Idx++]);
E->ParenOrBraceRange = ReadSourceRange(Record, Idx);

View File

@ -1150,6 +1150,7 @@ void ASTStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) {
Record.push_back(E->isElidable());
Record.push_back(E->hadMultipleCandidates());
Record.push_back(E->isListInitialization());
Record.push_back(E->isStdInitListInitialization());
Record.push_back(E->requiresZeroInitialization());
Record.push_back(E->getConstructionKind()); // FIXME: stable encoding
Writer.AddSourceRange(E->getParenOrBraceRange(), Record);

View File

@ -242,6 +242,7 @@ namespace DR1070 {
namespace ListInitInstantiate {
struct A {
A(std::initializer_list<A>);
A(std::initializer_list<int>);
};
struct B : A {
B(int);
@ -253,4 +254,8 @@ namespace ListInitInstantiate {
template<typename T> X<T>::X() : a{B{0}, B{1}} {}
X<int> x;
int f(const A&);
template<typename T> void g() { int k = f({0}); }
template void g<int>();
}