Skip to content

builder: Emit a plain jump for a switch with no cases#891

Open
Dnreikronos wants to merge 3 commits into
rust-lang:masterfrom
Dnreikronos:fix-empty-switch-no-cases
Open

builder: Emit a plain jump for a switch with no cases#891
Dnreikronos wants to merge 3 commits into
rust-lang:masterfrom
Dnreikronos:fix-empty-switch-no-cases

Conversation

@Dnreikronos
Copy link
Copy Markdown

@Dnreikronos Dnreikronos commented May 29, 2026

Closes #881

A range-pattern match compiled with -Zmir-preserve-ub can leave a SwitchInt whose only target is otherwise. That reaches the backend as a switch with an empty case list, and in the reproducer the discriminant is the bool result of the range comparison. gcc_jit_block_end_with_switch only accepts an integer discriminant, so it errors out and leaves the block unterminated.

A switch with no cases always goes to the default block, so emit a plain jump in that case rather than building a degenerate switch. This is also what codegen_ssa already relies on for the LLVM backend, which tolerates the empty switch.

Verification

Built the backend locally and ran the exact reproducer from the issue with -Zmir-preserve-ub -Clink-dead-code=true:

  • Without this change, it reproduces the reported error verbatim:

    libgccjit.so: error: : gcc_jit_block_end_with_switch: expr: (...)53 <= (...)57 (type: bool) is not of integer type
    libgccjit.so: error: : unterminated block in ..._main: bb1
    
  • With this change, it compiles cleanly and the resulting binary runs (exit 0).

The MIR confirms the shape. bb0 holds switchInt(_2: bool) -> [0: bb2, otherwise: bb1], which has a single case and is lowered to a conditional branch by codegen_ssa, so it never reaches here. bb1 holds switchInt(_3: bool) -> bb2, a switch with zero cases, which is the one that hit the empty-case path.

No in-tree regression test, since the lang_tester harness has no per-file compile-flags and the bug needs -Zmir-preserve-ub. Happy to add one if there's a preferred spot.

@rustbot

This comment has been minimized.

@Dnreikronos Dnreikronos force-pushed the fix-empty-switch-no-cases branch from 288ecb5 to a41879d Compare May 29, 2026 16:32
A `SwitchInt` with only an `otherwise` target reaches the backend as a
switch with an empty case list. `gcc_jit_block_end_with_switch` requires
an integer discriminant, so it rejects the `bool` discriminant produced
by a range-pattern comparison under `-Zmir-preserve-ub`, which keeps the
otherwise-simplified switch instead of lowering it to a `goto`.

Such a switch is equivalent to an unconditional jump to the default
block, so emit that instead.
@Dnreikronos Dnreikronos force-pushed the fix-empty-switch-no-cases branch from a41879d to d865ac7 Compare May 29, 2026 16:40
@antoyo
Copy link
Copy Markdown
Contributor

antoyo commented May 29, 2026

Thanks for your work.

I believe we might be able to add the test the following way.
We could run it with adding a new env var (similar to TEST_FLAGS), and run it this way:

CARGO_TEST_FLAGS="-Zmir-preserve-ub" ./y.sh test --cargo-tests -- NEW_TEST_NAME

and add a commented line that does something like // ignore-if: <check-that-env-var-CARGO_TEST_FLAGS-is-not-set>.

Unlike the compile-time TEST_FLAGS, this is read at run time so a
single test can opt into flags such as -Zmir-preserve-ub through an
ignore-if directive that checks whether the variable is set.
A range-pattern match compiled with -Zmir-preserve-ub leaves a
SwitchInt with no cases whose discriminant is a bool comparison
result. The test is skipped unless CARGO_TEST_FLAGS is set so it only
runs when that flag is passed.
@Dnreikronos
Copy link
Copy Markdown
Author

Thanks for your work.

I believe we might be able to add the test the following way. We could run it with adding a new env var (similar to TEST_FLAGS), and run it this way:

CARGO_TEST_FLAGS="-Zmir-preserve-ub" ./y.sh test --cargo-tests -- NEW_TEST_NAME

and add a commented line that does something like // ignore-if: <check-that-env-var-CARGO_TEST_FLAGS-is-not-set>.

Just adjusted :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ICE libgccjit.so: error: : unterminated block (-Zmir-preserve-ub)

3 participants