diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-21 20:10:50 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2019-05-21 20:10:50 +0000 |
commit | b2997f579a8b6552a49eab97e33c437b9251eb0a (patch) | |
tree | 73c1636810d5a9a7b8d5e9af36cd2c6ab0182eac /clang/lib/Sema | |
parent | 6e19543a2a2013bd357eb15e383b435cd0cbb810 (diff) | |
download | bcm5719-llvm-b2997f579a8b6552a49eab97e33c437b9251eb0a.tar.gz bcm5719-llvm-b2997f579a8b6552a49eab97e33c437b9251eb0a.zip |
[c++20] P0780R2: Support pack-expansion of init-captures.
This permits an init-capture to introduce a new pack:
template<typename ...T> auto x = [...a = T()] { /* a is a pack */ };
To support this, the mechanism for allowing ParmVarDecls to be packs has
been extended to support arbitrary local VarDecls.
llvm-svn: 361300
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/SemaLambda.cpp | 42 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateDeduction.cpp | 33 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 56 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateVariadic.cpp | 38 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 143 |
5 files changed, 210 insertions, 102 deletions
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 1966e9e0803..b2055dd650e 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -753,11 +753,10 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) { } } -QualType Sema::buildLambdaInitCaptureInitialization(SourceLocation Loc, - bool ByRef, - IdentifierInfo *Id, - bool IsDirectInit, - Expr *&Init) { +QualType Sema::buildLambdaInitCaptureInitialization( + SourceLocation Loc, bool ByRef, SourceLocation EllipsisLoc, + Optional<unsigned> NumExpansions, IdentifierInfo *Id, bool IsDirectInit, + Expr *&Init) { // Create an 'auto' or 'auto&' TypeSourceInfo that we can use to // deduce against. QualType DeductType = Context.getAutoDeductType(); @@ -768,6 +767,18 @@ QualType Sema::buildLambdaInitCaptureInitialization(SourceLocation Loc, assert(!DeductType.isNull() && "can't build reference to auto"); TLB.push<ReferenceTypeLoc>(DeductType).setSigilLoc(Loc); } + if (EllipsisLoc.isValid()) { + if (Init->containsUnexpandedParameterPack()) { + Diag(EllipsisLoc, getLangOpts().CPlusPlus2a + ? diag::warn_cxx17_compat_init_capture_pack + : diag::ext_init_capture_pack); + DeductType = Context.getPackExpansionType(DeductType, NumExpansions); + TLB.push<PackExpansionTypeLoc>(DeductType).setEllipsisLoc(EllipsisLoc); + } else { + // Just ignore the ellipsis for now and form a non-pack variable. We'll + // diagnose this later when we try to capture it. + } + } TypeSourceInfo *TSI = TLB.getTypeSourceInfo(Context, DeductType); // Deduce the type of the init capture. @@ -808,10 +819,15 @@ QualType Sema::buildLambdaInitCaptureInitialization(SourceLocation Loc, VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc, QualType InitCaptureType, + SourceLocation EllipsisLoc, IdentifierInfo *Id, unsigned InitStyle, Expr *Init) { - TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(InitCaptureType, - Loc); + // FIXME: Retain the TypeSourceInfo from buildLambdaInitCaptureInitialization + // rather than reconstructing it here. + TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(InitCaptureType, Loc); + if (auto PETL = TSI->getTypeLoc().getAs<PackExpansionTypeLoc>()) + PETL.setEllipsisLoc(EllipsisLoc); + // Create a dummy variable representing the init-capture. This is not actually // used as a variable, and only exists as a way to name and refer to the // init-capture. @@ -1036,8 +1052,6 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, ? diag::warn_cxx11_compat_init_capture : diag::ext_init_capture); - if (C->Init.get()->containsUnexpandedParameterPack()) - ContainsUnexpandedParameterPack = true; // If the initializer expression is usable, but the InitCaptureType // is not, then an error has occurred - so ignore the capture for now. // for e.g., [n{0}] { }; <-- if no <initializer_list> is included. @@ -1046,6 +1060,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, if (C->InitCaptureType.get().isNull()) continue; + if (C->Init.get()->containsUnexpandedParameterPack() && + !C->InitCaptureType.get()->getAs<PackExpansionType>()) + ContainsUnexpandedParameterPack = true; + unsigned InitStyle; switch (C->InitKind) { case LambdaCaptureInitKind::NoInit: @@ -1061,7 +1079,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, break; } Var = createLambdaInitCaptureVarDecl(C->Loc, C->InitCaptureType.get(), - C->Id, InitStyle, C->Init.get()); + C->EllipsisLoc, C->Id, InitStyle, + C->Init.get()); // C++1y [expr.prim.lambda]p11: // An init-capture behaves as if it declares and explicitly // captures a variable [...] whose declarative region is the @@ -1153,7 +1172,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, EllipsisLoc = C->EllipsisLoc; } else { Diag(C->EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) - << SourceRange(C->Loc); + << (C->Init.isUsable() ? C->Init.get()->getSourceRange() + : SourceRange(C->Loc)); // Just ignore the ellipsis. } diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 4dccf2f459c..263bc3104ef 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -4280,19 +4280,26 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( } namespace { + struct DependentAuto { bool IsPack; }; /// Substitute the 'auto' specifier or deduced template specialization type /// specifier within a type for a given replacement type. class SubstituteDeducedTypeTransform : public TreeTransform<SubstituteDeducedTypeTransform> { QualType Replacement; + bool ReplacementIsPack; bool UseTypeSugar; public: + SubstituteDeducedTypeTransform(Sema &SemaRef, DependentAuto DA) + : TreeTransform<SubstituteDeducedTypeTransform>(SemaRef), Replacement(), + ReplacementIsPack(DA.IsPack), UseTypeSugar(true) {} + SubstituteDeducedTypeTransform(Sema &SemaRef, QualType Replacement, - bool UseTypeSugar = true) + bool UseTypeSugar = true) : TreeTransform<SubstituteDeducedTypeTransform>(SemaRef), - Replacement(Replacement), UseTypeSugar(UseTypeSugar) {} + Replacement(Replacement), ReplacementIsPack(false), + UseTypeSugar(UseTypeSugar) {} QualType TransformDesugared(TypeLocBuilder &TLB, DeducedTypeLoc TL) { assert(isa<TemplateTypeParmType>(Replacement) && @@ -4317,7 +4324,8 @@ namespace { return TransformDesugared(TLB, TL); QualType Result = SemaRef.Context.getAutoType( - Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull()); + Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull(), + ReplacementIsPack); auto NewTL = TLB.push<AutoTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; @@ -4408,9 +4416,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, Init = NonPlaceholder.get(); } + DependentAuto DependentResult = { + /*.IsPack = */ (bool)Type.getAs<PackExpansionTypeLoc>()}; + if (!DependentDeductionDepth && (Type.getType()->isDependentType() || Init->isTypeDependent())) { - Result = SubstituteDeducedTypeTransform(*this, QualType()).Apply(Type); + Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type); assert(!Result.isNull() && "substituting DependentTy can't fail"); return DAR_Succeeded; } @@ -4478,7 +4489,8 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, auto DeductionFailed = [&](TemplateDeductionResult TDK, ArrayRef<SourceRange> Ranges) -> DeduceAutoResult { if (Init->isTypeDependent()) { - Result = SubstituteDeducedTypeTransform(*this, QualType()).Apply(Type); + Result = + SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type); assert(!Result.isNull() && "substituting DependentTy can't fail"); return DAR_Succeeded; } @@ -4559,7 +4571,10 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, QualType Sema::SubstAutoType(QualType TypeWithAuto, QualType TypeToReplaceAuto) { if (TypeToReplaceAuto->isDependentType()) - TypeToReplaceAuto = QualType(); + return SubstituteDeducedTypeTransform( + *this, DependentAuto{ + TypeToReplaceAuto->containsUnexpandedParameterPack()}) + .TransformType(TypeWithAuto); return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto) .TransformType(TypeWithAuto); } @@ -4567,7 +4582,11 @@ QualType Sema::SubstAutoType(QualType TypeWithAuto, TypeSourceInfo *Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType TypeToReplaceAuto) { if (TypeToReplaceAuto->isDependentType()) - TypeToReplaceAuto = QualType(); + return SubstituteDeducedTypeTransform( + *this, + DependentAuto{ + TypeToReplaceAuto->containsUnexpandedParameterPack()}) + .TransformType(TypeWithAuto); return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto) .TransformType(TypeWithAuto); } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 55d1d94bd82..ba54d5010ba 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -819,7 +819,19 @@ namespace { SemaRef.InstantiateAttrs(TemplateArgs, Old, New); } - void transformedLocalDecl(Decl *Old, Decl *New) { + void transformedLocalDecl(Decl *Old, ArrayRef<Decl *> NewDecls) { + if (Old->isParameterPack()) { + SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Old); + for (auto *New : NewDecls) + SemaRef.CurrentInstantiationScope->InstantiatedLocalPackArg( + Old, cast<VarDecl>(New)); + return; + } + + assert(NewDecls.size() == 1 && + "should only have multiple expansions for a pack"); + Decl *New = NewDecls.front(); + // If we've instantiated the call operator of a lambda or the call // operator template of a generic lambda, update the "instantiation of" // information. @@ -888,12 +900,11 @@ namespace { ExprResult TransformSubstNonTypeTemplateParmPackExpr( SubstNonTypeTemplateParmPackExpr *E); - /// Rebuild a DeclRefExpr for a ParmVarDecl reference. - ExprResult RebuildParmVarDeclRefExpr(ParmVarDecl *PD, SourceLocation Loc); + /// Rebuild a DeclRefExpr for a VarDecl reference. + ExprResult RebuildVarDeclRefExpr(VarDecl *PD, SourceLocation Loc); - /// Transform a reference to a function parameter pack. - ExprResult TransformFunctionParmPackRefExpr(DeclRefExpr *E, - ParmVarDecl *PD); + /// Transform a reference to a function or init-capture parameter pack. + ExprResult TransformFunctionParmPackRefExpr(DeclRefExpr *E, VarDecl *PD); /// Transform a FunctionParmPackExpr which was built when we couldn't /// expand a function parameter pack reference which refers to an expanded @@ -1324,9 +1335,8 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr( Arg); } -ExprResult -TemplateInstantiator::RebuildParmVarDeclRefExpr(ParmVarDecl *PD, - SourceLocation Loc) { +ExprResult TemplateInstantiator::RebuildVarDeclRefExpr(VarDecl *PD, + SourceLocation Loc) { DeclarationNameInfo NameInfo(PD->getDeclName(), Loc); return getSema().BuildDeclarationNameExpr(CXXScopeSpec(), NameInfo, PD); } @@ -1335,11 +1345,11 @@ ExprResult TemplateInstantiator::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) { if (getSema().ArgumentPackSubstitutionIndex != -1) { // We can expand this parameter pack now. - ParmVarDecl *D = E->getExpansion(getSema().ArgumentPackSubstitutionIndex); - ValueDecl *VD = cast_or_null<ValueDecl>(TransformDecl(E->getExprLoc(), D)); + VarDecl *D = E->getExpansion(getSema().ArgumentPackSubstitutionIndex); + VarDecl *VD = cast_or_null<VarDecl>(TransformDecl(E->getExprLoc(), D)); if (!VD) return ExprError(); - return RebuildParmVarDeclRefExpr(cast<ParmVarDecl>(VD), E->getExprLoc()); + return RebuildVarDeclRefExpr(VD, E->getExprLoc()); } QualType T = TransformType(E->getType()); @@ -1348,25 +1358,24 @@ TemplateInstantiator::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) { // Transform each of the parameter expansions into the corresponding // parameters in the instantiation of the function decl. - SmallVector<ParmVarDecl *, 8> Parms; - Parms.reserve(E->getNumExpansions()); + SmallVector<VarDecl *, 8> Vars; + Vars.reserve(E->getNumExpansions()); for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end(); I != End; ++I) { - ParmVarDecl *D = - cast_or_null<ParmVarDecl>(TransformDecl(E->getExprLoc(), *I)); + VarDecl *D = cast_or_null<VarDecl>(TransformDecl(E->getExprLoc(), *I)); if (!D) return ExprError(); - Parms.push_back(D); + Vars.push_back(D); } return FunctionParmPackExpr::Create(getSema().Context, T, E->getParameterPack(), - E->getParameterPackLocation(), Parms); + E->getParameterPackLocation(), Vars); } ExprResult TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E, - ParmVarDecl *PD) { + VarDecl *PD) { typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found = getSema().CurrentInstantiationScope->findInstantiationOf(PD); @@ -1390,8 +1399,7 @@ TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E, } // We have either an unexpanded pack or a specific expansion. - return RebuildParmVarDeclRefExpr(cast<ParmVarDecl>(TransformedDecl), - E->getExprLoc()); + return RebuildVarDeclRefExpr(cast<VarDecl>(TransformedDecl), E->getExprLoc()); } ExprResult @@ -1409,7 +1417,7 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { } // Handle references to function parameter packs. - if (ParmVarDecl *PD = dyn_cast<ParmVarDecl>(D)) + if (VarDecl *PD = dyn_cast<VarDecl>(D)) if (PD->isParameterPack()) return TransformFunctionParmPackRefExpr(E, PD); @@ -2984,14 +2992,14 @@ void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) { #endif Stored = Inst; } else if (DeclArgumentPack *Pack = Stored.dyn_cast<DeclArgumentPack *>()) { - Pack->push_back(cast<ParmVarDecl>(Inst)); + Pack->push_back(cast<VarDecl>(Inst)); } else { assert(Stored.get<Decl *>() == Inst && "Already instantiated this local"); } } void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D, - ParmVarDecl *Inst) { + VarDecl *Inst) { D = getCanonicalParmVarDecl(D); DeclArgumentPack *Pack = LocalDecls[D].get<DeclArgumentPack *>(); Pack->push_back(Inst); diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 8773f45c30a..9b23624a9a8 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -39,11 +39,11 @@ namespace { unsigned DepthLimit = (unsigned)-1; void addUnexpanded(NamedDecl *ND, SourceLocation Loc = SourceLocation()) { - if (auto *PVD = dyn_cast<ParmVarDecl>(ND)) { + if (auto *VD = dyn_cast<VarDecl>(ND)) { // For now, the only problematic case is a generic lambda's templated // call operator, so we don't need to look for all the other ways we // could have reached a dependent parameter pack. - auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext()); + auto *FD = dyn_cast<FunctionDecl>(VD->getDeclContext()); auto *FTD = FD ? FD->getDescribedFunctionTemplate() : nullptr; if (FTD && FTD->getTemplateParameters()->getDepth() >= DepthLimit) return; @@ -313,11 +313,11 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Func)) { if (N == FunctionScopes.size()) { - for (auto &Param : Unexpanded) { - auto *PD = dyn_cast_or_null<ParmVarDecl>( - Param.first.dyn_cast<NamedDecl *>()); - if (PD && PD->getDeclContext() == LSI->CallOperator) - LambdaParamPackReferences.push_back(Param); + for (auto &Pack : Unexpanded) { + auto *VD = dyn_cast_or_null<VarDecl>( + Pack.first.dyn_cast<NamedDecl *>()); + if (VD && VD->getDeclContext() == LSI->CallOperator) + LambdaParamPackReferences.push_back(Pack); } } @@ -586,11 +586,15 @@ Sema::CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc, QualType Sema::CheckPackExpansion(QualType Pattern, SourceRange PatternRange, SourceLocation EllipsisLoc, Optional<unsigned> NumExpansions) { - // C++0x [temp.variadic]p5: + // C++11 [temp.variadic]p5: // The pattern of a pack expansion shall name one or more // parameter packs that are not expanded by a nested pack // expansion. - if (!Pattern->containsUnexpandedParameterPack()) { + // + // A pattern containing a deduced type can't occur "naturally" but arises in + // the desugaring of an init-capture pack. + if (!Pattern->containsUnexpandedParameterPack() && + !Pattern->getContainedDeducedType()) { Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) << PatternRange; return QualType(); @@ -641,7 +645,7 @@ bool Sema::CheckParameterPacksForExpansion( // Compute the depth and index for this parameter pack. unsigned Depth = 0, Index = 0; IdentifierInfo *Name; - bool IsFunctionParameterPack = false; + bool IsVarDeclPack = false; if (const TemplateTypeParmType *TTP = i->first.dyn_cast<const TemplateTypeParmType *>()) { @@ -650,8 +654,8 @@ bool Sema::CheckParameterPacksForExpansion( Name = TTP->getIdentifier(); } else { NamedDecl *ND = i->first.get<NamedDecl *>(); - if (isa<ParmVarDecl>(ND)) - IsFunctionParameterPack = true; + if (isa<VarDecl>(ND)) + IsVarDeclPack = true; else std::tie(Depth, Index) = getDepthAndIndex(ND); @@ -660,7 +664,7 @@ bool Sema::CheckParameterPacksForExpansion( // Determine the size of this argument pack. unsigned NewPackSize; - if (IsFunctionParameterPack) { + if (IsVarDeclPack) { // Figure out whether we're instantiating to an argument pack or not. typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; @@ -694,7 +698,7 @@ bool Sema::CheckParameterPacksForExpansion( // Template argument deduction can extend the sequence of template // arguments corresponding to a template parameter pack, even when the // sequence contains explicitly specified template arguments. - if (!IsFunctionParameterPack && CurrentInstantiationScope) { + if (!IsVarDeclPack && CurrentInstantiationScope) { if (NamedDecl *PartialPack = CurrentInstantiationScope->getPartiallySubstitutedPack()){ unsigned PartialDepth, PartialIndex; @@ -778,8 +782,8 @@ Optional<unsigned> Sema::getNumArgumentsInExpansion(QualType T, Index = TTP->getIndex(); } else { NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>(); - if (isa<ParmVarDecl>(ND)) { - // Function parameter pack. + if (isa<VarDecl>(ND)) { + // Function parameter pack or init-capture pack. typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation @@ -1084,7 +1088,7 @@ Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) { dyn_cast<SubstNonTypeTemplateParmPackExpr>(Arg.getAsExpr())) Pack = Subst->getArgumentPack(); else if (auto *Subst = dyn_cast<FunctionParmPackExpr>(Arg.getAsExpr())) { - for (ParmVarDecl *PD : *Subst) + for (VarDecl *PD : *Subst) if (PD->isParameterPack()) return None; return Subst->getNumExpansions(); 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 = |