[clang] [Clang] Lazily allocate rare expression evaluation state (NFC) (PR #223036)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 11 12:52:34 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Mehdi Amini (joker-eph)
<details>
<summary>Changes</summary>
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
---
Patch is 28.00 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/223036.diff
9 Files Affected:
- (modified) clang/include/clang/Sema/Sema.h (+47-31)
- (modified) clang/lib/Parse/ParseStmt.cpp (+5-4)
- (modified) clang/lib/Sema/SemaChecking.cpp (+12-6)
- (modified) clang/lib/Sema/SemaExpr.cpp (+83-44)
- (modified) clang/lib/Sema/SemaExprCXX.cpp (+10-8)
- (modified) clang/lib/Sema/SemaExprMember.cpp (+1-1)
- (modified) clang/lib/Sema/SemaInit.cpp (+3-1)
- (modified) clang/lib/Sema/SemaLambda.cpp (+1-1)
- (modified) clang/lib/Sema/TreeTransform.h (+10-6)
``````````diff
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()
+ ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/223036
More information about the cfe-commits
mailing list