authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-05-19 17:01:54-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-05 03:29:37+02:00
loge88566253d65a83e3564f95504fe034b4287c340
treeec55973b4700ead9f55cd253b9e4ed7151167b6a
parentf611a72e2eb7bba2ef5fc5f578ced3c711ff7374

sema: improve @errorCast safety check message


10 files changed, 55 insertions(+), 6 deletions(-)

lib/std/debug.zig+4
......@@ -151,6 +151,10 @@ pub fn FullPanic(comptime panicFn: fn ([]const u8, ?usize) noreturn) type {
151151 @branchHint(.cold);
152152 call("invalid error code", @returnAddress());
153153 }
154 pub fn unexpectedErrorCode(err: anyerror) noreturn {
155 @branchHint(.cold);
156 std.debug.panicExtra(@returnAddress(), "unexpected error code, found error.{s}", .{@errorName(err)});
157 }
154158 pub fn integerOutOfBounds() noreturn {
155159 @branchHint(.cold);
156160 call("integer does not fit in destination type", @returnAddress());
lib/std/debug/no_panic.zig+5
......@@ -65,6 +65,11 @@ pub fn invalidErrorCode() noreturn {
6565 @trap();
6666}
6767
68pub fn unexpectedErrorCode(_: anyerror) noreturn {
69 @branchHint(.cold);
70 @trap();
71}
72
6873pub fn integerOutOfBounds() noreturn {
6974 @branchHint(.cold);
7075 @trap();
lib/std/debug/simple_panic.zig+31
......@@ -20,110 +20,141 @@ pub fn call(msg: []const u8, ra: ?usize) noreturn {
2020}
2121
2222pub fn sentinelMismatch(expected: anytype, found: @TypeOf(expected)) noreturn {
23 @branchHint(.cold);
2324 _ = found;
2425 call("sentinel mismatch", null);
2526}
2627
2728pub fn unwrapError(err: anyerror) noreturn {
29 @branchHint(.cold);
2830 _ = &err;
2931 call("attempt to unwrap error", null);
3032}
3133
3234pub fn outOfBounds(index: usize, len: usize) noreturn {
35 @branchHint(.cold);
3336 _ = index;
3437 _ = len;
3538 call("index out of bounds", null);
3639}
3740
3841pub fn startGreaterThanEnd(start: usize, end: usize) noreturn {
42 @branchHint(.cold);
3943 _ = start;
4044 _ = end;
4145 call("start index is larger than end index", null);
4246}
4347
4448pub fn inactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn {
49 @branchHint(.cold);
4550 _ = accessed;
4651 call("access of inactive union field", null);
4752}
4853
4954pub fn sliceCastLenRemainder(src_len: usize) noreturn {
55 @branchHint(.cold);
5056 _ = src_len;
5157 call("slice length does not divide exactly into destination elements", null);
5258}
5359
5460pub fn reachedUnreachable() noreturn {
61 @branchHint(.cold);
5562 call("reached unreachable code", null);
5663}
5764
5865pub fn unwrapNull() noreturn {
66 @branchHint(.cold);
5967 call("attempt to use null value", null);
6068}
6169
6270pub fn castToNull() noreturn {
71 @branchHint(.cold);
6372 call("cast causes pointer to be null", null);
6473}
6574
6675pub fn incorrectAlignment() noreturn {
76 @branchHint(.cold);
6777 call("incorrect alignment", null);
6878}
6979
7080pub fn invalidErrorCode() noreturn {
81 @branchHint(.cold);
7182 call("invalid error code", null);
7283}
7384
85pub fn unexpectedErrorCode(err: anyerror) noreturn {
86 @branchHint(.cold);
87 _ = err;
88 call("unexpected error code", null);
89}
90
7491pub fn integerOutOfBounds() noreturn {
92 @branchHint(.cold);
7593 call("integer does not fit in destination type", null);
7694}
7795
7896pub fn integerOverflow() noreturn {
97 @branchHint(.cold);
7998 call("integer overflow", null);
8099}
81100
82101pub fn shlOverflow() noreturn {
102 @branchHint(.cold);
83103 call("left shift overflowed bits", null);
84104}
85105
86106pub fn shrOverflow() noreturn {
107 @branchHint(.cold);
87108 call("right shift overflowed bits", null);
88109}
89110
90111pub fn divideByZero() noreturn {
112 @branchHint(.cold);
91113 call("division by zero", null);
92114}
93115
94116pub fn exactDivisionRemainder() noreturn {
117 @branchHint(.cold);
95118 call("exact division produced remainder", null);
96119}
97120
98121pub fn integerPartOutOfBounds() noreturn {
122 @branchHint(.cold);
99123 call("integer part of floating point value out of bounds", null);
100124}
101125
102126pub fn corruptSwitch() noreturn {
127 @branchHint(.cold);
103128 call("switch on corrupt value", null);
104129}
105130
106131pub fn shiftRhsTooBig() noreturn {
132 @branchHint(.cold);
107133 call("shift amount is greater than the type size", null);
108134}
109135
110136pub fn invalidEnumValue() noreturn {
137 @branchHint(.cold);
111138 call("invalid enum value", null);
112139}
113140
114141pub fn forLenMismatch() noreturn {
142 @branchHint(.cold);
115143 call("for loop over objects with non-equal lengths", null);
116144}
117145
118146pub fn copyLenMismatch() noreturn {
147 @branchHint(.cold);
119148 call("source and destination have non-equal lengths", null);
120149}
121150
122151pub fn memcpyAlias() noreturn {
152 @branchHint(.cold);
123153 call("@memcpy arguments alias", null);
124154}
125155
126156pub fn noreturnReturned() noreturn {
157 @branchHint(.cold);
127158 call("'noreturn' function returned", null);
128159}
129160
src/Sema.zig+6-4
......@@ -21675,16 +21675,16 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
2167521675 const is_zero = try block.addBinOp(.cmp_eq, err_int_inst, zero_err);
2167621676 if (result == .disjoint) {
2167721677 // Error must be zero.
21678 try sema.addSafetyCheck(block, src, is_zero, .invalid_error_code);
21678 try sema.addSafetyCheckCall(block, src, is_zero, .@"panic.unexpectedErrorCode", &.{err_code_inst});
2167921679 } else {
2168021680 // Error must be in destination set or zero.
2168121681 const has_value = try block.addTyOp(.error_set_has_value, dest_err_ty, err_int_inst);
2168221682 const ok = try block.addBinOp(.bit_or, has_value, is_zero);
21683 try sema.addSafetyCheck(block, src, ok, .invalid_error_code);
21683 try sema.addSafetyCheckCall(block, src, ok, .@"panic.unexpectedErrorCode", &.{err_code_inst});
2168421684 }
2168521685 } else {
2168621686 const ok = try block.addTyOp(.error_set_has_value, dest_err_ty, err_int_inst);
21687 try sema.addSafetyCheck(block, src, ok, .invalid_error_code);
21687 try sema.addSafetyCheckCall(block, src, ok, .@"panic.unexpectedErrorCode", &.{err_code_inst});
2168821688 }
2168921689 }
2169021690
......@@ -35031,7 +35031,9 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.StdLangDecl) CompileError!Typ
3503135031 }),
3503235032
3503335033 // `fn (anyerror) noreturn`
35034 .@"panic.unwrapError" => try pt.funcType(.{
35034 .@"panic.unwrapError",
35035 .@"panic.unexpectedErrorCode",
35036 => try pt.funcType(.{
3503535037 .param_types = &.{.anyerror_type},
3503635038 .return_type = .noreturn_type,
3503735039 }),
src/Zcu.zig+2
......@@ -503,6 +503,7 @@ pub const StdLangDecl = enum {
503503 @"panic.castToNull",
504504 @"panic.incorrectAlignment",
505505 @"panic.invalidErrorCode",
506 @"panic.unexpectedErrorCode",
506507 @"panic.integerOutOfBounds",
507508 @"panic.integerOverflow",
508509 @"panic.shlOverflow",
......@@ -593,6 +594,7 @@ pub const StdLangDecl = enum {
593594 .@"panic.castToNull",
594595 .@"panic.incorrectAlignment",
595596 .@"panic.invalidErrorCode",
597 .@"panic.unexpectedErrorCode",
596598 .@"panic.integerOutOfBounds",
597599 .@"panic.integerOverflow",
598600 .@"panic.shlOverflow",
test/cases/compile_errors/bad_panic_call_signature.zig+1
......@@ -15,6 +15,7 @@ pub const panic = struct {
1515 pub const castToNull = simple_panic.castToNull;
1616 pub const incorrectAlignment = simple_panic.incorrectAlignment;
1717 pub const invalidErrorCode = simple_panic.invalidErrorCode;
18 pub const unexpectedErrorCode = simple_panic.unexpectedErrorCode;
1819 pub const integerOutOfBounds = simple_panic.integerOutOfBounds;
1920 pub const integerOverflow = simple_panic.integerOverflow;
2021 pub const shlOverflow = simple_panic.shlOverflow;
test/cases/compile_errors/bad_panic_generic_signature.zig+1
......@@ -11,6 +11,7 @@ pub const panic = struct {
1111 pub const castToNull = simple_panic.castToNull;
1212 pub const incorrectAlignment = simple_panic.incorrectAlignment;
1313 pub const invalidErrorCode = simple_panic.invalidErrorCode;
14 pub const unexpectedErrorCode = simple_panic.unexpectedErrorCode;
1415 pub const integerOutOfBounds = simple_panic.integerOutOfBounds;
1516 pub const integerOverflow = simple_panic.integerOverflow;
1617 pub const shlOverflow = simple_panic.shlOverflow;
test/cases/safety/@errorCast error not present in destination.zig +1-1
......@@ -2,7 +2,7 @@ const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
44 _ = stack_trace;
5 if (std.mem.eql(u8, message, "invalid error code")) {
5 if (std.mem.eql(u8, message, "unexpected error code, found error.B")) {
66 std.process.exit(0);
77 }
88 std.process.exit(1);
test/cases/safety/@errorCast error union casted to disjoint set.zig +1-1
......@@ -2,7 +2,7 @@ const std = @import("std");
22
33pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
44 _ = stack_trace;
5 if (std.mem.eql(u8, message, "invalid error code")) {
5 if (std.mem.eql(u8, message, "unexpected error code, found error.Bar")) {
66 std.process.exit(0);
77 }
88 std.process.exit(1);
test/incremental/change_panic_handler_explicit+3
......@@ -23,6 +23,7 @@ pub const panic = struct {
2323 pub const castToNull = no_panic.castToNull;
2424 pub const incorrectAlignment = no_panic.incorrectAlignment;
2525 pub const invalidErrorCode = no_panic.invalidErrorCode;
26 pub const unexpectedErrorCode = no_panic.unexpectedErrorCode;
2627 pub const integerOutOfBounds = no_panic.integerOutOfBounds;
2728 pub const shlOverflow = no_panic.shlOverflow;
2829 pub const shrOverflow = no_panic.shrOverflow;
......@@ -72,6 +73,7 @@ pub const panic = struct {
7273 pub const castToNull = no_panic.castToNull;
7374 pub const incorrectAlignment = no_panic.incorrectAlignment;
7475 pub const invalidErrorCode = no_panic.invalidErrorCode;
76 pub const unexpectedErrorCode = no_panic.unexpectedErrorCode;
7577 pub const integerOutOfBounds = no_panic.integerOutOfBounds;
7678 pub const shlOverflow = no_panic.shlOverflow;
7779 pub const shrOverflow = no_panic.shrOverflow;
......@@ -121,6 +123,7 @@ pub const panic = struct {
121123 pub const castToNull = no_panic.castToNull;
122124 pub const incorrectAlignment = no_panic.incorrectAlignment;
123125 pub const invalidErrorCode = no_panic.invalidErrorCode;
126 pub const unexpectedErrorCode = no_panic.unexpectedErrorCode;
124127 pub const integerOutOfBounds = no_panic.integerOutOfBounds;
125128 pub const shlOverflow = no_panic.shlOverflow;
126129 pub const shrOverflow = no_panic.shrOverflow;