summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/TreeTransform.h
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/TreeTransform.h')
-rw-r--r--clang/lib/Sema/TreeTransform.h143
1 files changed, 100 insertions, 43 deletions
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index f8b9b34ae7f..c653fb1d6e2 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -450,8 +450,10 @@ public:
/// TransformDefinition. However, in some cases (e.g., lambda expressions),
/// the transformer itself has to transform the declarations. This routine
/// can be overridden by a subclass that keeps track of such mappings.
- void transformedLocalDecl(Decl *Old, Decl *New) {
- TransformedLocalDecls[Old] = New;
+ void transformedLocalDecl(Decl *Old, ArrayRef<Decl *> New) {
+ assert(New.size() == 1 &&
+ "must override transformedLocalDecl if performing pack expansion");
+ TransformedLocalDecls[Old] = New.front();
}
/// Transform the definition of the given declaration.
@@ -7122,7 +7124,7 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) {
auto *Promise = SemaRef.buildCoroutinePromise(FD->getLocation());
if (!Promise)
return StmtError();
- getDerived().transformedLocalDecl(S->getPromiseDecl(), Promise);
+ getDerived().transformedLocalDecl(S->getPromiseDecl(), {Promise});
ScopeInfo->CoroutinePromise = Promise;
// Transform the implicit coroutine statements we built during the initial
@@ -11176,33 +11178,80 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
// Transform any init-capture expressions before entering the scope of the
// lambda body, because they are not semantically within that scope.
typedef std::pair<ExprResult, QualType> InitCaptureInfoTy;
- SmallVector<InitCaptureInfoTy, 8> InitCaptureExprsAndTypes;
- InitCaptureExprsAndTypes.resize(E->explicit_capture_end() -
- E->explicit_capture_begin());
+ struct TransformedInitCapture {
+ // The location of the ... if the result is retaining a pack expansion.
+ SourceLocation EllipsisLoc;
+ // Zero or more expansions of the init-capture.
+ SmallVector<InitCaptureInfoTy, 4> Expansions;
+ };
+ SmallVector<TransformedInitCapture, 4> InitCaptures;
+ InitCaptures.resize(E->explicit_capture_end() - E->explicit_capture_begin());
for (LambdaExpr::capture_iterator C = E->capture_begin(),
CEnd = E->capture_end();
C != CEnd; ++C) {
if (!E->isInitCapture(C))
continue;
- EnterExpressionEvaluationContext EEEC(
- getSema(), Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
- ExprResult NewExprInitResult = getDerived().TransformInitializer(
- C->getCapturedVar()->getInit(),
- C->getCapturedVar()->getInitStyle() == VarDecl::CallInit);
-
- if (NewExprInitResult.isInvalid())
- return ExprError();
- Expr *NewExprInit = NewExprInitResult.get();
+ TransformedInitCapture &Result = InitCaptures[C - E->capture_begin()];
VarDecl *OldVD = C->getCapturedVar();
- QualType NewInitCaptureType =
- getSema().buildLambdaInitCaptureInitialization(
- C->getLocation(), OldVD->getType()->isReferenceType(),
- OldVD->getIdentifier(),
- C->getCapturedVar()->getInitStyle() != VarDecl::CInit, NewExprInit);
- NewExprInitResult = NewExprInit;
- InitCaptureExprsAndTypes[C - E->capture_begin()] =
- std::make_pair(NewExprInitResult, NewInitCaptureType);
+
+ auto SubstInitCapture = [&](SourceLocation EllipsisLoc,
+ Optional<unsigned> NumExpansions) {
+ EnterExpressionEvaluationContext EEEC(
+ getSema(), Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
+ ExprResult NewExprInitResult = getDerived().TransformInitializer(
+ OldVD->getInit(), OldVD->getInitStyle() == VarDecl::CallInit);
+
+ if (NewExprInitResult.isInvalid()) {
+ Result.Expansions.push_back(InitCaptureInfoTy(ExprError(), QualType()));
+ return;
+ }
+ Expr *NewExprInit = NewExprInitResult.get();
+
+ QualType NewInitCaptureType =
+ getSema().buildLambdaInitCaptureInitialization(
+ C->getLocation(), OldVD->getType()->isReferenceType(),
+ EllipsisLoc, NumExpansions, OldVD->getIdentifier(),
+ C->getCapturedVar()->getInitStyle() != VarDecl::CInit,
+ NewExprInit);
+ Result.Expansions.push_back(
+ InitCaptureInfoTy(NewExprInit, NewInitCaptureType));
+ };
+
+ // If this is an init-capture pack, consider expanding the pack now.
+ if (OldVD->isParameterPack()) {
+ PackExpansionTypeLoc ExpansionTL = OldVD->getTypeSourceInfo()
+ ->getTypeLoc()
+ .castAs<PackExpansionTypeLoc>();
+ SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+ SemaRef.collectUnexpandedParameterPacks(OldVD->getInit(), Unexpanded);
+
+ // Determine whether the set of unexpanded parameter packs can and should
+ // be expanded.
+ bool Expand = true;
+ bool RetainExpansion = false;
+ Optional<unsigned> OrigNumExpansions =
+ ExpansionTL.getTypePtr()->getNumExpansions();
+ Optional<unsigned> NumExpansions = OrigNumExpansions;
+ if (getDerived().TryExpandParameterPacks(
+ ExpansionTL.getEllipsisLoc(),
+ OldVD->getInit()->getSourceRange(), Unexpanded, Expand,
+ RetainExpansion, NumExpansions))
+ return ExprError();
+ if (Expand) {
+ for (unsigned I = 0; I != *NumExpansions; ++I) {
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
+ SubstInitCapture(SourceLocation(), None);
+ }
+ }
+ if (!Expand || RetainExpansion) {
+ ForgetPartiallySubstitutedPackRAII Forget(getDerived());
+ SubstInitCapture(ExpansionTL.getEllipsisLoc(), NumExpansions);
+ Result.EllipsisLoc = ExpansionTL.getEllipsisLoc();
+ }
+ } else {
+ SubstInitCapture(SourceLocation(), None);
+ }
}
// Transform the template parameters, and add them to the current
@@ -11245,7 +11294,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
NewCallOpTSI,
/*KnownDependent=*/false,
E->getCaptureDefault());
- getDerived().transformedLocalDecl(E->getLambdaClass(), Class);
+ getDerived().transformedLocalDecl(E->getLambdaClass(), {Class});
// Build the call operator.
CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition(
@@ -11270,7 +11319,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
}
getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
- getDerived().transformedLocalDecl(E->getCallOperator(), NewCallOperator);
+ getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator});
// Introduce the context of the call operator.
Sema::ContextRAII SavedContext(getSema(), NewCallOperator,
@@ -11313,24 +11362,33 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
// Rebuild init-captures, including the implied field declaration.
if (E->isInitCapture(C)) {
- InitCaptureInfoTy InitExprTypePair =
- InitCaptureExprsAndTypes[C - E->capture_begin()];
- ExprResult Init = InitExprTypePair.first;
- QualType InitQualType = InitExprTypePair.second;
- if (Init.isInvalid() || InitQualType.isNull()) {
- Invalid = true;
- continue;
- }
+ TransformedInitCapture &NewC = InitCaptures[C - E->capture_begin()];
+
VarDecl *OldVD = C->getCapturedVar();
- VarDecl *NewVD = getSema().createLambdaInitCaptureVarDecl(
- OldVD->getLocation(), InitExprTypePair.second, OldVD->getIdentifier(),
- OldVD->getInitStyle(), Init.get());
- if (!NewVD)
- Invalid = true;
- else {
- getDerived().transformedLocalDecl(OldVD, NewVD);
+ llvm::SmallVector<Decl*, 4> NewVDs;
+
+ for (InitCaptureInfoTy &Info : NewC.Expansions) {
+ ExprResult Init = Info.first;
+ QualType InitQualType = Info.second;
+ if (Init.isInvalid() || InitQualType.isNull()) {
+ Invalid = true;
+ break;
+ }
+ VarDecl *NewVD = getSema().createLambdaInitCaptureVarDecl(
+ OldVD->getLocation(), InitQualType, NewC.EllipsisLoc,
+ OldVD->getIdentifier(), OldVD->getInitStyle(), Init.get());
+ if (!NewVD) {
+ Invalid = true;
+ break;
+ }
+ NewVDs.push_back(NewVD);
+ getSema().buildInitCaptureField(LSI, NewVD);
}
- getSema().buildInitCaptureField(LSI, NewVD);
+
+ if (Invalid)
+ break;
+
+ getDerived().transformedLocalDecl(OldVD, NewVDs);
continue;
}
@@ -12471,8 +12529,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
VarDecl *oldCapture = I.getVariable();
// Ignore parameter packs.
- if (isa<ParmVarDecl>(oldCapture) &&
- cast<ParmVarDecl>(oldCapture)->isParameterPack())
+ if (oldCapture->isParameterPack())
continue;
VarDecl *newCapture =
OpenPOWER on IntegriCloud