llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clangir

Author: Jiahao Guo (E00N777)

<details>
<summary>Changes</summary>

### summary

fix https://github.com/llvm/llvm-project/issues/224821

A lifetime marker is not a real cleanup, so it must never be the reason an 
unwind edge exists.

Assisted by : Claude Opus5

---
Full diff: https://github.com/llvm/llvm-project/pull/224829.diff


3 Files Affected:

- (modified) clang/lib/CIR/CodeGen/CIRGenCleanup.cpp (+3) 
- (modified) clang/lib/CIR/CodeGen/CIRGenStmt.cpp (+22-12) 
- (modified) clang/test/CIR/CodeGen/lifetime-marker.cpp (+24-25) 


``````````diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
index 8103ef37f9225c..53a0b78c6ec7c3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
@@ -349,6 +349,9 @@ void *EHScopeStack::pushCleanup(CleanupKind kind, size_t 
size) {
   bool isLifetimeMarker = kind & LifetimeMarker;
   bool skipCleanupScope = false;
 
+  if (isLifetimeMarker)
+    isEHCleanup = false;
+
   cir::CleanupKind cleanupKind = cir::CleanupKind::All;
   if (isEHCleanup && cgf->getLangOpts().Exceptions) {
     cleanupKind =
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp 
b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index e9f5e466c63d24..044947b9ef1bca 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -1026,10 +1026,10 @@ mlir::LogicalResult CIRGenFunction::emitForStmt(const 
ForStmt &s) {
     // per-iteration cleanup region. This scope is constructed after the
     // init-statement so the init-statement's cleanups are not captured.
     const VarDecl *condVar = s.getConditionVariable();
+    bool condVarNeedsDtor =
+        condVar && condVar->needsDestruction(getContext()) != 
QualType::DK_none;
     bool needsCondCleanup =
-        condVar &&
-        (condVar->needsDestruction(getContext()) != QualType::DK_none ||
-         shouldEmitLifetimeMarkersForAutoVar());
+        condVar && (condVarNeedsDtor || shouldEmitLifetimeMarkersForAutoVar());
     DeferredLoopConditionCleanup loopCondScope(*this, needsCondCleanup);
 
     auto condBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
@@ -1065,9 +1065,14 @@ mlir::LogicalResult CIRGenFunction::emitForStmt(const 
ForStmt &s) {
     };
 
     if (needsCondCleanup) {
-      cir::CleanupKind cleanupKind = getLangOpts().Exceptions
-                                         ? cir::CleanupKind::All
-                                         : cir::CleanupKind::Normal;
+      // Without a destructor the cleanup region holds nothing but
+      // cir.lifetime.end. A lifetime marker must not be the reason an unwind
+      // edge exists, and an EH kind here would make every call in the
+      // condition, body and step unwind to it.
+      cir::CleanupKind cleanupKind =
+          getLangOpts().Exceptions && condVarNeedsDtor
+              ? cir::CleanupKind::All
+              : cir::CleanupKind::Normal;
       forOp = builder.createFor(
           getLoc(s.getSourceRange()), condBuilder, bodyBuilder, stepBuilder,
           /*cleanupBuilder=*/
@@ -1158,10 +1163,10 @@ mlir::LogicalResult CIRGenFunction::emitWhileStmt(const 
WhileStmt &s) {
     // destructor and lifetime-end cleanups and emit them into the loop's
     // per-iteration cleanup region.
     const VarDecl *condVar = s.getConditionVariable();
+    bool condVarNeedsDtor =
+        condVar && condVar->needsDestruction(getContext()) != 
QualType::DK_none;
     bool needsCondCleanup =
-        condVar &&
-        (condVar->needsDestruction(getContext()) != QualType::DK_none ||
-         shouldEmitLifetimeMarkersForAutoVar());
+        condVar && (condVarNeedsDtor || shouldEmitLifetimeMarkersForAutoVar());
     DeferredLoopConditionCleanup loopCondScope(*this, needsCondCleanup);
 
     auto condBuilder = [&](mlir::OpBuilder &b, mlir::Location loc) {
@@ -1185,9 +1190,14 @@ mlir::LogicalResult CIRGenFunction::emitWhileStmt(const 
WhileStmt &s) {
     };
 
     if (needsCondCleanup) {
-      cir::CleanupKind cleanupKind = getLangOpts().Exceptions
-                                         ? cir::CleanupKind::All
-                                         : cir::CleanupKind::Normal;
+      // Without a destructor the cleanup region holds nothing but
+      // cir.lifetime.end. A lifetime marker must not be the reason an unwind
+      // edge exists, and an EH kind here would make every call in the
+      // condition and body unwind to it.
+      cir::CleanupKind cleanupKind =
+          getLangOpts().Exceptions && condVarNeedsDtor
+              ? cir::CleanupKind::All
+              : cir::CleanupKind::Normal;
       whileOp = builder.createWhile(
           getLoc(s.getSourceRange()), condBuilder, bodyBuilder,
           /*cleanupBuilder=*/
diff --git a/clang/test/CIR/CodeGen/lifetime-marker.cpp 
b/clang/test/CIR/CodeGen/lifetime-marker.cpp
index dde66fac13d963..d1de8ef9185c93 100644
--- a/clang/test/CIR/CodeGen/lifetime-marker.cpp
+++ b/clang/test/CIR/CodeGen/lifetime-marker.cpp
@@ -134,10 +134,10 @@ void if_body(int n) {
 // LLVM:       [[IF_END]]:
 // LLVM:         call void @_Z3usei
 
-// With exceptions enabled the scope cleanup runs on both the normal and the
-// exceptional edge, so the cleanup kind is "all" and lifetime.end is emitted 
in
-// the EH cleanup handler (the landing pad) as well as on the normal path. The
-// may_throw() call is what forces an unwind edge.
+// A lifetime marker is not a real cleanup, so even with exceptions enabled it
+// must never be the reason an unwind path exists. The cleanup kind stays
+// "normal" and may_throw() is a plain call, mirroring classic CodeGen, where
+// EHScopeStack::requiresLandingPad skips lifetime-marker cleanups.
 void may_throw();
 
 void eh_cleanup() {
@@ -151,19 +151,16 @@ void eh_cleanup() {
 // CIR-EH:         cir.lifetime.start %[[X]] : !cir.ptr<!s32i>
 // CIR-EH:         cir.cleanup.scope {
 // CIR-EH:           cir.call @_Z9may_throwv()
-// CIR-EH:         } cleanup all {
+// CIR-EH:         } cleanup normal {
 // CIR-EH:           cir.lifetime.end %[[X]] : !cir.ptr<!s32i>
 // CIR-EH:         }
 
-// LLVM-EH-LABEL: define{{.*}} void @_Z10eh_cleanupv()
+// The '{' right after the attribute group pins the absence of a personality
+// clause: the function needs no exception handling at all.
+// LLVM-EH-LABEL: define{{.*}} void @_Z10eh_cleanupv() #{{[0-9]+}} {
 // LLVM-EH:         %[[X:.*]] = alloca i32
 // LLVM-EH:         call void @llvm.lifetime.start.p0(ptr %[[X]])
-// LLVM-EH:         invoke void @_Z9may_throwv()
-// The normal-path end marker.
-// LLVM-EH:         call void @llvm.lifetime.end.p0(ptr %[[X]])
-// The EH cleanup handler runs the same end marker on the unwind path.
-// LLVM-EH:         landingpad { ptr, i32 }
-// LLVM-EH-NEXT:      cleanup
+// LLVM-EH:         call void @_Z9may_throwv()
 // LLVM-EH:         call void @llvm.lifetime.end.p0(ptr %[[X]])
 
 // A loop condition variable is destroyed and re-created on every iteration
@@ -188,19 +185,21 @@ void while_condvar() {
 // LLVM:         call void @llvm.lifetime.start.p0(ptr %[[C:.*]])
 // LLVM:         call void @llvm.lifetime.end.p0(ptr %[[C]])
 
+// A loop's cleanup region spans the condition, the body and the step, so an EH
+// cleanup kind here would make every call in the loop unwind to it. A
+// marker-only region must therefore stay "normal".
 // CIR-EH-LABEL: cir.func{{.*}} @_Z13while_condvarv
 // CIR-EH:         %[[C:.*]] = cir.alloca "c" {{.*}} : !cir.ptr<!s32i>
 // CIR-EH:         cir.while {
 // CIR-EH:           cir.lifetime.start %[[C]] : !cir.ptr<!s32i>
 // CIR-EH:         } do {
-// CIR-EH:         } cleanup all {
+// CIR-EH:         } cleanup normal {
 // CIR-EH:           cir.lifetime.end %[[C]] : !cir.ptr<!s32i>
 
-// LLVM-EH-LABEL: define{{.*}} void @_Z13while_condvarv
+// LLVM-EH-LABEL: define{{.*}} void @_Z13while_condvarv() #{{[0-9]+}} {
 // LLVM-EH:         call void @llvm.lifetime.start.p0(ptr %[[C:.*]])
-// LLVM-EH:         call void @llvm.lifetime.end.p0(ptr %[[C]])
-// LLVM-EH:         landingpad { ptr, i32 }
-// LLVM-EH-NEXT:      cleanup
+// LLVM-EH:         call noundef i32 @_Z6sourcev()
+// LLVM-EH:         call void @_Z3usei
 // LLVM-EH:         call void @llvm.lifetime.end.p0(ptr %[[C]])
 
 void for_condvar() {
@@ -227,14 +226,13 @@ void for_condvar() {
 // CIR-EH:           cir.lifetime.start %[[C]] : !cir.ptr<!s32i>
 // CIR-EH:         } body {
 // CIR-EH:         } step {
-// CIR-EH:         } cleanup all {
+// CIR-EH:         } cleanup normal {
 // CIR-EH:           cir.lifetime.end %[[C]] : !cir.ptr<!s32i>
 
-// LLVM-EH-LABEL: define{{.*}} void @_Z11for_condvarv
+// LLVM-EH-LABEL: define{{.*}} void @_Z11for_condvarv() #{{[0-9]+}} {
 // LLVM-EH:         call void @llvm.lifetime.start.p0(ptr %[[C:.*]])
-// LLVM-EH:         call void @llvm.lifetime.end.p0(ptr %[[C]])
-// LLVM-EH:         landingpad { ptr, i32 }
-// LLVM-EH-NEXT:      cleanup
+// LLVM-EH:         call noundef i32 @_Z6sourcev()
+// LLVM-EH:         call void @_Z3usei
 // LLVM-EH:         call void @llvm.lifetime.end.p0(ptr %[[C]])
 
 struct LoopCond {
@@ -243,7 +241,8 @@ struct LoopCond {
 };
 
 // A non-trivial condition variable runs its destructor before lifetime.end in
-// the loop cleanup region.
+// the loop cleanup region. That region is a real cleanup, so it keeps the 
"all"
+// kind and the marker rides along on the unwind path the destructor requires.
 void while_record_condvar() {
   while (LoopCond c{}) {}
 }
@@ -300,7 +299,7 @@ void catch_by_ref() {
 // CIR-EH:             } cleanup all {
 // CIR-EH:               cir.end_catch %[[CATCH_TOK]]
 // CIR-EH:             }
-// CIR-EH:           } cleanup all {
+// CIR-EH:           } cleanup normal {
 // CIR-EH-NEXT:        cir.lifetime.end %[[E]] : !cir.ptr<!cir.ptr<!rec_Ex>>
 
 // LLVM-EH-LABEL: define{{.*}} void @_Z12catch_by_refv()
@@ -330,7 +329,7 @@ void catch_by_value() {
 // CIR-EH-NEXT:        %[[CATCH_TOK:.*]], %{{.*}} = cir.begin_catch %[[TOK]]
 // CIR-EH:                 cir.call @_ZN4CopyD1Ev(%[[C]])
 // CIR-EH:               cir.end_catch %[[CATCH_TOK]]
-// CIR-EH:           } cleanup all {
+// CIR-EH:           } cleanup normal {
 // CIR-EH-NEXT:        cir.lifetime.end %[[C]] : !cir.ptr<!rec_Copy>
 
 // LLVM-EH-LABEL: define{{.*}} void @_Z14catch_by_valuev()

``````````

</details>


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

Reply via email to