https://github.com/erichkeane updated 
https://github.com/llvm/llvm-project/pull/197705

>From 48a7f45dc49d46040f93cfe6b6e01c55af6a6fc9 Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Thu, 14 May 2026 07:36:18 -0700
Subject: [PATCH 1/4] [CIR] Add lexical scope for the 'range-for' body
 statement.

Without this, we fail the verifier due to lack of a terminator on the
scope if there is a destructed type in the 'body', as the cleanup scope
on the cir.scope object will insert the yield in the body (since that
is the last place we needed a cleanup), rather than actually putting one
at the end of the scope itself.

This patch adds a lexical scope to the body-statement, which makes sure
the proper yields are emitted.
---
 clang/lib/CIR/CodeGen/CIRGenStmt.cpp |  1 +
 clang/test/CIR/CodeGen/forrange.cpp  | 35 ++++++++++++++++++++++++++++
 2 files changed, 36 insertions(+)

diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp 
b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index a64a2a080bade..55661751ac217 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -936,6 +936,7 @@ CIRGenFunction::emitCXXForRangeStmt(const CXXForRangeStmt 
&s,
           bool useCurrentScope = true;
           if (emitStmt(s.getLoopVarStmt(), useCurrentScope).failed())
             loopRes = mlir::failure();
+          LexicalScope lexScope{*this, loc, builder.getInsertionBlock()};
           if (emitStmt(s.getBody(), useCurrentScope).failed())
             loopRes = mlir::failure();
           emitStopPoint(&s);
diff --git a/clang/test/CIR/CodeGen/forrange.cpp 
b/clang/test/CIR/CodeGen/forrange.cpp
index 0ffe4e2f29743..bbf2a79c697da 100644
--- a/clang/test/CIR/CodeGen/forrange.cpp
+++ b/clang/test/CIR/CodeGen/forrange.cpp
@@ -131,3 +131,38 @@ void for_range3() {
 // CIR:        cir.yield
 // CIR:      }
 // CIR:    }
+
+struct HasDtor { ~HasDtor(); };
+
+void for_range4() {
+  C3 c;
+  for (Element &e : c) {
+    HasDtor hd;
+  }
+}
+// CIR: cir.func{{.*}} @_Z10for_range4v()
+// CIR:    cir.scope {
+// CIR:      %[[RANGE_ADDR:.*]] = cir.alloca !cir.ptr<!rec_C3>{{.*}} 
["__range1", init, const]
+// CIR:      %[[BEGIN_ADDR:.*]] = cir.alloca !rec_Iterator, 
!cir.ptr<!rec_Iterator>{{.*}} ["__begin1", init]
+// CIR:      %[[END_ADDR:.*]] = cir.alloca !rec_Iterator, 
!cir.ptr<!rec_Iterator>{{.*}} ["__end1", init]
+// CIR:      %[[E_ADDR:.*]] = cir.alloca !cir.ptr<!rec_Element>{{.*}} ["e", 
init, const]
+// CIR:      cir.store{{.*}} %[[C_ADDR]], %[[RANGE_ADDR]]
+// CIR:      cir.for : cond {
+// CIR:        %[[ITER_NE:.*]] = cir.call 
@_ZNK8IteratorneERKS_(%[[BEGIN_ADDR]], %[[END_ADDR]])
+// CIR:        cir.condition(%[[ITER_NE]])
+// CIR:      } body {
+// CIR:        %[[HD:.*]] = cir.alloca !rec_HasDtor, !cir.ptr<!rec_HasDtor>, 
["hd"]
+// CIR:        %[[E:.*]] = cir.call @_ZN8IteratordeEv(%[[BEGIN_ADDR]])
+// CIR:        cir.store{{.*}} %[[E]], %[[E_ADDR]]
+// CIR:        cir.cleanup.scope {
+// CIR:          cir.yield
+// CIR:        } cleanup normal {
+// CIR:          cir.call @_ZN7HasDtorD1Ev(%[[HD]]) nothrow 
+// CIR:          cir.yield
+// CIR:        }
+// CIR:        cir.yield
+// CIR:      } step {
+// CIR:        %[[ITER_NEXT:.*]] = cir.call @_ZN8IteratorppEv(%[[BEGIN_ADDR]])
+// CIR:        cir.yield
+// CIR:      }
+// CIR:    }

>From 6a01694f6a7b2a5e28c82dcd6d719ac8c6d80c7d Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Thu, 14 May 2026 07:41:41 -0700
Subject: [PATCH 2/4] Just make the body use its own scope!

---
 clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 13 +++++++------
 clang/test/CIR/CodeGen/forrange.cpp  | 14 ++++++++------
 2 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp 
b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index 55661751ac217..0e20d8f30b892 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -918,7 +918,9 @@ CIRGenFunction::emitCXXForRangeStmt(const CXXForRangeStmt 
&s,
     // We probably already do the right thing because of ScopeOp, but make
     // sure we handle all cases.
     assert(!cir::MissingFeatures::loopSpecificCleanupHandling());
-
+    // https://en.cppreference.com/w/cpp/language/for
+    // Given: 
+    // for ( init-statement condition (optional) ; expression (optional) ) 
statement
     forOp = builder.createFor(
         getLoc(s.getSourceRange()),
         /*condBuilder=*/
@@ -930,14 +932,13 @@ CIRGenFunction::emitCXXForRangeStmt(const CXXForRangeStmt 
&s,
         },
         /*bodyBuilder=*/
         [&](mlir::OpBuilder &b, mlir::Location loc) {
-          // https://en.cppreference.com/w/cpp/language/for
-          // In C++ the scope of the init-statement and the scope of
-          // statement are one and the same.
+          // https://en.cppreference.com/cpp/language/range-for
+          // The scope of statement and the scope of expression are disjoint
+          // and nested within the scope of init-statement and condition.
           bool useCurrentScope = true;
           if (emitStmt(s.getLoopVarStmt(), useCurrentScope).failed())
             loopRes = mlir::failure();
-          LexicalScope lexScope{*this, loc, builder.getInsertionBlock()};
-          if (emitStmt(s.getBody(), useCurrentScope).failed())
+          if (emitStmt(s.getBody(), /*useCurrentScope=*/false).failed())
             loopRes = mlir::failure();
           emitStopPoint(&s);
         },
diff --git a/clang/test/CIR/CodeGen/forrange.cpp 
b/clang/test/CIR/CodeGen/forrange.cpp
index bbf2a79c697da..f171171a01bb1 100644
--- a/clang/test/CIR/CodeGen/forrange.cpp
+++ b/clang/test/CIR/CodeGen/forrange.cpp
@@ -151,14 +151,16 @@ void for_range4() {
 // CIR:        %[[ITER_NE:.*]] = cir.call 
@_ZNK8IteratorneERKS_(%[[BEGIN_ADDR]], %[[END_ADDR]])
 // CIR:        cir.condition(%[[ITER_NE]])
 // CIR:      } body {
-// CIR:        %[[HD:.*]] = cir.alloca !rec_HasDtor, !cir.ptr<!rec_HasDtor>, 
["hd"]
 // CIR:        %[[E:.*]] = cir.call @_ZN8IteratordeEv(%[[BEGIN_ADDR]])
 // CIR:        cir.store{{.*}} %[[E]], %[[E_ADDR]]
-// CIR:        cir.cleanup.scope {
-// CIR:          cir.yield
-// CIR:        } cleanup normal {
-// CIR:          cir.call @_ZN7HasDtorD1Ev(%[[HD]]) nothrow 
-// CIR:          cir.yield
+// CIR:        cir.scope {
+// CIR:          %[[HD:.*]] = cir.alloca !rec_HasDtor, !cir.ptr<!rec_HasDtor>, 
["hd"]
+// CIR:          cir.cleanup.scope {
+// CIR:            cir.yield
+// CIR:          } cleanup normal {
+// CIR:            cir.call @_ZN7HasDtorD1Ev(%[[HD]]) nothrow 
+// CIR:            cir.yield
+// CIR:          }
 // CIR:        }
 // CIR:        cir.yield
 // CIR:      } step {

>From ab465c6f8e6f7af99b9c9a8f8ba59643ac30a408 Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Thu, 14 May 2026 07:58:50 -0700
Subject: [PATCH 3/4] Clang format

---
 clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp 
b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index 0e20d8f30b892..961b9ba8dd577 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -919,8 +919,9 @@ CIRGenFunction::emitCXXForRangeStmt(const CXXForRangeStmt 
&s,
     // sure we handle all cases.
     assert(!cir::MissingFeatures::loopSpecificCleanupHandling());
     // https://en.cppreference.com/w/cpp/language/for
-    // Given: 
-    // for ( init-statement condition (optional) ; expression (optional) ) 
statement
+    // Given:
+    // for ( init-statement condition (optional) ; expression (optional) )
+    // statement
     forOp = builder.createFor(
         getLoc(s.getSourceRange()),
         /*condBuilder=*/

>From 1f8f5800bf2b29f121190ba51c21496092e31306 Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Thu, 14 May 2026 08:47:13 -0700
Subject: [PATCH 4/4] clang-format

---
 clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp 
b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index 961b9ba8dd577..dbe53891979e2 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -920,8 +920,8 @@ CIRGenFunction::emitCXXForRangeStmt(const CXXForRangeStmt 
&s,
     assert(!cir::MissingFeatures::loopSpecificCleanupHandling());
     // https://en.cppreference.com/w/cpp/language/for
     // Given:
-    // for ( init-statement condition (optional) ; expression (optional) )
-    // statement
+    // for ( init-statement condition (optional) ; expression (optional)
+    // ) statement
     forOp = builder.createFor(
         getLoc(s.getSourceRange()),
         /*condBuilder=*/

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to