| author | |
| committer | |
| log | 2315e1b41073a8d6a7f7fe3deb98ec98e45d72f6 |
| tree | 1dc47e22eb261a98825051e31f691a39c1e87f97 |
| parent | 29ae6515f3adc23df3d889acaf7ec62a2d01b707 |
Closes #70534 files changed, 91 insertions(+), 0 deletions(-)
src/Sema.zig+15| ... | ... | @@ -9998,6 +9998,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 9998 | 9998 | return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges); |
| 9999 | 9999 | } |
| 10000 | 10000 | |
| 10001 | const backend_supports_is_named_enum = sema.mod.comp.bin_file.options.use_llvm; | |
| 10002 | ||
| 10001 | 10003 | if (scalar_cases_len + multi_cases_len == 0 and !special.is_inline) { |
| 10002 | 10004 | if (empty_enum) { |
| 10003 | 10005 | return Air.Inst.Ref.void_value; |
| ... | ... | @@ -10008,6 +10010,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10008 | 10010 | if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand)) { |
| 10009 | 10011 | return Air.Inst.Ref.unreachable_value; |
| 10010 | 10012 | } |
| 10013 | if (backend_supports_is_named_enum and block.wantSafety() and operand_ty.zigTypeTag() == .Enum and | |
| 10014 | (!operand_ty.isNonexhaustiveEnum() or union_originally)) | |
| 10015 | { | |
| 10016 | const ok = try block.addUnOp(.is_named_enum_value, operand); | |
| 10017 | try sema.addSafetyCheck(block, ok, .corrupt_switch); | |
| 10018 | } | |
| 10011 | 10019 | return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges); |
| 10012 | 10020 | } |
| 10013 | 10021 | |
| ... | ... | @@ -10465,6 +10473,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10465 | 10473 | case_block.wip_capture_scope = wip_captures.scope; |
| 10466 | 10474 | case_block.inline_case_capture = .none; |
| 10467 | 10475 | |
| 10476 | if (backend_supports_is_named_enum and special.body.len != 0 and block.wantSafety() and | |
| 10477 | operand_ty.zigTypeTag() == .Enum and (!operand_ty.isNonexhaustiveEnum() or union_originally)) | |
| 10478 | { | |
| 10479 | const ok = try case_block.addUnOp(.is_named_enum_value, operand); | |
| 10480 | try sema.addSafetyCheck(&case_block, ok, .corrupt_switch); | |
| 10481 | } | |
| 10482 | ||
| 10468 | 10483 | const analyze_body = if (union_originally and !special.is_inline) |
| 10469 | 10484 | for (seen_enum_fields) |seen_field, index| { |
| 10470 | 10485 | if (seen_field != null) continue; |
test/cases/safety/switch else on corrupt enum value - one prong.zig	 created+24| ... | ... | @@ -0,0 +1,24 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { | |
| 4 | _ = stack_trace; | |
| 5 | if (std.mem.eql(u8, message, "switch on corrupt value")) { | |
| 6 | std.process.exit(0); | |
| 7 | } | |
| 8 | std.process.exit(1); | |
| 9 | } | |
| 10 | const E = enum(u32) { | |
| 11 | one = 1, | |
| 12 | two = 2, | |
| 13 | }; | |
| 14 | pub fn main() !void { | |
| 15 | var a: E = undefined; | |
| 16 | @ptrCast(*u32, &a).* = 255; | |
| 17 | switch (a) { | |
| 18 | .one => @panic("one"), | |
| 19 | else => @panic("else"), | |
| 20 | } | |
| 21 | } | |
| 22 | // run | |
| 23 | // backend=llvm | |
| 24 | // target=native |
test/cases/safety/switch else on corrupt enum value - union.zig	 created+29| ... | ... | @@ -0,0 +1,29 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { | |
| 4 | _ = stack_trace; | |
| 5 | if (std.mem.eql(u8, message, "switch on corrupt value")) { | |
| 6 | std.process.exit(0); | |
| 7 | } | |
| 8 | std.process.exit(1); | |
| 9 | } | |
| 10 | const E = enum(u16) { | |
| 11 | one = 1, | |
| 12 | two = 2, | |
| 13 | _, | |
| 14 | }; | |
| 15 | const U = union(E) { | |
| 16 | one: u16, | |
| 17 | two: u16, | |
| 18 | }; | |
| 19 | pub fn main() !void { | |
| 20 | var a: U = undefined; | |
| 21 | @ptrCast(*align(@alignOf(U)) u32, &a).* = 0xFFFF_FFFF; | |
| 22 | switch (a) { | |
| 23 | .one => @panic("one"), | |
| 24 | else => @panic("else"), | |
| 25 | } | |
| 26 | } | |
| 27 | // run | |
| 28 | // backend=llvm | |
| 29 | // target=native |
test/cases/safety/switch else on corrupt enum value.zig	 created+23| ... | ... | @@ -0,0 +1,23 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { | |
| 4 | _ = stack_trace; | |
| 5 | if (std.mem.eql(u8, message, "switch on corrupt value")) { | |
| 6 | std.process.exit(0); | |
| 7 | } | |
| 8 | std.process.exit(1); | |
| 9 | } | |
| 10 | const E = enum(u32) { | |
| 11 | one = 1, | |
| 12 | two = 2, | |
| 13 | }; | |
| 14 | pub fn main() !void { | |
| 15 | var a: E = undefined; | |
| 16 | @ptrCast(*u32, &a).* = 255; | |
| 17 | switch (a) { | |
| 18 | else => @panic("else"), | |
| 19 | } | |
| 20 | } | |
| 21 | // run | |
| 22 | // backend=llvm | |
| 23 | // target=native |