| author | |
| committer | |
| log | eec2978fac240f6852873bdd9a3ae03b77df6199 |
| tree | 8a646d9184fff44217ae8de775341a0b497a92cb |
| parent | 18440cb239755c983f672b4902147c12e819e029 |
4 files changed, 17 insertions(+), 10 deletions(-)
src/Sema.zig+8-4| ... | @@ -9692,7 +9692,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -9692,7 +9692,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9692 | } | 9692 | } |
| 9693 | 9693 | ||
| 9694 | var final_else_body: []const Air.Inst.Index = &.{}; | 9694 | var final_else_body: []const Air.Inst.Index = &.{}; |
| 9695 | if (special.body.len != 0 or !is_first) { | 9695 | if (special.body.len != 0 or !is_first or case_block.wantSafety()) { |
| 9696 | var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope); | 9696 | var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope); |
| 9697 | defer wip_captures.deinit(); | 9697 | defer wip_captures.deinit(); |
| 9698 | 9698 | ||
| ... | @@ -9715,9 +9715,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError | ... | @@ -9715,9 +9715,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9715 | } else { | 9715 | } else { |
| 9716 | // We still need a terminator in this block, but we have proven | 9716 | // We still need a terminator in this block, but we have proven |
| 9717 | // that it is unreachable. | 9717 | // that it is unreachable. |
| 9718 | // TODO this should be a special safety panic other than unreachable, something | 9718 | if (case_block.wantSafety()) { |
| 9719 | // like "panic: switch operand had corrupt value not allowed by the type" | 9719 | _ = try sema.safetyPanic(&case_block, src, .corrupt_switch); |
| 9720 | try case_block.addUnreachable(src, true); | 9720 | } else { |
| 9721 | _ = try case_block.addNoOp(.unreach); | ||
| 9722 | } | ||
| 9721 | } | 9723 | } |
| 9722 | 9724 | ||
| 9723 | try wip_captures.finalize(); | 9725 | try wip_captures.finalize(); |
| ... | @@ -19970,6 +19972,7 @@ pub const PanicId = enum { | ... | @@ -19970,6 +19972,7 @@ pub const PanicId = enum { |
| 19970 | /// TODO make this call `std.builtin.panicInactiveUnionField`. | 19972 | /// TODO make this call `std.builtin.panicInactiveUnionField`. |
| 19971 | inactive_union_field, | 19973 | inactive_union_field, |
| 19972 | integer_part_out_of_bounds, | 19974 | integer_part_out_of_bounds, |
| 19975 | corrupt_switch, | ||
| 19973 | }; | 19976 | }; |
| 19974 | 19977 | ||
| 19975 | fn addSafetyCheck( | 19978 | fn addSafetyCheck( |
| ... | @@ -20265,6 +20268,7 @@ fn safetyPanic( | ... | @@ -20265,6 +20268,7 @@ fn safetyPanic( |
| 20265 | .exact_division_remainder => "exact division produced remainder", | 20268 | .exact_division_remainder => "exact division produced remainder", |
| 20266 | .inactive_union_field => "access of inactive union field", | 20269 | .inactive_union_field => "access of inactive union field", |
| 20267 | .integer_part_out_of_bounds => "integer part of floating point value out of bounds", | 20270 | .integer_part_out_of_bounds => "integer part of floating point value out of bounds", |
| 20271 | .corrupt_switch => "switch on corrupt value", | ||
| 20268 | }; | 20272 | }; |
| 20269 | 20273 | ||
| 20270 | const msg_inst = msg_inst: { | 20274 | const msg_inst = msg_inst: { |
test/behavior/switch.zig+1| ... | @@ -531,6 +531,7 @@ test "switch with null and T peer types and inferred result location type" { | ... | @@ -531,6 +531,7 @@ test "switch with null and T peer types and inferred result location type" { |
| 531 | test "switch prongs with cases with identical payload types" { | 531 | test "switch prongs with cases with identical payload types" { |
| 532 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 532 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 533 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 533 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 534 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 534 | 535 | ||
| 535 | const Union = union(enum) { | 536 | const Union = union(enum) { |
| 536 | A: usize, | 537 | A: usize, |
test/cases/safety/switch on corrupted enum value.zig	+4-3| ... | @@ -2,7 +2,7 @@ const std = @import("std"); | ... | @@ -2,7 +2,7 @@ const std = @import("std"); |
| 2 | 2 | ||
| 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = stack_trace; | 4 | _ = stack_trace; |
| 5 | if (std.mem.eql(u8, message, "reached unreachable code")) { | 5 | if (std.mem.eql(u8, message, "switch on corrupt value")) { |
| 6 | std.process.exit(0); | 6 | std.process.exit(0); |
| 7 | } | 7 | } |
| 8 | std.process.exit(1); | 8 | std.process.exit(1); |
| ... | @@ -10,17 +10,18 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur | ... | @@ -10,17 +10,18 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur |
| 10 | 10 | ||
| 11 | const E = enum(u32) { | 11 | const E = enum(u32) { |
| 12 | X = 1, | 12 | X = 1, |
| 13 | Y = 2, | ||
| 13 | }; | 14 | }; |
| 14 | 15 | ||
| 15 | pub fn main() !void { | 16 | pub fn main() !void { |
| 16 | var e: E = undefined; | 17 | var e: E = undefined; |
| 17 | @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E)); | 18 | @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E)); |
| 18 | switch (e) { | 19 | switch (e) { |
| 19 | .X => @breakpoint(), | 20 | .X, .Y => @breakpoint(), |
| 20 | } | 21 | } |
| 21 | return error.TestFailed; | 22 | return error.TestFailed; |
| 22 | } | 23 | } |
| 23 | 24 | ||
| 24 | // run | 25 | // run |
| 25 | // backend=stage1 | 26 | // backend=llvm |
| 26 | // target=native | 27 | // target=native |
test/cases/safety/switch on corrupted union value.zig	+4-3| ... | @@ -2,7 +2,7 @@ const std = @import("std"); | ... | @@ -2,7 +2,7 @@ const std = @import("std"); |
| 2 | 2 | ||
| 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = stack_trace; | 4 | _ = stack_trace; |
| 5 | if (std.mem.eql(u8, message, "reached unreachable code")) { | 5 | if (std.mem.eql(u8, message, "switch on corrupt value")) { |
| 6 | std.process.exit(0); | 6 | std.process.exit(0); |
| 7 | } | 7 | } |
| 8 | std.process.exit(1); | 8 | std.process.exit(1); |
| ... | @@ -10,17 +10,18 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur | ... | @@ -10,17 +10,18 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noretur |
| 10 | 10 | ||
| 11 | const U = union(enum(u32)) { | 11 | const U = union(enum(u32)) { |
| 12 | X: u8, | 12 | X: u8, |
| 13 | Y: i8, | ||
| 13 | }; | 14 | }; |
| 14 | 15 | ||
| 15 | pub fn main() !void { | 16 | pub fn main() !void { |
| 16 | var u: U = undefined; | 17 | var u: U = undefined; |
| 17 | @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U)); | 18 | @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U)); |
| 18 | switch (u) { | 19 | switch (u) { |
| 19 | .X => @breakpoint(), | 20 | .X, .Y => @breakpoint(), |
| 20 | } | 21 | } |
| 21 | return error.TestFailed; | 22 | return error.TestFailed; |
| 22 | } | 23 | } |
| 23 | 24 | ||
| 24 | // run | 25 | // run |
| 25 | // backend=stage1 | 26 | // backend=llvm |
| 26 | // target=native | 27 | // target=native |