[llvm-branch-commits] [clang] [CFG] Fix temporary CXXDefaultInitExpr (PR #191786)
Utkarsh Saxena via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Apr 13 03:16:44 PDT 2026
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/191786
>From 9855134d6e7ee0794f32d482d7b4d33950e93ce0 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Mon, 13 Apr 2026 10:10:43 +0000
Subject: [PATCH 1/2] [CFG] Fix temporary CXXDefaultInitExpr
---
.../Analyses/LifetimeSafety/FactsGenerator.h | 1 +
clang/lib/Analysis/CFG.cpp | 34 +++++++++++--------
.../LifetimeSafety/FactsGenerator.cpp | 5 +++
clang/test/Sema/warn-lifetime-safety.cpp | 12 +++++++
4 files changed, 38 insertions(+), 14 deletions(-)
diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
index 2dbadb27981a7..cab524f12bab3 100644
--- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
+++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/FactsGenerator.h
@@ -36,6 +36,7 @@ class FactsGenerator : public ConstStmtVisitor<FactsGenerator> {
void VisitDeclStmt(const DeclStmt *DS);
void VisitDeclRefExpr(const DeclRefExpr *DRE);
void VisitCXXConstructExpr(const CXXConstructExpr *CCE);
+ void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *DIE);
void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE);
void VisitMemberExpr(const MemberExpr *ME);
void VisitCallExpr(const CallExpr *CE);
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 543b9d8424488..cba6cec0f4f49 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -1824,29 +1824,31 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
if (!BuildOpts.AddInitializers)
return Block;
- bool HasTemporaries = false;
-
// Destructors of temporaries in initialization expression should be called
// after initialization finishes.
Expr *Init = I->getInit();
if (Init) {
- HasTemporaries = isa<ExprWithCleanups>(Init);
+ Expr *ActualInit = Init;
+ if (BuildOpts.AddCXXDefaultInitExprInCtors) {
+ if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(Init))
+ ActualInit = DIE->getExpr();
+ }
+
+ bool HasTemporaries = isa<ExprWithCleanups>(ActualInit);
if (HasTemporaries &&
(BuildOpts.AddTemporaryDtors || BuildOpts.AddLifetime)) {
// Generate destructors for temporaries in initialization expression.
TempDtorContext Context;
- VisitForTemporaries(cast<ExprWithCleanups>(Init)->getSubExpr(),
+ VisitForTemporaries(cast<ExprWithCleanups>(ActualInit)->getSubExpr(),
/*ExternallyDestructed=*/false, Context);
addFullExprCleanupMarker(Context);
}
- }
- autoCreateBlock();
- appendInitializer(Block, I);
+ autoCreateBlock();
+ appendInitializer(Block, I);
- if (Init) {
// If the initializer is an ArrayInitLoopExpr, we want to extract the
// initializer, that's used for each element.
auto *AILEInit = extractElementInitializerFromNestedAILE(
@@ -1856,11 +1858,6 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
ConstructionContextLayer::create(cfg->getBumpVectorContext(), I),
AILEInit ? AILEInit : Init);
- if (HasTemporaries) {
- // For expression with temporaries go directly to subexpression to omit
- // generating destructors for the second time.
- return Visit(cast<ExprWithCleanups>(Init)->getSubExpr());
- }
if (BuildOpts.AddCXXDefaultInitExprInCtors) {
if (CXXDefaultInitExpr *Default = dyn_cast<CXXDefaultInitExpr>(Init)) {
// In general, appending the expression wrapped by a CXXDefaultInitExpr
@@ -1868,12 +1865,21 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) {
// here is safe because there's only one initializer per field.
autoCreateBlock();
appendStmt(Block, Default);
- if (Stmt *Child = Default->getExpr())
+ if (Stmt *Child = Default->getExpr()) {
+ if (HasTemporaries)
+ Child = cast<ExprWithCleanups>(Child)->getSubExpr();
if (CFGBlock *R = Visit(Child))
Block = R;
+ }
return Block;
}
}
+
+ if (HasTemporaries) {
+ // For expression with temporaries go directly to subexpression to omit
+ // generating destructors for the second time.
+ return Visit(cast<ExprWithCleanups>(Init)->getSubExpr());
+ }
return Visit(Init);
}
diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
index 69a64d08e0385..be9dd03dfe3da 100644
--- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
+++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp
@@ -207,6 +207,11 @@ void FactsGenerator::VisitCXXConstructExpr(const CXXConstructExpr *CCE) {
/*IsGslConstruction=*/false);
}
+void FactsGenerator::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *DIE) {
+ if (const Expr *Init = DIE->getExpr())
+ killAndFlowOrigin(*DIE, *Init);
+}
+
void FactsGenerator::handleCXXCtorInitializer(const CXXCtorInitializer *CII) {
// Flows origins from the initializer expression to the field.
// Example: `MyObj(std::string s) : view(s) {}`
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index 07562c4b33f8e..b348bb362e6f9 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -2615,3 +2615,15 @@ int *noreturn_dead_nested(bool cond, bool cond2, int *num) {
}
} // namespace conditional_operator_control_flow
+
+namespace CXXDefaultInitExprTests {
+struct Holder {
+ std::string_view view = std::string("temporary"); // expected-warning {{address of stack memory escapes to a field}} expected-note {{this field dangles}}
+ Holder() {}
+};
+
+void test() {
+ Holder h;
+ (void)h;
+}
+} // namespace CXXDefaultInitExprTests
>From aaba1c2b9d24397033b3af57997fda626b64bc92 Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Mon, 13 Apr 2026 10:15:58 +0000
Subject: [PATCH 2/2] remove extra usage
---
clang/test/Sema/warn-lifetime-safety.cpp | 5 -----
1 file changed, 5 deletions(-)
diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp
index b348bb362e6f9..ee777af909eab 100644
--- a/clang/test/Sema/warn-lifetime-safety.cpp
+++ b/clang/test/Sema/warn-lifetime-safety.cpp
@@ -2621,9 +2621,4 @@ struct Holder {
std::string_view view = std::string("temporary"); // expected-warning {{address of stack memory escapes to a field}} expected-note {{this field dangles}}
Holder() {}
};
-
-void test() {
- Holder h;
- (void)h;
-}
} // namespace CXXDefaultInitExprTests
More information about the llvm-branch-commits
mailing list