https://github.com/joker-eph created 
https://github.com/llvm/llvm-project/pull/223036

Keep common expression evaluation records compact by moving diagnostic and 
feature-specific collections behind one lazily allocated rare-data object. Add 
a no-rare-data pop path to avoid checking empty collections.

CTMark O0 (3 samples): 29.439800 s -> 29.219367 s (-0.749%).

Impact on significant TUs in MLIR build time:
- `mlir/lib/RegisterAllDialects.cpp`: 1.6043% fewer retired instructions.
- `mlir/lib/Dialect/LLVMIR/IR/NVVMDialect.cpp`: 0.9162% fewer retired 
instructions.

Assisted-by: Codex

>From eca1b20992d7349d3d96fdfb09eb21b56a9b986f Mon Sep 17 00:00:00 2001
From: Mehdi Amini <[email protected]>
Date: Thu, 10 Sep 2026 08:26:30 -0700
Subject: [PATCH] Lazily allocate rare expression evaluation state

Keep common expression evaluation records compact by moving diagnostic
and feature-specific collections behind one lazily allocated rare-data
object. Add a no-rare-data pop path to avoid checking empty collections.

CTMark O0 (3 samples, CPU 6): 29.439800 s -> 29.219367 s (-0.749%).

Impact on significant TUs in MLIR build time:
- `mlir/lib/RegisterAllDialects.cpp`: 1.6043% fewer retired
  instructions.
- `mlir/lib/Dialect/LLVMIR/IR/NVVMDialect.cpp`: 0.9162% fewer retired
  instructions.

