[clang] [Clang] Lazily allocate rare expression evaluation state (NFC) (PR #223036)
Mehdi Amini via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 11 12:51:51 PDT 2026
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 <joker.eph at gmail.com>
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 *>());
}
}
More information about the cfe-commits
mailing list