mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 01:04:43 +01:00
llvm: fix jump table gen for labeled switch with single else prong
Avoids a null unwrap if there are no cases with explicit values present while trying to construct a jump table for a labeled switch statement.
This commit is contained in:
parent
d840bb5118
commit
42dea36ce9
2 changed files with 55 additions and 2 deletions
|
|
@ -6432,7 +6432,7 @@ pub const FuncGen = struct {
|
|||
|
||||
// Don't worry about the size of the type -- it's irrelevant, because the prong values could be fairly dense.
|
||||
// If they are, then we will construct a jump table.
|
||||
const min, const max = self.switchCaseItemRange(switch_br);
|
||||
const min, const max = self.switchCaseItemRange(switch_br) orelse break :jmp_table null;
|
||||
const min_int = min.getUnsignedInt(zcu) orelse break :jmp_table null;
|
||||
const max_int = max.getUnsignedInt(zcu) orelse break :jmp_table null;
|
||||
const table_len = max_int - min_int + 1;
|
||||
|
|
@ -6595,7 +6595,7 @@ pub const FuncGen = struct {
|
|||
}
|
||||
}
|
||||
|
||||
fn switchCaseItemRange(self: *FuncGen, switch_br: Air.UnwrappedSwitch) [2]Value {
|
||||
fn switchCaseItemRange(self: *FuncGen, switch_br: Air.UnwrappedSwitch) ?[2]Value {
|
||||
const zcu = self.ng.pt.zcu;
|
||||
var it = switch_br.iterateCases();
|
||||
var min: ?Value = null;
|
||||
|
|
@ -6619,6 +6619,10 @@ pub const FuncGen = struct {
|
|||
if (high) max = vals[1];
|
||||
}
|
||||
}
|
||||
if (min == null) {
|
||||
assert(max == null);
|
||||
return null;
|
||||
}
|
||||
return .{ min.?, max.? };
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -297,3 +297,52 @@ test "switch loop with discarded tag capture" {
|
|||
S.doTheTest();
|
||||
comptime S.doTheTest();
|
||||
}
|
||||
|
||||
test "switch loop with single catch-all prong" {
|
||||
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
|
||||
|
||||
const S = struct {
|
||||
const E = enum { a, b, c };
|
||||
const U = union(E) { a: u32, b: u16, c: u8 };
|
||||
|
||||
fn doTheTest() !void {
|
||||
var x: usize = 0;
|
||||
label: switch (E.a) {
|
||||
else => {
|
||||
x += 1;
|
||||
if (x >= 5) continue :label .b;
|
||||
if (x == 10) break :label;
|
||||
continue :label .c;
|
||||
},
|
||||
}
|
||||
try expect(x == 10);
|
||||
|
||||
label: switch (E.a) {
|
||||
.a, .b, .c => {
|
||||
x += 1;
|
||||
if (x >= 15) continue :label .b;
|
||||
if (x == 20) break :label;
|
||||
continue :label .c;
|
||||
},
|
||||
}
|
||||
try expect(x == 20);
|
||||
|
||||
label: switch (E.a) {
|
||||
else => if (false) continue :label true,
|
||||
}
|
||||
|
||||
const ok = label: switch (U{ .a = 123 }) {
|
||||
else => |u| {
|
||||
const y: u32 = switch (u) {
|
||||
inline else => |y| y,
|
||||
};
|
||||
if (y == 456) break :label true;
|
||||
continue :label .{ .b = 456 };
|
||||
},
|
||||
};
|
||||
try expect(ok);
|
||||
}
|
||||
};
|
||||
try S.doTheTest();
|
||||
try comptime S.doTheTest();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue