https://github.com/Sirraide updated https://github.com/llvm/llvm-project/pull/169684
>From 7a310e24ccc08ac7ebf3970d9b862ae822cfc44a Mon Sep 17 00:00:00 2001 From: Sirraide <[email protected]> Date: Wed, 26 Nov 2025 16:18:02 +0100 Subject: [PATCH] [Clang] [C++26] Expansion Statements (Part 5) --- .../clang/Basic/DiagnosticSemaKinds.td | 11 + clang/include/clang/Sema/Sema.h | 11 + clang/lib/Sema/SemaExpand.cpp | 317 +++++++++++++++++- clang/lib/Sema/SemaStmt.cpp | 8 + clang/lib/Sema/TreeTransform.h | 71 ++++ 5 files changed, 404 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 598196cd185a3..6da6d3cf56b35 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -165,6 +165,10 @@ def err_ice_too_large : Error< def err_expr_not_string_literal : Error<"expression is not a string literal">; def note_constexpr_assert_failed : Note< "assertion failed during evaluation of constant expression">; +def err_expansion_size_expr_not_ice : Error< + "expansion statement size is not a constant expression">; +def err_iterating_expansion_stmt_unsupported : Error< + "iterating expansion statements are currently not supported">; // Semantic analysis of constant literals. def ext_predef_outside_function : Warning< @@ -3734,6 +3738,13 @@ def err_conflicting_codeseg_attribute : Error< def warn_duplicate_codeseg_attribute : Warning< "duplicate code segment specifiers">, InGroup<Section>; +def err_expansion_stmt_vla : Error< + "cannot expand variable length array type %0">; +def err_expansion_stmt_incomplete : Error< + "cannot expand expression of incomplete type %0">; +def err_expansion_stmt_lambda : Error< + "cannot expand lambda closure type">; + def err_attribute_patchable_function_entry_invalid_section : Error<"section argument to 'patchable_function_entry' attribute is not " "valid for this target: %0">; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 5a7ac72af5df3..8df017f1f197b 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11210,6 +11210,11 @@ class Sema final : public SemaBase { VarDecl *BuildForRangeVarDecl(SourceLocation Loc, QualType Type, IdentifierInfo *Name, bool Constexpr); + /// Helper used by the expansion statements and for-range code to build + /// a variable declaration for e.g. 'begin' and 'end'. + VarDecl *BuildForRangeVarDecl(SourceLocation Loc, QualType Type, + StringRef Name, bool Constexpr); + /// Build the range variable of a range-based for loop or iterating /// expansion statement and return its DeclStmt. StmtResult BuildCXXForRangeRangeVar(Scope *S, Expr *Range, QualType Type, @@ -15881,6 +15886,12 @@ class Sema final : public SemaBase { SourceLocation ColonLoc, SourceLocation RParenLoc); + StmtResult BuildNonEnumeratingCXXExpansionStmtPattern( + CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVarStmt, + Expr *ExpansionInitializer, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation RParenLoc, + ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps = {}); + ExprResult BuildCXXExpansionSelectExpr(InitListExpr *Range, Expr *Idx); std::optional<uint64_t> diff --git a/clang/lib/Sema/SemaExpand.cpp b/clang/lib/Sema/SemaExpand.cpp index f1fef24d59479..97a051a34d13f 100644 --- a/clang/lib/Sema/SemaExpand.cpp +++ b/clang/lib/Sema/SemaExpand.cpp @@ -20,9 +20,28 @@ #include "clang/Sema/Overload.h" #include "clang/Sema/Sema.h" #include "clang/Sema/Template.h" +#include "llvm/ADT/ScopeExit.h" using namespace clang; +namespace { +struct IterableExpansionStmtData { + enum class State { + NotIterable, + Error, + Ok, + }; + + DeclStmt *RangeDecl = nullptr; + DeclStmt *BeginDecl = nullptr; + DeclStmt *IterDecl = nullptr; + State TheState = State::NotIterable; + + bool isIterable() const { return TheState == State::Ok; } + bool hasError() { return TheState == State::Error; } +}; +} // namespace + // Build a 'DeclRefExpr' designating the template parameter that is used as // the expansion index static DeclRefExpr *BuildIndexDRE(Sema &S, CXXExpansionStmtDecl *ESD) { @@ -47,7 +66,8 @@ static auto InitListContainsPack(const InitListExpr *ILE) { [](const Expr *E) { return isa<PackExpansionExpr>(E); }); } -static bool HasDependentSize(const CXXExpansionStmtPattern *Pattern) { +static bool HasDependentSize(const DeclContext *CurContext, + const CXXExpansionStmtPattern *Pattern) { switch (Pattern->getKind()) { case CXXExpansionStmtPattern::ExpansionStmtKind::Enumerating: { auto *SelectExpr = cast<CXXExpansionSelectExpr>( @@ -56,14 +76,154 @@ static bool HasDependentSize(const CXXExpansionStmtPattern *Pattern) { } case CXXExpansionStmtPattern::ExpansionStmtKind::Iterating: - case CXXExpansionStmtPattern::ExpansionStmtKind::Destructuring: + // Even if the size isn't technically dependent, delay expansion until + // we're no longer in a template since evaluating a lambda declared in + // a template doesn't work too well. + assert(CurContext->isExpansionStmt()); + return CurContext->getParent()->isDependentContext(); + case CXXExpansionStmtPattern::ExpansionStmtKind::Dependent: + return true; + + case CXXExpansionStmtPattern::ExpansionStmtKind::Destructuring: llvm_unreachable("TODO"); } llvm_unreachable("invalid pattern kind"); } +static IterableExpansionStmtData TryBuildIterableExpansionStmtInitializer( + Sema &S, Expr *ExpansionInitializer, Expr *Index, SourceLocation ColonLoc, + bool VarIsConstexpr, + ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps) { + IterableExpansionStmtData Data; + + // C++26 [stmt.expand]p3: An expression is expansion-iterable if it does not + // have array type [...] + QualType Ty = ExpansionInitializer->getType().getNonReferenceType(); + if (Ty->isArrayType()) + return Data; + + // Lookup member and ADL 'begin()'/'end()'. Only check if they exist; even if + // they're deleted, inaccessible, etc., this is still an iterating expansion + // statement, albeit an ill-formed one. + DeclarationNameInfo BeginName(&S.PP.getIdentifierTable().get("begin"), + ColonLoc); + DeclarationNameInfo EndName(&S.PP.getIdentifierTable().get("end"), ColonLoc); + + bool FoundBeginEnd = false; + if (auto *Record = Ty->getAsCXXRecordDecl()) { + LookupResult BeginLR(S, BeginName, Sema::LookupMemberName); + LookupResult EndLR(S, EndName, Sema::LookupMemberName); + FoundBeginEnd = S.LookupQualifiedName(BeginLR, Record) && + S.LookupQualifiedName(EndLR, Record); + } + + // If member lookup doesn't yield anything, try ADL. + // + // If overload resolution for 'begin()' *and* 'end()' succeeds (irrespective + // of whether it results in a usable candidate), then assume this is an + // iterating expansion statement. + auto HasADLCandidate = [&](DeclarationName Name) { + OverloadCandidateSet Candidates(ColonLoc, OverloadCandidateSet::CSK_Normal); + OverloadCandidateSet::iterator Best; + + S.AddArgumentDependentLookupCandidates(Name, ColonLoc, ExpansionInitializer, + /*ExplicitTemplateArgs=*/nullptr, + Candidates); + + return Candidates.BestViableFunction(S, ColonLoc, Best) != + OR_No_Viable_Function; + }; + + if (!FoundBeginEnd && (!HasADLCandidate(BeginName.getName()) || + !HasADLCandidate(EndName.getName()))) + return Data; + + auto Ctx = Sema::ExpressionEvaluationContext::PotentiallyEvaluated; + if (VarIsConstexpr) + Ctx = Sema::ExpressionEvaluationContext::ImmediateFunctionContext; + EnterExpressionEvaluationContext ExprEvalCtx(S, Ctx); + + // The declarations should be attached to the parent decl context. + Sema::ContextRAII CtxGuard(S, S.CurContext->getParent(), + /*NewThis=*/false); + + // We know that this is supposed to be an iterable expansion statement; + // delegate to the for-range code to build the range/begin/end variables. + // + // Any failure at this point is a hard error. + Data.TheState = IterableExpansionStmtData::State::Error; + Scope *Scope = S.getCurScope(); + + // CWG 3131: The declaration of 'range' is of the form + // + // constexpr[opt] decltype(auto) range = (expansion-initializer); + // + // where 'constexpr' is present iff the for-range-declaration is 'constexpr'. + StmtResult Var = S.BuildCXXForRangeRangeVar( + Scope, S.ActOnParenExpr(ColonLoc, ColonLoc, ExpansionInitializer).get(), + S.Context.getAutoType(DeducedKind::Undeduced, QualType(), + AutoTypeKeyword::DecltypeAuto), + VarIsConstexpr); + if (Var.isInvalid()) + return Data; + + // CWG 3140: 'range', 'begin', and 'iter' are 'constexpr' iff the + // for-range-declaration is declared 'constexpr'. + // + // FIXME: As of CWG 3140, we should only create 'begin' here, and not 'end', + // but that requires another substantial refactor of the for-range code. + auto *RangeVar = cast<DeclStmt>(Var.get()); + Sema::ForRangeBeginEndInfo Info = S.BuildCXXForRangeBeginEndVars( + Scope, cast<VarDecl>(RangeVar->getSingleDecl()), ColonLoc, + /*CoawaitLoc=*/{}, + /*LifetimeExtendTemps=*/{}, Sema::BFRK_Build, VarIsConstexpr); + + if (!Info.isValid()) + return Data; + + // CWG 3140: At runtime, we only need to evaluate 'begin', whereas 'end' is + // only used at compile-time; we'll rebuild it when we compute the expansion + // size, so only build 'begin' here. + StmtResult BeginStmt = S.ActOnDeclStmt( + S.ConvertDeclToDeclGroup(Info.BeginVar), ColonLoc, ColonLoc); + if (BeginStmt.isInvalid()) + return Data; + + // TODO: Build 'constexpr auto iter = begin + decltype(begin - begin){i};'. + S.Diag(ColonLoc, diag::err_iterating_expansion_stmt_unsupported); + return Data; + +#if 0 // This will be used once we support iterating expansion statements. + // Store it in a variable. + // See also Sema::BuildCXXForRangeBeginEndVars(). + const auto DepthStr = std::to_string(Scope->getDepth() / 2); + IdentifierInfo *Name = + S.PP.getIdentifierInfo(std::string("__iter") + DepthStr); + VarDecl *IterVar = S.BuildForRangeVarDecl( + ColonLoc, S.Context.getAutoDeductType(), Name, VarIsConstexpr); + S.AddInitializerToDecl(IterVar, BeginPlusI.get(), /*DirectInit=*/false); + if (IterVar->isInvalidDecl()) + return Data; + + StmtResult IterVarStmt = + S.ActOnDeclStmt(S.ConvertDeclToDeclGroup(IterVar), ColonLoc, ColonLoc); + if (IterVarStmt.isInvalid()) + return Data; + + // CWG 3149: Apply lifetime extension to iterating expansion statements. + S.ApplyForRangeOrExpansionStatementLifetimeExtension( + cast<VarDecl>(RangeVar->getSingleDecl()), LifetimeExtendTemps); + + Data.BeginDecl = BeginStmt.getAs<DeclStmt>(); + Data.RangeDecl = RangeVar; + Data.IterDecl = IterVarStmt.getAs<DeclStmt>(); + Data.TheState = IterableExpansionStmtData::State::Ok; + return Data; +#endif +} + CXXExpansionStmtDecl * Sema::ActOnCXXExpansionStmtDecl(unsigned TemplateDepth, SourceLocation TemplateKWLoc) { @@ -129,12 +289,27 @@ StmtResult Sema::ActOnCXXExpansionStmtPattern( // Note that lifetime extension only applies to destructuring expansion // statements, so we just ignore 'LifetimeExtendedTemps' entirely for other // types of expansion statements (this is CWG 3043). + // + // TODO: CWG 3131 makes it so the 'range' variable of an iterating + // expansion statement need no longer be 'constexpr'... so do we want + // lifetime extension for iterating expansion statements after all? return BuildCXXEnumeratingExpansionStmtPattern(ESD, Init, DS, LParenLoc, ColonLoc, RParenLoc); } - Diag(ESD->getLocation(), diag::err_expansion_statements_todo); - return StmtError(); + if (ExpansionInitializer->hasPlaceholderType()) { + ExprResult R = CheckPlaceholderExpr(ExpansionInitializer); + if (R.isInvalid()) + return StmtError(); + ExpansionInitializer = R.get(); + } + + if (DiagnoseUnexpandedParameterPack(ExpansionInitializer)) + return StmtError(); + + return BuildNonEnumeratingCXXExpansionStmtPattern( + ESD, Init, DS, ExpansionInitializer, LParenLoc, ColonLoc, RParenLoc, + LifetimeExtendTemps); } StmtResult Sema::BuildCXXEnumeratingExpansionStmtPattern( @@ -145,6 +320,74 @@ StmtResult Sema::BuildCXXEnumeratingExpansionStmtPattern( cast<DeclStmt>(ExpansionVar), LParenLoc, ColonLoc, RParenLoc); } +StmtResult Sema::BuildNonEnumeratingCXXExpansionStmtPattern( + CXXExpansionStmtDecl *ESD, Stmt *Init, DeclStmt *ExpansionVarStmt, + Expr *ExpansionInitializer, SourceLocation LParenLoc, + SourceLocation ColonLoc, SourceLocation RParenLoc, + ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps) { + VarDecl *ExpansionVar = cast<VarDecl>(ExpansionVarStmt->getSingleDecl()); + + // Reject lambdas early. + if (auto *RD = ExpansionInitializer->getType()->getAsCXXRecordDecl(); + RD && RD->isLambda()) { + Diag(ExpansionInitializer->getBeginLoc(), diag::err_expansion_stmt_lambda); + return StmtError(); + } + + if (ExpansionInitializer->isTypeDependent()) { + ActOnDependentForRangeInitializer(ExpansionVar, BFRK_Build); + return CXXExpansionStmtPattern::CreateDependent( + Context, ESD, Init, ExpansionVarStmt, ExpansionInitializer, LParenLoc, + ColonLoc, RParenLoc); + } + + if (RequireCompleteType(ExpansionInitializer->getExprLoc(), + ExpansionInitializer->getType(), + diag::err_expansion_stmt_incomplete)) + return StmtError(); + + if (ExpansionInitializer->getType()->isVariableArrayType()) { + Diag(ExpansionInitializer->getExprLoc(), diag::err_expansion_stmt_vla) + << ExpansionInitializer->getType(); + return StmtError(); + } + + // Otherwise, if it can be an iterating expansion statement, it is one. + DeclRefExpr *Index = BuildIndexDRE(*this, ESD); + IterableExpansionStmtData Data = TryBuildIterableExpansionStmtInitializer( + *this, ExpansionInitializer, Index, ColonLoc, ExpansionVar->isConstexpr(), + LifetimeExtendTemps); + if (Data.hasError()) { + ActOnInitializerError(ExpansionVar); + return StmtError(); + } + + if (Data.isIterable()) { + // Build '*iter'. + auto *IterVar = cast<VarDecl>(Data.IterDecl->getSingleDecl()); + DeclRefExpr *IterDRE = BuildDeclRefExpr( + IterVar, IterVar->getType().getNonReferenceType(), VK_LValue, ColonLoc); + ExprResult Deref = + ActOnUnaryOp(getCurScope(), ColonLoc, tok::star, IterDRE); + if (Deref.isInvalid()) { + ActOnInitializerError(ExpansionVar); + return StmtError(); + } + + Deref = MaybeCreateExprWithCleanups(Deref.get()); + + if (FinalizeExpansionVar(*this, ExpansionVar, Deref.get())) + return StmtError(); + + return CXXExpansionStmtPattern::CreateIterating( + Context, ESD, Init, ExpansionVarStmt, Data.RangeDecl, Data.BeginDecl, + Data.IterDecl, LParenLoc, ColonLoc, RParenLoc); + } + + Diag(ESD->getLocation(), diag::err_expansion_statements_todo); + return StmtError(); +} + StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) { if (!Exp || !Body) return StmtError(); @@ -154,9 +397,14 @@ StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) { "should not rebuild expansion statement after instantiation"); Expansion->setBody(Body); - if (HasDependentSize(Expansion)) + if (HasDependentSize(CurContext, Expansion)) return Expansion; + // Now that we're expanding this, exit the context of the expansion stmt + // so that we no longer treat this as dependent. + ContextRAII CtxGuard(*this, CurContext->getParent(), + /*NewThis=*/false); + // This can fail if this is an iterating expansion statement. std::optional<uint64_t> NumInstantiations = ComputeExpansionSize(Expansion); if (!NumInstantiations) @@ -173,7 +421,12 @@ StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) { if (Expansion->getInit()) Shared.push_back(Expansion->getInit()); - assert(Expansion->isEnumerating() && "TODO"); + if (Expansion->isIterating()) { + Shared.push_back(Expansion->getRangeVarStmt()); + Shared.push_back(Expansion->getBeginVarStmt()); + } else { + assert(Expansion->isEnumerating() && "TODO"); + } // Return an empty statement if the range is empty. if (*NumInstantiations == 0) { @@ -184,21 +437,21 @@ StmtResult Sema::FinishCXXExpansionStmt(Stmt *Exp, Stmt *Body) { return Expansion; } - // Create a compound statement binding the expansion variable and body. - Stmt *VarAndBody[] = {Expansion->getExpansionVarStmt(), Body}; + // Create a compound statement binding the expansion variable and body, + // as well as the 'iter' variable if this is an iterating expansion statement. + SmallVector<Stmt *, 3> StmtsToInstantiate; + if (Expansion->isIterating()) + StmtsToInstantiate.push_back(Expansion->getIterVarStmt()); + StmtsToInstantiate.push_back(Expansion->getExpansionVarStmt()); + StmtsToInstantiate.push_back(Body); Stmt *CombinedBody = - CompoundStmt::Create(Context, VarAndBody, FPOptionsOverride(), + CompoundStmt::Create(Context, StmtsToInstantiate, FPOptionsOverride(), Body->getBeginLoc(), Body->getEndLoc()); // Expand the body for each instantiation. SmallVector<Stmt *, 4> Instantiations; CXXExpansionStmtDecl *ESD = Expansion->getDecl(); for (uint64_t I = 0; I < *NumInstantiations; ++I) { - // Now that we're expanding this, exit the context of the expansion stmt - // so that we no longer treat this as dependent. - ContextRAII CtxGuard(*this, CurContext->getParent(), - /*NewThis=*/false); - TemplateArgument Arg{Context, llvm::APSInt::get(I), Context.getPointerDiffType()}; MultiLevelTemplateArgumentList MTArgList(ESD, Arg, true); @@ -242,5 +495,41 @@ Sema::ComputeExpansionSize(CXXExpansionStmtPattern *Expansion) { ->getRangeExpr() ->getNumInits(); + // CWG 3131: N is the result of evaluating the expression + // + // [&] consteval { + // std::ptrdiff_t result = 0; + // auto b = begin-expr; + // auto e = end-expr; + // for (; b != e; ++b) ++result; + // return result; + // }() + if (Expansion->isIterating()) { + SourceLocation Loc = Expansion->getColonLoc(); + EnterExpressionEvaluationContext ExprEvalCtx( + *this, ExpressionEvaluationContext::ConstantEvaluated); + + // TODO: Build the lambda and evaluate it. + Diag(Loc, diag::err_iterating_expansion_stmt_unsupported); + return std::nullopt; + +#if 0 // This will be used once we support iterating expansion statements. + Expr::EvalResult ER; + SmallVector<PartialDiagnosticAt, 4> Notes; + ER.Diag = &Notes; + if (!Call.get()->EvaluateAsInt(ER, Context)) { + Diag(Loc, diag::err_expansion_size_expr_not_ice); + for (const auto &[Location, PDiag] : Notes) + Diag(Location, PDiag); + return std::nullopt; + } + + // It shouldn't be possible for this to be negative since we compute this + // via the built-in '++' on a ptrdiff_t. + assert(ER.Val.getInt().isNonNegative()); + return ER.Val.getInt().getZExtValue(); +#endif + } + llvm_unreachable("TODO"); } diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 9793788fb75b8..df12dd837d45e 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -2436,12 +2436,20 @@ void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E, /// Build a variable declaration for a for-range statement. VarDecl *Sema::BuildForRangeVarDecl(SourceLocation Loc, QualType Type, IdentifierInfo *II, bool Constexpr) { + // Making the variable constexpr doesn't automatically add 'const' to the + // type, so do that now. + if (Constexpr && !Type->isReferenceType()) + Type = Type.withConst(); + DeclContext *DC = CurContext; TypeSourceInfo *TInfo = Context.getTrivialTypeSourceInfo(Type, Loc); VarDecl *Decl = VarDecl::Create(Context, DC, Loc, Loc, II, Type, TInfo, SC_None); Decl->setImplicit(); Decl->setCXXForRangeImplicitVar(true); + if (Constexpr) + // CWG 3044: Do not make the variable 'static'. + Decl->setConstexpr(true); return Decl; } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 42c094fc2e94d..864667d784e6d 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -9397,6 +9397,40 @@ StmtResult TreeTransform<Derived>::TransformCXXExpansionStmtPattern( Init = SR.get(); } + // Collect lifetime-extended temporaries in case this ends up being a + // destructuring or iterating expansion statement. + // + // CWG 3140: Additionally, for iterating expansions statements, we need to + // apply lifetime extension to the initializer of the range. + ExprResult ExpansionInitializer; + StmtResult Range; + SmallVector<MaterializeTemporaryExpr *, 8> LifetimeExtendTemps; + if (S->isDependent() || S->isIterating()) { + EnterExpressionEvaluationContext ExprEvalCtx( + SemaRef, SemaRef.currentEvaluationContext().Context); + SemaRef.currentEvaluationContext().InLifetimeExtendingContext = true; + SemaRef.currentEvaluationContext().RebuildDefaultArgOrDefaultInit = true; + + if (S->isDependent()) { + // The expansion initializer should not be in the context of the expansion + // statement because it isn't instantiated when the expansion statement is + // expanded. + Sema::ContextRAII CtxGuard(SemaRef, SemaRef.CurContext->getParent(), + /*NewThis=*/false); + ExpansionInitializer = + getDerived().TransformExpr(S->getExpansionInitializer()); + if (ExpansionInitializer.isInvalid()) + return StmtError(); + } else if (S->isIterating()) { + Range = TransformStmtInParentContext(S->getRangeVarStmt()); + if (Range.isInvalid()) + return StmtError(); + } + + LifetimeExtendTemps = + SemaRef.currentEvaluationContext().ForRangeLifetimeExtendTemps; + } + CXXExpansionStmtPattern *NewPattern = nullptr; if (S->isEnumerating()) { StmtResult ExpansionVar = @@ -9407,6 +9441,43 @@ StmtResult TreeTransform<Derived>::TransformCXXExpansionStmtPattern( NewPattern = CXXExpansionStmtPattern::CreateEnumerating( SemaRef.Context, NewESD, Init, ExpansionVar.getAs<DeclStmt>(), S->getLParenLoc(), S->getColonLoc(), S->getRParenLoc()); + } else if (S->isIterating()) { + StmtResult Begin = TransformStmtInParentContext(S->getBeginVarStmt()); + StmtResult Iter = TransformStmtInParentContext(S->getIterVarStmt()); + if (Begin.isInvalid() || Iter.isInvalid()) + return StmtError(); + + // The expansion variable is part of the pattern only and never ends + // up in the instantiations, so keep it in the expansion statement's + // DeclContext. + StmtResult ExpansionVar = + getDerived().TransformStmt(S->getExpansionVarStmt()); + if (ExpansionVar.isInvalid()) + return StmtError(); + + NewPattern = CXXExpansionStmtPattern::CreateIterating( + SemaRef.Context, NewESD, Init, ExpansionVar.getAs<DeclStmt>(), + Range.getAs<DeclStmt>(), Begin.getAs<DeclStmt>(), + Iter.getAs<DeclStmt>(), S->getLParenLoc(), S->getColonLoc(), + S->getRParenLoc()); + + SemaRef.ApplyForRangeOrExpansionStatementLifetimeExtension( + NewPattern->getRangeVar(), LifetimeExtendTemps); + } else if (S->isDependent()) { + StmtResult ExpansionVar = + getDerived().TransformStmt(S->getExpansionVarStmt()); + if (ExpansionVar.isInvalid()) + return StmtError(); + + StmtResult Res = SemaRef.BuildNonEnumeratingCXXExpansionStmtPattern( + NewESD, Init, ExpansionVar.getAs<DeclStmt>(), + ExpansionInitializer.get(), S->getLParenLoc(), S->getColonLoc(), + S->getRParenLoc(), LifetimeExtendTemps); + + if (Res.isInvalid()) + return StmtError(); + + NewPattern = cast<CXXExpansionStmtPattern>(Res.get()); } else { llvm_unreachable("TODO"); } _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
