[clang] [clang] Fix lifetime extension of temporaries in for-range-initializers in templates (PR #177191)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Jan 21 08:09:50 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: None (yronglin)
<details>
<summary>Changes</summary>
Fixes https://github.com/llvm/llvm-project/issues/165182.
This patch fix the lifetime extension of temporaries in for-range-initializers in templates. Whether this issue was occurred when the for-range statement in a dependent context, but itself is not type/value dependent.
---
Full diff: https://github.com/llvm/llvm-project/pull/177191.diff
2 Files Affected:
- (modified) clang/lib/Sema/SemaStmt.cpp (+7-8)
- (modified) clang/test/CXX/special/class.temporary/p6.cpp (+34)
``````````diff
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1b1643250d05e..5ab10fdfc7b74 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -2753,14 +2753,6 @@ StmtResult Sema::BuildCXXForRangeStmt(
diag::err_for_range_incomplete_type))
return StmtError();
- // P2718R0 - Lifetime extension in range-based for loops.
- if (getLangOpts().CPlusPlus23 && !LifetimeExtendTemps.empty()) {
- InitializedEntity Entity =
- InitializedEntity::InitializeVariable(RangeVar);
- for (auto *MTE : LifetimeExtendTemps)
- MTE->setExtendingDecl(RangeVar, Entity.allocateManglingNumber());
- }
-
// Build auto __begin = begin-expr, __end = end-expr.
// Divide by 2, since the variables are in the inner scope (loop body).
const auto DepthStr = std::to_string(S->getDepth() / 2);
@@ -3017,6 +3009,13 @@ StmtResult Sema::BuildCXXForRangeStmt(
if (getLangOpts().OpenMP >= 50 && BeginDeclStmt.isUsable())
OpenMP().ActOnOpenMPLoopInitialization(ForLoc, BeginDeclStmt.get());
+ // P2718R0 - Lifetime extension in range-based for loops.
+ if (getLangOpts().CPlusPlus23 && !LifetimeExtendTemps.empty()) {
+ InitializedEntity Entity = InitializedEntity::InitializeVariable(RangeVar);
+ for (auto *MTE : LifetimeExtendTemps)
+ MTE->setExtendingDecl(RangeVar, Entity.allocateManglingNumber());
+ }
+
return new (Context) CXXForRangeStmt(
InitStmt, RangeDS, cast_or_null<DeclStmt>(BeginDeclStmt.get()),
cast_or_null<DeclStmt>(EndDeclStmt.get()), NotEqExpr.get(),
diff --git a/clang/test/CXX/special/class.temporary/p6.cpp b/clang/test/CXX/special/class.temporary/p6.cpp
index 2b1b531b7172c..12e760b60e65b 100644
--- a/clang/test/CXX/special/class.temporary/p6.cpp
+++ b/clang/test/CXX/special/class.temporary/p6.cpp
@@ -700,4 +700,38 @@ void default_init2() {
for (auto &&x : B{0}.a.arr) {}
}
} // namespace default_init
+
+namespace GH165182 {
+extern "C" int printf(const char *, ...);
+
+const char* s = "1";
+
+struct Foo {
+ int& x;
+ Foo(int& x) noexcept : x{x} {}
+ ~Foo() noexcept { x = 42; }
+ const char* begin() const noexcept { return s; }
+ const char* end() const noexcept { return s + 1; }
+};
+
+const Foo& f1(const Foo& t) noexcept { return t; }
+Foo g(int& x) noexcept { return Foo(x); }
+
+// Lifetime extension is missing!
+template <typename T>
+int test1() {
+ int x = 5;
+ int sum = 0;
+ // CHECK-CXX23: for.cond.cleanup:
+ // CHECK-CXX23-NEXT: call void @_ZN7P2718R08GH1651823FooD1Ev(
+ for (int _ : f1(g(x))) sum += x;
+ sum += x;
+ return sum;
+}
+
+int foo() {
+ printf("%i\n", test1<int>());
+}
+
+} // namespace GH165182
} // namespace P2718R0
``````````
</details>
https://github.com/llvm/llvm-project/pull/177191
More information about the cfe-commits
mailing list