PR13470: Ensure that copy-list-initialization isntantiates as
copy-list-initialization (and doesn't add an additional copy step):
Fill in the ListInitialization bit when creating a CXXConstructExpr. Use it
when instantiating initializers in order to correctly handle instantiation of
copy-list-initialization. Teach TreeTransform that function arguments are
initializations, and so need this special treatment too. Finally, remove some
hacks which were working around SubstInitializer's shortcomings.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@170489 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 99366b6..8385e85 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1932,11 +1932,7 @@
}
ExprResult Init = InitExpr;
- if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent() &&
- !FD->getDeclContext()->isDependentContext()) {
- // Note: We don't type-check when we're in a dependent context, because
- // the initialization-substitution code does not properly handle direct
- // list initialization. We have the same hackaround for ctor-initializers.
+ if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) {
if (isa<InitListExpr>(InitExpr) && isStdInitializerList(FD->getType(), 0)) {
Diag(FD->getLocation(), diag::warn_dangling_std_initializer_list)
<< /*at end of ctor*/1 << InitExpr->getSourceRange();
@@ -2318,10 +2314,13 @@
if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) {
Args = ParenList->getExprs();
NumArgs = ParenList->getNumExprs();
- } else {
- InitListExpr *InitList = cast<InitListExpr>(Init);
+ } else if (InitListExpr *InitList = dyn_cast<InitListExpr>(Init)) {
Args = InitList->getInits();
NumArgs = InitList->getNumInits();
+ } else {
+ // Template instantiation doesn't reconstruct ParenListExprs for us.
+ Args = &Init;
+ NumArgs = 1;
}
if (getDiagnostics().getDiagnosticLevel(diag::warn_field_is_uninit, IdLoc)
@@ -2382,19 +2381,8 @@
if (MemberInit.isInvalid())
return true;
- // If we are in a dependent context, template instantiation will
- // perform this type-checking again. Just save the arguments that we
- // received.
- // FIXME: This isn't quite ideal, since our ASTs don't capture all
- // of the information that we have about the member
- // initializer. However, deconstructing the ASTs is a dicey process,
- // and this approach is far more likely to get the corner cases right.
- if (CurContext->isDependentContext()) {
- // The existing Init will do fine.
- } else {
- Init = MemberInit.get();
- CheckForDanglingReferenceOrPointer(*this, Member, Init, IdLoc);
- }
+ Init = MemberInit.get();
+ CheckForDanglingReferenceOrPointer(*this, Member, Init, IdLoc);
}
if (DirectMember) {
@@ -9515,6 +9503,7 @@
CXXConstructorDecl *Constructor,
MultiExprArg ExprArgs,
bool HadMultipleCandidates,
+ bool IsListInitialization,
bool RequiresZeroInit,
unsigned ConstructKind,
SourceRange ParenRange) {
@@ -9538,7 +9527,8 @@
return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
Elidable, ExprArgs, HadMultipleCandidates,
- RequiresZeroInit, ConstructKind, ParenRange);
+ IsListInitialization, RequiresZeroInit,
+ ConstructKind, ParenRange);
}
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
@@ -9548,39 +9538,19 @@
CXXConstructorDecl *Constructor, bool Elidable,
MultiExprArg ExprArgs,
bool HadMultipleCandidates,
+ bool IsListInitialization,
bool RequiresZeroInit,
unsigned ConstructKind,
SourceRange ParenRange) {
MarkFunctionReferenced(ConstructLoc, Constructor);
return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc,
Constructor, Elidable, ExprArgs,
- HadMultipleCandidates, /*FIXME*/false,
- RequiresZeroInit,
+ HadMultipleCandidates,
+ IsListInitialization, RequiresZeroInit,
static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind),
ParenRange));
}
-bool Sema::InitializeVarWithConstructor(VarDecl *VD,
- CXXConstructorDecl *Constructor,
- MultiExprArg Exprs,
- bool HadMultipleCandidates) {
- // FIXME: Provide the correct paren SourceRange when available.
- ExprResult TempResult =
- BuildCXXConstructExpr(VD->getLocation(), VD->getType(), Constructor,
- Exprs, HadMultipleCandidates, false,
- CXXConstructExpr::CK_Complete, SourceRange());
- if (TempResult.isInvalid())
- return true;
-
- Expr *Temp = TempResult.takeAs<Expr>();
- CheckImplicitConversions(Temp, VD->getLocation());
- MarkFunctionReferenced(VD->getLocation(), Constructor);
- Temp = MaybeCreateExprWithCleanups(Temp);
- VD->setInit(Temp);
-
- return false;
-}
-
void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) {
if (VD->isInvalidDecl()) return;
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 4a93b11..629c9b2 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -2323,11 +2323,11 @@
S.CheckConstructorAccess(CastLoc, Constructor,
InitializedEntity::InitializeTemporary(Ty),
Constructor->getAccess());
-
+
ExprResult Result
= S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method),
- ConstructorArgs,
- HadMultipleCandidates, /*ZeroInit*/ false,
+ ConstructorArgs, HadMultipleCandidates,
+ /*ListInit*/ false, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete, SourceRange());
if (Result.isInvalid())
return ExprError();
@@ -2479,14 +2479,14 @@
ToType, SCS.CopyConstructor,
ConstructorArgs,
/*HadMultipleCandidates*/ false,
- /*ZeroInit*/ false,
+ /*ListInit*/ false, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
}
return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(),
ToType, SCS.CopyConstructor,
From, /*HadMultipleCandidates*/ false,
- /*ZeroInit*/ false,
+ /*ListInit*/ false, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
}
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index a5a0a11..a40bf9f 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -4563,6 +4563,7 @@
CurInit = S.BuildCXXConstructExpr(Loc, T, Constructor, Elidable,
ConstructorArgs,
HadMultipleCandidates,
+ /*ListInit*/ false,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
@@ -4652,7 +4653,8 @@
const InitializationKind &Kind,
MultiExprArg Args,
const InitializationSequence::Step& Step,
- bool &ConstructorInitRequiresZeroInit) {
+ bool &ConstructorInitRequiresZeroInit,
+ bool IsListInitialization) {
unsigned NumArgs = Args.size();
CXXConstructorDecl *Constructor
= cast<CXXConstructorDecl>(Step.Function.Function);
@@ -4710,13 +4712,12 @@
if (Kind.getKind() != InitializationKind::IK_DirectList)
ParenRange = Kind.getParenRange();
- CurInit = S.Owned(new (S.Context) CXXTemporaryObjectExpr(S.Context,
- Constructor,
- TSInfo,
- ConstructorArgs,
- ParenRange,
- HadMultipleCandidates,
- ConstructorInitRequiresZeroInit));
+ CurInit = S.Owned(
+ new (S.Context) CXXTemporaryObjectExpr(S.Context, Constructor,
+ TSInfo, ConstructorArgs,
+ ParenRange, IsListInitialization,
+ HadMultipleCandidates,
+ ConstructorInitRequiresZeroInit));
} else {
CXXConstructExpr::ConstructionKind ConstructKind =
CXXConstructExpr::CK_Complete;
@@ -4741,6 +4742,7 @@
Constructor, /*Elidable=*/true,
ConstructorArgs,
HadMultipleCandidates,
+ IsListInitialization,
ConstructorInitRequiresZeroInit,
ConstructKind,
parenRange);
@@ -4749,6 +4751,7 @@
Constructor,
ConstructorArgs,
HadMultipleCandidates,
+ IsListInitialization,
ConstructorInitRequiresZeroInit,
ConstructKind,
parenRange);
@@ -5084,6 +5087,7 @@
CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor,
ConstructorArgs,
HadMultipleCandidates,
+ /*ListInit*/ false,
/*ZeroInit*/ false,
CXXConstructExpr::CK_Complete,
SourceRange());
@@ -5239,7 +5243,8 @@
CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity :
Entity,
Kind, Arg, *Step,
- ConstructorInitRequiresZeroInit);
+ ConstructorInitRequiresZeroInit,
+ /*IsListInitialization*/ true);
break;
}
@@ -5272,7 +5277,8 @@
CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity
: Entity,
Kind, Args, *Step,
- ConstructorInitRequiresZeroInit);
+ ConstructorInitRequiresZeroInit,
+ /*IsListInitialization*/ false);
break;
}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 5ad7b34..6d0aa21 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2582,12 +2582,21 @@
return Instantiator.TransformExpr(E);
}
+ExprResult Sema::SubstInitializer(Expr *Init,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ bool CXXDirectInit) {
+ TemplateInstantiator Instantiator(*this, TemplateArgs,
+ SourceLocation(),
+ DeclarationName());
+ return Instantiator.TransformInitializer(Init, CXXDirectInit);
+}
+
bool Sema::SubstExprs(Expr **Exprs, unsigned NumExprs, bool IsCall,
const MultiLevelTemplateArgumentList &TemplateArgs,
SmallVectorImpl<Expr *> &Outputs) {
if (NumExprs == 0)
return false;
-
+
TemplateInstantiator Instantiator(*this, TemplateArgs,
SourceLocation(),
DeclarationName());
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index cca7df3..abe0471 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3138,45 +3138,6 @@
AnyErrors);
}
-ExprResult Sema::SubstInitializer(Expr *Init,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- bool CXXDirectInit) {
- // Initializers are instantiated like expressions, except that various outer
- // layers are stripped.
- if (!Init)
- return Owned(Init);
-
- if (ExprWithCleanups *ExprTemp = dyn_cast<ExprWithCleanups>(Init))
- Init = ExprTemp->getSubExpr();
-
- while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(Init))
- Init = Binder->getSubExpr();
-
- if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Init))
- Init = ICE->getSubExprAsWritten();
-
- // If this is a direct-initializer, we take apart CXXConstructExprs.
- // Everything else is passed through.
- CXXConstructExpr *Construct;
- if (!CXXDirectInit || !(Construct = dyn_cast<CXXConstructExpr>(Init)) ||
- isa<CXXTemporaryObjectExpr>(Construct))
- return SubstExpr(Init, TemplateArgs);
-
- SmallVector<Expr*, 8> NewArgs;
- if (SubstExprs(Construct->getArgs(), Construct->getNumArgs(), true,
- TemplateArgs, NewArgs))
- return ExprError();
-
- // Treat an empty initializer like none.
- if (NewArgs.empty())
- return Owned((Expr*)0);
-
- // Build a ParenListExpr to represent anything else.
- // FIXME: Fake locations!
- SourceLocation Loc = PP.getLocForEndOfToken(Init->getLocStart());
- return ActOnParenListExpr(Loc, Loc, NewArgs);
-}
-
// TODO: this could be templated if the various decl types used the
// same method name.
static bool isInstantiationOf(ClassTemplateDecl *Pattern,
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 8d66acb..52f6c4d 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -323,6 +323,15 @@
/// \returns the transformed expression.
ExprResult TransformExpr(Expr *E);
+ /// \brief Transform the given initializer.
+ ///
+ /// By default, this routine transforms an initializer by stripping off the
+ /// semantic nodes added by initialization, then passing the result to
+ /// TransformExpr or TransformExprs.
+ ///
+ /// \returns the transformed initializer.
+ ExprResult TransformInitializer(Expr *Init, bool CXXDirectInit);
+
/// \brief Transform the given list of expressions.
///
/// This routine transforms a list of expressions by invoking
@@ -2113,6 +2122,7 @@
bool IsElidable,
MultiExprArg Args,
bool HadMultipleCandidates,
+ bool ListInitialization,
bool RequiresZeroInit,
CXXConstructExpr::ConstructionKind ConstructKind,
SourceRange ParenRange) {
@@ -2124,6 +2134,7 @@
return getSema().BuildCXXConstructExpr(Loc, T, Constructor, IsElidable,
ConvertedArgs,
HadMultipleCandidates,
+ ListInitialization,
RequiresZeroInit, ConstructKind,
ParenRange);
}
@@ -2575,6 +2586,53 @@
}
template<typename Derived>
+ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
+ bool CXXDirectInit) {
+ // Initializers are instantiated like expressions, except that various outer
+ // layers are stripped.
+ if (!Init)
+ return SemaRef.Owned(Init);
+
+ if (ExprWithCleanups *ExprTemp = dyn_cast<ExprWithCleanups>(Init))
+ Init = ExprTemp->getSubExpr();
+
+ while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(Init))
+ Init = Binder->getSubExpr();
+
+ if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Init))
+ Init = ICE->getSubExprAsWritten();
+
+ // If this is a direct-initializer, we take apart CXXConstructExprs.
+ // Everything else is passed through.
+ CXXConstructExpr *Construct;
+ if (!(Construct = dyn_cast<CXXConstructExpr>(Init)) ||
+ isa<CXXTemporaryObjectExpr>(Construct) ||
+ (!CXXDirectInit && !Construct->isListInitialization()))
+ return getDerived().TransformExpr(Init);
+
+ SmallVector<Expr*, 8> NewArgs;
+ bool ArgChanged = false;
+ if (getDerived().TransformExprs(Construct->getArgs(), Construct->getNumArgs(),
+ /*IsCall*/true, NewArgs, &ArgChanged))
+ return ExprError();
+
+ // If this was list initialization, revert to list form.
+ if (Construct->isListInitialization())
+ return getDerived().RebuildInitList(Construct->getLocStart(), NewArgs,
+ Construct->getLocEnd(),
+ Construct->getType());
+
+ // Treat an empty initializer like none.
+ if (NewArgs.empty())
+ return SemaRef.Owned((Expr*)0);
+
+ // Build a ParenListExpr to represent anything else.
+ SourceRange Parens = Construct->getParenRange();
+ return getDerived().RebuildParenListExpr(Parens.getBegin(), NewArgs,
+ Parens.getEnd());
+}
+
+template<typename Derived>
bool TreeTransform<Derived>::TransformExprs(Expr **Inputs,
unsigned NumInputs,
bool IsCall,
@@ -2656,7 +2714,9 @@
continue;
}
- ExprResult Result = getDerived().TransformExpr(Inputs[I]);
+ ExprResult Result =
+ IsCall ? getDerived().TransformInitializer(Inputs[I], /*DirectInit*/false)
+ : getDerived().TransformExpr(Inputs[I]);
if (Result.isInvalid())
return true;
@@ -7747,11 +7807,13 @@
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
- // CXXConstructExprs are always implicit, so when we have a
- // 1-argument construction we just transform that argument.
+ // CXXConstructExprs other than for list-initialization and
+ // CXXTemporaryObjectExpr are always implicit, so when we have
+ // a 1-argument construction we just transform that argument.
if ((E->getNumArgs() == 1 ||
(E->getNumArgs() > 1 && getDerived().DropCallArgument(E->getArg(1)))) &&
- (!getDerived().DropCallArgument(E->getArg(0))))
+ (!getDerived().DropCallArgument(E->getArg(0))) &&
+ !E->isListInitialization())
return getDerived().TransformExpr(E->getArg(0));
TemporaryBase Rebase(*this, /*FIXME*/E->getLocStart(), DeclarationName());
@@ -7787,6 +7849,7 @@
Constructor, E->isElidable(),
Args,
E->hadMultipleCandidates(),
+ E->isListInitialization(),
E->requiresZeroInitialization(),
E->getConstructionKind(),
E->getParenRange());
@@ -7844,6 +7907,7 @@
return SemaRef.MaybeBindToTemporary(E);
}
+ // FIXME: Pass in E->isListInitialization().
return getDerived().RebuildCXXTemporaryObjectExpr(T,
/*FIXME:*/T->getTypeLoc().getEndLoc(),
Args,