Assisted-by: Codex
---
 clang/include/clang/Sema/Sema.h   |  78 ++++++++++--------
 clang/lib/Parse/ParseStmt.cpp     |   9 ++-
 clang/lib/Sema/SemaChecking.cpp   |  18 +++--
 clang/lib/Sema/SemaExpr.cpp       | 127 +++++++++++++++++++-----------
 clang/lib/Sema/SemaExprCXX.cpp    |  18 +++--
 clang/lib/Sema/SemaExprMember.cpp |   2 +-
 clang/lib/Sema/SemaInit.cpp       |   4 +-
 clang/lib/Sema/SemaLambda.cpp     |   2 +-
 clang/lib/Sema/TreeTransform.h    |  16 ++--
 9 files changed, 172 insertions(+), 102 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 4ff4c669a6b70..a74d1b58a4a8a 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -6809,12 +6809,6 @@ class Sema final : public SemaBase {
     /// this expression evaluation context.
     unsigned NumCleanupObjects;
 
-    MaybeODRUseExprSet SavedMaybeODRUseExprs;
-
-    /// The lambdas that are present within this context, if it
-    /// is indeed an unevaluated context.
-    SmallVector<LambdaExpr *, 2> Lambdas;
-
     /// The declaration that provides context for lambda expressions
     /// and block literals if the normal declaration context does not
     /// suffice, e.g., in a default function argument.
@@ -6825,38 +6819,60 @@ class Sema final : public SemaBase {
     /// diagnostic to reference the declaration as a whole.
     VarDecl *DeclForInitializer = nullptr;
 
-    /// If we are processing a decltype type, a set of call expressions
-    /// for which we have deferred checking the completeness of the return 
type.
-    SmallVector<CallExpr *, 8> DelayedDecltypeCalls;
+    /// Collections used by uncommon evaluation-context features. Keeping them
+    /// out of line avoids constructing empty containers for ordinary contexts.
+    struct RareData {
+      MaybeODRUseExprSet SavedMaybeODRUseExprs;
+
+      /// The lambdas that are present within an unevaluated context.
+      SmallVector<LambdaExpr *, 2> Lambdas;
+
+      /// If we are processing a decltype type, call expressions for which we
+      /// have deferred checking the completeness of the return type.
+      SmallVector<CallExpr *, 8> DelayedDecltypeCalls;
+
+      /// If we are processing a decltype type, temporary binding expressions
+      /// for which we have deferred checking the destructor.
+      SmallVector<CXXBindTemporaryExpr *, 8> DelayedDecltypeBinds;
 
-    /// If we are processing a decltype type, a set of temporary binding
-    /// expressions for which we have deferred checking the destructor.
-    SmallVector<CXXBindTemporaryExpr *, 8> DelayedDecltypeBinds;
+      llvm::SmallPtrSet<const Expr *, 8> PossibleDerefs;
 
-    llvm::SmallPtrSet<const Expr *, 8> PossibleDerefs;
+      /// Expressions appearing as the LHS of a volatile assignment in this
+      /// context. We warn when popping the context unless they are discarded-
+      /// value expressions or unevaluated operands.
+      SmallVector<Expr *, 2> VolatileAssignmentLHSs;
 
-    /// Expressions appearing as the LHS of a volatile assignment in this
-    /// context. We produce a warning for these when popping the context if
-    /// they are not discarded-value expressions nor unevaluated operands.
-    SmallVector<Expr *, 2> VolatileAssignmentLHSs;
+      /// Set of candidates for starting an immediate invocation.
+      llvm::SmallVector<ImmediateInvocationCandidate, 4>
+          ImmediateInvocationCandidates;
 
-    /// Set of candidates for starting an immediate invocation.
-    llvm::SmallVector<ImmediateInvocationCandidate, 4>
-        ImmediateInvocationCandidates;
+      /// DeclRefExprs referencing a consteval function in a context not 
already
+      /// known to be immediately invoked.
+      llvm::SmallPtrSet<DeclRefExpr *, 4> ReferenceToConsteval;
 
-    /// Set of DeclRefExprs referencing a consteval function when used in a
-    /// context not already known to be immediately invoked.
-    llvm::SmallPtrSet<DeclRefExpr *, 4> ReferenceToConsteval;
+      /// P2718R0 - Lifetime extension in range-based for loops.
+      /// Materialized temporaries in for-range-init expressions whose lifetime
+      /// needs extending. Collected when InLifetimeExtendingContext is true.
+      SmallVector<MaterializeTemporaryExpr *, 8> ForRangeLifetimeExtendTemps;
 
-    /// P2718R0 - Lifetime extension in range-based for loops.
-    /// MaterializeTemporaryExprs in for-range-init expressions which need to
-    /// extend lifetime. Add MaterializeTemporaryExpr* if the value of
-    /// InLifetimeExtendingContext is true.
-    SmallVector<MaterializeTemporaryExpr *, 8> ForRangeLifetimeExtendTemps;
+      /// Gathered accesses to potentially misaligned members due to the packed
+      /// attribute.
+      SmallVector<MisalignedMember, 4> MisalignedMembers;
+    };
+
+    /// Null means that every rare-data collection is empty.
+    std::unique_ptr<RareData> Rare;
+
+    /// Obtain storage for adding rare state, allocating it on first use.
+    RareData &getOrCreateRareData() {
+      if (!Rare)
+        Rare = std::make_unique<RareData>();
+      return *Rare;
+    }
 
-    /// Small set of gathered accesses to potentially misaligned members
-    /// due to the packed attribute.
-    SmallVector<MisalignedMember, 4> MisalignedMembers;
+    /// Inspect rare state without allocating storage for an empty context.
+    RareData *getRareData() { return Rare.get(); }
+    const RareData *getRareData() const { return Rare.get(); }
 
     /// \brief Describes whether we are in an expression constext which we have
     /// to handle differently.
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 5e67cd551bff8..029b6c3f7ead6 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -1965,13 +1965,14 @@ void 
Parser::ParseForRangeInitializerAfterColon(ForRangeInit &FRI,
   }
 
   // Before c++23, ForRangeLifetimeExtendTemps should be empty.
-  assert(getLangOpts().CPlusPlus23 ||
-         Actions.ExprEvalContexts.back().ForRangeLifetimeExtendTemps.empty());
+  auto *Rare = Actions.ExprEvalContexts.back().getRareData();
+  assert(getLangOpts().CPlusPlus23 || !Rare ||
+         Rare->ForRangeLifetimeExtendTemps.empty());
 
   // Move the collected materialized temporaries into ForRangeInit before
   // ForRangeInitContext exit.
-  FRI.LifetimeExtendTemps =
-      std::move(Actions.ExprEvalContexts.back().ForRangeLifetimeExtendTemps);
+  if (Rare)
+    FRI.LifetimeExtendTemps = std::move(Rare->ForRangeLifetimeExtendTemps);
 }
 
 StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc,
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 25996ddbc0558..86e1062c8cc8f 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -16950,12 +16950,16 @@ void Sema::CheckArgumentWithTypeTag(const 
ArgumentWithTypeTagAttr *Attr,
 
 void Sema::AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl 
*MD,
                                          CharUnits Alignment) {
-  currentEvaluationContext().MisalignedMembers.emplace_back(E, RD, MD,
-                                                            Alignment);
+  currentEvaluationContext()
+      .getOrCreateRareData()
+      .MisalignedMembers.emplace_back(E, RD, MD, Alignment);
 }
 
 void Sema::DiagnoseMisalignedMembers() {
-  for (MisalignedMember &m : currentEvaluationContext().MisalignedMembers) {
+  auto *Rare = currentEvaluationContext().getRareData();
+  if (!Rare)
+    return;
+  for (MisalignedMember &m : Rare->MisalignedMembers) {
     const NamedDecl *ND = m.RD;
     if (ND->getName().empty()) {
       if (const TypedefNameDecl *TD = m.RD->getTypedefNameForAnonDecl())
@@ -16964,7 +16968,7 @@ void Sema::DiagnoseMisalignedMembers() {
     Diag(m.E->getBeginLoc(), diag::warn_taking_address_of_packed_member)
         << m.MD << ND << m.E->getSourceRange();
   }
-  currentEvaluationContext().MisalignedMembers.clear();
+  Rare->MisalignedMembers.clear();
 }
 
 void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) {
@@ -16975,8 +16979,10 @@ void Sema::DiscardMisalignedMemberAddress(const Type 
*T, Expr *E) {
       cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) {
     auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();
     if (isa<MemberExpr>(Op)) {
-      auto &MisalignedMembersForExpr =
-          currentEvaluationContext().MisalignedMembers;
+      auto *Rare = currentEvaluationContext().getRareData();
+      if (!Rare)
+        return;
+      auto &MisalignedMembersForExpr = Rare->MisalignedMembers;
       auto *MA = llvm::find(MisalignedMembersForExpr, MisalignedMember(Op));
       if (MA != MisalignedMembersForExpr.end() &&
           (T->isDependentType() || T->isIntegerType() ||
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 9fa8e517d9098..86e7f0dcf47ba 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -5382,7 +5382,8 @@ void Sema::CheckAddressOfNoDeref(const Expr *E) {
   while ((Member = dyn_cast<MemberExpr>(StrippedExpr)) && !Member->isArrow())
     StrippedExpr = Member->getBase()->IgnoreParenImpCasts();
 
-  LastRecord.PossibleDerefs.erase(StrippedExpr);
+  if (auto *Rare = LastRecord.getRareData())
+    Rare->PossibleDerefs.erase(StrippedExpr);
 }
 
 void Sema::CheckSubscriptAccessOfNoDeref(const ArraySubscriptExpr *E) {
@@ -5397,7 +5398,7 @@ void Sema::CheckSubscriptAccessOfNoDeref(const 
ArraySubscriptExpr *E) {
     return;
 
   if (ResultTy->hasAttr(attr::NoDeref)) {
-    LastRecord.PossibleDerefs.insert(E);
+    LastRecord.getOrCreateRareData().PossibleDerefs.insert(E);
     return;
   }
 
@@ -5416,7 +5417,7 @@ void Sema::CheckSubscriptAccessOfNoDeref(const 
ArraySubscriptExpr *E) {
 
   if (const auto *Ptr = dyn_cast<PointerType>(Base->getType())) {
     if (Ptr->getPointeeType()->hasAttr(attr::NoDeref))
-      LastRecord.PossibleDerefs.insert(E);
+      LastRecord.getOrCreateRareData().PossibleDerefs.insert(E);
   }
 }
 
@@ -6799,7 +6800,8 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, 
SourceLocation LParenLoc,
     // an invalid immediate call.
     if (auto *DRE = dyn_cast<DeclRefExpr>(Fn->IgnoreParens());
         DRE && Call.get()->isValueDependent()) {
-      currentEvaluationContext().ReferenceToConsteval.erase(DRE);
+      if (auto *Rare = currentEvaluationContext().getRareData())
+        Rare->ReferenceToConsteval.erase(DRE);
     }
   }
   return Call;
@@ -14730,7 +14732,9 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, 
ExprResult &RHS,
       //   A simple-assignment whose left operand is of a volatile-qualified
       //   type is deprecated unless the assignment is either a discarded-value
       //   expression or an unevaluated operand
-      ExprEvalContexts.back().VolatileAssignmentLHSs.push_back(LHSExpr);
+      ExprEvalContexts.back()
+          .getOrCreateRareData()
+          .VolatileAssignmentLHSs.push_back(LHSExpr);
     }
   }
 
@@ -16584,7 +16588,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation 
OpLoc,
   if (Opc == UO_Deref && UO->getType()->hasAttr(attr::NoDeref) &&
       !isa<ArrayType>(UO->getType().getDesugaredType(Context)) &&
       !isUnevaluatedContext())
-    ExprEvalContexts.back().PossibleDerefs.insert(UO);
+    ExprEvalContexts.back().getOrCreateRareData().PossibleDerefs.insert(UO);
 
   // Convert the result back to a half vector.
   if (ConvertHalfVec)
@@ -18322,29 +18326,35 @@ void
 Sema::PushExpressionEvaluationContext(
     ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl,
     ExpressionEvaluationContextRecord::ExpressionKind ExprContext) {
+  const auto &Prev = currentEvaluationContext();
+  bool InDiscardedStatement = Prev.isDiscardedStatementContext();
+  bool InImmediateFunctionContext =
+      Prev.isImmediateFunctionContext() || Prev.isConstantEvaluated();
+  bool InImmediateEscalatingFunctionContext =
+      Prev.InImmediateEscalatingFunctionContext;
+
   ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup,
                                 LambdaContextDecl, ExprContext);
+  auto &Current = currentEvaluationContext();
 
   // Discarded statements and immediate contexts nested in other
   // discarded statements or immediate context are themselves
   // a discarded statement or an immediate context, respectively.
-  ExprEvalContexts.back().InDiscardedStatement =
-      parentEvaluationContext().isDiscardedStatementContext();
+  Current.InDiscardedStatement = InDiscardedStatement;
 
   // C++23 [expr.const]/p15
   // An expression or conversion is in an immediate function context if [...]
   // it is a subexpression of a manifestly constant-evaluated expression or
   // conversion.
-  const auto &Prev = parentEvaluationContext();
-  ExprEvalContexts.back().InImmediateFunctionContext =
-      Prev.isImmediateFunctionContext() || Prev.isConstantEvaluated();
+  Current.InImmediateFunctionContext = InImmediateFunctionContext;
 
-  ExprEvalContexts.back().InImmediateEscalatingFunctionContext =
-      Prev.InImmediateEscalatingFunctionContext;
+  Current.InImmediateEscalatingFunctionContext =
+      InImmediateEscalatingFunctionContext;
 
   Cleanup.reset();
   if (!MaybeODRUseExprs.empty())
-    std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs);
+    std::swap(MaybeODRUseExprs,
+              Current.getOrCreateRareData().SavedMaybeODRUseExprs);
 }
 
 void
@@ -18434,7 +18444,10 @@ const DeclRefExpr *CheckPossibleDeref(Sema &S, const 
Expr *PossibleDeref) {
 } // namespace
 
 void Sema::WarnOnPendingNoDerefs(ExpressionEvaluationContextRecord &Rec) {
-  for (const Expr *E : Rec.PossibleDerefs) {
+  auto *Rare = Rec.getRareData();
+  if (!Rare)
+    return;
+  for (const Expr *E : Rare->PossibleDerefs) {
     const DeclRefExpr *DeclRef = CheckPossibleDeref(*this, E);
     if (DeclRef) {
       const ValueDecl *Decl = DeclRef->getDecl();
@@ -18446,7 +18459,7 @@ void 
Sema::WarnOnPendingNoDerefs(ExpressionEvaluationContextRecord &Rec) {
           << E->getSourceRange();
     }
   }
-  Rec.PossibleDerefs.clear();
+  Rare->PossibleDerefs.clear();
 }
 
 void Sema::CheckUnusedVolatileAssignment(Expr *E) {
@@ -18458,8 +18471,8 @@ void Sema::CheckUnusedVolatileAssignment(Expr *E) {
   // drives a deprecation warning so doesn't affect conformance.
   if (auto *BO = dyn_cast<BinaryOperator>(E->IgnoreParenImpCasts())) {
     if (BO->getOpcode() == BO_Assign) {
-      auto &LHSs = ExprEvalContexts.back().VolatileAssignmentLHSs;
-      llvm::erase(LHSs, BO->getLHS());
+      if (auto *Rare = ExprEvalContexts.back().getRareData())
+        llvm::erase(Rare->VolatileAssignmentLHSs, BO->getLHS());
     }
   }
 }
@@ -18499,7 +18512,8 @@ ExprResult Sema::CheckForImmediateInvocation(ExprResult 
E, FunctionDecl *Decl) {
   if (auto *Call = dyn_cast<CallExpr>(E.get()->IgnoreImplicit()))
     if (auto *DeclRef =
             dyn_cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit()))
-      ExprEvalContexts.back().ReferenceToConsteval.erase(DeclRef);
+      if (auto *Rare = ExprEvalContexts.back().getRareData())
+        Rare->ReferenceToConsteval.erase(DeclRef);
 
   // C++23 [expr.const]/p16
   // An expression or conversion is immediate-escalating if it is not initially
@@ -18555,7 +18569,9 @@ ExprResult Sema::CheckForImmediateInvocation(ExprResult 
E, FunctionDecl *Decl) {
   /// Value-dependent constant expressions should not be immediately
   /// evaluated until they are instantiated.
   if (!Res->isValueDependent())
-    ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0);
+    ExprEvalContexts.back()
+        .getOrCreateRareData()
+        .ImmediateInvocationCandidates.emplace_back(Res, 0);
   return Res;
 }
 
@@ -18691,8 +18707,8 @@ static void RemoveNestedImmediateInvocation(
       return Res;
     }
     bool AllowSkippingFirstCXXConstructExpr = true;
-  } Transformer(SemaRef, Rec.ReferenceToConsteval,
-                Rec.ImmediateInvocationCandidates, It);
+  } Transformer(SemaRef, Rec.getRareData()->ReferenceToConsteval,
+                Rec.getRareData()->ImmediateInvocationCandidates, It);
 
   /// CXXConstructExpr with a single argument are getting skipped by
   /// TreeTransform in some situtation because they could be implicit. This
@@ -18716,8 +18732,10 @@ static void RemoveNestedImmediateInvocation(
 static void
 HandleImmediateInvocations(Sema &SemaRef,
                            Sema::ExpressionEvaluationContextRecord &Rec) {
-  if ((Rec.ImmediateInvocationCandidates.size() == 0 &&
-       Rec.ReferenceToConsteval.size() == 0) ||
+  auto *Rare = Rec.getRareData();
+  if (!Rare ||
+      (Rare->ImmediateInvocationCandidates.empty() &&
+       Rare->ReferenceToConsteval.empty()) ||
       Rec.isImmediateFunctionContext() || 
SemaRef.RebuildingImmediateInvocation)
     return;
 
@@ -18745,7 +18763,7 @@ HandleImmediateInvocations(Sema &SemaRef,
   /// ImmediateInvocationCandidates in order to avoid duplicate diagnostics.
   /// Otherwise we only need to remove ReferenceToConsteval in the immediate
   /// invocation.
-  if (Rec.ImmediateInvocationCandidates.size() > 1 ||
+  if (Rare->ImmediateInvocationCandidates.size() > 1 ||
       !SemaRef.FailedImmediateInvocations.empty()) {
 
     /// Prevent sema calls during the tree transform from adding pointers that
@@ -18756,12 +18774,12 @@ HandleImmediateInvocations(Sema &SemaRef,
     /// Prevent diagnostic during tree transfrom as they are duplicates
     Sema::TentativeAnalysisScope DisableDiag(SemaRef);
 
-    for (auto It = Rec.ImmediateInvocationCandidates.rbegin();
-         It != Rec.ImmediateInvocationCandidates.rend(); It++)
+    for (auto It = Rare->ImmediateInvocationCandidates.rbegin();
+         It != Rare->ImmediateInvocationCandidates.rend(); It++)
       if (!It->getInt())
         RemoveNestedImmediateInvocation(SemaRef, Rec, It);
-  } else if (Rec.ImmediateInvocationCandidates.size() == 1 &&
-             Rec.ReferenceToConsteval.size()) {
+  } else if (Rare->ImmediateInvocationCandidates.size() == 1 &&
+             !Rare->ReferenceToConsteval.empty()) {
     struct SimpleRemove : DynamicRecursiveASTVisitor {
       llvm::SmallPtrSetImpl<DeclRefExpr *> &DRSet;
       SimpleRemove(llvm::SmallPtrSetImpl<DeclRefExpr *> &S) : DRSet(S) {}
@@ -18769,14 +18787,14 @@ HandleImmediateInvocations(Sema &SemaRef,
         DRSet.erase(E);
         return DRSet.size();
       }
-    } Visitor(Rec.ReferenceToConsteval);
+    } Visitor(Rare->ReferenceToConsteval);
     Visitor.TraverseStmt(
-        Rec.ImmediateInvocationCandidates.front().getPointer()->getSubExpr());
+        
Rare->ImmediateInvocationCandidates.front().getPointer()->getSubExpr());
   }
-  for (auto CE : Rec.ImmediateInvocationCandidates)
+  for (auto CE : Rare->ImmediateInvocationCandidates)
     if (!CE.getInt())
       EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE);
-  for (auto *DR : Rec.ReferenceToConsteval) {
+  for (auto *DR : Rare->ReferenceToConsteval) {
     // If the expression is immediate escalating, it is not an error;
     // The outer context itself becomes immediate and further errors,
     // if any, will be handled by DiagnoseImmediateEscalatingReason.
@@ -18825,7 +18843,23 @@ HandleImmediateInvocations(Sema &SemaRef,
 
 void Sema::PopExpressionEvaluationContext() {
   ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back();
-  if (!Rec.Lambdas.empty()) {
+  auto *Rare = Rec.getRareData();
+  if (!Rare) {
+    if (Rec.isUnevaluated() || Rec.isConstantEvaluated()) {
+      ExprCleanupObjects.erase(ExprCleanupObjects.begin() +
+                                   Rec.NumCleanupObjects,
+                               ExprCleanupObjects.end());
+      Cleanup = Rec.ParentCleanup;
+      CleanupVarDeclMarking();
+      MaybeODRUseExprs.clear();
+    } else {
+      Cleanup.mergeFrom(Rec.ParentCleanup);
+    }
+    ExprEvalContexts.pop_back();
+    return;
+  }
+
+  if (!Rare->Lambdas.empty()) {
     using ExpressionKind = ExpressionEvaluationContextRecord::ExpressionKind;
     if (!getLangOpts().CPlusPlus20 &&
         (Rec.ExprContext == ExpressionKind::EK_TemplateArgument ||
@@ -18850,7 +18884,7 @@ void Sema::PopExpressionEvaluationContext() {
       } else
         llvm_unreachable("Couldn't infer lambda error message.");
 
-      for (const auto *L : Rec.Lambdas)
+      for (const auto *L : Rare->Lambdas)
         Diag(L->getBeginLoc(), D);
     }
   }
@@ -18859,9 +18893,10 @@ void Sema::PopExpressionEvaluationContext() {
   // exit if the previous also is a lifetime extending context.
   if (getLangOpts().CPlusPlus23 && Rec.InLifetimeExtendingContext &&
       parentEvaluationContext().InLifetimeExtendingContext &&
-      !Rec.ForRangeLifetimeExtendTemps.empty()) {
-    parentEvaluationContext().ForRangeLifetimeExtendTemps.append(
-        Rec.ForRangeLifetimeExtendTemps);
+      !Rare->ForRangeLifetimeExtendTemps.empty()) {
+    parentEvaluationContext()
+        .getOrCreateRareData()
+        .ForRangeLifetimeExtendTemps.append(Rare->ForRangeLifetimeExtendTemps);
   }
 
   WarnOnPendingNoDerefs(Rec);
@@ -18870,7 +18905,7 @@ void Sema::PopExpressionEvaluationContext() {
   // Warn on any volatile-qualified simple-assignments that are not discarded-
   // value expressions nor unevaluated operands (those cases get removed from
   // this list by CheckUnusedVolatileAssignment).
-  for (auto *BO : Rec.VolatileAssignmentLHSs)
+  for (auto *BO : Rare->VolatileAssignmentLHSs)
     Diag(BO->getBeginLoc(), diag::warn_deprecated_simple_assign_volatile)
         << BO->getType();
 
@@ -18883,11 +18918,12 @@ void Sema::PopExpressionEvaluationContext() {
                              ExprCleanupObjects.end());
     Cleanup = Rec.ParentCleanup;
     CleanupVarDeclMarking();
-    std::swap(MaybeODRUseExprs, Rec.SavedMaybeODRUseExprs);
-  // Otherwise, merge the contexts together.
+    if (!MaybeODRUseExprs.empty() || !Rare->SavedMaybeODRUseExprs.empty())
+      std::swap(MaybeODRUseExprs, Rare->SavedMaybeODRUseExprs);
+    // Otherwise, merge the contexts together.
   } else {
     Cleanup.mergeFrom(Rec.ParentCleanup);
-    MaybeODRUseExprs.insert_range(Rec.SavedMaybeODRUseExprs);
+    MaybeODRUseExprs.insert_range(Rare->SavedMaybeODRUseExprs);
   }
 
   DiagnoseMisalignedMembers();
@@ -21057,7 +21093,8 @@ void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const 
Expr *Base) {
         !isCheckingDefaultArgumentOrInitializer() &&
         FD->isImmediateFunction() && !RebuildingImmediateInvocation &&
         !FD->isDependentContext())
-      ExprEvalContexts.back().ReferenceToConsteval.insert(E);
+      
ExprEvalContexts.back().getOrCreateRareData().ReferenceToConsteval.insert(
+          E);
   }
   MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse,
                      RefsMinusAssignments);
@@ -21307,7 +21344,9 @@ bool Sema::CheckCallReturnType(QualType ReturnType, 
SourceLocation Loc,
   // type or construct temporaries until we know whether this is the last call.
   if (ExprEvalContexts.back().ExprContext ==
       ExpressionEvaluationContextRecord::EK_Decltype) {
-    ExprEvalContexts.back().DelayedDecltypeCalls.push_back(CE);
+    ExprEvalContexts.back()
+        .getOrCreateRareData()
+        .DelayedDecltypeCalls.push_back(CE);
     return false;
   }
 
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index d3835d00eb1db..aa7d7c3bfb277 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -6867,7 +6867,9 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
   CXXBindTemporaryExpr *Bind = CXXBindTemporaryExpr::Create(Context, Temp, E);
 
   if (IsDecltype)
-    ExprEvalContexts.back().DelayedDecltypeBinds.push_back(Bind);
+    ExprEvalContexts.back()
+        .getOrCreateRareData()
+        .DelayedDecltypeBinds.push_back(Bind);
 
   return Bind;
 }
@@ -6988,9 +6990,10 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
     return E;
 
   // Perform the semantic checks we delayed until this point.
-  for (unsigned I = 0, N = ExprEvalContexts.back().DelayedDecltypeCalls.size();
-       I != N; ++I) {
-    CallExpr *Call = ExprEvalContexts.back().DelayedDecltypeCalls[I];
+  auto *Rare = ExprEvalContexts.back().getRareData();
+  unsigned NumDelayedCalls = Rare ? Rare->DelayedDecltypeCalls.size() : 0;
+  for (unsigned I = 0; I != NumDelayedCalls; ++I) {
+    CallExpr *Call = Rare->DelayedDecltypeCalls[I];
     if (Call == TopCall)
       continue;
 
@@ -7001,10 +7004,9 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
 
   // Now all relevant types are complete, check the destructors are accessible
   // and non-deleted, and annotate them on the temporaries.
-  for (unsigned I = 0, N = ExprEvalContexts.back().DelayedDecltypeBinds.size();
-       I != N; ++I) {
-    CXXBindTemporaryExpr *Bind =
-      ExprEvalContexts.back().DelayedDecltypeBinds[I];
+  unsigned NumDelayedBinds = Rare ? Rare->DelayedDecltypeBinds.size() : 0;
+  for (unsigned I = 0; I != NumDelayedBinds; ++I) {
+    CXXBindTemporaryExpr *Bind = Rare->DelayedDecltypeBinds[I];
     if (Bind == TopBind)
       continue;
 
diff --git a/clang/lib/Sema/SemaExprMember.cpp 
b/clang/lib/Sema/SemaExprMember.cpp
index 227b4256e9627..48b90016e4a45 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -1793,7 +1793,7 @@ void Sema::CheckMemberAccessOfNoDeref(const MemberExpr 
*E) {
     if (const auto *Ptr = dyn_cast<PointerType>(
             E->getBase()->getType().getDesugaredType(Context))) {
       if (Ptr->getPointeeType()->hasAttr(attr::NoDeref))
-        ExprEvalContexts.back().PossibleDerefs.insert(E);
+        ExprEvalContexts.back().getOrCreateRareData().PossibleDerefs.insert(E);
     }
   }
 }
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 1ff66e0d927df..a48790a271577 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -7892,7 +7892,9 @@ Sema::CreateMaterializeTemporaryExpr(QualType T, Expr 
*Temporary,
   // but there may be a chance to merge them.
   Cleanup.setExprNeedsCleanups(false);
   if (isInLifetimeExtendingContext())
-    currentEvaluationContext().ForRangeLifetimeExtendTemps.push_back(MTE);
+    currentEvaluationContext()
+        .getOrCreateRareData()
+        .ForRangeLifetimeExtendTemps.push_back(MTE);
   return MTE;
 }
 
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 288f3c4f664cb..d20b23f1f5eba 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -2371,7 +2371,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc,
       // We don't actually diagnose this case immediately, because we
       // could be within a context where we might find out later that
       // the expression is potentially evaluated (e.g., for typeid).
-      ExprEvalContexts.back().Lambdas.push_back(Lambda);
+      ExprEvalContexts.back().getOrCreateRareData().Lambdas.push_back(Lambda);
       break;
 
     case ExpressionEvaluationContext::DiscardedStatement:
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index c8458fda58a88..d870f8e3261a5 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -9469,10 +9469,12 @@ 
TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
     return StmtError();
 
   // Before c++23, ForRangeLifetimeExtendTemps should be empty.
-  assert(getSema().getLangOpts().CPlusPlus23 ||
-         
getSema().ExprEvalContexts.back().ForRangeLifetimeExtendTemps.empty());
+  auto *Rare = getSema().ExprEvalContexts.back().getRareData();
+  assert(getSema().getLangOpts().CPlusPlus23 || !Rare ||
+         Rare->ForRangeLifetimeExtendTemps.empty());
   auto ForRangeLifetimeExtendTemps =
-      getSema().ExprEvalContexts.back().ForRangeLifetimeExtendTemps;
+      Rare ? Rare->ForRangeLifetimeExtendTemps
+           : SmallVector<MaterializeTemporaryExpr *, 8>();
 
   StmtResult Begin = getDerived().TransformStmt(S->getBeginStmt());
   if (Begin.isInvalid())
@@ -9611,8 +9613,8 @@ StmtResult 
TreeTransform<Derived>::TransformCXXExpansionStmtPattern(
     ExpansionInitializer =
         SemaRef.MaybeCreateExprWithCleanups(ExpansionInitializer);
 
-    LifetimeExtendTemps =
-        SemaRef.currentEvaluationContext().ForRangeLifetimeExtendTemps;
+    if (auto *Rare = SemaRef.currentEvaluationContext().getRareData())
+      LifetimeExtendTemps = Rare->ForRangeLifetimeExtendTemps;
   }
 
   CXXExpansionStmtPattern *NewPattern = nullptr;
@@ -9718,8 +9720,10 @@ StmtResult 
TreeTransform<Derived>::TransformCXXExpansionStmtInstantiation(
     if (S->shouldApplyLifetimeExtensionToPreamble()) {
       auto *VD =
           
cast<VarDecl>(cast<DeclStmt>(PreambleStmts.front())->getSingleDecl());
+      auto *Rare = SemaRef.currentEvaluationContext().getRareData();
       SemaRef.ApplyForRangeOrExpansionStatementLifetimeExtension(
-          VD, SemaRef.currentEvaluationContext().ForRangeLifetimeExtendTemps);
+          VD, Rare ? ArrayRef(Rare->ForRangeLifetimeExtendTemps)
+                   : ArrayRef<MaterializeTemporaryExpr *>());
     }
   }
 

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

Reply via email to