[clang] [Clang] Extend lifetime of temporaries in mem-default-init for P2718R0 (PR #86960)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Apr 6 09:18:42 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-codegen
Author: None (yronglin)
<details>
<summary>Changes</summary>
Fixes https://github.com/llvm/llvm-project/issues/85613.
In https://github.com/llvm/llvm-project/pull/76361, we've not implement the lifetime extensions for the temporaries which in `CXXDefaultInitExpr`. As the confirmation in https://github.com/llvm/llvm-project/issues/85613, we should extend lifetime for that.
There are two main modifications made to this PR:
- Extend lifetime of temporaries in `CXXDefaultInitExpr`. This reuse `CXXDefaultInitExpr` rewrite machinery.
- Before emitting the `__range` variable, we store the `__range` variable decl in `LexicalScope`. During emitting the `__range` variable, if we encounter a `MaterializedTemporaryExpr` whose lifetime is extended by the `__range` variable, we collect these temporaries and store into `LexicalScope::ForRangeInitTemps`. Once `__range` variable emitting finished, we will emitting the cleanups for the temporaries which we collected.
TODO: The lit test not add yet, because I'm not sure it's the correct approach, but I've posted some cases in https://github.com/llvm/llvm-project/issues/85613.
---
Patch is 27.12 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/86960.diff
15 Files Affected:
- (modified) clang/include/clang/Sema/Sema.h (-47)
- (modified) clang/lib/CodeGen/CGExpr.cpp (+33-29)
- (modified) clang/lib/CodeGen/CGStmt.cpp (+18)
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+31)
- (modified) clang/lib/Parse/ParseDecl.cpp (-4)
- (modified) clang/lib/Sema/SemaExpr.cpp (+6-5)
- (modified) clang/lib/Sema/SemaExprCXX.cpp (+1-1)
- (modified) clang/lib/Sema/SemaInit.cpp (+23-13)
- (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (-1)
- (modified) clang/lib/Sema/TreeTransform.h (-4)
- (modified) clang/test/CXX/drs/dr16xx.cpp (+1-2)
- (modified) clang/test/CXX/drs/dr18xx.cpp (+2-5)
- (modified) clang/test/CXX/special/class.temporary/p6.cpp (+106)
- (modified) clang/test/SemaCXX/constexpr-default-arg.cpp (+2-2)
- (modified) clang/test/SemaCXX/eval-crashes.cpp (+2-4)
``````````diff
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index f49bc724c96c89..0a07e850c74e47 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -5078,34 +5078,6 @@ class Sema final : public SemaBase {
/// example, in a for-range initializer).
bool InLifetimeExtendingContext = false;
- /// Whether we are currently in a context in which all temporaries must be
- /// materialized.
- ///
- /// [class.temporary]/p2:
- /// The materialization of a temporary object is generally delayed as long
- /// as possible in order to avoid creating unnecessary temporary objects.
- ///
- /// Temporary objects are materialized:
- /// (2.1) when binding a reference to a prvalue ([dcl.init.ref],
- /// [expr.type.conv], [expr.dynamic.cast], [expr.static.cast],
- /// [expr.const.cast], [expr.cast]),
- ///
- /// (2.2) when performing member access on a class prvalue ([expr.ref],
- /// [expr.mptr.oper]),
- ///
- /// (2.3) when performing an array-to-pointer conversion or subscripting
- /// on an array prvalue ([conv.array], [expr.sub]),
- ///
- /// (2.4) when initializing an object of type
- /// std::initializer_list<T> from a braced-init-list
- /// ([dcl.init.list]),
- ///
- /// (2.5) for certain unevaluated operands ([expr.typeid], [expr.sizeof])
- ///
- /// (2.6) when a prvalue that has type other than cv void appears as a
- /// discarded-value expression ([expr.context]).
- bool InMaterializeTemporaryObjectContext = false;
-
// When evaluating immediate functions in the initializer of a default
// argument or default member initializer, this is the declaration whose
// default initializer is being evaluated and the location of the call
@@ -6386,19 +6358,6 @@ class Sema final : public SemaBase {
}
}
- /// keepInMaterializeTemporaryObjectContext - Pull down
- /// InMaterializeTemporaryObjectContext flag from previous context.
- void keepInMaterializeTemporaryObjectContext() {
- if (ExprEvalContexts.size() > 2 &&
- ExprEvalContexts[ExprEvalContexts.size() - 2]
- .InMaterializeTemporaryObjectContext) {
- auto &LastRecord = ExprEvalContexts.back();
- auto &PrevRecord = ExprEvalContexts[ExprEvalContexts.size() - 2];
- LastRecord.InMaterializeTemporaryObjectContext =
- PrevRecord.InMaterializeTemporaryObjectContext;
- }
- }
-
DefaultedComparisonKind getDefaultedComparisonKind(const FunctionDecl *FD) {
return getDefaultedFunctionKind(FD).asComparison();
}
@@ -6542,12 +6501,6 @@ class Sema final : public SemaBase {
/// used in initializer of the field.
llvm::MapVector<FieldDecl *, DeleteLocs> DeleteExprs;
- bool isInMaterializeTemporaryObjectContext() const {
- assert(!ExprEvalContexts.empty() &&
- "Must be in an expression evaluation context");
- return ExprEvalContexts.back().InMaterializeTemporaryObjectContext;
- }
-
ParsedType getInheritingConstructorName(CXXScopeSpec &SS,
SourceLocation NameLoc,
IdentifierInfo &Name);
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 2480972f1432f7..27f616d497a2c5 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -274,9 +274,9 @@ void CodeGenFunction::EmitAnyExprToMem(const Expr *E,
llvm_unreachable("bad evaluation kind");
}
-static void
-pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M,
- const Expr *E, Address ReferenceTemporary) {
+void CodeGenFunction::pushTemporaryCleanup(const MaterializeTemporaryExpr *M,
+ const Expr *E,
+ Address ReferenceTemporary) {
// Objective-C++ ARC:
// If we are binding a reference to a temporary that has ownership, we
// need to perform retain/release operations on the temporary.
@@ -311,9 +311,9 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M,
CleanupKind CleanupKind;
if (Lifetime == Qualifiers::OCL_Strong) {
const ValueDecl *VD = M->getExtendingDecl();
- bool Precise =
- VD && isa<VarDecl>(VD) && VD->hasAttr<ObjCPreciseLifetimeAttr>();
- CleanupKind = CGF.getARCCleanupKind();
+ bool Precise = isa_and_nonnull<VarDecl>(VD) &&
+ VD->hasAttr<ObjCPreciseLifetimeAttr>();
+ CleanupKind = getARCCleanupKind();
Destroy = Precise ? &CodeGenFunction::destroyARCStrongPrecise
: &CodeGenFunction::destroyARCStrongImprecise;
} else {
@@ -323,13 +323,12 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M,
Destroy = &CodeGenFunction::destroyARCWeak;
}
if (Duration == SD_FullExpression)
- CGF.pushDestroy(CleanupKind, ReferenceTemporary,
- M->getType(), *Destroy,
- CleanupKind & EHCleanup);
+ pushDestroy(CleanupKind, ReferenceTemporary, M->getType(), *Destroy,
+ CleanupKind & EHCleanup);
else
- CGF.pushLifetimeExtendedDestroy(CleanupKind, ReferenceTemporary,
- M->getType(),
- *Destroy, CleanupKind & EHCleanup);
+ pushLifetimeExtendedDestroy(CleanupKind, ReferenceTemporary,
+ M->getType(), *Destroy,
+ CleanupKind & EHCleanup);
return;
case SD_Dynamic:
@@ -358,32 +357,31 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M,
llvm::FunctionCallee CleanupFn;
llvm::Constant *CleanupArg;
if (E->getType()->isArrayType()) {
- CleanupFn = CodeGenFunction(CGF.CGM).generateDestroyHelper(
- ReferenceTemporary, E->getType(),
- CodeGenFunction::destroyCXXObject, CGF.getLangOpts().Exceptions,
+ CleanupFn = CodeGenFunction(CGM).generateDestroyHelper(
+ ReferenceTemporary, E->getType(), CodeGenFunction::destroyCXXObject,
+ getLangOpts().Exceptions,
dyn_cast_or_null<VarDecl>(M->getExtendingDecl()));
- CleanupArg = llvm::Constant::getNullValue(CGF.Int8PtrTy);
+ CleanupArg = llvm::Constant::getNullValue(Int8PtrTy);
} else {
- CleanupFn = CGF.CGM.getAddrAndTypeOfCXXStructor(
+ CleanupFn = CGM.getAddrAndTypeOfCXXStructor(
GlobalDecl(ReferenceTemporaryDtor, Dtor_Complete));
- CleanupArg = cast<llvm::Constant>(ReferenceTemporary.emitRawPointer(CGF));
+ CleanupArg =
+ cast<llvm::Constant>(ReferenceTemporary.emitRawPointer(*this));
}
- CGF.CGM.getCXXABI().registerGlobalDtor(
- CGF, *cast<VarDecl>(M->getExtendingDecl()), CleanupFn, CleanupArg);
+ CGM.getCXXABI().registerGlobalDtor(
+ *this, *cast<VarDecl>(M->getExtendingDecl()), CleanupFn, CleanupArg);
break;
}
case SD_FullExpression:
- CGF.pushDestroy(NormalAndEHCleanup, ReferenceTemporary, E->getType(),
- CodeGenFunction::destroyCXXObject,
- CGF.getLangOpts().Exceptions);
+ pushDestroy(NormalAndEHCleanup, ReferenceTemporary, E->getType(),
+ CodeGenFunction::destroyCXXObject, getLangOpts().Exceptions);
break;
case SD_Automatic:
- CGF.pushLifetimeExtendedDestroy(NormalAndEHCleanup,
- ReferenceTemporary, E->getType(),
- CodeGenFunction::destroyCXXObject,
- CGF.getLangOpts().Exceptions);
+ pushLifetimeExtendedDestroy(NormalAndEHCleanup, ReferenceTemporary,
+ E->getType(), CodeGenFunction::destroyCXXObject,
+ getLangOpts().Exceptions);
break;
case SD_Dynamic:
@@ -490,7 +488,7 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
}
}
- pushTemporaryCleanup(*this, M, E, Object);
+ pushTemporaryCleanup(M, E, Object);
return RefTempDst;
}
@@ -579,7 +577,13 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
}
EmitAnyExprToMem(E, Object, Qualifiers(), /*IsInit*/true);
}
- pushTemporaryCleanup(*this, M, E, Object);
+
+ // If this temporary extended by for-range variable, delay to emitting
+ // cleanup.
+ if (CurLexicalScope && CurLexicalScope->isExtendedByForRangeVar(M))
+ CurLexicalScope->addForRangeInitTemp(M, Object);
+ else
+ pushTemporaryCleanup(M, E, Object);
// Perform derived-to-base casts and/or field accesses, to get from the
// temporary object we created (and, potentially, for which we extended
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 576fe2f7a2d46f..d277d15b17df13 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -1230,11 +1230,29 @@ CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S,
JumpDest LoopExit = getJumpDestInCurrentScope("for.end");
LexicalScope ForScope(*this, S.getSourceRange());
+ const DeclStmt *RangeDS = cast<DeclStmt>(S.getRangeStmt());
+ const VarDecl *RangeVar = cast<VarDecl>(RangeDS->getSingleDecl());
+ if (getLangOpts().CPlusPlus23)
+ ForScope.setForRangeVar(RangeVar);
// Evaluate the first pieces before the loop.
if (S.getInit())
EmitStmt(S.getInit());
EmitStmt(S.getRangeStmt());
+
+ // Emit cleanup for tempories in for-range-init expression.
+ if (getLangOpts().CPlusPlus23) {
+ RunCleanupsScope Scope(*this);
+ auto LifetimeExtendTemps = ForScope.getForRangeInitTemps();
+ for (const auto &Temp : LifetimeExtendTemps) {
+ // llvm::errs() << "===============Begin===============\n";
+ auto [M, Object] = Temp;
+ // M->dumpColor();
+ pushTemporaryCleanup(M, M->getSubExpr(), Object);
+ // llvm::errs() << "================End================\n";
+ }
+ }
+
EmitStmt(S.getBeginStmt());
EmitStmt(S.getEndStmt());
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index e2a7e28c8211ea..167ac71fefb722 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -875,6 +875,9 @@ class CodeGenFunction : public CodeGenTypeCache {
new (Buffer + sizeof(Header) + sizeof(T)) RawAddress(ActiveFlag);
}
+ void pushTemporaryCleanup(const MaterializeTemporaryExpr *M, const Expr *E,
+ Address ReferenceTemporary);
+
/// Set up the last cleanup that was pushed as a conditional
/// full-expression cleanup.
void initFullExprCleanup() {
@@ -982,11 +985,24 @@ class CodeGenFunction : public CodeGenTypeCache {
EHScopeStack::stable_iterator CurrentCleanupScopeDepth =
EHScopeStack::stable_end();
+ struct ForRangeInitLifetimeExtendTemporary {
+ const MaterializeTemporaryExpr *M;
+ RawAddress Object;
+ };
+
class LexicalScope : public RunCleanupsScope {
SourceRange Range;
SmallVector<const LabelDecl*, 4> Labels;
+ SmallVector<ForRangeInitLifetimeExtendTemporary, 4> ForRangeInitTemps;
LexicalScope *ParentScope;
+ // This will be set to `__range` variable when we emitting a
+ // CXXForRangeStmt. It was used to check whether we are emitting a
+ // materialized temporary which in for-range-init and lifetime-extended by
+ // __range var. If so, the codegen of cleanup for that temporary object
+ // needs to be delayed.
+ const VarDecl *ForRangeVar = nullptr;
+
LexicalScope(const LexicalScope &) = delete;
void operator=(const LexicalScope &) = delete;
@@ -1004,6 +1020,21 @@ class CodeGenFunction : public CodeGenTypeCache {
Labels.push_back(label);
}
+ void addForRangeInitTemp(const MaterializeTemporaryExpr *M,
+ RawAddress Object) {
+ assert(PerformCleanup && "adding temps to dead scope?");
+ ForRangeInitTemps.push_back({M, Object});
+ }
+
+ ArrayRef<ForRangeInitLifetimeExtendTemporary> getForRangeInitTemps() const {
+ return ForRangeInitTemps;
+ }
+
+ void setForRangeVar(const VarDecl *Var) { ForRangeVar = Var; }
+ bool isExtendedByForRangeVar(const MaterializeTemporaryExpr *M) const {
+ return M && ForRangeVar && M->getExtendingDecl() == ForRangeVar;
+ }
+
/// Exit this cleanup scope, emitting any accumulated
/// cleanups.
~LexicalScope() {
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 0aa14b0510746b..ae5d2cae06e536 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2379,10 +2379,6 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
if (getLangOpts().CPlusPlus23) {
auto &LastRecord = Actions.ExprEvalContexts.back();
LastRecord.InLifetimeExtendingContext = true;
-
- // Materialize non-`cv void` prvalue temporaries in discarded
- // expressions. These materialized temporaries may be lifetime-extented.
- LastRecord.InMaterializeTemporaryObjectContext = true;
}
if (getLangOpts().OpenMP)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index ffe7e44e2387f4..2caf8a3a3c8e83 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -6331,7 +6331,6 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
// Pass down lifetime extending flag, and collect temporaries in
// CreateMaterializeTemporaryExpr when we rewrite the call argument.
keepInLifetimeExtendingContext();
- keepInMaterializeTemporaryObjectContext();
EnsureImmediateInvocationInDefaultArgs Immediate(*this);
ExprResult Res;
runWithSufficientStackSpace(CallLoc, [&] {
@@ -6377,7 +6376,7 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
Expr *Init = nullptr;
bool NestedDefaultChecking = isCheckingDefaultArgumentOrInitializer();
-
+ bool InLifetimeExtendingContext = isInLifetimeExtendingContext();
EnterExpressionEvaluationContext EvalContext(
*this, ExpressionEvaluationContext::PotentiallyEvaluated, Field);
@@ -6412,19 +6411,21 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
ImmediateCallVisitor V(getASTContext());
if (!NestedDefaultChecking)
V.TraverseDecl(Field);
- if (V.HasImmediateCalls) {
+ if (V.HasImmediateCalls || InLifetimeExtendingContext) {
ExprEvalContexts.back().DelayedDefaultInitializationContext = {Loc, Field,
CurContext};
ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer =
NestedDefaultChecking;
-
+ // Pass down lifetime extending flag, and collect temporaries in
+ // CreateMaterializeTemporaryExpr when we rewrite the call argument.
+ keepInLifetimeExtendingContext();
EnsureImmediateInvocationInDefaultArgs Immediate(*this);
ExprResult Res;
runWithSufficientStackSpace(Loc, [&] {
Res = Immediate.TransformInitializer(Field->getInClassInitializer(),
/*CXXDirectInit=*/false);
});
- if (!Res.isInvalid())
+ if (Res.isUsable())
Res = ConvertMemberDefaultInitExpression(Field, Res.get(), Loc);
if (Res.isInvalid()) {
Field->setInvalidDecl();
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index db84f181012268..9f13e3827c742d 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -8361,7 +8361,7 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) {
// unnecessary temporary objects. If we skip this step, IR generation is
// able to synthesize the storage for itself in the aggregate case, and
// adding the extra node to the AST is just clutter.
- if (isInMaterializeTemporaryObjectContext() && getLangOpts().CPlusPlus17 &&
+ if (isInLifetimeExtendingContext() && getLangOpts().CPlusPlus17 &&
E->isPRValue() && !E->getType()->isVoidType()) {
ExprResult Res = TemporaryMaterializationConversion(E);
if (Res.isInvalid())
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index a75e9925a43146..c2269206988efc 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -710,6 +710,26 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
if (VerifyOnly)
return;
+ // Enter a lifetime extension context, then we can support lifetime
+ // extension of temporary created by aggregate initialization using a
+ // default member initializer (DR1815 https://wg21.link/CWG1815).
+ //
+ // In a lifetime extension context, BuildCXXDefaultInitExpr will clone the
+ // initializer expression on each use that would lifetime extend its
+ // temporaries.
+ EnterExpressionEvaluationContext LifetimeExtensionContext(
+ SemaRef, Sema::ExpressionEvaluationContext::PotentiallyEvaluated,
+ /*LambdaContextDecl=*/nullptr,
+ Sema::ExpressionEvaluationContextRecord::EK_Other, true);
+
+ // Lifetime extension in default-member-init.
+ auto &LastRecord = SemaRef.ExprEvalContexts.back();
+
+ // Just copy previous record, make sure we haven't forget anything.
+ LastRecord =
+ SemaRef.ExprEvalContexts[SemaRef.ExprEvalContexts.size() - 2];
+ LastRecord.InLifetimeExtendingContext = true;
+
ExprResult DIE = SemaRef.BuildCXXDefaultInitExpr(Loc, Field);
if (DIE.isInvalid()) {
hadError = true;
@@ -7699,6 +7719,8 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
// Step into CXXDefaultInitExprs so we can diagnose cases where a
// constructor inherits one as an implicit mem-initializer.
if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(Init)) {
+ assert(DIE->hasRewrittenInit() &&
+ "CXXDefaultInitExpr must has rewritten init");
Path.push_back(
{IndirectLocalPathEntry::DefaultInit, DIE, DIE->getField()});
Init = DIE->getExpr();
@@ -8194,24 +8216,12 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
switch (shouldLifetimeExtendThroughPath(Path)) {
case PathLifetimeKind::Extend:
+ case PathLifetimeKind::ShouldExtend:
// Update the storage duration of the materialized temporary.
- // FIXME: Rebuild the expression instead of mutating it.
MTE->setExtendingDecl(ExtendingEntity->getDecl(),
ExtendingEntity->allocateManglingNumber());
- // Also visit the temporaries lifetime-extended by this initializer.
return true;
- case PathLifetimeKind::ShouldExtend:
- // We're supposed to lifetime-extend the temporary along this path (per
- // the resolution of DR1815), but we don't support that yet.
- //
- // FIXME: Properly handle this situation. Perhaps the easiest approach
- // would be to clone the initializer expression on each use that would
- // lifetime extend its temporaries.
- Diag(DiagLoc, diag::warn_unsupported_lifetime_extension)
- << RK << DiagRange;
- break;
-
case PathLifetimeKind::NoExtend:
// If the path goes through the initialization of a variable or field,
// it can't possibly reach a temporary created in this full-expression.
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 1cb071e4eb7d1c..15d0b8a69bcd2c 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5477,7 +5477,6 @@ void Sema::InstantiateVariableInitializer(
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var);
keepInLifetimeExtendingContext();
- keepInMaterializeTemporaryObjectContext();
// Instantiate the initializer.
ExprResult Init;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 7df352c24e8648..818837064a38b7 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransfo...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/86960
More information about the cfe-commits
mailing list