https://github.com/Sirraide updated 
https://github.com/llvm/llvm-project/pull/169683

>From d0c4da5350c179af92776fc8f4035bfb889c89d0 Mon Sep 17 00:00:00 2001
From: Sirraide <[email protected]>
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 4d25143cffaf4..1101ee9e10778 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11066,6 +11066,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
@@ -11207,6 +11238,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 655fa31bbf5c7..47c8f9ab6725c 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 8a3ae34c852e924a0a1019b0c04185a28c7e0e90 Mon Sep 17 00:00:00 2001
From: Sirraide <[email protected]>
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 47c8f9ab6725c..f948f516b5136 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 d1fba2babf8a1671a0e1658d3e981bd402389ef6 Mon Sep 17 00:00:00 2001
From: Sirraide <[email protected]>
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 1101ee9e10778..4920456ffe6db 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 32a406e2c065f..8118dff41b89d 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();
@@ -4969,7 +4970,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(),
@@ -5028,7 +5029,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
@@ -5143,7 +5144,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 a6fc676f23a51..4aa14e0b6d7a8 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.
@@ -1275,8 +1241,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);
@@ -1304,8 +1270,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);
@@ -1323,8 +1289,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.
@@ -1476,8 +1442,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 5fbfb4023ee4d..efd33fd393dd0 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,
@@ -2962,3 +2963,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 180f532561ece..c260df676570c 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -2255,7 +2255,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 46e2331a493eaed168b8d0e28fd43d6d6a567231 Mon Sep 17 00:00:00 2001
From: Sirraide <[email protected]>
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 4920456ffe6db..fc98f9326da17 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11099,14 +11099,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 f948f516b5136..da1005f8a6d80 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;

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to