Skip to content

[CIR] Breaking from a loop misses cleanups #1951

@andykaylor

Description

@andykaylor

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 #1123

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions