| 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,7 +6432,7 @@ pub const FuncGen = struct { |
| 6432 | 6432 | ||
| 6433 | // Don't worry about the size of the type -- it's irrelevant, because the prong values could be fairly dense. | 6433 | // Don't worry about the size of the type -- it's irrelevant, because the prong values could be fairly dense. |
| 6434 | // If they are, then we will construct a jump table. | 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 | const min_int = min.getUnsignedInt(zcu) orelse break :jmp_table null; | 6436 | const min_int = min.getUnsignedInt(zcu) orelse break :jmp_table null; |
| 6437 | const max_int = max.getUnsignedInt(zcu) orelse break :jmp_table null; | 6437 | const max_int = max.getUnsignedInt(zcu) orelse break :jmp_table null; |
| 6438 | const table_len = max_int - min_int + 1; | 6438 | const table_len = max_int - min_int + 1; |
| ... | @@ -6595,7 +6595,7 @@ pub const FuncGen = struct { | ... | @@ -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 | const zcu = self.ng.pt.zcu; | 6599 | const zcu = self.ng.pt.zcu; |
| 6600 | var it = switch_br.iterateCases(); | 6600 | var it = switch_br.iterateCases(); |
| 6601 | var min: ?Value = null; | 6601 | var min: ?Value = null; |
| ... | @@ -6619,6 +6619,10 @@ pub const FuncGen = struct { | ... | @@ -6619,6 +6619,10 @@ pub const FuncGen = struct { |
| 6619 | if (high) max = vals[1]; | 6619 | if (high) max = vals[1]; |
| 6620 | } | 6620 | } |
| 6621 | } | 6621 | } |
| 6622 | if (min == null) { | ||
| 6623 | assert(max == null); | ||
| 6624 | return null; | ||
| 6625 | } | ||
| 6622 | return .{ min.?, max.? }; | 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,3 +297,52 @@ test "switch loop with discarded tag capture" { |
| 297 | S.doTheTest(); | 297 | S.doTheTest(); |
| 298 | comptime S.doTheTest(); | 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 | } |