[clang] [CIR] Introduce loop cleanup regions (PR #210212)
Erich Keane via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 17 06:36:33 PDT 2026
erichkeane 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.
Thanks, this is really helpful!
https://github.com/llvm/llvm-project/pull/210212
More information about the cfe-commits
mailing list