[llvm-branch-commits] [clang] [Clang] [NFC] Expansion Statements (Part 4: for-range and `ParseScope` refactor) (PR #169683)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Dec 5 09:55:09 PST 2025
https://github.com/Sirraide updated https://github.com/llvm/llvm-project/pull/169683
>From 26f413ff4d537911520369e1f1833cf940dd2ab8 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Wed, 26 Nov 2025 16:11:59 +0100
Subject: [PATCH 1/4] [Clang] [C++26] Expansion Statements (Part 4)
---
clang/include/clang/Sema/Sema.h | 34 +++
clang/lib/Sema/SemaStmt.cpp | 503 ++++++++++++++++++--------------
2 files changed, 313 insertions(+), 224 deletions(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 707f9eefccf36..7e23bb486bdda 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11067,6 +11067,37 @@ class Sema final : public SemaBase {
BuildForRangeKind Kind,
ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps = {});
+ /// Set the type of a for-range declaration whose for-range or expansion
+ /// initialiser is dependent.
+ void ActOnDependentForRangeInitializer(VarDecl *LoopVar,
+ BuildForRangeKind BFRK);
+
+ /// Holds the 'begin' and 'end' variables of a range-based for loop or
+ /// expansion statement; begin-expr and end-expr are also provided; the
+ /// latter are used in some diagnostics.
+ struct ForRangeBeginEndInfo {
+ VarDecl *BeginVar = nullptr;
+ VarDecl *EndVar = nullptr;
+ Expr *BeginExpr = nullptr;
+ Expr *EndExpr = nullptr;
+ bool isValid() const { return BeginVar != nullptr && EndVar != nullptr; }
+ };
+
+ /// Determine begin-expr and end-expr and build variable declarations for
+ /// them as per [stmt.ranged].
+ ForRangeBeginEndInfo BuildCXXForRangeBeginEndVars(
+ Scope *S, VarDecl *RangeVar, SourceLocation ColonLoc,
+ SourceLocation CoawaitLoc,
+ ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps,
+ BuildForRangeKind Kind, bool ForExpansionStmt,
+ StmtResult *RebuildResult = nullptr,
+ llvm::function_ref<StmtResult()> RebuildWithDereference = {});
+
+ /// Build the range variable of a range-based for loop or iterating
+ /// expansion statement and return its DeclStmt.
+ StmtResult BuildCXXForRangeRangeVar(Scope *S, Expr *Range,
+ bool ForExpansionStmt);
+
/// FinishCXXForRangeStmt - Attach the body to a C++0x for-range statement.
/// This is a separate step from ActOnCXXForRangeStmt because analysis of the
/// body cannot be performed until after the type of the range variable is
@@ -11208,6 +11239,9 @@ class Sema final : public SemaBase {
SourceLocation Loc,
unsigned NumParams);
+ void ApplyForRangeOrExpansionStatementLifetimeExtension(
+ VarDecl *RangeVar, ArrayRef<MaterializeTemporaryExpr *> Temporaries);
+
private:
/// Check whether the given statement can have musttail applied to it,
/// issuing a diagnostic and returning false if not.
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 6bb1a27d1800c..3a1d73fdacf09 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -2409,8 +2409,13 @@ void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E,
}
/// Build a variable declaration for a for-range statement.
-VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc,
- QualType Type, StringRef Name) {
+VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc, QualType Type,
+ StringRef Name, bool ForExpansionStmt) {
+ // Making the variable constexpr doesn't automatically add 'const' to the
+ // type, so do that now.
+ if (ForExpansionStmt && !Type->isReferenceType())
+ Type = Type.withConst();
+
DeclContext *DC = SemaRef.CurContext;
IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name);
TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc);
@@ -2418,9 +2423,11 @@ VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc,
TInfo, SC_None);
Decl->setImplicit();
Decl->setCXXForRangeImplicitVar(true);
+ if (ForExpansionStmt)
+ // CWG 3044: Do not make the variable 'static'.
+ Decl->setConstexpr(true);
return Decl;
}
-
}
static bool ObjCEnumerationCollection(Expr *Collection) {
@@ -2428,6 +2435,25 @@ static bool ObjCEnumerationCollection(Expr *Collection) {
&& Collection->getType()->getAs<ObjCObjectPointerType>() != nullptr;
}
+StmtResult Sema::BuildCXXForRangeRangeVar(Scope *S, Expr *Range,
+ bool ForExpansionStmt) {
+ // Divide by 2, since the variables are in the inner scope (loop body).
+ const auto DepthStr = std::to_string(S->getDepth() / 2);
+ SourceLocation RangeLoc = Range->getBeginLoc();
+ VarDecl *RangeVar =
+ BuildForRangeVarDecl(*this, RangeLoc, Context.getAutoRRefDeductType(),
+ std::string("__range") + DepthStr, ForExpansionStmt);
+ if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
+ diag::err_for_range_deduction_failure))
+
+ return StmtError();
+
+ // Claim the type doesn't contain auto: we've already done the checking.
+ DeclGroupPtrTy RangeGroup =
+ BuildDeclaratorGroup(MutableArrayRef<Decl *>((Decl **)&RangeVar, 1));
+ return ActOnDeclStmt(RangeGroup, RangeLoc, RangeLoc);
+}
+
StmtResult Sema::ActOnCXXForRangeStmt(
Scope *S, SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *InitStmt,
Stmt *First, SourceLocation ColonLoc, Expr *Range, SourceLocation RParenLoc,
@@ -2472,22 +2498,8 @@ StmtResult Sema::ActOnCXXForRangeStmt(
}
// Build auto && __range = range-init
- // Divide by 2, since the variables are in the inner scope (loop body).
- const auto DepthStr = std::to_string(S->getDepth() / 2);
- SourceLocation RangeLoc = Range->getBeginLoc();
- VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc,
- Context.getAutoRRefDeductType(),
- std::string("__range") + DepthStr);
- if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
- diag::err_for_range_deduction_failure)) {
- ActOnInitializerError(LoopVar);
- return StmtError();
- }
-
- // Claim the type doesn't contain auto: we've already done the checking.
- DeclGroupPtrTy RangeGroup =
- BuildDeclaratorGroup(MutableArrayRef<Decl *>((Decl **)&RangeVar, 1));
- StmtResult RangeDecl = ActOnDeclStmt(RangeGroup, RangeLoc, RangeLoc);
+ auto RangeDecl =
+ BuildCXXForRangeRangeVar(S, Range, /*ForExpansionStmt=*/false);
if (RangeDecl.isInvalid()) {
ActOnInitializerError(LoopVar);
return StmtError();
@@ -2686,6 +2698,229 @@ static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S,
AdjustedRange.get(), RParenLoc, Sema::BFRK_Rebuild);
}
+void Sema::ApplyForRangeOrExpansionStatementLifetimeExtension(
+ VarDecl *RangeVar, ArrayRef<MaterializeTemporaryExpr *> Temporaries) {
+ if (Temporaries.empty())
+ return;
+
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(RangeVar);
+ for (auto *MTE : Temporaries)
+ MTE->setExtendingDecl(RangeVar, Entity.allocateManglingNumber());
+}
+
+Sema::ForRangeBeginEndInfo Sema::BuildCXXForRangeBeginEndVars(
+ Scope *S, VarDecl *RangeVar, SourceLocation ColonLoc,
+ SourceLocation CoawaitLoc,
+ ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps,
+ BuildForRangeKind Kind, bool ForExpansionStmt, StmtResult *RebuildResult,
+ llvm::function_ref<StmtResult()> RebuildWithDereference) {
+ QualType RangeVarType = RangeVar->getType();
+ SourceLocation RangeLoc = RangeVar->getLocation();
+ const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType();
+
+ ExprResult BeginRangeRef =
+ BuildDeclRefExpr(RangeVar, RangeVarNonRefType, VK_LValue, ColonLoc);
+ if (BeginRangeRef.isInvalid())
+ return {};
+
+ ExprResult EndRangeRef =
+ BuildDeclRefExpr(RangeVar, RangeVarNonRefType, VK_LValue, ColonLoc);
+ if (EndRangeRef.isInvalid())
+ return {};
+
+ QualType AutoType = Context.getAutoDeductType();
+ Expr *Range = RangeVar->getInit();
+ if (!Range)
+ return {};
+ QualType RangeType = Range->getType();
+
+ if (RequireCompleteType(RangeLoc, RangeType,
+ diag::err_for_range_incomplete_type))
+ return {};
+
+ // P2718R0 - Lifetime extension in range-based for loops.
+ //
+ // CWG 3043 – Do not apply lifetime extension to iterating
+ // expansion statements.
+ if (getLangOpts().CPlusPlus23 && !ForExpansionStmt)
+ ApplyForRangeOrExpansionStatementLifetimeExtension(RangeVar,
+ LifetimeExtendTemps);
+
+ // Build auto __begin = begin-expr, __end = end-expr.
+ // Divide by 2, since the variables are in the inner scope (loop body).
+ const auto DepthStr = std::to_string(S->getDepth() / 2);
+ VarDecl *BeginVar =
+ BuildForRangeVarDecl(*this, ColonLoc, AutoType,
+ std::string("__begin") + DepthStr, ForExpansionStmt);
+ VarDecl *EndVar =
+ BuildForRangeVarDecl(*this, ColonLoc, AutoType,
+ std::string("__end") + DepthStr, ForExpansionStmt);
+
+ // Build begin-expr and end-expr and attach to __begin and __end variables.
+ ExprResult BeginExpr, EndExpr;
+ if (const ArrayType *UnqAT = RangeType->getAsArrayTypeUnsafe()) {
+ // - if _RangeT is an array type, begin-expr and end-expr are __range and
+ // __range + __bound, respectively, where __bound is the array bound. If
+ // _RangeT is an array of unknown size or an array of incomplete type,
+ // the program is ill-formed;
+
+ // begin-expr is __range.
+ BeginExpr = BeginRangeRef;
+ if (!CoawaitLoc.isInvalid()) {
+ BeginExpr = ActOnCoawaitExpr(S, ColonLoc, BeginExpr.get());
+ if (BeginExpr.isInvalid())
+ return {};
+ }
+ if (FinishForRangeVarDecl(*this, BeginVar, BeginRangeRef.get(), ColonLoc,
+ diag::err_for_range_iter_deduction_failure)) {
+ NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
+ return {};
+ }
+
+ // Find the array bound.
+ ExprResult BoundExpr;
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(UnqAT))
+ BoundExpr = IntegerLiteral::Create(
+ Context, CAT->getSize(), Context.getPointerDiffType(), RangeLoc);
+ else if (const VariableArrayType *VAT =
+ dyn_cast<VariableArrayType>(UnqAT)) {
+ // For a variably modified type we can't just use the expression within
+ // the array bounds, since we don't want that to be re-evaluated here.
+ // Rather, we need to determine what it was when the array was first
+ // created - so we resort to using sizeof(vla)/sizeof(element).
+ // For e.g.
+ // void f(int b) {
+ // int vla[b];
+ // b = -1; <-- This should not affect the num of iterations below
+ // for (int &c : vla) { .. }
+ // }
+
+ // FIXME: This results in codegen generating IR that recalculates the
+ // run-time number of elements (as opposed to just using the IR Value
+ // that corresponds to the run-time value of each bound that was
+ // generated when the array was created.) If this proves too embarrassing
+ // even for unoptimized IR, consider passing a magic-value/cookie to
+ // codegen that then knows to simply use that initial llvm::Value (that
+ // corresponds to the bound at time of array creation) within
+ // getelementptr. But be prepared to pay the price of increasing a
+ // customized form of coupling between the two components - which could
+ // be hard to maintain as the codebase evolves.
+
+ ExprResult SizeOfVLAExprR = ActOnUnaryExprOrTypeTraitExpr(
+ EndVar->getLocation(), UETT_SizeOf,
+ /*IsType=*/true,
+ CreateParsedType(VAT->desugar(), Context.getTrivialTypeSourceInfo(
+ VAT->desugar(), RangeLoc))
+ .getAsOpaquePtr(),
+ EndVar->getSourceRange());
+ if (SizeOfVLAExprR.isInvalid())
+ return {};
+
+ ExprResult SizeOfEachElementExprR = ActOnUnaryExprOrTypeTraitExpr(
+ EndVar->getLocation(), UETT_SizeOf,
+ /*IsType=*/true,
+ CreateParsedType(VAT->desugar(), Context.getTrivialTypeSourceInfo(
+ VAT->getElementType(), RangeLoc))
+ .getAsOpaquePtr(),
+ EndVar->getSourceRange());
+ if (SizeOfEachElementExprR.isInvalid())
+ return {};
+
+ BoundExpr =
+ ActOnBinOp(S, EndVar->getLocation(), tok::slash, SizeOfVLAExprR.get(),
+ SizeOfEachElementExprR.get());
+ if (BoundExpr.isInvalid())
+ return {};
+
+ } else {
+ // Can't be a DependentSizedArrayType or an IncompleteArrayType since
+ // UnqAT is not incomplete and Range is not type-dependent.
+ llvm_unreachable("Unexpected array type in for-range");
+ }
+
+ // end-expr is __range + __bound.
+ EndExpr =
+ ActOnBinOp(S, ColonLoc, tok::plus, EndRangeRef.get(), BoundExpr.get());
+ if (EndExpr.isInvalid())
+ return {};
+ if (FinishForRangeVarDecl(*this, EndVar, EndExpr.get(), ColonLoc,
+ diag::err_for_range_iter_deduction_failure)) {
+ NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
+ return {};
+ }
+ } else {
+ OverloadCandidateSet CandidateSet(RangeLoc,
+ OverloadCandidateSet::CSK_Normal);
+ BeginEndFunction BEFFailure;
+ ForRangeStatus RangeStatus =
+ BuildNonArrayForRange(*this, BeginRangeRef.get(), EndRangeRef.get(),
+ RangeType, BeginVar, EndVar, ColonLoc, CoawaitLoc,
+ &CandidateSet, &BeginExpr, &EndExpr, &BEFFailure);
+
+ if (Kind == BFRK_Build && RangeStatus == FRS_NoViableFunction &&
+ BEFFailure == BEF_begin) {
+ // If the range is being built from an array parameter, emit a
+ // a diagnostic that it is being treated as a pointer.
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Range)) {
+ if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
+ QualType ArrayTy = PVD->getOriginalType();
+ QualType PointerTy = PVD->getType();
+ if (PointerTy->isPointerType() && ArrayTy->isArrayType()) {
+ Diag(Range->getBeginLoc(), diag::err_range_on_array_parameter)
+ << RangeLoc << PVD << ArrayTy << PointerTy;
+ Diag(PVD->getLocation(), diag::note_declared_at);
+ return {};
+ }
+ }
+ }
+
+ // If building the range failed, try dereferencing the range expression
+ // unless a diagnostic was issued or the end function is problematic.
+ if (RebuildWithDereference) {
+ assert(RebuildResult);
+ StmtResult SR = RebuildWithDereference();
+ if (SR.isInvalid() || SR.isUsable()) {
+ *RebuildResult = SR;
+ return {};
+ }
+ }
+ }
+
+ // Otherwise, emit diagnostics if we haven't already.
+ if (RangeStatus == FRS_NoViableFunction) {
+ Expr *Range = BEFFailure ? EndRangeRef.get() : BeginRangeRef.get();
+ CandidateSet.NoteCandidates(
+ PartialDiagnosticAt(Range->getBeginLoc(),
+ PDiag(diag::err_for_range_invalid)
+ << RangeLoc << Range->getType()
+ << BEFFailure),
+ *this, OCD_AllCandidates, Range);
+ }
+ // Return an error if no fix was discovered.
+ if (RangeStatus != FRS_Success)
+ return {};
+ }
+
+ assert(!BeginExpr.isInvalid() && !EndExpr.isInvalid() &&
+ "invalid range expression in for loop");
+
+ return {BeginVar, EndVar, BeginExpr.get(), EndExpr.get()};
+}
+
+void Sema::ActOnDependentForRangeInitializer(VarDecl *LoopVar,
+ BuildForRangeKind BFRK) {
+ // Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill
+ // them in properly when we instantiate the loop.
+ if (!LoopVar->isInvalidDecl() && BFRK != BFRK_Check) {
+ if (auto *DD = dyn_cast<DecompositionDecl>(LoopVar))
+ for (auto *Binding : DD->bindings()) {
+ if (!Binding->isParameterPack())
+ Binding->setType(Context.DependentTy);
+ }
+ LoopVar->setType(SubstAutoTypeDependent(LoopVar->getType()));
+ }
+}
+
StmtResult Sema::BuildCXXForRangeStmt(
SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *InitStmt,
SourceLocation ColonLoc, Stmt *RangeDecl, Stmt *Begin, Stmt *End,
@@ -2717,216 +2952,36 @@ StmtResult Sema::BuildCXXForRangeStmt(
if (RangeVarType->isDependentType()) {
// The range is implicitly used as a placeholder when it is dependent.
RangeVar->markUsed(Context);
-
- // Deduce any 'auto's in the loop variable as 'DependentTy'. We'll fill
- // them in properly when we instantiate the loop.
- if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) {
- if (auto *DD = dyn_cast<DecompositionDecl>(LoopVar))
- for (auto *Binding : DD->bindings()) {
- if (!Binding->isParameterPack())
- Binding->setType(Context.DependentTy);
- }
- LoopVar->setType(SubstAutoTypeDependent(LoopVar->getType()));
- }
+ ActOnDependentForRangeInitializer(LoopVar, Kind);
} else if (!BeginDeclStmt.get()) {
- SourceLocation RangeLoc = RangeVar->getLocation();
-
- const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType();
-
- ExprResult BeginRangeRef = BuildDeclRefExpr(RangeVar, RangeVarNonRefType,
- VK_LValue, ColonLoc);
- if (BeginRangeRef.isInvalid())
- return StmtError();
+ StmtResult RebuildResult;
+ auto RebuildWithDereference = [&] {
+ return RebuildForRangeWithDereference(
+ *this, S, ForLoc, CoawaitLoc, InitStmt, LoopVarDecl, ColonLoc,
+ RangeVar->getInit(), RangeVar->getLocation(), RParenLoc);
+ };
- ExprResult EndRangeRef = BuildDeclRefExpr(RangeVar, RangeVarNonRefType,
- VK_LValue, ColonLoc);
- if (EndRangeRef.isInvalid())
- return StmtError();
+ auto BeginRangeRefTy = RangeVar->getType().getNonReferenceType();
+ auto [BeginVar, EndVar, BeginExpr, EndExpr] = BuildCXXForRangeBeginEndVars(
+ S, RangeVar, ColonLoc, CoawaitLoc, LifetimeExtendTemps, Kind,
+ /*ForExpansionStmt=*/false, &RebuildResult, RebuildWithDereference);
- QualType AutoType = Context.getAutoDeductType();
- Expr *Range = RangeVar->getInit();
- if (!Range)
+ if (!RebuildResult.isUnset())
+ return RebuildResult;
+ if (!BeginVar || !EndVar)
return StmtError();
- QualType RangeType = Range->getType();
-
- if (RequireCompleteType(RangeLoc, RangeType,
- diag::err_for_range_incomplete_type))
- return StmtError();
-
- // P2718R0 - Lifetime extension in range-based for loops.
- if (getLangOpts().CPlusPlus23 && !LifetimeExtendTemps.empty()) {
- InitializedEntity Entity =
- InitializedEntity::InitializeVariable(RangeVar);
- for (auto *MTE : LifetimeExtendTemps)
- MTE->setExtendingDecl(RangeVar, Entity.allocateManglingNumber());
- }
-
- // Build auto __begin = begin-expr, __end = end-expr.
- // Divide by 2, since the variables are in the inner scope (loop body).
- const auto DepthStr = std::to_string(S->getDepth() / 2);
- VarDecl *BeginVar = BuildForRangeVarDecl(*this, ColonLoc, AutoType,
- std::string("__begin") + DepthStr);
- VarDecl *EndVar = BuildForRangeVarDecl(*this, ColonLoc, AutoType,
- std::string("__end") + DepthStr);
-
- // Build begin-expr and end-expr and attach to __begin and __end variables.
- ExprResult BeginExpr, EndExpr;
- if (const ArrayType *UnqAT = RangeType->getAsArrayTypeUnsafe()) {
- // - if _RangeT is an array type, begin-expr and end-expr are __range and
- // __range + __bound, respectively, where __bound is the array bound. If
- // _RangeT is an array of unknown size or an array of incomplete type,
- // the program is ill-formed;
-
- // begin-expr is __range.
- BeginExpr = BeginRangeRef;
- if (!CoawaitLoc.isInvalid()) {
- BeginExpr = ActOnCoawaitExpr(S, ColonLoc, BeginExpr.get());
- if (BeginExpr.isInvalid())
- return StmtError();
- }
- if (FinishForRangeVarDecl(*this, BeginVar, BeginRangeRef.get(), ColonLoc,
- diag::err_for_range_iter_deduction_failure)) {
- NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
- return StmtError();
- }
-
- // Find the array bound.
- ExprResult BoundExpr;
- if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(UnqAT))
- BoundExpr = IntegerLiteral::Create(
- Context, CAT->getSize(), Context.getPointerDiffType(), RangeLoc);
- else if (const VariableArrayType *VAT =
- dyn_cast<VariableArrayType>(UnqAT)) {
- // For a variably modified type we can't just use the expression within
- // the array bounds, since we don't want that to be re-evaluated here.
- // Rather, we need to determine what it was when the array was first
- // created - so we resort to using sizeof(vla)/sizeof(element).
- // For e.g.
- // void f(int b) {
- // int vla[b];
- // b = -1; <-- This should not affect the num of iterations below
- // for (int &c : vla) { .. }
- // }
-
- // FIXME: This results in codegen generating IR that recalculates the
- // run-time number of elements (as opposed to just using the IR Value
- // that corresponds to the run-time value of each bound that was
- // generated when the array was created.) If this proves too embarrassing
- // even for unoptimized IR, consider passing a magic-value/cookie to
- // codegen that then knows to simply use that initial llvm::Value (that
- // corresponds to the bound at time of array creation) within
- // getelementptr. But be prepared to pay the price of increasing a
- // customized form of coupling between the two components - which could
- // be hard to maintain as the codebase evolves.
-
- ExprResult SizeOfVLAExprR = ActOnUnaryExprOrTypeTraitExpr(
- EndVar->getLocation(), UETT_SizeOf,
- /*IsType=*/true,
- CreateParsedType(VAT->desugar(), Context.getTrivialTypeSourceInfo(
- VAT->desugar(), RangeLoc))
- .getAsOpaquePtr(),
- EndVar->getSourceRange());
- if (SizeOfVLAExprR.isInvalid())
- return StmtError();
-
- ExprResult SizeOfEachElementExprR = ActOnUnaryExprOrTypeTraitExpr(
- EndVar->getLocation(), UETT_SizeOf,
- /*IsType=*/true,
- CreateParsedType(VAT->desugar(),
- Context.getTrivialTypeSourceInfo(
- VAT->getElementType(), RangeLoc))
- .getAsOpaquePtr(),
- EndVar->getSourceRange());
- if (SizeOfEachElementExprR.isInvalid())
- return StmtError();
-
- BoundExpr =
- ActOnBinOp(S, EndVar->getLocation(), tok::slash,
- SizeOfVLAExprR.get(), SizeOfEachElementExprR.get());
- if (BoundExpr.isInvalid())
- return StmtError();
-
- } else {
- // Can't be a DependentSizedArrayType or an IncompleteArrayType since
- // UnqAT is not incomplete and Range is not type-dependent.
- llvm_unreachable("Unexpected array type in for-range");
- }
-
- // end-expr is __range + __bound.
- EndExpr = ActOnBinOp(S, ColonLoc, tok::plus, EndRangeRef.get(),
- BoundExpr.get());
- if (EndExpr.isInvalid())
- return StmtError();
- if (FinishForRangeVarDecl(*this, EndVar, EndExpr.get(), ColonLoc,
- diag::err_for_range_iter_deduction_failure)) {
- NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
- return StmtError();
- }
- } else {
- OverloadCandidateSet CandidateSet(RangeLoc,
- OverloadCandidateSet::CSK_Normal);
- BeginEndFunction BEFFailure;
- ForRangeStatus RangeStatus = BuildNonArrayForRange(
- *this, BeginRangeRef.get(), EndRangeRef.get(), RangeType, BeginVar,
- EndVar, ColonLoc, CoawaitLoc, &CandidateSet, &BeginExpr, &EndExpr,
- &BEFFailure);
-
- if (Kind == BFRK_Build && RangeStatus == FRS_NoViableFunction &&
- BEFFailure == BEF_begin) {
- // If the range is being built from an array parameter, emit a
- // a diagnostic that it is being treated as a pointer.
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Range)) {
- if (ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
- QualType ArrayTy = PVD->getOriginalType();
- QualType PointerTy = PVD->getType();
- if (PointerTy->isPointerType() && ArrayTy->isArrayType()) {
- Diag(Range->getBeginLoc(), diag::err_range_on_array_parameter)
- << RangeLoc << PVD << ArrayTy << PointerTy;
- Diag(PVD->getLocation(), diag::note_declared_at);
- return StmtError();
- }
- }
- }
-
- // If building the range failed, try dereferencing the range expression
- // unless a diagnostic was issued or the end function is problematic.
- StmtResult SR = RebuildForRangeWithDereference(*this, S, ForLoc,
- CoawaitLoc, InitStmt,
- LoopVarDecl, ColonLoc,
- Range, RangeLoc,
- RParenLoc);
- if (SR.isInvalid() || SR.isUsable())
- return SR;
- }
-
- // Otherwise, emit diagnostics if we haven't already.
- if (RangeStatus == FRS_NoViableFunction) {
- Expr *Range = BEFFailure ? EndRangeRef.get() : BeginRangeRef.get();
- CandidateSet.NoteCandidates(
- PartialDiagnosticAt(Range->getBeginLoc(),
- PDiag(diag::err_for_range_invalid)
- << RangeLoc << Range->getType()
- << BEFFailure),
- *this, OCD_AllCandidates, Range);
- }
- // Return an error if no fix was discovered.
- if (RangeStatus != FRS_Success)
- return StmtError();
- }
-
- assert(!BeginExpr.isInvalid() && !EndExpr.isInvalid() &&
- "invalid range expression in for loop");
// C++11 [dcl.spec.auto]p7: BeginType and EndType must be the same.
// C++1z removes this restriction.
+ SourceLocation RangeLoc = RangeVar->getLocation();
QualType BeginType = BeginVar->getType(), EndType = EndVar->getType();
if (!Context.hasSameType(BeginType, EndType)) {
Diag(RangeLoc, getLangOpts().CPlusPlus17
? diag::warn_for_range_begin_end_types_differ
: diag::ext_for_range_begin_end_types_differ)
<< BeginType << EndType;
- NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
- NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
+ NoteForRangeBeginEndFunction(*this, BeginExpr, BEF_begin);
+ NoteForRangeBeginEndFunction(*this, EndExpr, BEF_end);
}
BeginDeclStmt =
@@ -2955,10 +3010,10 @@ StmtResult Sema::BuildCXXForRangeStmt(
ActOnFinishFullExpr(NotEqExpr.get(), /*DiscardedValue*/ false);
if (NotEqExpr.isInvalid()) {
Diag(RangeLoc, diag::note_for_range_invalid_iterator)
- << RangeLoc << 0 << BeginRangeRef.get()->getType();
- NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
+ << RangeLoc << 0 << BeginRangeRefTy;
+ NoteForRangeBeginEndFunction(*this, BeginExpr, BEF_begin);
if (!Context.hasSameType(BeginType, EndType))
- NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
+ NoteForRangeBeginEndFunction(*this, EndExpr, BEF_end);
return StmtError();
}
@@ -2978,8 +3033,8 @@ StmtResult Sema::BuildCXXForRangeStmt(
IncrExpr = ActOnFinishFullExpr(IncrExpr.get(), /*DiscardedValue*/ false);
if (IncrExpr.isInvalid()) {
Diag(RangeLoc, diag::note_for_range_invalid_iterator)
- << RangeLoc << 2 << BeginRangeRef.get()->getType() ;
- NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
+ << RangeLoc << 2 << BeginRangeRefTy;
+ NoteForRangeBeginEndFunction(*this, BeginExpr, BEF_begin);
return StmtError();
}
@@ -2992,8 +3047,8 @@ StmtResult Sema::BuildCXXForRangeStmt(
ExprResult DerefExpr = ActOnUnaryOp(S, ColonLoc, tok::star, BeginRef.get());
if (DerefExpr.isInvalid()) {
Diag(RangeLoc, diag::note_for_range_invalid_iterator)
- << RangeLoc << 1 << BeginRangeRef.get()->getType();
- NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
+ << RangeLoc << 1 << BeginRangeRefTy;
+ NoteForRangeBeginEndFunction(*this, BeginExpr, BEF_begin);
return StmtError();
}
@@ -3003,7 +3058,7 @@ StmtResult Sema::BuildCXXForRangeStmt(
AddInitializerToDecl(LoopVar, DerefExpr.get(), /*DirectInit=*/false);
if (LoopVar->isInvalidDecl() ||
(LoopVar->getInit() && LoopVar->getInit()->containsErrors()))
- NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
+ NoteForRangeBeginEndFunction(*this, BeginExpr, BEF_begin);
}
}
>From eb3ffb3f13d4cc31ee9ec241bd8eba821ee9b352 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Wed, 26 Nov 2025 16:16:51 +0100
Subject: [PATCH 2/4] Remove most expansion-statement-specific code
---
clang/lib/Sema/SemaStmt.cpp | 13 +------------
1 file changed, 1 insertion(+), 12 deletions(-)
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 3a1d73fdacf09..8f3e37d7d75c8 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -2411,11 +2411,6 @@ void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E,
/// Build a variable declaration for a for-range statement.
VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc, QualType Type,
StringRef Name, bool ForExpansionStmt) {
- // Making the variable constexpr doesn't automatically add 'const' to the
- // type, so do that now.
- if (ForExpansionStmt && !Type->isReferenceType())
- Type = Type.withConst();
-
DeclContext *DC = SemaRef.CurContext;
IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name);
TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc);
@@ -2423,9 +2418,6 @@ VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc, QualType Type,
TInfo, SC_None);
Decl->setImplicit();
Decl->setCXXForRangeImplicitVar(true);
- if (ForExpansionStmt)
- // CWG 3044: Do not make the variable 'static'.
- Decl->setConstexpr(true);
return Decl;
}
}
@@ -2739,10 +2731,7 @@ Sema::ForRangeBeginEndInfo Sema::BuildCXXForRangeBeginEndVars(
return {};
// P2718R0 - Lifetime extension in range-based for loops.
- //
- // CWG 3043 – Do not apply lifetime extension to iterating
- // expansion statements.
- if (getLangOpts().CPlusPlus23 && !ForExpansionStmt)
+ if (getLangOpts().CPlusPlus23)
ApplyForRangeOrExpansionStatementLifetimeExtension(RangeVar,
LifetimeExtendTemps);
>From 48e079b6119e4a4bc1a866cb32abba20a2d72e2a Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Wed, 3 Dec 2025 01:51:31 +0100
Subject: [PATCH 3/4] Move ParseScope and friends into Sema
---
clang/include/clang/Parse/Parser.h | 85 +--------------------
clang/include/clang/Sema/Scope.h | 41 +++++++++-
clang/include/clang/Sema/Sema.h | 17 ++++-
clang/lib/Interpreter/IncrementalParser.cpp | 4 +-
clang/lib/Parse/ParseCXXInlineMethods.cpp | 9 ++-
clang/lib/Parse/ParseDecl.cpp | 28 +++----
clang/lib/Parse/ParseDeclCXX.cpp | 22 +++---
clang/lib/Parse/ParseExpr.cpp | 5 +-
clang/lib/Parse/ParseExprCXX.cpp | 22 +++---
clang/lib/Parse/ParseHLSL.cpp | 2 +-
clang/lib/Parse/ParseObjc.cpp | 28 +++----
clang/lib/Parse/ParseOpenACC.cpp | 2 +-
clang/lib/Parse/ParseOpenMP.cpp | 33 ++++----
clang/lib/Parse/ParsePragma.cpp | 4 +-
clang/lib/Parse/ParseStmt.cpp | 37 ++++-----
clang/lib/Parse/ParseTemplate.cpp | 10 +--
clang/lib/Parse/Parser.cpp | 55 +++----------
clang/lib/Sema/Scope.cpp | 33 ++++++++
clang/lib/Sema/Sema.cpp | 32 ++++++++
clang/lib/Sema/SemaDecl.cpp | 2 +-
20 files changed, 240 insertions(+), 231 deletions(-)
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 26ff4246487b8..370e2aa193f9a 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -210,10 +210,6 @@ class Parser : public CodeCompletionHandler {
const Token &getCurToken() const { return Tok; }
Scope *getCurScope() const { return Actions.getCurScope(); }
- void incrementMSManglingNumber() const {
- return Actions.incrementMSManglingNumber();
- }
-
// Type forwarding. All of these are statically 'void*', but they may all be
// different actual classes based on the actions in place.
typedef OpaquePtr<DeclGroupRef> DeclGroupPtrTy;
@@ -384,78 +380,6 @@ class Parser : public CodeCompletionHandler {
return MightBeCXXScopeToken() && TryAnnotateCXXScopeToken(EnteringContext);
}
- //===--------------------------------------------------------------------===//
- // Scope manipulation
-
- /// ParseScope - Introduces a new scope for parsing. The kind of
- /// scope is determined by ScopeFlags. Objects of this type should
- /// be created on the stack to coincide with the position where the
- /// parser enters the new scope, and this object's constructor will
- /// create that new scope. Similarly, once the object is destroyed
- /// the parser will exit the scope.
- class ParseScope {
- Parser *Self;
- ParseScope(const ParseScope &) = delete;
- void operator=(const ParseScope &) = delete;
-
- public:
- // ParseScope - Construct a new object to manage a scope in the
- // parser Self where the new Scope is created with the flags
- // ScopeFlags, but only when we aren't about to enter a compound statement.
- ParseScope(Parser *Self, unsigned ScopeFlags, bool EnteredScope = true,
- bool BeforeCompoundStmt = false)
- : Self(Self) {
- if (EnteredScope && !BeforeCompoundStmt)
- Self->EnterScope(ScopeFlags);
- else {
- if (BeforeCompoundStmt)
- Self->incrementMSManglingNumber();
-
- this->Self = nullptr;
- }
- }
-
- // Exit - Exit the scope associated with this object now, rather
- // than waiting until the object is destroyed.
- void Exit() {
- if (Self) {
- Self->ExitScope();
- Self = nullptr;
- }
- }
-
- ~ParseScope() { Exit(); }
- };
-
- /// Introduces zero or more scopes for parsing. The scopes will all be exited
- /// when the object is destroyed.
- class MultiParseScope {
- Parser &Self;
- unsigned NumScopes = 0;
-
- MultiParseScope(const MultiParseScope &) = delete;
-
- public:
- MultiParseScope(Parser &Self) : Self(Self) {}
- void Enter(unsigned ScopeFlags) {
- Self.EnterScope(ScopeFlags);
- ++NumScopes;
- }
- void Exit() {
- while (NumScopes) {
- Self.ExitScope();
- --NumScopes;
- }
- }
- ~MultiParseScope() { Exit(); }
- };
-
- /// EnterScope - Start a new scope.
- void EnterScope(unsigned ScopeFlags);
-
- /// ExitScope - Pop a scope off the scope stack.
- void ExitScope();
-
//===--------------------------------------------------------------------===//
// Diagnostic Emission and Error recovery.
@@ -546,11 +470,6 @@ class Parser : public CodeCompletionHandler {
StackExhaustionHandler StackHandler;
- /// ScopeCache - Cache scopes to reduce malloc traffic.
- static constexpr int ScopeCacheSize = 16;
- unsigned NumCachedScopes;
- Scope *ScopeCache[ScopeCacheSize];
-
/// Identifiers used for SEH handling in Borland. These are only
/// allowed in particular circumstances
// __except block
@@ -2532,7 +2451,7 @@ class Parser : public CodeCompletionHandler {
assert(SS.isSet() && "C++ scope was not set!");
CreatedScope = true;
- P.EnterScope(0); // Not a decl scope.
+ P.Actions.EnterScope(0); // Not a decl scope.
if (!P.Actions.ActOnCXXEnterDeclaratorScope(P.getCurScope(), SS))
EnteredScope = true;
@@ -2544,7 +2463,7 @@ class Parser : public CodeCompletionHandler {
P.Actions.ActOnCXXExitDeclaratorScope(P.getCurScope(), SS);
}
if (CreatedScope)
- P.ExitScope();
+ P.Actions.ExitScope();
}
};
diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h
index 0d1c0ff6a1e91..01d5471992efa 100644
--- a/clang/include/clang/Sema/Scope.h
+++ b/clang/include/clang/Sema/Scope.h
@@ -29,11 +29,11 @@ class raw_ostream;
} // namespace llvm
namespace clang {
-
class Decl;
class DeclContext;
class UsingDirectiveDecl;
class VarDecl;
+class Sema;
/// Scope - A scope is a transient data structure that is used while parsing the
/// program. It assists with resolving identifiers to the appropriate
@@ -667,6 +667,45 @@ class Scope {
void dump() const;
};
+/// ParseScope - Introduces a new scope for parsing. The kind of
+/// scope is determined by ScopeFlags. Objects of this type should
+/// be created on the stack to coincide with the position where the
+/// parser enters the new scope, and this object's constructor will
+/// create that new scope. Similarly, once the object is destroyed
+/// the parser will exit the scope.
+class ParseScope {
+ Sema *S;
+ ParseScope(const ParseScope &) = delete;
+ void operator=(const ParseScope &) = delete;
+
+public:
+ // ParseScope - Construct a new object to manage a scope in the
+ // parser Self where the new Scope is created with the flags
+ // ScopeFlags, but only when we aren't about to enter a compound statement.
+ ParseScope(Sema &S, unsigned ScopeFlags, bool EnteredScope = true,
+ bool BeforeCompoundStmt = false);
+
+ // Exit - Exit the scope associated with this object now, rather
+ // than waiting until the object is destroyed.
+ void Exit();
+
+ ~ParseScope() { Exit(); }
+};
+
+/// Introduces zero or more scopes for parsing. The scopes will all be exited
+/// when the object is destroyed.
+class MultiParseScope {
+ Sema &S;
+ unsigned NumScopes = 0;
+
+ MultiParseScope(const MultiParseScope &) = delete;
+
+public:
+ MultiParseScope(Sema &S) : S(S) {}
+ void Enter(unsigned ScopeFlags);
+ void Exit();
+ ~MultiParseScope() { Exit(); }
+};
} // namespace clang
#endif // LLVM_CLANG_SEMA_SCOPE_H
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 7e23bb486bdda..3d49dc85da027 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1200,6 +1200,15 @@ class Sema final : public SemaBase {
/// Scope actions.
void ActOnTranslationUnitScope(Scope *S);
+ /// EnterScope - Start a new scope.
+ void EnterScope(unsigned ScopeFlags);
+
+ /// ExitScope - Pop a scope off the scope stack.
+ void ExitScope();
+
+ /// Delete the scope stack and all cached scopes.
+ void FreeScopes();
+
/// Determine whether \param D is function like (function or function
/// template) for parsing.
bool isDeclaratorFunctionLike(Declarator &D);
@@ -1575,10 +1584,12 @@ class Sema final : public SemaBase {
sema::SemaPPCallbacks *SemaPPCallbackHandler;
/// The parser's current scope.
- ///
- /// The parser maintains this state here.
Scope *CurScope;
+ /// ScopeCache - Cache scopes to reduce malloc traffic.
+ static constexpr unsigned MaxScopeCacheSize = 16;
+ SmallVector<std::unique_ptr<Scope>, MaxScopeCacheSize> ScopeCache;
+
mutable IdentifierInfo *Ident_super;
std::unique_ptr<SemaAMDGPU> AMDGPUPtr;
@@ -4218,7 +4229,7 @@ class Sema final : public SemaBase {
TopLevelStmtDecl *ActOnStartTopLevelStmtDecl(Scope *S);
void ActOnFinishTopLevelStmtDecl(TopLevelStmtDecl *D, Stmt *Statement);
- void ActOnPopScope(SourceLocation Loc, Scope *S);
+ void ActOnPopScope(Scope *S);
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
/// no declarator (e.g. "struct foo;") is parsed.
diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp
index bf08911e23533..b2439a518a464 100644
--- a/clang/lib/Interpreter/IncrementalParser.cpp
+++ b/clang/lib/Interpreter/IncrementalParser.cpp
@@ -63,10 +63,10 @@ IncrementalParser::ParseOrWrapTopLevelDecl() {
P->ConsumeAnyToken();
// FIXME: Clang does not call ExitScope on finalizing the regular TU, we
// might want to do that around HandleEndOfTranslationUnit.
- P->ExitScope();
+ S.ExitScope();
S.CurContext = nullptr;
// Start a new PTU.
- P->EnterScope(Scope::DeclScope);
+ S.EnterScope(Scope::DeclScope);
S.ActOnTranslationUnitScope(P->getCurScope());
}
diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp
index 74e25002e468b..90e274ed51c89 100644
--- a/clang/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp
@@ -328,7 +328,8 @@ struct Parser::ReenterTemplateScopeRAII {
TemplateParameterDepthRAII CurTemplateDepthTracker;
ReenterTemplateScopeRAII(Parser &P, Decl *MaybeTemplated, bool Enter = true)
- : P(P), Scopes(P), CurTemplateDepthTracker(P.TemplateParameterDepth) {
+ : P(P), Scopes(P.Actions),
+ CurTemplateDepthTracker(P.TemplateParameterDepth) {
if (Enter) {
CurTemplateDepthTracker.addDepth(
P.ReenterTemplateScopes(Scopes, MaybeTemplated));
@@ -510,7 +511,7 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
// };
// Setup the CurScope to match the function DeclContext - we have such
// assumption in IsInFnTryBlockHandler().
- ParseScope FnScope(this, Scope::FnScope);
+ ParseScope FnScope(Actions, Scope::FnScope);
Sema::ContextRAII FnContext(Actions, FunctionToPush,
/*NewThisContext=*/false);
Sema::FunctionScopeRAII PopFnContext(Actions);
@@ -597,8 +598,8 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
// Parse the method body. Function body parsing code is similar enough
// to be re-used for method bodies as well.
- ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope);
+ ParseScope FnScope(Actions, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);
Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D);
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 5e1ff2be28f38..ecf1cba8cff6f 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -677,9 +677,9 @@ void Parser::ParseGNUAttributeArgs(
if (normalizeAttrName(AttrName->getName()) == "enable_if" &&
D && D->isFunctionDeclarator()) {
const DeclaratorChunk::FunctionTypeInfo& FTI = D->getFunctionTypeInfo();
- PrototypeScope.emplace(this, Scope::FunctionPrototypeScope |
- Scope::FunctionDeclarationScope |
- Scope::DeclScope);
+ PrototypeScope.emplace(Actions, Scope::FunctionPrototypeScope |
+ Scope::FunctionDeclarationScope |
+ Scope::DeclScope);
for (unsigned i = 0; i != FTI.NumParams; ++i) {
ParmVarDecl *Param = cast<ParmVarDecl>(FTI.Params[i].Param);
Actions.ActOnReenterCXXMethodParameter(getCurScope(), Param);
@@ -2454,7 +2454,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
if (ThisDecl && P.getLangOpts().CPlusPlus) {
Scope *S = nullptr;
if (D.getCXXScopeSpec().isSet()) {
- P.EnterScope(0);
+ P.Actions.EnterScope(0);
S = P.getCurScope();
}
if (ThisDecl && !ThisDecl->isInvalidDecl()) {
@@ -2472,7 +2472,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(
if (Entered)
P.Actions.ActOnCXXExitDeclInitializer(S, ThisDecl);
if (S)
- P.ExitScope();
+ P.Actions.ExitScope();
}
ThisDecl = nullptr;
}
@@ -4826,7 +4826,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
if (T.consumeOpen())
return;
- ParseScope StructScope(this, Scope::ClassScope|Scope::DeclScope);
+ ParseScope StructScope(Actions, Scope::ClassScope|Scope::DeclScope);
Actions.ActOnTagStartDefinition(getCurScope(), TagDecl);
// `LateAttrParseExperimentalExtOnly=true` requests that only attributes
@@ -5338,7 +5338,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl,
SkipBodyInfo *SkipBody) {
// Enter the scope of the enum body and start the definition.
- ParseScope EnumScope(this, Scope::DeclScope | Scope::EnumScope);
+ ParseScope EnumScope(Actions, Scope::DeclScope | Scope::EnumScope);
Actions.ActOnTagStartDefinition(getCurScope(), EnumDecl);
BalancedDelimiterTracker T(*this, tok::l_brace);
@@ -5681,8 +5681,8 @@ Parser::DeclGroupPtrTy Parser::ParseTopLevelStmtDecl() {
// Parse a top-level-stmt.
Parser::StmtVector Stmts;
ParsedStmtContext SubStmtCtx = ParsedStmtContext();
- ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope);
+ ParseScope FnScope(Actions, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
TopLevelStmtDecl *TLSD = Actions.ActOnStartTopLevelStmtDecl(getCurScope());
StmtResult R = ParseStatementOrDeclaration(Stmts, SubStmtCtx);
Actions.ActOnFinishTopLevelStmtDecl(TLSD, R.get());
@@ -6804,9 +6804,9 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
// Enter function-declaration scope, limiting any declarators to the
// function prototype scope, including parameter declarators.
ParseScope PrototypeScope(
- this, Scope::FunctionPrototypeScope | Scope::DeclScope |
- (IsFunctionDeclaration ? Scope::FunctionDeclarationScope
- : Scope::NoScope));
+ Actions, Scope::FunctionPrototypeScope | Scope::DeclScope |
+ (IsFunctionDeclaration ? Scope::FunctionDeclarationScope
+ : Scope::NoScope));
// The paren may be part of a C++ direct initializer, eg. "int x(1);".
// In such a case, check if we actually have a function declarator; if it
@@ -7085,7 +7085,7 @@ void Parser::ParseParenDeclarator(Declarator &D) {
// Enter function-declaration scope, limiting any declarators to the
// function prototype scope, including parameter declarators.
- ParseScope PrototypeScope(this,
+ ParseScope PrototypeScope(Actions,
Scope::FunctionPrototypeScope | Scope::DeclScope |
(D.isFunctionDeclaratorAFunctionDeclaration()
? Scope::FunctionDeclarationScope
@@ -8126,7 +8126,7 @@ TypeResult Parser::ParseTypeFromString(StringRef TypeStr, StringRef Context,
ConsumeAnyToken();
// Enter a new scope.
- ParseScope LocalScope(this, 0);
+ ParseScope LocalScope(Actions, 0);
// Parse the type.
TypeResult Result = ParseTypeName(nullptr);
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index d8ed7e3ff96bd..fc7b4d2eb92bf 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -199,7 +199,7 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context,
: diag::ext_inline_namespace);
// Enter a scope for the namespace.
- ParseScope NamespaceScope(this, Scope::DeclScope);
+ ParseScope NamespaceScope(Actions, Scope::DeclScope);
UsingDirectiveDecl *ImplicitUsingDirectiveDecl = nullptr;
Decl *NamespcDecl = Actions.ActOnStartNamespaceDef(
@@ -246,7 +246,7 @@ void Parser::ParseInnerNamespace(const InnerNamespaceInfoList &InnerNSs,
// Handle a nested namespace definition.
// FIXME: Preserve the source information through to the AST rather than
// desugaring it here.
- ParseScope NamespaceScope(this, Scope::DeclScope);
+ ParseScope NamespaceScope(Actions, Scope::DeclScope);
UsingDirectiveDecl *ImplicitUsingDirectiveDecl = nullptr;
Decl *NamespcDecl = Actions.ActOnStartNamespaceDef(
getCurScope(), InnerNSs[index].InlineLoc, InnerNSs[index].NamespaceLoc,
@@ -316,7 +316,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) {
assert(isTokenStringLiteral() && "Not a string literal!");
ExprResult Lang = ParseUnevaluatedStringLiteralExpression();
- ParseScope LinkageScope(this, Scope::DeclScope);
+ ParseScope LinkageScope(Actions, Scope::DeclScope);
Decl *LinkageSpec =
Lang.isInvalid()
? nullptr
@@ -409,7 +409,7 @@ Decl *Parser::ParseExportDeclaration() {
return nullptr;
}
- ParseScope ExportScope(this, Scope::DeclScope);
+ ParseScope ExportScope(Actions, Scope::DeclScope);
Decl *ExportDecl = Actions.ActOnStartExportDecl(
getCurScope(), ExportLoc,
Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation());
@@ -3385,7 +3385,7 @@ void Parser::SkipCXXMemberSpecification(SourceLocation RecordLoc,
// within a template argument).
if (Tok.is(tok::colon)) {
// Enter the scope of the class so that we can correctly parse its bases.
- ParseScope ClassScope(this, Scope::ClassScope | Scope::DeclScope);
+ ParseScope ClassScope(Actions, Scope::ClassScope | Scope::DeclScope);
ParsingClassDefinition ParsingDef(*this, TagDecl, /*NonNestedClass*/ true,
TagType == DeclSpec::TST_interface);
auto OldContext =
@@ -3573,7 +3573,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
}
// Enter a scope for the class.
- ParseScope ClassScope(this, Scope::ClassScope | Scope::DeclScope);
+ ParseScope ClassScope(Actions, Scope::ClassScope | Scope::DeclScope);
// Note that we are parsing a new (potentially-nested) class definition.
ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass,
@@ -3678,8 +3678,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
}
if (Tok.is(tok::colon)) {
- ParseScope InheritanceScope(this, getCurScope()->getFlags() |
- Scope::ClassInheritanceScope);
+ ParseScope InheritanceScope(Actions, getCurScope()->getFlags() |
+ Scope::ClassInheritanceScope);
ParseBaseClause(TagDecl);
if (!Tok.is(tok::l_brace)) {
@@ -4192,9 +4192,9 @@ void Parser::ParseTrailingRequiresClause(Declarator &D) {
DeclScopeObj.EnterDeclaratorScope();
ExprResult TrailingRequiresClause;
- ParseScope ParamScope(this, Scope::DeclScope |
- Scope::FunctionDeclarationScope |
- Scope::FunctionPrototypeScope);
+ ParseScope ParamScope(Actions, Scope::DeclScope |
+ Scope::FunctionDeclarationScope |
+ Scope::FunctionPrototypeScope);
Actions.ActOnStartTrailingRequiresClause(getCurScope(), D);
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index ea3b1749717d2..1f26f886aa702 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -3275,8 +3275,9 @@ ExprResult Parser::ParseBlockLiteralExpression() {
// argument decls, decls within the compound expression, etc. This also
// allows determining whether a variable reference inside the block is
// within or outside of the block.
- ParseScope BlockScope(this, Scope::BlockScope | Scope::FnScope |
- Scope::CompoundStmtScope | Scope::DeclScope);
+ ParseScope BlockScope(Actions, Scope::BlockScope | Scope::FnScope |
+ Scope::CompoundStmtScope |
+ Scope::DeclScope);
// Inform sema that we are starting a block.
Actions.ActOnBlockStart(CaretLoc, getCurScope());
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 7a5d28caf8521..73abf2733be01 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -1219,9 +1219,9 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
Declarator D(DS, ParsedAttributesView::none(), DeclaratorContext::LambdaExpr);
TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth);
- ParseScope LambdaScope(this, Scope::LambdaScope | Scope::DeclScope |
- Scope::FunctionDeclarationScope |
- Scope::FunctionPrototypeScope);
+ ParseScope LambdaScope(Actions, Scope::LambdaScope | Scope::DeclScope |
+ Scope::FunctionDeclarationScope |
+ Scope::FunctionPrototypeScope);
Actions.PushLambdaScope();
Actions.ActOnLambdaExpressionAfterIntroducer(Intro, getCurScope());
@@ -1249,7 +1249,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
D.takeAttributesAppending(Attributes);
}
- MultiParseScope TemplateParamScope(*this);
+ MultiParseScope TemplateParamScope(Actions);
if (Tok.is(tok::less)) {
Diag(Tok, getLangOpts().CPlusPlus20
? diag::warn_cxx17_compat_lambda_template_parameter_list
@@ -1313,9 +1313,9 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
bool HasSpecifiers = false;
SourceLocation MutableLoc;
- ParseScope Prototype(this, Scope::FunctionPrototypeScope |
- Scope::FunctionDeclarationScope |
- Scope::DeclScope);
+ ParseScope Prototype(Actions, Scope::FunctionPrototypeScope |
+ Scope::FunctionDeclarationScope |
+ Scope::DeclScope);
// Parse parameter-declaration-clause.
SmallVector<DeclaratorChunk::ParamInfo, 16> ParamInfo;
@@ -1469,7 +1469,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
// it.
unsigned ScopeFlags = Scope::BlockScope | Scope::FnScope | Scope::DeclScope |
Scope::CompoundStmtScope;
- ParseScope BodyScope(this, ScopeFlags);
+ ParseScope BodyScope(Actions, ScopeFlags);
Actions.ActOnStartOfLambdaDefinition(Intro, D, DS);
@@ -3139,8 +3139,8 @@ ExprResult Parser::ParseRequiresExpression() {
BalancedDelimiterTracker Parens(*this, tok::l_paren);
if (Tok.is(tok::l_paren)) {
// requirement parameter list is present.
- ParseScope LocalParametersScope(this, Scope::FunctionPrototypeScope |
- Scope::DeclScope);
+ ParseScope LocalParametersScope(Actions, Scope::FunctionPrototypeScope |
+ Scope::DeclScope);
Parens.consumeOpen();
if (!Tok.is(tok::r_paren)) {
ParsedAttributes FirstArgAttrs(getAttrFactory());
@@ -3169,7 +3169,7 @@ ExprResult Parser::ParseRequiresExpression() {
EnterExpressionEvaluationContext Ctx(
Actions, Sema::ExpressionEvaluationContext::Unevaluated);
- ParseScope BodyScope(this, Scope::DeclScope);
+ ParseScope BodyScope(Actions, Scope::DeclScope);
// Create a separate diagnostic pool for RequiresExprBodyDecl.
// Dependent diagnostics are attached to this Decl and non-depenedent
// diagnostics are surfaced after this parse.
diff --git a/clang/lib/Parse/ParseHLSL.cpp b/clang/lib/Parse/ParseHLSL.cpp
index c727ee3a1f1a6..f1fc21bee25a6 100644
--- a/clang/lib/Parse/ParseHLSL.cpp
+++ b/clang/lib/Parse/ParseHLSL.cpp
@@ -65,7 +65,7 @@ Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd,
MaybeParseHLSLAnnotations(Attrs, nullptr);
- ParseScope BufferScope(this, Scope::DeclScope);
+ ParseScope BufferScope(Actions, Scope::DeclScope);
BalancedDelimiterTracker T(*this, tok::l_brace);
if (T.consumeOpen()) {
Diag(Tok, diag::err_expected) << tok::l_brace;
diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp
index 0b9f113d9edc7..27f5a6a54613f 100644
--- a/clang/lib/Parse/ParseObjc.cpp
+++ b/clang/lib/Parse/ParseObjc.cpp
@@ -1224,8 +1224,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
SmallVector<const IdentifierInfo *, 12> KeyIdents;
SmallVector<SourceLocation, 12> KeyLocs;
SmallVector<SemaObjC::ObjCArgInfo, 12> ArgInfos;
- ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
- Scope::FunctionDeclarationScope | Scope::DeclScope);
+ ParseScope PrototypeScope(Actions, Scope::FunctionPrototypeScope |
+ Scope::FunctionDeclarationScope |
+ Scope::DeclScope);
AttributePool allParamAttrs(AttrFactory);
while (true) {
@@ -1701,7 +1702,7 @@ void Parser::ParseObjCClassInstanceVariables(ObjCContainerDecl *interfaceDecl,
assert(Tok.is(tok::l_brace) && "expected {");
SmallVector<Decl *, 32> AllIvarDecls;
- ParseScope ClassScope(this, Scope::DeclScope | Scope::ClassScope);
+ ParseScope ClassScope(Actions, Scope::DeclScope | Scope::ClassScope);
BalancedDelimiterTracker T(*this, tok::l_brace);
T.consumeOpen();
@@ -2237,7 +2238,7 @@ Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
Actions.ObjC().ActOnObjCAtSynchronizedOperand(atLoc, operand.get());
// Parse the compound statement within a new scope.
- ParseScope bodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
+ ParseScope bodyScope(Actions, Scope::DeclScope | Scope::CompoundStmtScope);
StmtResult body(ParseCompoundStatementBody());
bodyScope.Exit();
@@ -2263,7 +2264,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
}
StmtVector CatchStmts;
StmtResult FinallyStmt;
- ParseScope TryScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
+ ParseScope TryScope(Actions, Scope::DeclScope | Scope::CompoundStmtScope);
StmtResult TryBody(ParseCompoundStatementBody());
TryScope.Exit();
if (TryBody.isInvalid())
@@ -2284,9 +2285,9 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
ConsumeToken(); // consume catch
if (Tok.is(tok::l_paren)) {
ConsumeParen();
- ParseScope CatchScope(this, Scope::DeclScope |
- Scope::CompoundStmtScope |
- Scope::AtCatchScope);
+ ParseScope CatchScope(Actions, Scope::DeclScope |
+ Scope::CompoundStmtScope |
+ Scope::AtCatchScope);
if (Tok.isNot(tok::ellipsis)) {
DeclSpec DS(AttrFactory);
ParsedTemplateInfo TemplateInfo;
@@ -2331,7 +2332,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
} else {
assert(Tok.isObjCAtKeyword(tok::objc_finally) && "Lookahead confused?");
ConsumeToken(); // consume finally
- ParseScope FinallyScope(this,
+ ParseScope FinallyScope(Actions,
Scope::DeclScope | Scope::CompoundStmtScope);
bool ShouldCapture =
@@ -2378,7 +2379,7 @@ Parser::ParseObjCAutoreleasePoolStmt(SourceLocation atLoc) {
}
// Enter a scope to hold everything within the compound stmt. Compound
// statements can always hold declarations.
- ParseScope BodyScope(this, Scope::DeclScope | Scope::CompoundStmtScope);
+ ParseScope BodyScope(Actions, Scope::DeclScope | Scope::CompoundStmtScope);
StmtResult AutoreleasePoolBody(ParseCompoundStatementBody());
@@ -3295,9 +3296,10 @@ void Parser::ParseLexedObjCMethodDefs(LexedMethod &LM, bool parseMethod) {
assert(Tok.isOneOf(tok::l_brace, tok::kw_try, tok::colon) &&
"Inline objective-c method not starting with '{' or 'try' or ':'");
// Enter a scope for the method or c-function body.
- ParseScope BodyScope(
- this, (parseMethod ? Scope::ObjCMethodScope : Scope::NoScope) |
- Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope);
+ ParseScope BodyScope(Actions,
+ (parseMethod ? Scope::ObjCMethodScope : Scope::NoScope) |
+ Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
Sema::FPFeaturesStateRAII SaveFPFeatures(Actions);
// Tell the actions module that we have entered a method or c-function definition
diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp
index b79a956d51505..78418ee0a8b2e 100644
--- a/clang/lib/Parse/ParseOpenACC.cpp
+++ b/clang/lib/Parse/ParseOpenACC.cpp
@@ -1682,7 +1682,7 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() {
getActions().OpenACC(), DirInfo.DirKind, DirInfo.DirLoc, {},
DirInfo.Clauses);
ParsingOpenACCDirectiveRAII DirScope(*this, /*Value=*/false);
- ParseScope ACCScope(this, getOpenACCScopeFlags(DirInfo.DirKind));
+ ParseScope ACCScope(Actions, getOpenACCScopeFlags(DirInfo.DirKind));
AssocStmt = getActions().OpenACC().ActOnAssociatedStmt(
DirInfo.StartLoc, DirInfo.DirKind, DirInfo.AtomicKind, DirInfo.Clauses,
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 15c3f7594bf44..7ae792fa8b461 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -246,9 +246,9 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {
unsigned I = 0, E = ReductionTypes.size();
for (Decl *D : DRD.get()) {
TentativeParsingAction TPA(*this);
- ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope |
- Scope::OpenMPDirectiveScope);
+ ParseScope OMPDRScope(Actions, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope |
+ Scope::OpenMPDirectiveScope);
// Parse <combiner> expression.
Actions.OpenMP().ActOnOpenMPDeclareReductionCombinerStart(getCurScope(), D);
ExprResult CombinerResult = Actions.ActOnFinishFullExpr(
@@ -282,9 +282,9 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {
!T.expectAndConsume(diag::err_expected_lparen_after, "initializer") &&
IsCorrect;
if (Tok.isNot(tok::annot_pragma_openmp_end)) {
- ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope |
- Scope::OpenMPDirectiveScope);
+ ParseScope OMPDRScope(Actions, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope |
+ Scope::OpenMPDirectiveScope);
// Parse expression.
VarDecl *OmpPrivParm =
Actions.OpenMP().ActOnOpenMPDeclareReductionInitializerStart(
@@ -463,7 +463,7 @@ Parser::ParseOpenMPDeclareMapperDirective(AccessSpecifier AS) {
SourceLocation Loc = Tok.getLocation();
unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |
Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope;
- ParseScope OMPDirectiveScope(this, ScopeFlags);
+ ParseScope OMPDirectiveScope(Actions, ScopeFlags);
Actions.OpenMP().StartOpenMPDSABlock(OMPD_declare_mapper, DirName,
getCurScope(), Loc);
@@ -611,14 +611,15 @@ namespace {
class FNContextRAII final {
Parser &P;
Sema::CXXThisScopeRAII *ThisScope;
- Parser::MultiParseScope Scopes;
+ MultiParseScope Scopes;
bool HasFunScope = false;
FNContextRAII() = delete;
FNContextRAII(const FNContextRAII &) = delete;
FNContextRAII &operator=(const FNContextRAII &) = delete;
public:
- FNContextRAII(Parser &P, Parser::DeclGroupPtrTy Ptr) : P(P), Scopes(P) {
+ FNContextRAII(Parser &P, Parser::DeclGroupPtrTy Ptr)
+ : P(P), Scopes(P.getActions()) {
Decl *D = *Ptr.get().begin();
NamedDecl *ND = dyn_cast<NamedDecl>(D);
RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext());
@@ -2332,7 +2333,7 @@ StmtResult Parser::ParseOpenMPExecutableDirective(
ScopeFlags |= Scope::OpenMPLoopDirectiveScope;
if (isOpenMPSimdDirective(DKind))
ScopeFlags |= Scope::OpenMPSimdDirectiveScope;
- ParseScope OMPDirectiveScope(this, ScopeFlags);
+ ParseScope OMPDirectiveScope(Actions, ScopeFlags);
Actions.OpenMP().StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(),
Loc);
@@ -2459,7 +2460,7 @@ StmtResult Parser::ParseOpenMPInformationalDirective(
DeclarationNameInfo DirName;
unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |
Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope;
- ParseScope OMPDirectiveScope(this, ScopeFlags);
+ ParseScope OMPDirectiveScope(Actions, ScopeFlags);
Actions.OpenMP().StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(),
Loc);
@@ -4748,7 +4749,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
// where iterator-specifier is [ iterator-type ] identifier =
// range-specification
HasIterator = true;
- EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);
+ Actions.EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);
ExprResult IteratorRes = ParseOpenMPIteratorsExpr();
Data.DepModOrTailExpr = IteratorRes.get();
// Parse ','
@@ -4861,7 +4862,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
// Handle optional iterator map modifier.
if (Tok.is(tok::identifier) && PP.getSpelling(Tok) == "iterator") {
HasIterator = true;
- EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);
+ Actions.EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);
Data.MapTypeModifiers.push_back(OMPC_MAP_MODIFIER_iterator);
Data.MapTypeModifiersLoc.push_back(Tok.getLocation());
ExprResult IteratorRes = ParseOpenMPIteratorsExpr();
@@ -4978,7 +4979,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
Tail = parseOpenMPAllocateClauseModifiers(*this, Kind, Data);
} else {
HasIterator = true;
- EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);
+ Actions.EnterScope(Scope::OpenMPDirectiveScope | Scope::DeclScope);
Tail = ParseOpenMPIteratorsExpr();
}
Tail = Actions.ActOnFinishFullExpr(Tail.get(), T.getOpenLocation(),
@@ -5068,7 +5069,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned);
while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) &&
Tok.isNot(tok::annot_pragma_openmp_end))) {
- ParseScope OMPListScope(this, Scope::OpenMPDirectiveScope);
+ ParseScope OMPListScope(Actions, Scope::OpenMPDirectiveScope);
ColonProtectionRAIIObject ColonRAII(*this, MayHaveTail);
if (!ParseOpenMPReservedLocator(Kind, Data, getLangOpts())) {
// Parse variable
@@ -5183,7 +5184,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind,
Data.RLoc = T.getCloseLocation();
// Exit from scope when the iterator is used in depend clause.
if (HasIterator)
- ExitScope();
+ Actions.ExitScope();
return (Kind != OMPC_depend && Kind != OMPC_doacross && Kind != OMPC_map &&
Vars.empty()) ||
(MustHaveTail && !Data.DepModOrTailExpr && StepFound) ||
diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp
index 7c2b9280f0b76..487d38a9e9e6a 100644
--- a/clang/lib/Parse/ParsePragma.cpp
+++ b/clang/lib/Parse/ParsePragma.cpp
@@ -934,8 +934,8 @@ StmtResult Parser::HandlePragmaCaptured()
SourceLocation Loc = Tok.getLocation();
- ParseScope CapturedRegionScope(this, Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope);
+ ParseScope CapturedRegionScope(Actions, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_Default,
/*NumParams=*/1);
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 0c652fc3c16f3..59eac05e8f39e 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -645,8 +645,8 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) {
if (ExpectAndConsume(tok::l_paren))
return StmtError();
- ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope |
- Scope::SEHExceptScope);
+ ParseScope ExpectScope(Actions, Scope::DeclScope | Scope::ControlScope |
+ Scope::SEHExceptScope);
if (getLangOpts().Borland) {
Ident__exception_info->setIsPoisoned(false);
@@ -692,7 +692,7 @@ StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyLoc) {
if (Tok.isNot(tok::l_brace))
return StmtError(Diag(Tok, diag::err_expected) << tok::l_brace);
- ParseScope FinallyScope(this, 0);
+ ParseScope FinallyScope(Actions, 0);
Actions.ActOnStartSEHFinallyBlock();
StmtResult Block(ParseCompoundStatement());
@@ -1003,7 +1003,7 @@ StmtResult Parser::ParseCompoundStatement(bool isStmtExpr,
// Enter a scope to hold everything within the compound stmt. Compound
// statements can always hold declarations.
- ParseScope CompoundScope(this, ScopeFlags);
+ ParseScope CompoundScope(Actions, ScopeFlags);
// Parse the statements in the body.
StmtResult R;
@@ -1494,7 +1494,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
// while, for, and switch statements are local to the if, while, for, or
// switch statement (including the controlled statement).
//
- ParseScope IfScope(this, Scope::DeclScope | Scope::ControlScope, C99orCXX);
+ ParseScope IfScope(Actions, Scope::DeclScope | Scope::ControlScope, C99orCXX);
// Parse the condition.
StmtResult InitStmt;
@@ -1534,7 +1534,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
// would have to notify ParseStatement not to create a new scope. It's
// simpler to let it create a new scope.
//
- ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, IsBracedThen);
+ ParseScope InnerScope(Actions, Scope::DeclScope, C99orCXX, IsBracedThen);
MisleadingIndentationChecker MIChecker(*this, MSK_if, IfLoc);
@@ -1585,7 +1585,7 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) {
// The substatement in a selection-statement (each substatement, in the else
// form of the if statement) implicitly defines a local scope.
//
- ParseScope InnerScope(this, Scope::DeclScope, C99orCXX,
+ ParseScope InnerScope(Actions, Scope::DeclScope, C99orCXX,
Tok.is(tok::l_brace));
MisleadingIndentationChecker MIChecker(*this, MSK_else, ElseLoc);
@@ -1691,7 +1691,7 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc,
unsigned ScopeFlags = Scope::SwitchScope;
if (C99orCXX)
ScopeFlags |= Scope::DeclScope | Scope::ControlScope;
- ParseScope SwitchScope(this, ScopeFlags);
+ ParseScope SwitchScope(Actions, ScopeFlags);
// Parse the condition.
StmtResult InitStmt;
@@ -1731,7 +1731,8 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc,
//
getCurScope()->AddFlags(Scope::BreakScope);
getCurScope()->setPrecedingLabel(PrecedingLabel);
- ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
+ ParseScope InnerScope(Actions, Scope::DeclScope, C99orCXX,
+ Tok.is(tok::l_brace));
// We have incremented the mangling number for the SwitchScope and the
// InnerScope, which is one too many.
@@ -1780,7 +1781,7 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc,
Scope::DeclScope | Scope::ControlScope;
else
ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
- ParseScope WhileScope(this, ScopeFlags);
+ ParseScope WhileScope(Actions, ScopeFlags);
// Parse the condition.
Sema::ConditionResult Cond;
@@ -1807,7 +1808,8 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc,
// See comments in ParseIfStatement for why we create a scope for the
// condition and a new scope for substatement in C++.
//
- ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
+ ParseScope InnerScope(Actions, Scope::DeclScope, C99orCXX,
+ Tok.is(tok::l_brace));
MisleadingIndentationChecker MIChecker(*this, MSK_while, WhileLoc);
@@ -1838,7 +1840,7 @@ StmtResult Parser::ParseDoStatement(LabelDecl *PrecedingLabel) {
else
ScopeFlags = Scope::BreakScope | Scope::ContinueScope;
- ParseScope DoScope(this, ScopeFlags);
+ ParseScope DoScope(Actions, ScopeFlags);
// OpenACC Restricts a do-while-loop inside of certain construct/clause
// combinations, so diagnose that here in OpenACC mode.
@@ -1855,7 +1857,8 @@ StmtResult Parser::ParseDoStatement(LabelDecl *PrecedingLabel) {
// which is entered and exited each time through the loop.
//
bool C99orCXX = getLangOpts().C99 || getLangOpts().CPlusPlus;
- ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace));
+ ParseScope InnerScope(Actions, Scope::DeclScope, C99orCXX,
+ Tok.is(tok::l_brace));
// Read the body statement.
StmtResult Body(ParseStatement());
@@ -2013,7 +2016,7 @@ Parser::ParseForStatement(SourceLocation *TrailingElseLoc,
if (CXXExpansionStmtDecl)
ScopeFlags |= Scope::TemplateParamScope;
- ParseScope ForScope(this, ScopeFlags);
+ ParseScope ForScope(Actions, ScopeFlags);
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
@@ -2333,7 +2336,7 @@ Parser::ParseForStatement(SourceLocation *TrailingElseLoc,
// See comments in ParseIfStatement for why we create a scope for
// for-init-statement/condition and a new scope for substatement in C++.
//
- ParseScope InnerScope(this, Scope::DeclScope, C99orCXXorObjC,
+ ParseScope InnerScope(Actions, Scope::DeclScope, C99orCXXorObjC,
Tok.is(tok::l_brace));
// The body of the for loop has the same local mangling number as the
@@ -2698,8 +2701,8 @@ StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) {
// The name in a catch exception-declaration is local to the handler and
// shall not be redeclared in the outermost block of the handler.
ParseScope CatchScope(
- this, Scope::DeclScope | Scope::ControlScope | Scope::CatchScope |
- (FnCatch ? Scope::FnTryCatchScope : Scope::NoScope));
+ Actions, Scope::DeclScope | Scope::ControlScope | Scope::CatchScope |
+ (FnCatch ? Scope::FnTryCatchScope : Scope::NoScope));
// exception-declaration is equivalent to '...' or a parameter-declaration
// without default arguments.
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index 330a9c6aea0c5..78a4892f3b47e 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -50,7 +50,7 @@ Parser::DeclGroupPtrTy Parser::ParseTemplateDeclarationOrSpecialization(
assert(Tok.isOneOf(tok::kw_export, tok::kw_template) &&
"Token does not start a template declaration.");
- MultiParseScope TemplateParamScopes(*this);
+ MultiParseScope TemplateParamScopes(Actions);
// Tell the action that names should be checked in the context of
// the declaration to come.
@@ -700,7 +700,7 @@ NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth,
SourceLocation LAngleLoc, RAngleLoc;
ExprResult OptionalRequiresClauseConstraintER;
{
- MultiParseScope TemplateParmScope(*this);
+ MultiParseScope TemplateParmScope(Actions);
if (ParseTemplateParameters(TemplateParmScope, Depth + 1, TemplateParams,
LAngleLoc, RAngleLoc)) {
return nullptr;
@@ -1456,7 +1456,7 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
Sema::ContextRAII GlobalSavedContext(
Actions, Actions.Context.getTranslationUnitDecl());
- MultiParseScope Scopes(*this);
+ MultiParseScope Scopes(Actions);
// Get the list of DeclContexts to reenter.
SmallVector<DeclContext*, 4> DeclContextsToReenter;
@@ -1493,8 +1493,8 @@ void Parser::ParseLateTemplatedFuncDef(LateParsedTemplate &LPT) {
// Parse the method body. Function body parsing code is similar enough
// to be re-used for method bodies as well.
- ParseScope FnScope(this, Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope);
+ ParseScope FnScope(Actions, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
// Recreate the containing function DeclContext.
Sema::ContextRAII FunctionSavedContext(Actions, FunD->getLexicalParent());
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 7b425dd3dda43..af9e1ad157702 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -64,7 +64,6 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
Tok.startToken();
Tok.setKind(tok::eof);
Actions.CurScope = nullptr;
- NumCachedScopes = 0;
CurParsedObjCImpl = nullptr;
// Add #pragma handlers. These are removed and destroyed in the
@@ -416,33 +415,6 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) {
//===----------------------------------------------------------------------===//
// Scope manipulation
//===----------------------------------------------------------------------===//
-
-void Parser::EnterScope(unsigned ScopeFlags) {
- if (NumCachedScopes) {
- Scope *N = ScopeCache[--NumCachedScopes];
- N->Init(getCurScope(), ScopeFlags);
- Actions.CurScope = N;
- } else {
- Actions.CurScope = new Scope(getCurScope(), ScopeFlags, Diags);
- }
-}
-
-void Parser::ExitScope() {
- assert(getCurScope() && "Scope imbalance!");
-
- // Inform the actions module that this scope is going away if there are any
- // decls in it.
- Actions.ActOnPopScope(Tok.getLocation(), getCurScope());
-
- Scope *OldScope = getCurScope();
- Actions.CurScope = OldScope->getParent();
-
- if (NumCachedScopes == ScopeCacheSize)
- delete OldScope;
- else
- ScopeCache[NumCachedScopes++] = OldScope;
-}
-
Parser::ParseScopeFlags::ParseScopeFlags(Parser *Self, unsigned ScopeFlags,
bool ManageFlags)
: CurScope(ManageFlags ? Self->getCurScope() : nullptr) {
@@ -463,13 +435,7 @@ Parser::ParseScopeFlags::~ParseScopeFlags() {
//===----------------------------------------------------------------------===//
Parser::~Parser() {
- // If we still have scopes active, delete the scope tree.
- delete getCurScope();
- Actions.CurScope = nullptr;
-
- // Free the scope cache.
- for (unsigned i = 0, e = NumCachedScopes; i != e; ++i)
- delete ScopeCache[i];
+ Actions.FreeScopes();
resetPragmaHandlers();
@@ -483,7 +449,7 @@ Parser::~Parser() {
void Parser::Initialize() {
// Create the translation unit scope. Install it as the current scope.
assert(getCurScope() == nullptr && "A scope is already active?");
- EnterScope(Scope::DeclScope);
+ Actions.EnterScope(Scope::DeclScope);
Actions.ActOnTranslationUnitScope(getCurScope());
// Initialization for Objective-C context sensitive keywords recognition.
@@ -1270,8 +1236,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
LateParsedAttrs->empty() && Actions.canDelayFunctionBody(D)) {
MultiTemplateParamsArg TemplateParameterLists(*TemplateInfo.TemplateParams);
- ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope);
+ ParseScope BodyScope(Actions, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
Scope *ParentScope = getCurScope()->getParent();
D.setFunctionDefinitionKind(FunctionDefinitionKind::Definition);
@@ -1299,8 +1265,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
if (CurParsedObjCImpl && !TemplateInfo.TemplateParams &&
(Tok.is(tok::l_brace) || Tok.is(tok::kw_try) || Tok.is(tok::colon)) &&
Actions.CurContext->isTranslationUnit()) {
- ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope);
+ ParseScope BodyScope(Actions, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
Scope *ParentScope = getCurScope()->getParent();
D.setFunctionDefinitionKind(FunctionDefinitionKind::Definition);
@@ -1318,8 +1284,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
}
// Enter a scope for the function body.
- ParseScope BodyScope(this, Scope::FnScope | Scope::DeclScope |
- Scope::CompoundStmtScope);
+ ParseScope BodyScope(Actions, Scope::FnScope | Scope::DeclScope |
+ Scope::CompoundStmtScope);
// Parse function body eagerly if it is either '= delete;' or '= default;' as
// ActOnStartOfFunctionDef needs to know whether the function is deleted.
@@ -1471,8 +1437,9 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) {
// Enter function-declaration scope, limiting any declarators to the
// function prototype scope, including parameter declarators.
- ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope |
- Scope::FunctionDeclarationScope | Scope::DeclScope);
+ ParseScope PrototypeScope(Actions, Scope::FunctionPrototypeScope |
+ Scope::FunctionDeclarationScope |
+ Scope::DeclScope);
// Read all the argument declarations.
while (isDeclarationSpecifier(ImplicitTypenameContext::No)) {
diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp
index e66cce255230b..79938b5db5b52 100644
--- a/clang/lib/Sema/Scope.cpp
+++ b/clang/lib/Sema/Scope.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/Scope.h"
+#include "clang/Sema/Sema.h"
#include "clang/AST/Decl.h"
#include "llvm/Support/raw_ostream.h"
@@ -268,3 +269,35 @@ void Scope::dumpImpl(raw_ostream &OS) const {
else
OS << "NRVO is not allowed\n";
}
+
+ParseScope::ParseScope(Sema &S, unsigned ScopeFlags, bool EnteredScope,
+ bool BeforeCompoundStmt)
+ : S(&S) {
+ if (EnteredScope && !BeforeCompoundStmt)
+ S.EnterScope(ScopeFlags);
+ else {
+ if (BeforeCompoundStmt)
+ S.incrementMSManglingNumber();
+
+ this->S = nullptr;
+ }
+}
+
+void ParseScope::Exit() {
+ if (S) {
+ S->ExitScope();
+ S = nullptr;
+ }
+}
+
+void MultiParseScope::Enter(unsigned ScopeFlags) {
+ S.EnterScope(ScopeFlags);
+ ++NumScopes;
+}
+
+void MultiParseScope::Exit() {
+ while (NumScopes) {
+ S.ExitScope();
+ --NumScopes;
+ }
+}
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 8c44cc45539a5..c4c1a5e5c1e44 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -620,6 +620,7 @@ Sema::~Sema() {
// Detach from the PP callback handler which outlives Sema since it's owned
// by the preprocessor.
SemaPPCallbackHandler->reset();
+ FreeScopes();
}
void Sema::runWithSufficientStackSpace(SourceLocation Loc,
@@ -2959,3 +2960,34 @@ Attr *Sema::CreateAnnotationAttr(const ParsedAttr &AL) {
return CreateAnnotationAttr(AL, Str, Args);
}
+
+void Sema::EnterScope(unsigned ScopeFlags) {
+ if (!ScopeCache.empty()) {
+ Scope *N = ScopeCache.pop_back_val().release();
+ N->Init(getCurScope(), ScopeFlags);
+ CurScope = N;
+ } else {
+ CurScope = new Scope(getCurScope(), ScopeFlags, Diags);
+ }
+}
+
+void Sema::ExitScope() {
+ assert(getCurScope() && "Scope imbalance!");
+ ActOnPopScope(getCurScope());
+ Scope *OldScope = getCurScope();
+ CurScope = OldScope->getParent();
+ if (ScopeCache.size() == MaxScopeCacheSize)
+ delete OldScope;
+ else
+ ScopeCache.emplace_back(OldScope);
+}
+
+void Sema::FreeScopes() {
+ // Take care not to delete 'CurScope' twice.
+ auto IsCurScope = [&](auto& S) { return S.get() == CurScope; };
+ if (llvm::find_if(ScopeCache, IsCurScope) == ScopeCache.end())
+ delete CurScope;
+
+ ScopeCache.clear();
+ CurScope = nullptr;
+}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 4bafc5cdca7cb..53142c8ba4207 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2256,7 +2256,7 @@ static void CheckPoppedLabel(LabelDecl *L, Sema &S,
<< L);
}
-void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
+void Sema::ActOnPopScope(Scope *S) {
S->applyNRVO();
if (S->decl_empty()) return;
>From e3fc9d47fd61d34f4b5ba0f3797a02446d215246 Mon Sep 17 00:00:00 2001
From: Sirraide <aeternalmail at gmail.com>
Date: Wed, 3 Dec 2025 03:24:51 +0100
Subject: [PATCH 4/4] CWG 3131
---
clang/include/clang/Sema/Sema.h | 6 +++---
clang/lib/Sema/SemaStmt.cpp | 20 ++++++++++----------
2 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 3d49dc85da027..5dee71b23422e 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11100,14 +11100,14 @@ class Sema final : public SemaBase {
Scope *S, VarDecl *RangeVar, SourceLocation ColonLoc,
SourceLocation CoawaitLoc,
ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps,
- BuildForRangeKind Kind, bool ForExpansionStmt,
+ BuildForRangeKind Kind, bool Constexpr,
StmtResult *RebuildResult = nullptr,
llvm::function_ref<StmtResult()> RebuildWithDereference = {});
/// Build the range variable of a range-based for loop or iterating
/// expansion statement and return its DeclStmt.
- StmtResult BuildCXXForRangeRangeVar(Scope *S, Expr *Range,
- bool ForExpansionStmt);
+ StmtResult BuildCXXForRangeRangeVar(Scope *S, Expr *Range, QualType Type,
+ bool Constexpr = false);
/// FinishCXXForRangeStmt - Attach the body to a C++0x for-range statement.
/// This is a separate step from ActOnCXXForRangeStmt because analysis of the
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 8f3e37d7d75c8..a9fa0c3910c86 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -2427,14 +2427,14 @@ static bool ObjCEnumerationCollection(Expr *Collection) {
&& Collection->getType()->getAs<ObjCObjectPointerType>() != nullptr;
}
-StmtResult Sema::BuildCXXForRangeRangeVar(Scope *S, Expr *Range,
- bool ForExpansionStmt) {
+StmtResult Sema::BuildCXXForRangeRangeVar(Scope *S, Expr *Range, QualType Type,
+ bool Constexpr) {
+
// Divide by 2, since the variables are in the inner scope (loop body).
const auto DepthStr = std::to_string(S->getDepth() / 2);
SourceLocation RangeLoc = Range->getBeginLoc();
- VarDecl *RangeVar =
- BuildForRangeVarDecl(*this, RangeLoc, Context.getAutoRRefDeductType(),
- std::string("__range") + DepthStr, ForExpansionStmt);
+ VarDecl *RangeVar = BuildForRangeVarDecl(
+ *this, RangeLoc, Type, std::string("__range") + DepthStr, Constexpr);
if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
diag::err_for_range_deduction_failure))
@@ -2491,7 +2491,7 @@ StmtResult Sema::ActOnCXXForRangeStmt(
// Build auto && __range = range-init
auto RangeDecl =
- BuildCXXForRangeRangeVar(S, Range, /*ForExpansionStmt=*/false);
+ BuildCXXForRangeRangeVar(S, Range, Context.getAutoRRefDeductType());
if (RangeDecl.isInvalid()) {
ActOnInitializerError(LoopVar);
return StmtError();
@@ -2704,7 +2704,7 @@ Sema::ForRangeBeginEndInfo Sema::BuildCXXForRangeBeginEndVars(
Scope *S, VarDecl *RangeVar, SourceLocation ColonLoc,
SourceLocation CoawaitLoc,
ArrayRef<MaterializeTemporaryExpr *> LifetimeExtendTemps,
- BuildForRangeKind Kind, bool ForExpansionStmt, StmtResult *RebuildResult,
+ BuildForRangeKind Kind, bool Constexpr, StmtResult *RebuildResult,
llvm::function_ref<StmtResult()> RebuildWithDereference) {
QualType RangeVarType = RangeVar->getType();
SourceLocation RangeLoc = RangeVar->getLocation();
@@ -2740,10 +2740,10 @@ Sema::ForRangeBeginEndInfo Sema::BuildCXXForRangeBeginEndVars(
const auto DepthStr = std::to_string(S->getDepth() / 2);
VarDecl *BeginVar =
BuildForRangeVarDecl(*this, ColonLoc, AutoType,
- std::string("__begin") + DepthStr, ForExpansionStmt);
+ std::string("__begin") + DepthStr, Constexpr);
VarDecl *EndVar =
BuildForRangeVarDecl(*this, ColonLoc, AutoType,
- std::string("__end") + DepthStr, ForExpansionStmt);
+ std::string("__end") + DepthStr, Constexpr);
// Build begin-expr and end-expr and attach to __begin and __end variables.
ExprResult BeginExpr, EndExpr;
@@ -2953,7 +2953,7 @@ StmtResult Sema::BuildCXXForRangeStmt(
auto BeginRangeRefTy = RangeVar->getType().getNonReferenceType();
auto [BeginVar, EndVar, BeginExpr, EndExpr] = BuildCXXForRangeBeginEndVars(
S, RangeVar, ColonLoc, CoawaitLoc, LifetimeExtendTemps, Kind,
- /*ForExpansionStmt=*/false, &RebuildResult, RebuildWithDereference);
+ /*Constexpr=*/false, &RebuildResult, RebuildWithDereference);
if (!RebuildResult.isUnset())
return RebuildResult;
More information about the llvm-branch-commits
mailing list