clangir icon indicating copy to clipboard operation
clangir copied to clipboard

[CIR] Breaking from a loop misses cleanups

Open andykaylor opened this issue 2 months ago • 0 comments

If I have a loop that constructs variables that require cleanup, the cleanup is missed if I use a break statement to exit the loop.

Reproducer:

struct S {
  S();
  ~S();
};

void f() {
  while (true) {
    S s;
    if (true)
      break;
  }
}

Results in this CIR:

  cir.func dso_local @_Z1fv() attributes {ast = #cir.function.decl.ast} extra(#fn_attr1) {
    cir.scope {
      cir.while {
        %0 = cir.const #true
        cir.condition(%0)
      } do {
        cir.scope {
          %0 = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s", init] ast #cir.var.decl.ast {alignment = 1 : i64}
          cir.call @_ZN1SC1Ev(%0) : (!cir.ptr<!rec_S>) -> ()
          cir.scope {
            %1 = cir.const #true
            cir.if %1 {
              cir.break
            }
          }
          cir.call @_ZN1SD1Ev(%0) : (!cir.ptr<!rec_S>) -> () extra(#fn_attr)
        }
        cir.yield
      }
    }
    cir.return
  }

That's wrong because the cir.break skips the cleanup. After FlattenCFG, it looks like this:

  cir.func dso_local @_Z1fv() extra(#fn_attr1) {
    %0 = cir.alloca !rec_S, !cir.ptr<!rec_S>, ["s", init] {alignment = 1 : i64}
    cir.br ^bb1
  ^bb1:  // pred: ^bb0
    cir.br ^bb2
  ^bb2:  // 2 preds: ^bb1, ^bb9
    %1 = cir.const #true
    cir.brcond %1 ^bb3, ^bb10
  ^bb3:  // pred: ^bb2
    cir.br ^bb4
  ^bb4:  // pred: ^bb3
    cir.call @_ZN1SC1Ev(%0) : (!cir.ptr<!rec_S>) -> ()
    cir.br ^bb5
  ^bb5:  // pred: ^bb4
    %2 = cir.const #true
    cir.brcond %2 ^bb6, ^bb7
  ^bb6:  // pred: ^bb5
    cir.br ^bb10
  ^bb7:  // pred: ^bb5
    cir.br ^bb8
  ^bb8:  // pred: ^bb7
    cir.call @_ZN1SD1Ev(%0) : (!cir.ptr<!rec_S>) -> () extra(#fn_attr)
    cir.br ^bb9
  ^bb9:  // pred: ^bb8
    cir.br ^bb2
  ^bb10:  // 2 preds: ^bb2, ^bb6
    cir.br ^bb11
  ^bb11:  // pred: ^bb10
    cir.return
  }

The break is handled in ^bb6 and results in the cleanup (^bb8) being skipped entirely.

https://godbolt.org/z/r1KnnK35T

This is probably related to https://github.com/llvm/clangir/issues/1123

andykaylor avatar Oct 13 '25 22:10 andykaylor