| author | |
| committer | |
| log | 42dea36ce91db4d79711a8005ae9124bfb1364b3 |
| tree | 27c1ecb5ab0a23c0e9978e5588b84ec1cea412f4 |
| parent | d840bb511839464c852699acce471efccdd67f3e |
| signature |
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.2 files changed, 55 insertions(+), 2 deletions(-)
src/codegen/llvm.zig+6-2| ... | ... | @@ -6432,7 +6432,7 @@ pub const FuncGen = struct { |
| 6432 | 6432 | |
| 6433 | 6433 | // Don't worry about the size of the type -- it's irrelevant, because the prong values could be fairly dense. |
| 6434 | 6434 | // If they are, then we will construct a jump table. |
| 6435 | const min, const max = self.switchCaseItemRange(switch_br); | |
| 6435 | const min, const max = self.switchCaseItemRange(switch_br) orelse break :jmp_table null; | |
| 6436 | 6436 | const min_int = min.getUnsignedInt(zcu) orelse break :jmp_table null; |
| 6437 | 6437 | const max_int = max.getUnsignedInt(zcu) orelse break :jmp_table null; |
| 6438 | 6438 | const table_len = max_int - min_int + 1; |
| ... | ... | @@ -6595,7 +6595,7 @@ pub const FuncGen = struct { |
| 6595 | 6595 | } |
| 6596 | 6596 | } |
| 6597 | 6597 | |
| 6598 | fn switchCaseItemRange(self: *FuncGen, switch_br: Air.UnwrappedSwitch) [2]Value { | |
| 6598 | fn switchCaseItemRange(self: *FuncGen, switch_br: Air.UnwrappedSwitch) ?[2]Value { | |
| 6599 | 6599 | const zcu = self.ng.pt.zcu; |
| 6600 | 6600 | var it = switch_br.iterateCases(); |
| 6601 | 6601 | var min: ?Value = null; |
| ... | ... | @@ -6619,6 +6619,10 @@ pub const FuncGen = struct { |
| 6619 | 6619 | if (high) max = vals[1]; |
| 6620 | 6620 | } |
| 6621 | 6621 | } |
| 6622 | if (min == null) { | |
| 6623 | assert(max == null); | |
| 6624 | return null; | |
| 6625 | } | |
| 6622 | 6626 | return .{ min.?, max.? }; |
| 6623 | 6627 | } |
| 6624 | 6628 |
test/behavior/switch_loop.zig+49| ... | ... | @@ -297,3 +297,52 @@ test "switch loop with discarded tag capture" { |
| 297 | 297 | S.doTheTest(); |
| 298 | 298 | comptime S.doTheTest(); |
| 299 | 299 | } |
| 300 | ||
| 301 | test "switch loop with single catch-all prong" { | |
| 302 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | |
| 303 | ||
| 304 | const S = struct { | |
| 305 | const E = enum { a, b, c }; | |
| 306 | const U = union(E) { a: u32, b: u16, c: u8 }; | |
| 307 | ||
| 308 | fn doTheTest() !void { | |
| 309 | var x: usize = 0; | |
| 310 | label: switch (E.a) { | |
| 311 | else => { | |
| 312 | x += 1; | |
| 313 | if (x >= 5) continue :label .b; | |
| 314 | if (x == 10) break :label; | |
| 315 | continue :label .c; | |
| 316 | }, | |
| 317 | } | |
| 318 | try expect(x == 10); | |
| 319 | ||
| 320 | label: switch (E.a) { | |
| 321 | .a, .b, .c => { | |
| 322 | x += 1; | |
| 323 | if (x >= 15) continue :label .b; | |
| 324 | if (x == 20) break :label; | |
| 325 | continue :label .c; | |
| 326 | }, | |
| 327 | } | |
| 328 | try expect(x == 20); | |
| 329 | ||
| 330 | label: switch (E.a) { | |
| 331 | else => if (false) continue :label true, | |
| 332 | } | |
| 333 | ||
| 334 | const ok = label: switch (U{ .a = 123 }) { | |
| 335 | else => |u| { | |
| 336 | const y: u32 = switch (u) { | |
| 337 | inline else => |y| y, | |
| 338 | }; | |
| 339 | if (y == 456) break :label true; | |
| 340 | continue :label .{ .b = 456 }; | |
| 341 | }, | |
| 342 | }; | |
| 343 | try expect(ok); | |
| 344 | } | |
| 345 | }; | |
| 346 | try S.doTheTest(); | |
| 347 | try comptime S.doTheTest(); | |
| 348 | } |