AstGen: allow labels to provide separate break and continue targets

Enhances `GenZir` to allow labels to provide separate `break` and `continue`
target blocks and adds some more information on continue targets to
communicate whether the target is a switch block or cannot be targeted by
`continue` at all.

The main motivation is enabling this:
```
const result: u32 = operand catch |err| label: switch (err) {
    else => continue :label error.MyError,
    error.MyError => break :label 1,
};
```
to be lowered to something like this:
```
%1 = block({
  %2 = is_non_err(%operand)
  %3 = condbr(%2, {
    %4 = err_union_payload_unsafe(%operand)
    %5 = break(%1, result) // targets enclosing `block`
  }, {
    %6 = err_union_code(%operand)
    %7 = switch_block(%6,
      else => {
        %8 = switch_continue(%7, "error.MyError") // targets `switch_block`
      },
      "error.MyError" => {
        %9 = break(%1, @one) // targets enclosing `block`
      },
    )
    %10 = break(%1, @void_value)
  })
})
```
which makes the non-error case and all breaks from switch prongs, but not
continues from switch prongs, peers.

This is required to avoid the problems described in gh#11957 for labeled
switches without having to introduce a fairly complex special case to the
`switch_block_err_union` logic. Since this construct is very rare in practice,
introducing this additional complexity just to save a few ZIR bytes is
likely not worth it, so the simplified lowering described above will be
used instead.

As a nice bonus, AstGen can now also detect a `continue` trying to target
a labeled block and emit an appropriate error message.
This commit is contained in:
Justus Klausecker 2025-12-17 16:43:28 +01:00 committed by Matthew Lugg
parent aa2b178029
commit e0108dec54
No known key found for this signature in database
GPG key ID: 3F5B7DCCBF4AF02E
2 changed files with 235 additions and 188 deletions

View file

@ -0,0 +1,10 @@
export fn foo() void {
const result: u32 = b: {
continue :b 123;
};
_ = result;
}
// error
//
// :3:9: error: continue cannot target labeled block