[clang] [CIR] Introduce loop cleanup regions (PR #210212)

Andy Kaylor via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 16 18:09:42 PDT 2026


andykaylor wrote:

> Can we get a C++ test for this? I'm having a hard time figuring out what this looks like/what the lifetime of these cleanups are.

I won't be able to give you a C++ test until the third PR in this series. Here's a preview though:

```
struct S {
  S();
  ~S();
  explicit operator bool();
};

void while_cond_var() {
  while (S s{})
    doSomething();
}

// CIR-LABEL: cir.func {{.*}} @_Z14while_cond_vari
// CIR:   %[[FLAG:.*]] = cir.alloca {{.*}}"cond.cleanup.isactive"{{.*}} : !cir.ptr<!cir.bool>
// CIR:   cir.scope {
// CIR:     %[[S:.*]] = cir.alloca {{.*}}"s"{{.*}} : !cir.ptr<!rec_S>
// CIR:     cir.while {
// CIR:       %[[FALSE:.*]] = cir.const #false
// CIR:       cir.store %[[FALSE]], %[[FLAG]]
// CIR:       cir.call @_ZN1SC1Ev(%[[S]])
// CIR:       %[[TRUE:.*]] = cir.const #true
// CIR:       cir.store %[[TRUE]], %[[FLAG]]
// CIR:       %[[COND:.*]] = cir.call @_ZN1ScvbEv(%[[S]])
// CIR:       cir.condition(%[[COND]])
// CIR:     } do {
// CIR:     } cleanup all {
// CIR:       %[[ACTIVE:.*]] = cir.load {{.*}}%[[FLAG]]
// CIR:       cir.if %[[ACTIVE]] {
// CIR:         cir.call @_ZN1SD1Ev(%[[S]]) nothrow
// CIR:       }
// CIR:       cir.yield
// CIR:     }
// CIR:   }
```
We create the alloca for the condition variable in the scope outside the loop (as we have before this change). In theory, we could get rid of that scope and let the alloca go to the next higher scope or the entry block, but it has to be outside the loop operation. It has nothing to do with the actual scope of the variable.

If we were generating lifetime markers (as we will soon after this series of PRs land), the lifetime_begin would go in the condition region (above FALSE, I think), and the lifetime_end would go in the cleanup.

The use of the "cond.cleanup.isactive" flag here is an unfortunate artifact of not having a proper place to insert the cleanup scope. We're treating the entire condition and body region as the scope of the cleanup. Any exception thrown by the ctor would unwind to the cleanup, so we need to do something to avoid calling the dtor if the object was never constructed. We might be able to fix that in flattening or with a post-codegen optimization, but at least for the first working implementation I thought this was the way to go.

https://github.com/llvm/llvm-project/pull/210212


More information about the cfe-commits mailing list