authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-01-24 02:19:28+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-01-24 19:29:51+00:00
log83991efe10d92c4b920d7b7fc75be98ed7854ad7
tree7137ee5eb01517aede1c5503c29a2003fca71f80
parentb3d9b0e3f6bab5d662ec385cf754872f8a90607f
signaturelock-open Commit is signed but in an unrecognized format.

compiler: yet more panic handler changes

* `std.builtin.Panic` -> `std.builtin.panic`, because it is a namespace. * `root.Panic` -> `root.panic` for the same reason. There are type checks so that we still allow the legacy `pub fn panic` strategy in the 0.14.0 release. * `std.debug.SimplePanic` -> `std.debug.simple_panic`, same reason. * `std.debug.NoPanic` -> `std.debug.no_panic`, same reason. * `std.debug.FormattedPanic` is now a function `std.debug.FullPanic` which takes as input a `panicFn` and returns a namespace with all the panic functions. This handles the incredibly common case of just wanting to override how the message is printed, whilst keeping nice formatted panics. * Remove `std.builtin.panic.messages`; now, every safety panic has its own function. This reduces binary bloat, as calls to these functions no longer need to prepare any arguments (aside from the error return trace). * Remove some legacy declarations, since a zig1.wasm update has happened. Most of these were related to the panic handler, but a quick grep for "zig1" brought up a couple more results too. Also, add some missing type checks to Sema. Resolves: #22584 formatted -> full

20 files changed, 864 insertions(+), 482 deletions(-)

lib/std/Target.zig+1-1
...@@ -370,7 +370,7 @@ pub const Os = struct {...@@ -370,7 +370,7 @@ pub const Os = struct {
370 range: std.SemanticVersion.Range,370 range: std.SemanticVersion.Range,
371 glibc: std.SemanticVersion,371 glibc: std.SemanticVersion,
372 /// Android API level.372 /// Android API level.
373 android: u32 = 14, // This default value is to be deleted after zig1.wasm is updated.373 android: u32,
374374
375 pub inline fn includesVersion(range: LinuxVersionRange, ver: std.SemanticVersion) bool {375 pub inline fn includesVersion(range: LinuxVersionRange, ver: std.SemanticVersion) bool {
376 return range.range.includesVersion(ver);376 return range.range.includesVersion(ver);
lib/std/builtin.zig+16-33
...@@ -1110,45 +1110,28 @@ pub const TestFn = struct {...@@ -1110,45 +1110,28 @@ pub const TestFn = struct {
1110/// Deprecated, use the `Panic` namespace instead.1110/// Deprecated, use the `Panic` namespace instead.
1111/// To be deleted after 0.14.0 is released.1111/// To be deleted after 0.14.0 is released.
1112pub const PanicFn = fn ([]const u8, ?*StackTrace, ?usize) noreturn;1112pub const PanicFn = fn ([]const u8, ?*StackTrace, ?usize) noreturn;
1113/// Deprecated, use the `Panic` namespace instead.
1114/// To be deleted after 0.14.0 is released.
1115pub const panic: PanicFn = Panic.call;
11161113
1117/// This namespace is used by the Zig compiler to emit various kinds of safety1114/// This namespace is used by the Zig compiler to emit various kinds of safety
1118/// panics. These can be overridden by making a public `Panic` namespace in the1115/// panics. These can be overridden by making a public `panic` namespace in the
1119/// root source file.1116/// root source file.
1120pub const Panic: type = if (@hasDecl(root, "Panic"))1117pub const panic: type = p: {
1121 root.Panic1118 if (@hasDecl(root, "panic")) {
1122else if (@hasDecl(root, "panic")) // Deprecated, use `Panic` instead.1119 if (@TypeOf(root.panic) != type) {
1123 DeprecatedPanic1120 break :p std.debug.FullPanic(root.panic); // Deprecated; make `panic` a namespace instead.
1124else if (builtin.zig_backend == .stage2_riscv64)1121 }
1125 std.debug.SimplePanic // https://github.com/ziglang/zig/issues/215191122 break :p root.panic;
1126else1123 }
1127 std.debug.FormattedPanic;1124 if (@hasDecl(root, "Panic")) {
11281125 break :p root.Panic; // Deprecated; use `panic` instead.
1129/// To be deleted after 0.14.0 is released.1126 }
1130const DeprecatedPanic = struct {1127 if (builtin.zig_backend == .stage2_riscv64) {
1131 pub const call = root.panic;1128 break :p std.debug.simple_panic;
1132 pub const sentinelMismatch = std.debug.FormattedPanic.sentinelMismatch;1129 }
1133 pub const unwrapError = std.debug.FormattedPanic.unwrapError;1130 break :p std.debug.FullPanic(std.debug.defaultPanic);
1134 pub const outOfBounds = std.debug.FormattedPanic.outOfBounds;
1135 pub const startGreaterThanEnd = std.debug.FormattedPanic.startGreaterThanEnd;
1136 pub const inactiveUnionField = std.debug.FormattedPanic.inactiveUnionField;
1137 pub const messages = std.debug.FormattedPanic.messages;
1138};1131};
11391132
1140/// To be deleted after zig1.wasm is updated.1133/// To be deleted after zig1.wasm is updated.
1141pub const panicSentinelMismatch = Panic.sentinelMismatch;1134pub const Panic = panic;
1142/// To be deleted after zig1.wasm is updated.
1143pub const panicUnwrapError = Panic.unwrapError;
1144/// To be deleted after zig1.wasm is updated.
1145pub const panicOutOfBounds = Panic.outOfBounds;
1146/// To be deleted after zig1.wasm is updated.
1147pub const panicStartGreaterThanEnd = Panic.startGreaterThanEnd;
1148/// To be deleted after zig1.wasm is updated.
1149pub const panicInactiveUnionField = Panic.inactiveUnionField;
1150/// To be deleted after zig1.wasm is updated.
1151pub const panic_messages = Panic.messages;
11521135
1153pub noinline fn returnError() void {1136pub noinline fn returnError() void {
1154 @branchHint(.unlikely);1137 @branchHint(.unlikely);
lib/std/debug.zig+119-4
...@@ -21,9 +21,124 @@ pub const SelfInfo = @import("debug/SelfInfo.zig");...@@ -21,9 +21,124 @@ pub const SelfInfo = @import("debug/SelfInfo.zig");
21pub const Info = @import("debug/Info.zig");21pub const Info = @import("debug/Info.zig");
22pub const Coverage = @import("debug/Coverage.zig");22pub const Coverage = @import("debug/Coverage.zig");
2323
24pub const FormattedPanic = @import("debug/FormattedPanic.zig");24pub const simple_panic = @import("debug/simple_panic.zig");
25pub const SimplePanic = @import("debug/SimplePanic.zig");25pub const no_panic = @import("debug/no_panic.zig");
26pub const NoPanic = @import("debug/NoPanic.zig");26
27/// A fully-featured panic handler namespace which lowers all panics to calls to `panicFn`.
28/// Safety panics will use formatted printing to provide a meaningful error message.
29/// The signature of `panicFn` should match that of `defaultPanic`.
30pub fn FullPanic(comptime panicFn: fn ([]const u8, ?*std.builtin.StackTrace, ?usize) noreturn) type {
31 return struct {
32 pub const call = panicFn;
33 pub fn sentinelMismatch(expected: anytype, found: @TypeOf(expected)) noreturn {
34 @branchHint(.cold);
35 std.debug.panicExtra(null, @returnAddress(), "sentinel mismatch: expected {any}, found {any}", .{
36 expected, found,
37 });
38 }
39 pub fn unwrapError(ert: ?*std.builtin.StackTrace, err: anyerror) noreturn {
40 @branchHint(.cold);
41 std.debug.panicExtra(ert, @returnAddress(), "attempt to unwrap error: {s}", .{@errorName(err)});
42 }
43 pub fn outOfBounds(index: usize, len: usize) noreturn {
44 @branchHint(.cold);
45 std.debug.panicExtra(null, @returnAddress(), "index out of bounds: index {d}, len {d}", .{ index, len });
46 }
47 pub fn startGreaterThanEnd(start: usize, end: usize) noreturn {
48 @branchHint(.cold);
49 std.debug.panicExtra(null, @returnAddress(), "start index {d} is larger than end index {d}", .{ start, end });
50 }
51 pub fn inactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn {
52 @branchHint(.cold);
53 std.debug.panicExtra(null, @returnAddress(), "access of union field '{s}' while field '{s}' is active", .{
54 @tagName(accessed), @tagName(active),
55 });
56 }
57 pub fn reachedUnreachable() noreturn {
58 @branchHint(.cold);
59 call("reached unreachable code", null, @returnAddress());
60 }
61 pub fn unwrapNull() noreturn {
62 @branchHint(.cold);
63 call("attempt to use null value", null, @returnAddress());
64 }
65 pub fn castToNull() noreturn {
66 @branchHint(.cold);
67 call("cast causes pointer to be null", null, @returnAddress());
68 }
69 pub fn incorrectAlignment() noreturn {
70 @branchHint(.cold);
71 call("incorrect alignment", null, @returnAddress());
72 }
73 pub fn invalidErrorCode() noreturn {
74 @branchHint(.cold);
75 call("invalid error code", null, @returnAddress());
76 }
77 pub fn castTruncatedData() noreturn {
78 @branchHint(.cold);
79 call("integer cast truncated bits", null, @returnAddress());
80 }
81 pub fn negativeToUnsigned() noreturn {
82 @branchHint(.cold);
83 call("attempt to cast negative value to unsigned integer", null, @returnAddress());
84 }
85 pub fn integerOverflow() noreturn {
86 @branchHint(.cold);
87 call("integer overflow", null, @returnAddress());
88 }
89 pub fn shlOverflow() noreturn {
90 @branchHint(.cold);
91 call("left shift overflowed bits", null, @returnAddress());
92 }
93 pub fn shrOverflow() noreturn {
94 @branchHint(.cold);
95 call("right shift overflowed bits", null, @returnAddress());
96 }
97 pub fn divideByZero() noreturn {
98 @branchHint(.cold);
99 call("division by zero", null, @returnAddress());
100 }
101 pub fn exactDivisionRemainder() noreturn {
102 @branchHint(.cold);
103 call("exact division produced remainder", null, @returnAddress());
104 }
105 pub fn integerPartOutOfBounds() noreturn {
106 @branchHint(.cold);
107 call("integer part of floating point value out of bounds", null, @returnAddress());
108 }
109 pub fn corruptSwitch() noreturn {
110 @branchHint(.cold);
111 call("switch on corrupt value", null, @returnAddress());
112 }
113 pub fn shiftRhsTooBig() noreturn {
114 @branchHint(.cold);
115 call("shift amount is greater than the type size", null, @returnAddress());
116 }
117 pub fn invalidEnumValue() noreturn {
118 @branchHint(.cold);
119 call("invalid enum value", null, @returnAddress());
120 }
121 pub fn forLenMismatch() noreturn {
122 @branchHint(.cold);
123 call("for loop over objects with non-equal lengths", null, @returnAddress());
124 }
125 pub fn memcpyLenMismatch() noreturn {
126 @branchHint(.cold);
127 call("@memcpy arguments have non-equal lengths", null, @returnAddress());
128 }
129 pub fn memcpyAlias() noreturn {
130 @branchHint(.cold);
131 call("@memcpy arguments alias", null, @returnAddress());
132 }
133 pub fn noreturnReturned() noreturn {
134 @branchHint(.cold);
135 call("'noreturn' function returned", null, @returnAddress());
136 }
137
138 /// To be deleted after zig1.wasm update.
139 pub const messages = simple_panic.messages;
140 };
141}
27142
28/// Unresolved source locations can be represented with a single `usize` that143/// Unresolved source locations can be represented with a single `usize` that
29/// corresponds to a virtual memory address of the program counter. Combined144/// corresponds to a virtual memory address of the program counter. Combined
...@@ -441,7 +556,7 @@ pub fn panicExtra(...@@ -441,7 +556,7 @@ pub fn panicExtra(
441 break :blk &buf;556 break :blk &buf;
442 },557 },
443 };558 };
444 std.builtin.Panic.call(msg, trace, ret_addr);559 std.builtin.panic.call(msg, trace, ret_addr);
445}560}
446561
447/// Non-zero whenever the program triggered a panic.562/// Non-zero whenever the program triggered a panic.
lib/std/debug/FormattedPanic.zig deleted-45
...@@ -1,45 +0,0 @@
1//! This namespace is the default one used by the Zig compiler to emit various
2//! kinds of safety panics, due to the logic in `std.builtin.Panic`.
3//!
4//! Since Zig does not have interfaces, this file serves as an example template
5//! for users to provide their own alternative panic handling.
6//!
7//! As an alternative, see `std.debug.SimplePanic`.
8
9const std = @import("../std.zig");
10
11/// Dumps a stack trace to standard error, then aborts.
12///
13/// Explicit calls to `@panic` lower to calling this function.
14pub const call: fn ([]const u8, ?*std.builtin.StackTrace, ?usize) noreturn = std.debug.defaultPanic;
15
16pub fn sentinelMismatch(expected: anytype, found: @TypeOf(expected)) noreturn {
17 @branchHint(.cold);
18 std.debug.panicExtra(null, @returnAddress(), "sentinel mismatch: expected {any}, found {any}", .{
19 expected, found,
20 });
21}
22
23pub fn unwrapError(ert: ?*std.builtin.StackTrace, err: anyerror) noreturn {
24 @branchHint(.cold);
25 std.debug.panicExtra(ert, @returnAddress(), "attempt to unwrap error: {s}", .{@errorName(err)});
26}
27
28pub fn outOfBounds(index: usize, len: usize) noreturn {
29 @branchHint(.cold);
30 std.debug.panicExtra(null, @returnAddress(), "index out of bounds: index {d}, len {d}", .{ index, len });
31}
32
33pub fn startGreaterThanEnd(start: usize, end: usize) noreturn {
34 @branchHint(.cold);
35 std.debug.panicExtra(null, @returnAddress(), "start index {d} is larger than end index {d}", .{ start, end });
36}
37
38pub fn inactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn {
39 @branchHint(.cold);
40 std.debug.panicExtra(null, @returnAddress(), "access of union field '{s}' while field '{s}' is active", .{
41 @tagName(accessed), @tagName(active),
42 });
43}
44
45pub const messages = std.debug.SimplePanic.messages;
lib/std/debug/NoPanic.zig deleted-59
...@@ -1,59 +0,0 @@
1//! This namespace can be used with `pub const Panic = std.debug.NoPanic;` in the root file.
2//! It emits as little code as possible, for testing purposes.
3//!
4//! For a functional alternative, see `std.debug.FormattedPanic`.
5
6const std = @import("../std.zig");
7
8pub fn call(_: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
9 @branchHint(.cold);
10 @trap();
11}
12
13pub fn sentinelMismatch(_: anytype, _: anytype) noreturn {
14 @branchHint(.cold);
15 @trap();
16}
17
18pub fn unwrapError(_: ?*std.builtin.StackTrace, _: anyerror) noreturn {
19 @branchHint(.cold);
20 @trap();
21}
22
23pub fn outOfBounds(_: usize, _: usize) noreturn {
24 @branchHint(.cold);
25 @trap();
26}
27
28pub fn startGreaterThanEnd(_: usize, _: usize) noreturn {
29 @branchHint(.cold);
30 @trap();
31}
32
33pub fn inactiveUnionField(_: anytype, _: anytype) noreturn {
34 @branchHint(.cold);
35 @trap();
36}
37
38pub const messages = struct {
39 pub const reached_unreachable = "";
40 pub const unwrap_null = "";
41 pub const cast_to_null = "";
42 pub const incorrect_alignment = "";
43 pub const invalid_error_code = "";
44 pub const cast_truncated_data = "";
45 pub const negative_to_unsigned = "";
46 pub const integer_overflow = "";
47 pub const shl_overflow = "";
48 pub const shr_overflow = "";
49 pub const divide_by_zero = "";
50 pub const exact_division_remainder = "";
51 pub const integer_part_out_of_bounds = "";
52 pub const corrupt_switch = "";
53 pub const shift_rhs_too_big = "";
54 pub const invalid_enum_value = "";
55 pub const for_len_mismatch = "";
56 pub const memcpy_len_mismatch = "";
57 pub const memcpy_alias = "";
58 pub const noreturn_returned = "";
59};
lib/std/debug/SimplePanic.zig deleted-86
...@@ -1,86 +0,0 @@
1//! This namespace is the default one used by the Zig compiler to emit various
2//! kinds of safety panics, due to the logic in `std.builtin.Panic`.
3//!
4//! Since Zig does not have interfaces, this file serves as an example template
5//! for users to provide their own alternative panic handling.
6//!
7//! As an alternative, see `std.debug.FormattedPanic`.
8
9const std = @import("../std.zig");
10
11/// Prints the message to stderr without a newline and then traps.
12///
13/// Explicit calls to `@panic` lower to calling this function.
14pub fn call(msg: []const u8, ert: ?*std.builtin.StackTrace, ra: ?usize) noreturn {
15 @branchHint(.cold);
16 _ = ert;
17 _ = ra;
18 std.debug.lockStdErr();
19 const stderr = std.io.getStdErr();
20 stderr.writeAll(msg) catch {};
21 @trap();
22}
23
24pub fn sentinelMismatch(expected: anytype, found: @TypeOf(expected)) noreturn {
25 _ = found;
26 call("sentinel mismatch", null, null);
27}
28
29pub fn unwrapError(ert: ?*std.builtin.StackTrace, err: anyerror) noreturn {
30 _ = ert;
31 _ = &err;
32 call("attempt to unwrap error", null, null);
33}
34
35pub fn outOfBounds(index: usize, len: usize) noreturn {
36 _ = index;
37 _ = len;
38 call("index out of bounds", null, null);
39}
40
41pub fn startGreaterThanEnd(start: usize, end: usize) noreturn {
42 _ = start;
43 _ = end;
44 call("start index is larger than end index", null, null);
45}
46
47pub fn inactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn {
48 _ = accessed;
49 call("access of inactive union field", null, null);
50}
51
52pub const messages = struct {
53 pub const reached_unreachable = "reached unreachable code";
54 pub const unwrap_null = "attempt to use null value";
55 pub const cast_to_null = "cast causes pointer to be null";
56 pub const incorrect_alignment = "incorrect alignment";
57 pub const invalid_error_code = "invalid error code";
58 pub const cast_truncated_data = "integer cast truncated bits";
59 pub const negative_to_unsigned = "attempt to cast negative value to unsigned integer";
60 pub const integer_overflow = "integer overflow";
61 pub const shl_overflow = "left shift overflowed bits";
62 pub const shr_overflow = "right shift overflowed bits";
63 pub const divide_by_zero = "division by zero";
64 pub const exact_division_remainder = "exact division produced remainder";
65 pub const integer_part_out_of_bounds = "integer part of floating point value out of bounds";
66 pub const corrupt_switch = "switch on corrupt value";
67 pub const shift_rhs_too_big = "shift amount is greater than the type size";
68 pub const invalid_enum_value = "invalid enum value";
69 pub const for_len_mismatch = "for loop over objects with non-equal lengths";
70 pub const memcpy_len_mismatch = "@memcpy arguments have non-equal lengths";
71 pub const memcpy_alias = "@memcpy arguments alias";
72 pub const noreturn_returned = "'noreturn' function returned";
73
74 /// To be deleted after zig1.wasm is updated.
75 pub const inactive_union_field = "access of inactive union field";
76 /// To be deleted after zig1.wasm is updated.
77 pub const sentinel_mismatch = "sentinel mismatch";
78 /// To be deleted after zig1.wasm is updated.
79 pub const unwrap_error = "attempt to unwrap error";
80 /// To be deleted after zig1.wasm is updated.
81 pub const index_out_of_bounds = "index out of bounds";
82 /// To be deleted after zig1.wasm is updated.
83 pub const start_index_greater_than_end = "start index is larger than end index";
84 /// To be deleted after zig1.wasm is updated.
85 pub const unreach = reached_unreachable;
86};
lib/std/debug/no_panic.zig created+160
...@@ -0,0 +1,160 @@
1//! This namespace can be used with `pub const panic = std.debug.no_panic;` in the root file.
2//! It emits as little code as possible, for testing purposes.
3//!
4//! For a functional alternative, see `std.debug.FullPanic`.
5
6const std = @import("../std.zig");
7
8pub fn call(_: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
9 @branchHint(.cold);
10 @trap();
11}
12
13pub fn sentinelMismatch(_: anytype, _: anytype) noreturn {
14 @branchHint(.cold);
15 @trap();
16}
17
18pub fn unwrapError(_: ?*std.builtin.StackTrace, _: anyerror) noreturn {
19 @branchHint(.cold);
20 @trap();
21}
22
23pub fn outOfBounds(_: usize, _: usize) noreturn {
24 @branchHint(.cold);
25 @trap();
26}
27
28pub fn startGreaterThanEnd(_: usize, _: usize) noreturn {
29 @branchHint(.cold);
30 @trap();
31}
32
33pub fn inactiveUnionField(_: anytype, _: anytype) noreturn {
34 @branchHint(.cold);
35 @trap();
36}
37
38pub fn reachedUnreachable() noreturn {
39 @branchHint(.cold);
40 @trap();
41}
42
43pub fn unwrapNull() noreturn {
44 @branchHint(.cold);
45 @trap();
46}
47
48pub fn castToNull() noreturn {
49 @branchHint(.cold);
50 @trap();
51}
52
53pub fn incorrectAlignment() noreturn {
54 @branchHint(.cold);
55 @trap();
56}
57
58pub fn invalidErrorCode() noreturn {
59 @branchHint(.cold);
60 @trap();
61}
62
63pub fn castTruncatedData() noreturn {
64 @branchHint(.cold);
65 @trap();
66}
67
68pub fn negativeToUnsigned() noreturn {
69 @branchHint(.cold);
70 @trap();
71}
72
73pub fn integerOverflow() noreturn {
74 @branchHint(.cold);
75 @trap();
76}
77
78pub fn shlOverflow() noreturn {
79 @branchHint(.cold);
80 @trap();
81}
82
83pub fn shrOverflow() noreturn {
84 @branchHint(.cold);
85 @trap();
86}
87
88pub fn divideByZero() noreturn {
89 @branchHint(.cold);
90 @trap();
91}
92
93pub fn exactDivisionRemainder() noreturn {
94 @branchHint(.cold);
95 @trap();
96}
97
98pub fn integerPartOutOfBounds() noreturn {
99 @branchHint(.cold);
100 @trap();
101}
102
103pub fn corruptSwitch() noreturn {
104 @branchHint(.cold);
105 @trap();
106}
107
108pub fn shiftRhsTooBig() noreturn {
109 @branchHint(.cold);
110 @trap();
111}
112
113pub fn invalidEnumValue() noreturn {
114 @branchHint(.cold);
115 @trap();
116}
117
118pub fn forLenMismatch() noreturn {
119 @branchHint(.cold);
120 @trap();
121}
122
123pub fn memcpyLenMismatch() noreturn {
124 @branchHint(.cold);
125 @trap();
126}
127
128pub fn memcpyAlias() noreturn {
129 @branchHint(.cold);
130 @trap();
131}
132
133pub fn noreturnReturned() noreturn {
134 @branchHint(.cold);
135 @trap();
136}
137
138/// To be deleted after zig1.wasm update.
139pub const messages = struct {
140 pub const reached_unreachable = "";
141 pub const unwrap_null = "";
142 pub const cast_to_null = "";
143 pub const incorrect_alignment = "";
144 pub const invalid_error_code = "";
145 pub const cast_truncated_data = "";
146 pub const negative_to_unsigned = "";
147 pub const integer_overflow = "";
148 pub const shl_overflow = "";
149 pub const shr_overflow = "";
150 pub const divide_by_zero = "";
151 pub const exact_division_remainder = "";
152 pub const integer_part_out_of_bounds = "";
153 pub const corrupt_switch = "";
154 pub const shift_rhs_too_big = "";
155 pub const invalid_enum_value = "";
156 pub const for_len_mismatch = "";
157 pub const memcpy_len_mismatch = "";
158 pub const memcpy_alias = "";
159 pub const noreturn_returned = "";
160};
lib/std/debug/simple_panic.zig created+154
...@@ -0,0 +1,154 @@
1//! This namespace is the default one used by the Zig compiler to emit various
2//! kinds of safety panics, due to the logic in `std.builtin.panic`.
3//!
4//! Since Zig does not have interfaces, this file serves as an example template
5//! for users to provide their own alternative panic handling.
6//!
7//! As an alternative, see `std.debug.FullPanic`.
8
9const std = @import("../std.zig");
10
11/// Prints the message to stderr without a newline and then traps.
12///
13/// Explicit calls to `@panic` lower to calling this function.
14pub fn call(msg: []const u8, ert: ?*std.builtin.StackTrace, ra: ?usize) noreturn {
15 @branchHint(.cold);
16 _ = ert;
17 _ = ra;
18 std.debug.lockStdErr();
19 const stderr = std.io.getStdErr();
20 stderr.writeAll(msg) catch {};
21 @trap();
22}
23
24pub fn sentinelMismatch(expected: anytype, found: @TypeOf(expected)) noreturn {
25 _ = found;
26 call("sentinel mismatch", null, null);
27}
28
29pub fn unwrapError(ert: ?*std.builtin.StackTrace, err: anyerror) noreturn {
30 _ = ert;
31 _ = &err;
32 call("attempt to unwrap error", null, null);
33}
34
35pub fn outOfBounds(index: usize, len: usize) noreturn {
36 _ = index;
37 _ = len;
38 call("index out of bounds", null, null);
39}
40
41pub fn startGreaterThanEnd(start: usize, end: usize) noreturn {
42 _ = start;
43 _ = end;
44 call("start index is larger than end index", null, null);
45}
46
47pub fn inactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn {
48 _ = accessed;
49 call("access of inactive union field", null, null);
50}
51
52pub fn reachedUnreachable() noreturn {
53 call("reached unreachable code", null, null);
54}
55
56pub fn unwrapNull() noreturn {
57 call("attempt to use null value", null, null);
58}
59
60pub fn castToNull() noreturn {
61 call("cast causes pointer to be null", null, null);
62}
63
64pub fn incorrectAlignment() noreturn {
65 call("incorrect alignment", null, null);
66}
67
68pub fn invalidErrorCode() noreturn {
69 call("invalid error code", null, null);
70}
71
72pub fn castTruncatedData() noreturn {
73 call("integer cast truncated bits", null, null);
74}
75
76pub fn negativeToUnsigned() noreturn {
77 call("attempt to cast negative value to unsigned integer", null, null);
78}
79
80pub fn integerOverflow() noreturn {
81 call("integer overflow", null, null);
82}
83
84pub fn shlOverflow() noreturn {
85 call("left shift overflowed bits", null, null);
86}
87
88pub fn shrOverflow() noreturn {
89 call("right shift overflowed bits", null, null);
90}
91
92pub fn divideByZero() noreturn {
93 call("division by zero", null, null);
94}
95
96pub fn exactDivisionRemainder() noreturn {
97 call("exact division produced remainder", null, null);
98}
99
100pub fn integerPartOutOfBounds() noreturn {
101 call("integer part of floating point value out of bounds", null, null);
102}
103
104pub fn corruptSwitch() noreturn {
105 call("switch on corrupt value", null, null);
106}
107
108pub fn shiftRhsTooBig() noreturn {
109 call("shift amount is greater than the type size", null, null);
110}
111
112pub fn invalidEnumValue() noreturn {
113 call("invalid enum value", null, null);
114}
115
116pub fn forLenMismatch() noreturn {
117 call("for loop over objects with non-equal lengths", null, null);
118}
119
120pub fn memcpyLenMismatch() noreturn {
121 call("@memcpy arguments have non-equal lengths", null, null);
122}
123
124pub fn memcpyAlias() noreturn {
125 call("@memcpy arguments alias", null, null);
126}
127
128pub fn noreturnReturned() noreturn {
129 call("'noreturn' function returned", null, null);
130}
131
132/// To be deleted after zig1.wasm update.
133pub const messages = struct {
134 pub const reached_unreachable = "reached unreachable code";
135 pub const unwrap_null = "attempt to use null value";
136 pub const cast_to_null = "cast causes pointer to be null";
137 pub const incorrect_alignment = "incorrect alignment";
138 pub const invalid_error_code = "invalid error code";
139 pub const cast_truncated_data = "integer cast truncated bits";
140 pub const negative_to_unsigned = "attempt to cast negative value to unsigned integer";
141 pub const integer_overflow = "integer overflow";
142 pub const shl_overflow = "left shift overflowed bits";
143 pub const shr_overflow = "right shift overflowed bits";
144 pub const divide_by_zero = "division by zero";
145 pub const exact_division_remainder = "exact division produced remainder";
146 pub const integer_part_out_of_bounds = "integer part of floating point value out of bounds";
147 pub const corrupt_switch = "switch on corrupt value";
148 pub const shift_rhs_too_big = "shift amount is greater than the type size";
149 pub const invalid_enum_value = "invalid enum value";
150 pub const for_len_mismatch = "for loop over objects with non-equal lengths";
151 pub const memcpy_len_mismatch = "@memcpy arguments have non-equal lengths";
152 pub const memcpy_alias = "@memcpy arguments alias";
153 pub const noreturn_returned = "'noreturn' function returned";
154};
lib/std/meta.zig+1-2
...@@ -448,8 +448,7 @@ pub fn fieldNames(comptime T: type) *const [fields(T).len][:0]const u8 {...@@ -448,8 +448,7 @@ pub fn fieldNames(comptime T: type) *const [fields(T).len][:0]const u8 {
448 return comptime blk: {448 return comptime blk: {
449 const fieldInfos = fields(T);449 const fieldInfos = fields(T);
450 var names: [fieldInfos.len][:0]const u8 = undefined;450 var names: [fieldInfos.len][:0]const u8 = undefined;
451 // This concat can be removed with the next zig1 update.451 for (&names, fieldInfos) |*name, field| name.* = field.name;
452 for (&names, fieldInfos) |*name, field| name.* = field.name ++ "";
453 const final = names;452 const final = names;
454 break :blk &final;453 break :blk &final;
455 };454 };
src/Sema.zig+89-66
...@@ -5918,13 +5918,14 @@ fn zirCompileLog(...@@ -5918,13 +5918,14 @@ fn zirCompileLog(
5918}5918}
59195919
5920fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {5920fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
5921 const pt = sema.pt;
5922 const zcu = pt.zcu;
5923
5921 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;5924 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
5922 const src = block.nodeOffset(inst_data.src_node);5925 const src = block.nodeOffset(inst_data.src_node);
5923 const msg_inst = try sema.resolveInst(inst_data.operand);5926 const msg_inst = try sema.resolveInst(inst_data.operand);
59245927
5925 // `panicWithMsg` would perform this coercion for us, but we can get a better5928 const coerced_msg = try sema.coerce(block, .slice_const_u8, msg_inst, block.builtinCallArgSrc(inst_data.src_node, 0));
5926 // source location if we do it here.
5927 const coerced_msg = try sema.coerce(block, Type.slice_const_u8, msg_inst, block.builtinCallArgSrc(inst_data.src_node, 0));
59285929
5929 if (block.isComptime()) {5930 if (block.isComptime()) {
5930 return sema.fail(block, src, "encountered @panic at comptime", .{});5931 return sema.fail(block, src, "encountered @panic at comptime", .{});
...@@ -5936,7 +5937,23 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -5936,7 +5937,23 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
5936 sema.branch_hint = .cold;5937 sema.branch_hint = .cold;
5937 }5938 }
59385939
5939 try sema.panicWithMsg(block, src, coerced_msg, .@"@panic");5940 if (!zcu.backendSupportsFeature(.panic_fn)) {
5941 _ = try block.addNoOp(.trap);
5942 return;
5943 }
5944
5945 try sema.ensureMemoizedStateResolved(src, .panic);
5946 try zcu.ensureFuncBodyAnalysisQueued(zcu.builtin_decl_values.get(.@"panic.call"));
5947
5948 const panic_fn = Air.internedToRef(zcu.builtin_decl_values.get(.@"panic.call"));
5949 const null_stack_trace = Air.internedToRef(zcu.null_stack_trace);
5950
5951 const opt_usize_ty = try pt.optionalType(.usize_type);
5952 const null_ret_addr = Air.internedToRef((try pt.intern(.{ .opt = .{
5953 .ty = opt_usize_ty.toIntern(),
5954 .val = .none,
5955 } })));
5956 try sema.callBuiltin(block, src, panic_fn, .auto, &.{ coerced_msg, null_stack_trace, null_ret_addr }, .@"@panic");
5940}5957}
59415958
5942fn zirTrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {5959fn zirTrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
...@@ -13787,7 +13804,7 @@ fn maybeErrorUnwrap(...@@ -13787,7 +13804,7 @@ fn maybeErrorUnwrap(
13787 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;13804 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
13788 const msg_inst = try sema.resolveInst(inst_data.operand);13805 const msg_inst = try sema.resolveInst(inst_data.operand);
1378913806
13790 const panic_fn = try getBuiltin(sema, operand_src, .@"Panic.call");13807 const panic_fn = try getBuiltin(sema, operand_src, .@"panic.call");
13791 const err_return_trace = try sema.getErrorReturnTrace(block);13808 const err_return_trace = try sema.getErrorReturnTrace(block);
13792 const args: [3]Air.Inst.Ref = .{ msg_inst, err_return_trace, .null_value };13809 const args: [3]Air.Inst.Ref = .{ msg_inst, err_return_trace, .null_value };
13793 try sema.callBuiltin(block, operand_src, Air.internedToRef(panic_fn), .auto, &args, .@"safety check");13810 try sema.callBuiltin(block, operand_src, Air.internedToRef(panic_fn), .auto, &args, .@"safety check");
...@@ -27083,15 +27100,16 @@ fn explainWhyTypeIsNotPacked(...@@ -27083,15 +27100,16 @@ fn explainWhyTypeIsNotPacked(
27083/// Backends depend on panic decls being available when lowering safety-checked27100/// Backends depend on panic decls being available when lowering safety-checked
27084/// instructions. This function ensures the panic function will be available to27101/// instructions. This function ensures the panic function will be available to
27085/// be called during that time.27102/// be called during that time.
27086fn preparePanicId(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.PanicId) !InternPool.Index {27103fn preparePanicId(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) !InternPool.Index {
27087 const zcu = sema.pt.zcu;27104 const zcu = sema.pt.zcu;
27088 try sema.ensureMemoizedStateResolved(src, .panic);27105 try sema.ensureMemoizedStateResolved(src, .panic);
27089 try zcu.ensureFuncBodyAnalysisQueued(zcu.builtin_decl_values.get(.@"Panic.call"));27106 const panic_func = zcu.builtin_decl_values.get(panic_id.toBuiltin());
27107 try zcu.ensureFuncBodyAnalysisQueued(panic_func);
27090 switch (sema.owner.unwrap()) {27108 switch (sema.owner.unwrap()) {
27091 .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},27109 .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},
27092 .func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(owner_func, true),27110 .func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(owner_func, true),
27093 }27111 }
27094 return zcu.builtin_decl_values.get(panic_id.toBuiltin());27112 return panic_func;
27095}27113}
2709627114
27097fn addSafetyCheck(27115fn addSafetyCheck(
...@@ -27099,7 +27117,7 @@ fn addSafetyCheck(...@@ -27099,7 +27117,7 @@ fn addSafetyCheck(
27099 parent_block: *Block,27117 parent_block: *Block,
27100 src: LazySrcLoc,27118 src: LazySrcLoc,
27101 ok: Air.Inst.Ref,27119 ok: Air.Inst.Ref,
27102 panic_id: Zcu.PanicId,27120 panic_id: Zcu.SimplePanicId,
27103) !void {27121) !void {
27104 const gpa = sema.gpa;27122 const gpa = sema.gpa;
27105 assert(!parent_block.isComptime());27123 assert(!parent_block.isComptime());
...@@ -27186,29 +27204,6 @@ fn addSafetyCheckExtra(...@@ -27186,29 +27204,6 @@ fn addSafetyCheckExtra(
27186 parent_block.instructions.appendAssumeCapacity(block_inst);27204 parent_block.instructions.appendAssumeCapacity(block_inst);
27187}27205}
2718827206
27189fn panicWithMsg(sema: *Sema, block: *Block, src: LazySrcLoc, msg_inst: Air.Inst.Ref, operation: CallOperation) !void {
27190 const pt = sema.pt;
27191 const zcu = pt.zcu;
27192
27193 if (!zcu.backendSupportsFeature(.panic_fn)) {
27194 _ = try block.addNoOp(.trap);
27195 return;
27196 }
27197
27198 try sema.ensureMemoizedStateResolved(src, .panic);
27199 try zcu.ensureFuncBodyAnalysisQueued(zcu.builtin_decl_values.get(.@"Panic.call"));
27200
27201 const panic_fn = Air.internedToRef(zcu.builtin_decl_values.get(.@"Panic.call"));
27202 const null_stack_trace = Air.internedToRef(zcu.null_stack_trace);
27203
27204 const opt_usize_ty = try pt.optionalType(.usize_type);
27205 const null_ret_addr = Air.internedToRef((try pt.intern(.{ .opt = .{
27206 .ty = opt_usize_ty.toIntern(),
27207 .val = .none,
27208 } })));
27209 try sema.callBuiltin(block, src, panic_fn, .auto, &.{ msg_inst, null_stack_trace, null_ret_addr }, operation);
27210}
27211
27212fn addSafetyCheckUnwrapError(27207fn addSafetyCheckUnwrapError(
27213 sema: *Sema,27208 sema: *Sema,
27214 parent_block: *Block,27209 parent_block: *Block,
...@@ -27246,7 +27241,7 @@ fn safetyPanicUnwrapError(sema: *Sema, block: *Block, src: LazySrcLoc, err: Air....@@ -27246,7 +27241,7 @@ fn safetyPanicUnwrapError(sema: *Sema, block: *Block, src: LazySrcLoc, err: Air.
27246 if (!zcu.backendSupportsFeature(.panic_fn)) {27241 if (!zcu.backendSupportsFeature(.panic_fn)) {
27247 _ = try block.addNoOp(.trap);27242 _ = try block.addNoOp(.trap);
27248 } else {27243 } else {
27249 const panic_fn = try getBuiltin(sema, src, .@"Panic.unwrapError");27244 const panic_fn = try getBuiltin(sema, src, .@"panic.unwrapError");
27250 const err_return_trace = try sema.getErrorReturnTrace(block);27245 const err_return_trace = try sema.getErrorReturnTrace(block);
27251 const args: [2]Air.Inst.Ref = .{ err_return_trace, err };27246 const args: [2]Air.Inst.Ref = .{ err_return_trace, err };
27252 try sema.callBuiltin(block, src, Air.internedToRef(panic_fn), .auto, &args, .@"safety check");27247 try sema.callBuiltin(block, src, Air.internedToRef(panic_fn), .auto, &args, .@"safety check");
...@@ -27263,7 +27258,7 @@ fn addSafetyCheckIndexOob(...@@ -27263,7 +27258,7 @@ fn addSafetyCheckIndexOob(
27263) !void {27258) !void {
27264 assert(!parent_block.isComptime());27259 assert(!parent_block.isComptime());
27265 const ok = try parent_block.addBinOp(cmp_op, index, len);27260 const ok = try parent_block.addBinOp(cmp_op, index, len);
27266 return addSafetyCheckCall(sema, parent_block, src, ok, .@"Panic.outOfBounds", &.{ index, len });27261 return addSafetyCheckCall(sema, parent_block, src, ok, .@"panic.outOfBounds", &.{ index, len });
27267}27262}
2726827263
27269fn addSafetyCheckInactiveUnionField(27264fn addSafetyCheckInactiveUnionField(
...@@ -27275,7 +27270,7 @@ fn addSafetyCheckInactiveUnionField(...@@ -27275,7 +27270,7 @@ fn addSafetyCheckInactiveUnionField(
27275) !void {27270) !void {
27276 assert(!parent_block.isComptime());27271 assert(!parent_block.isComptime());
27277 const ok = try parent_block.addBinOp(.cmp_eq, active_tag, wanted_tag);27272 const ok = try parent_block.addBinOp(.cmp_eq, active_tag, wanted_tag);
27278 return addSafetyCheckCall(sema, parent_block, src, ok, .@"Panic.inactiveUnionField", &.{ active_tag, wanted_tag });27273 return addSafetyCheckCall(sema, parent_block, src, ok, .@"panic.inactiveUnionField", &.{ active_tag, wanted_tag });
27279}27274}
2728027275
27281fn addSafetyCheckSentinelMismatch(27276fn addSafetyCheckSentinelMismatch(
...@@ -27316,7 +27311,7 @@ fn addSafetyCheckSentinelMismatch(...@@ -27316,7 +27311,7 @@ fn addSafetyCheckSentinelMismatch(
27316 break :ok try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel);27311 break :ok try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel);
27317 };27312 };
2731827313
27319 return addSafetyCheckCall(sema, parent_block, src, ok, .@"Panic.sentinelMismatch", &.{27314 return addSafetyCheckCall(sema, parent_block, src, ok, .@"panic.sentinelMismatch", &.{
27320 expected_sentinel, actual_sentinel,27315 expected_sentinel, actual_sentinel,
27321 });27316 });
27322}27317}
...@@ -27358,9 +27353,13 @@ fn addSafetyCheckCall(...@@ -27358,9 +27353,13 @@ fn addSafetyCheckCall(
27358}27353}
2735927354
27360/// This does not set `sema.branch_hint`.27355/// This does not set `sema.branch_hint`.
27361fn safetyPanic(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.PanicId) CompileError!void {27356fn safetyPanic(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) CompileError!void {
27362 const msg_val = try sema.preparePanicId(src, panic_id);27357 if (!sema.pt.zcu.backendSupportsFeature(.panic_fn)) {
27363 try sema.panicWithMsg(block, src, Air.internedToRef(msg_val), .@"safety check");27358 _ = try block.addNoOp(.trap);
27359 } else {
27360 const panic_fn = try sema.preparePanicId(src, panic_id);
27361 try sema.callBuiltin(block, src, Air.internedToRef(panic_fn), .auto, &.{}, .@"safety check");
27362 }
27364}27363}
2736527364
27366fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void {27365fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
...@@ -32818,7 +32817,7 @@ fn analyzeSlice(...@@ -32818,7 +32817,7 @@ fn analyzeSlice(
32818 assert(!block.isComptime());32817 assert(!block.isComptime());
32819 try sema.requireRuntimeBlock(block, src, runtime_src.?);32818 try sema.requireRuntimeBlock(block, src, runtime_src.?);
32820 const ok = try block.addBinOp(.cmp_lte, start, end);32819 const ok = try block.addBinOp(.cmp_lte, start, end);
32821 try sema.addSafetyCheckCall(block, src, ok, .@"Panic.startGreaterThanEnd", &.{ start, end });32820 try sema.addSafetyCheckCall(block, src, ok, .@"panic.startGreaterThanEnd", &.{ start, end });
32822 }32821 }
32823 const new_len = if (by_length)32822 const new_len = if (by_length)
32824 try sema.coerce(block, Type.usize, uncasted_end_opt, end_src)32823 try sema.coerce(block, Type.usize, uncasted_end_opt, end_src)
...@@ -38525,14 +38524,9 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc,...@@ -38525,14 +38524,9 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc,
38525 break :val uncoerced_val;38524 break :val uncoerced_val;
38526 },38525 },
38527 .func => val: {38526 .func => val: {
38528 if (try sema.getExpectedBuiltinFnType(src, builtin_decl)) |func_ty| {38527 const func_ty = try sema.getExpectedBuiltinFnType(src, builtin_decl);
38529 const coerced = try sema.coerce(block, func_ty, Air.internedToRef(uncoerced_val.toIntern()), src);38528 const coerced = try sema.coerce(block, func_ty, Air.internedToRef(uncoerced_val.toIntern()), src);
38530 break :val .fromInterned(coerced.toInterned().?);38529 break :val .fromInterned(coerced.toInterned().?);
38531 }
38532 if (uncoerced_val.typeOf(zcu).zigTypeTag(zcu) != .@"fn") {
38533 return sema.fail(block, src, "{s}.{s} is not a function", .{ parent_name, name });
38534 }
38535 break :val uncoerced_val;
38536 },38530 },
38537 .string => val: {38531 .string => val: {
38538 const coerced = try sema.coerce(block, .slice_const_u8, Air.internedToRef(uncoerced_val.toIntern()), src);38532 const coerced = try sema.coerce(block, .slice_const_u8, Air.internedToRef(uncoerced_val.toIntern()), src);
...@@ -38567,16 +38561,19 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc,...@@ -38567,16 +38561,19 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc,
38567 return any_changed;38561 return any_changed;
38568}38562}
3856938563
38570/// Given that `decl.kind() == .func`, get the type expected of the function if necessary.38564/// Given that `decl.kind() == .func`, get the type expected of the function.
38571/// If this will be type checked by `Sema` anyway, this function may return `null`. In38565fn getExpectedBuiltinFnType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) CompileError!Type {
38572/// particular, generic functions should return `null`, as `Sema` will necessarily check
38573/// them at instantiation time. Returning non-null is necessary only when backends can emit
38574/// calls to the function, as is the case with the panic handler.
38575fn getExpectedBuiltinFnType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) CompileError!?Type {
38576 const pt = sema.pt;38566 const pt = sema.pt;
38577 return switch (decl) {38567 return switch (decl) {
38568 // `noinline fn () void`
38569 .returnError => try pt.funcType(.{
38570 .param_types = &.{},
38571 .return_type = .void_type,
38572 .is_noinline = true,
38573 }),
38574
38578 // `fn ([]const u8, ?*StackTrace, ?usize) noreturn`38575 // `fn ([]const u8, ?*StackTrace, ?usize) noreturn`
38579 .@"Panic.call" => try pt.funcType(.{38576 .@"panic.call" => try pt.funcType(.{
38580 .param_types = &.{38577 .param_types = &.{
38581 .slice_const_u8_type,38578 .slice_const_u8_type,
38582 (try pt.optionalType(38579 (try pt.optionalType(
...@@ -38589,8 +38586,17 @@ fn getExpectedBuiltinFnType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl)...@@ -38589,8 +38586,17 @@ fn getExpectedBuiltinFnType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl)
38589 .return_type = .noreturn_type,38586 .return_type = .noreturn_type,
38590 }),38587 }),
3859138588
38589 // `fn (anytype, anytype) noreturn`
38590 .@"panic.sentinelMismatch",
38591 .@"panic.inactiveUnionField",
38592 => try pt.funcType(.{
38593 .param_types = &.{ .generic_poison_type, .generic_poison_type },
38594 .return_type = .noreturn_type,
38595 .is_generic = true,
38596 }),
38597
38592 // `fn (?*StackTrace, anyerror) noreturn`38598 // `fn (?*StackTrace, anyerror) noreturn`
38593 .@"Panic.unwrapError" => try pt.funcType(.{38599 .@"panic.unwrapError" => try pt.funcType(.{
38594 .param_types = &.{38600 .param_types = &.{
38595 (try pt.optionalType(38601 (try pt.optionalType(
38596 (try pt.singleMutPtrType(38602 (try pt.singleMutPtrType(
...@@ -38603,21 +38609,38 @@ fn getExpectedBuiltinFnType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl)...@@ -38603,21 +38609,38 @@ fn getExpectedBuiltinFnType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl)
38603 }),38609 }),
3860438610
38605 // `fn (usize, usize) noreturn`38611 // `fn (usize, usize) noreturn`
38606 .@"Panic.outOfBounds",38612 .@"panic.outOfBounds",
38607 .@"Panic.startGreaterThanEnd",38613 .@"panic.startGreaterThanEnd",
38608 => try pt.funcType(.{38614 => try pt.funcType(.{
38609 .param_types = &.{ .usize_type, .usize_type },38615 .param_types = &.{ .usize_type, .usize_type },
38610 .return_type = .noreturn_type,38616 .return_type = .noreturn_type,
38611 }),38617 }),
3861238618
38613 // Generic functions, so calls are necessarily validated by Sema38619 // `fn () noreturn`
38614 .@"Panic.sentinelMismatch",38620 .@"panic.reachedUnreachable",
38615 .@"Panic.inactiveUnionField",38621 .@"panic.unwrapNull",
38616 => null,38622 .@"panic.castToNull",
3861738623 .@"panic.incorrectAlignment",
38618 // Other functions called exclusively by Sema38624 .@"panic.invalidErrorCode",
38619 .returnError,38625 .@"panic.castTruncatedData",
38620 => null,38626 .@"panic.negativeToUnsigned",
38627 .@"panic.integerOverflow",
38628 .@"panic.shlOverflow",
38629 .@"panic.shrOverflow",
38630 .@"panic.divideByZero",
38631 .@"panic.exactDivisionRemainder",
38632 .@"panic.integerPartOutOfBounds",
38633 .@"panic.corruptSwitch",
38634 .@"panic.shiftRhsTooBig",
38635 .@"panic.invalidEnumValue",
38636 .@"panic.forLenMismatch",
38637 .@"panic.memcpyLenMismatch",
38638 .@"panic.memcpyAlias",
38639 .@"panic.noreturnReturned",
38640 => try pt.funcType(.{
38641 .param_types = &.{},
38642 .return_type = .noreturn_type,
38643 }),
3862138644
38622 else => unreachable,38645 else => unreachable,
38623 };38646 };
src/Zcu.zig+81-74
...@@ -269,34 +269,33 @@ pub const BuiltinDecl = enum {...@@ -269,34 +269,33 @@ pub const BuiltinDecl = enum {
269 @"Type.Opaque",269 @"Type.Opaque",
270 @"Type.Declaration",270 @"Type.Declaration",
271271
272 Panic,272 panic,
273 @"Panic.call",273 @"panic.call",
274 @"Panic.sentinelMismatch",274 @"panic.sentinelMismatch",
275 @"Panic.unwrapError",275 @"panic.unwrapError",
276 @"Panic.outOfBounds",276 @"panic.outOfBounds",
277 @"Panic.startGreaterThanEnd",277 @"panic.startGreaterThanEnd",
278 @"Panic.inactiveUnionField",278 @"panic.inactiveUnionField",
279 @"Panic.messages",279 @"panic.reachedUnreachable",
280 @"Panic.messages.reached_unreachable",280 @"panic.unwrapNull",
281 @"Panic.messages.unwrap_null",281 @"panic.castToNull",
282 @"Panic.messages.cast_to_null",282 @"panic.incorrectAlignment",
283 @"Panic.messages.incorrect_alignment",283 @"panic.invalidErrorCode",
284 @"Panic.messages.invalid_error_code",284 @"panic.castTruncatedData",
285 @"Panic.messages.cast_truncated_data",285 @"panic.negativeToUnsigned",
286 @"Panic.messages.negative_to_unsigned",286 @"panic.integerOverflow",
287 @"Panic.messages.integer_overflow",287 @"panic.shlOverflow",
288 @"Panic.messages.shl_overflow",288 @"panic.shrOverflow",
289 @"Panic.messages.shr_overflow",289 @"panic.divideByZero",
290 @"Panic.messages.divide_by_zero",290 @"panic.exactDivisionRemainder",
291 @"Panic.messages.exact_division_remainder",291 @"panic.integerPartOutOfBounds",
292 @"Panic.messages.integer_part_out_of_bounds",292 @"panic.corruptSwitch",
293 @"Panic.messages.corrupt_switch",293 @"panic.shiftRhsTooBig",
294 @"Panic.messages.shift_rhs_too_big",294 @"panic.invalidEnumValue",
295 @"Panic.messages.invalid_enum_value",295 @"panic.forLenMismatch",
296 @"Panic.messages.for_len_mismatch",296 @"panic.memcpyLenMismatch",
297 @"Panic.messages.memcpy_len_mismatch",297 @"panic.memcpyAlias",
298 @"Panic.messages.memcpy_alias",298 @"panic.noreturnReturned",
299 @"Panic.messages.noreturn_returned",
300299
301 VaList,300 VaList,
302301
...@@ -345,39 +344,35 @@ pub const BuiltinDecl = enum {...@@ -345,39 +344,35 @@ pub const BuiltinDecl = enum {
345 .@"Type.Declaration",344 .@"Type.Declaration",
346 => .type,345 => .type,
347346
348 .Panic => .type,347 .panic => .type,
349348
350 .@"Panic.call",349 .@"panic.call",
351 .@"Panic.sentinelMismatch",350 .@"panic.sentinelMismatch",
352 .@"Panic.unwrapError",351 .@"panic.unwrapError",
353 .@"Panic.outOfBounds",352 .@"panic.outOfBounds",
354 .@"Panic.startGreaterThanEnd",353 .@"panic.startGreaterThanEnd",
355 .@"Panic.inactiveUnionField",354 .@"panic.inactiveUnionField",
355 .@"panic.reachedUnreachable",
356 .@"panic.unwrapNull",
357 .@"panic.castToNull",
358 .@"panic.incorrectAlignment",
359 .@"panic.invalidErrorCode",
360 .@"panic.castTruncatedData",
361 .@"panic.negativeToUnsigned",
362 .@"panic.integerOverflow",
363 .@"panic.shlOverflow",
364 .@"panic.shrOverflow",
365 .@"panic.divideByZero",
366 .@"panic.exactDivisionRemainder",
367 .@"panic.integerPartOutOfBounds",
368 .@"panic.corruptSwitch",
369 .@"panic.shiftRhsTooBig",
370 .@"panic.invalidEnumValue",
371 .@"panic.forLenMismatch",
372 .@"panic.memcpyLenMismatch",
373 .@"panic.memcpyAlias",
374 .@"panic.noreturnReturned",
356 => .func,375 => .func,
357
358 .@"Panic.messages" => .type,
359
360 .@"Panic.messages.reached_unreachable",
361 .@"Panic.messages.unwrap_null",
362 .@"Panic.messages.cast_to_null",
363 .@"Panic.messages.incorrect_alignment",
364 .@"Panic.messages.invalid_error_code",
365 .@"Panic.messages.cast_truncated_data",
366 .@"Panic.messages.negative_to_unsigned",
367 .@"Panic.messages.integer_overflow",
368 .@"Panic.messages.shl_overflow",
369 .@"Panic.messages.shr_overflow",
370 .@"Panic.messages.divide_by_zero",
371 .@"Panic.messages.exact_division_remainder",
372 .@"Panic.messages.integer_part_out_of_bounds",
373 .@"Panic.messages.corrupt_switch",
374 .@"Panic.messages.shift_rhs_too_big",
375 .@"Panic.messages.invalid_enum_value",
376 .@"Panic.messages.for_len_mismatch",
377 .@"Panic.messages.memcpy_len_mismatch",
378 .@"Panic.messages.memcpy_alias",
379 .@"Panic.messages.noreturn_returned",
380 => .string,
381 };376 };
382 }377 }
383378
...@@ -423,7 +418,7 @@ pub const BuiltinDecl = enum {...@@ -423,7 +418,7 @@ pub const BuiltinDecl = enum {
423 const Memoized = std.enums.EnumArray(BuiltinDecl, InternPool.Index);418 const Memoized = std.enums.EnumArray(BuiltinDecl, InternPool.Index);
424};419};
425420
426pub const PanicId = enum {421pub const SimplePanicId = enum {
427 reached_unreachable,422 reached_unreachable,
428 unwrap_null,423 unwrap_null,
429 cast_to_null,424 cast_to_null,
...@@ -445,19 +440,31 @@ pub const PanicId = enum {...@@ -445,19 +440,31 @@ pub const PanicId = enum {
445 memcpy_alias,440 memcpy_alias,
446 noreturn_returned,441 noreturn_returned,
447442
448 pub fn toBuiltin(id: PanicId) BuiltinDecl {443 pub fn toBuiltin(id: SimplePanicId) BuiltinDecl {
449 const first_msg: PanicId = @enumFromInt(0);444 return switch (id) {
450 const first_decl = @field(BuiltinDecl, "Panic.messages." ++ @tagName(first_msg));445 // zig fmt: off
451 comptime {446 .reached_unreachable => .@"panic.reachedUnreachable",
452 // Ensure that the messages are ordered the same in `BuiltinDecl` as they are here.447 .unwrap_null => .@"panic.unwrapNull",
453 for (@typeInfo(PanicId).@"enum".fields) |panic_field| {448 .cast_to_null => .@"panic.castToNull",
454 const expect_name = "Panic.messages." ++ panic_field.name;449 .incorrect_alignment => .@"panic.incorrectAlignment",
455 const expect_idx = @intFromEnum(first_decl) + panic_field.value;450 .invalid_error_code => .@"panic.invalidErrorCode",
456 const actual_idx = @intFromEnum(@field(BuiltinDecl, expect_name));451 .cast_truncated_data => .@"panic.castTruncatedData",
457 assert(expect_idx == actual_idx);452 .negative_to_unsigned => .@"panic.negativeToUnsigned",
458 }453 .integer_overflow => .@"panic.integerOverflow",
459 }454 .shl_overflow => .@"panic.shlOverflow",
460 return @enumFromInt(@intFromEnum(first_decl) + @intFromEnum(id));455 .shr_overflow => .@"panic.shrOverflow",
456 .divide_by_zero => .@"panic.divideByZero",
457 .exact_division_remainder => .@"panic.exactDivisionRemainder",
458 .integer_part_out_of_bounds => .@"panic.integerPartOutOfBounds",
459 .corrupt_switch => .@"panic.corruptSwitch",
460 .shift_rhs_too_big => .@"panic.shiftRhsTooBig",
461 .invalid_enum_value => .@"panic.invalidEnumValue",
462 .for_len_mismatch => .@"panic.forLenMismatch",
463 .memcpy_len_mismatch => .@"panic.memcpyLenMismatch",
464 .memcpy_alias => .@"panic.memcpyAlias",
465 .noreturn_returned => .@"panic.noreturnReturned",
466 // zig fmt: on
467 };
461 }468 }
462};469};
463470
src/Zcu/PerThread.zig+1-1
...@@ -605,7 +605,7 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized...@@ -605,7 +605,7 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized
605 // We use an arbitrary element to check if the state has been resolved yet.605 // We use an arbitrary element to check if the state has been resolved yet.
606 const to_check: Zcu.BuiltinDecl = switch (stage) {606 const to_check: Zcu.BuiltinDecl = switch (stage) {
607 .main => .Type,607 .main => .Type,
608 .panic => .Panic,608 .panic => .panic,
609 .va_list => .VaList,609 .va_list => .VaList,
610 };610 };
611 if (zcu.builtin_decl_values.get(to_check) != .none) return;611 if (zcu.builtin_decl_values.get(to_check) != .none) return;
src/codegen/llvm.zig+5-44
...@@ -5019,18 +5019,6 @@ pub const FuncGen = struct {...@@ -5019,18 +5019,6 @@ pub const FuncGen = struct {
5019 );5019 );
5020 }5020 }
50215021
5022 fn resolveNullOptUsize(self: *FuncGen) Error!Builder.Constant {
5023 const o = self.ng.object;
5024 const pt = o.pt;
5025 if (o.null_opt_usize == .no_init) {
5026 o.null_opt_usize = try self.resolveValue(Value.fromInterned(try pt.intern(.{ .opt = .{
5027 .ty = try pt.intern(.{ .opt_type = .usize_type }),
5028 .val = .none,
5029 } })));
5030 }
5031 return o.null_opt_usize;
5032 }
5033
5034 fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air.CoveragePoint) Error!void {5022 fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air.CoveragePoint) Error!void {
5035 const o = self.ng.object;5023 const o = self.ng.object;
5036 const zcu = o.pt.zcu;5024 const zcu = o.pt.zcu;
...@@ -5732,30 +5720,14 @@ pub const FuncGen = struct {...@@ -5732,30 +5720,14 @@ pub const FuncGen = struct {
5732 }5720 }
5733 }5721 }
57345722
5735 fn buildSimplePanic(fg: *FuncGen, panic_id: Zcu.PanicId) !void {5723 fn buildSimplePanic(fg: *FuncGen, panic_id: Zcu.SimplePanicId) !void {
5736 const o = fg.ng.object;5724 const o = fg.ng.object;
5737 const zcu = o.pt.zcu;5725 const zcu = o.pt.zcu;
5738 const ip = &zcu.intern_pool;
5739 const msg_len: u64, const msg_ptr: Builder.Constant = msg: {
5740 const str_val = zcu.builtin_decl_values.get(panic_id.toBuiltin());
5741 assert(str_val != .none);
5742 const slice = ip.indexToKey(str_val).slice;
5743 break :msg .{ Value.fromInterned(slice.len).toUnsignedInt(zcu), try o.lowerValue(slice.ptr) };
5744 };
5745 const null_opt_addr_global = try fg.resolveNullOptUsize();
5746 const target = zcu.getTarget();5726 const target = zcu.getTarget();
5747 const llvm_usize = try o.lowerType(Type.usize);5727 const panic_func = zcu.funcInfo(zcu.builtin_decl_values.get(panic_id.toBuiltin()));
5748 // example:5728 const fn_info = zcu.typeToFunc(.fromInterned(panic_func.ty)).?;
5749 // call fastcc void @test2.panic(
5750 // ptr @builtin.panic_messages.integer_overflow__anon_987, ; msg.ptr
5751 // i64 16, ; msg.len
5752 // ptr null, ; stack trace
5753 // ptr @2, ; addr (null ?usize)
5754 // )
5755 const panic_func = zcu.funcInfo(zcu.builtin_decl_values.get(.@"Panic.call"));
5756 const panic_nav = ip.getNav(panic_func.owner_nav);
5757 const fn_info = zcu.typeToFunc(Type.fromInterned(panic_nav.typeOf(ip))).?;
5758 const panic_global = try o.resolveLlvmFunction(panic_func.owner_nav);5729 const panic_global = try o.resolveLlvmFunction(panic_func.owner_nav);
5730
5759 const has_err_trace = zcu.comp.config.any_error_tracing and fn_info.cc == .auto;5731 const has_err_trace = zcu.comp.config.any_error_tracing and fn_info.cc == .auto;
5760 if (has_err_trace) assert(fg.err_ret_trace != .none);5732 if (has_err_trace) assert(fg.err_ret_trace != .none);
5761 _ = try fg.wip.callIntrinsicAssumeCold();5733 _ = try fg.wip.callIntrinsicAssumeCold();
...@@ -5765,18 +5737,7 @@ pub const FuncGen = struct {...@@ -5765,18 +5737,7 @@ pub const FuncGen = struct {
5765 .none,5737 .none,
5766 panic_global.typeOf(&o.builder),5738 panic_global.typeOf(&o.builder),
5767 panic_global.toValue(&o.builder),5739 panic_global.toValue(&o.builder),
5768 if (has_err_trace) &.{5740 if (has_err_trace) &.{fg.err_ret_trace} else &.{},
5769 fg.err_ret_trace,
5770 msg_ptr.toValue(),
5771 try o.builder.intValue(llvm_usize, msg_len),
5772 try o.builder.nullValue(.ptr),
5773 null_opt_addr_global.toValue(),
5774 } else &.{
5775 msg_ptr.toValue(),
5776 try o.builder.intValue(llvm_usize, msg_len),
5777 try o.builder.nullValue(.ptr),
5778 null_opt_addr_global.toValue(),
5779 },
5780 "",5741 "",
5781 );5742 );
5782 _ = try fg.wip.@"unreachable"();5743 _ = try fg.wip.@"unreachable"();
src/crash_report.zig+5-11
...@@ -18,18 +18,12 @@ const dev = @import("dev.zig");...@@ -18,18 +18,12 @@ const dev = @import("dev.zig");
18/// To use these crash report diagnostics, publish this panic in your main file18/// To use these crash report diagnostics, publish this panic in your main file
19/// and add `pub const enable_segfault_handler = false;` to your `std_options`.19/// and add `pub const enable_segfault_handler = false;` to your `std_options`.
20/// You will also need to call initialize() on startup, preferably as the very first operation in your program.20/// You will also need to call initialize() on startup, preferably as the very first operation in your program.
21pub const Panic = if (build_options.enable_debug_extensions) struct {21pub const panic = if (build_options.enable_debug_extensions)
22 pub const call = compilerPanic;22 std.debug.FullPanic(compilerPanic)
23 pub const sentinelMismatch = std.debug.FormattedPanic.sentinelMismatch;23else if (dev.env == .bootstrap)
24 pub const unwrapError = std.debug.FormattedPanic.unwrapError;24 std.debug.simple_panic
25 pub const outOfBounds = std.debug.FormattedPanic.outOfBounds;
26 pub const startGreaterThanEnd = std.debug.FormattedPanic.startGreaterThanEnd;
27 pub const inactiveUnionField = std.debug.FormattedPanic.inactiveUnionField;
28 pub const messages = std.debug.FormattedPanic.messages;
29} else if (dev.env == .bootstrap)
30 std.debug.SimplePanic
31else25else
32 std.debug.FormattedPanic;26 std.debug.FullPanic(std.debug.defaultPanic);
3327
34/// Install signal handlers to identify crashes and report diagnostics.28/// Install signal handlers to identify crashes and report diagnostics.
35pub fn initialize() void {29pub fn initialize() void {
src/main.zig+1-1
...@@ -56,7 +56,7 @@ pub const std_options: std.Options = .{...@@ -56,7 +56,7 @@ pub const std_options: std.Options = .{
56 },56 },
57};57};
5858
59pub const Panic = crash_report.Panic;59pub const panic = crash_report.panic;
6060
61var wasi_preopens: fs.wasi.Preopens = undefined;61var wasi_preopens: fs.wasi.Preopens = undefined;
62pub fn wasi_cwd() std.os.wasi.fd_t {62pub fn wasi_cwd() std.os.wasi.fd_t {
test/cases/compile_errors/bad_panic_call_signature.zig created+46
...@@ -0,0 +1,46 @@
1const simple_panic = std.debug.simple_panic;
2pub const panic = struct {
3 pub fn call(msg: []const u8, bad1: usize, bad2: void) noreturn {
4 _ = msg;
5 _ = bad1;
6 _ = bad2;
7 @trap();
8 }
9 pub const sentinelMismatch = simple_panic.sentinelMismatch;
10 pub const unwrapError = simple_panic.unwrapError;
11 pub const outOfBounds = simple_panic.outOfBounds;
12 pub const startGreaterThanEnd = simple_panic.startGreaterThanEnd;
13 pub const inactiveUnionField = simple_panic.inactiveUnionField;
14 pub const reachedUnreachable = simple_panic.reachedUnreachable;
15 pub const unwrapNull = simple_panic.unwrapNull;
16 pub const castToNull = simple_panic.castToNull;
17 pub const incorrectAlignment = simple_panic.incorrectAlignment;
18 pub const invalidErrorCode = simple_panic.invalidErrorCode;
19 pub const castTruncatedData = simple_panic.castTruncatedData;
20 pub const negativeToUnsigned = simple_panic.negativeToUnsigned;
21 pub const integerOverflow = simple_panic.integerOverflow;
22 pub const shlOverflow = simple_panic.shlOverflow;
23 pub const shrOverflow = simple_panic.shrOverflow;
24 pub const divideByZero = simple_panic.divideByZero;
25 pub const exactDivisionRemainder = simple_panic.exactDivisionRemainder;
26 pub const integerPartOutOfBounds = simple_panic.integerPartOutOfBounds;
27 pub const corruptSwitch = simple_panic.corruptSwitch;
28 pub const shiftRhsTooBig = simple_panic.shiftRhsTooBig;
29 pub const invalidEnumValue = simple_panic.invalidEnumValue;
30 pub const forLenMismatch = simple_panic.forLenMismatch;
31 pub const memcpyLenMismatch = simple_panic.memcpyLenMismatch;
32 pub const memcpyAlias = simple_panic.memcpyAlias;
33 pub const noreturnReturned = simple_panic.noreturnReturned;
34};
35
36export fn foo(a: u8) void {
37 @setRuntimeSafety(true);
38 _ = a + 1; // safety check to reference the panic handler
39}
40
41const std = @import("std");
42
43// error
44//
45// :3:9: error: expected type 'fn ([]const u8, ?*builtin.StackTrace, ?usize) noreturn', found 'fn ([]const u8, usize, void) noreturn'
46// :3:9: note: parameter 1 'usize' cannot cast into '?*builtin.StackTrace'
test/cases/compile_errors/bad_panic_generic_signature.zig created+41
...@@ -0,0 +1,41 @@
1const simple_panic = std.debug.simple_panic;
2pub const panic = struct {
3 pub fn sentinelMismatch() void {} // invalid
4 pub const call = simple_panic.call;
5 pub const unwrapError = simple_panic.unwrapError;
6 pub const outOfBounds = simple_panic.outOfBounds;
7 pub const startGreaterThanEnd = simple_panic.startGreaterThanEnd;
8 pub const inactiveUnionField = simple_panic.inactiveUnionField;
9 pub const reachedUnreachable = simple_panic.reachedUnreachable;
10 pub const unwrapNull = simple_panic.unwrapNull;
11 pub const castToNull = simple_panic.castToNull;
12 pub const incorrectAlignment = simple_panic.incorrectAlignment;
13 pub const invalidErrorCode = simple_panic.invalidErrorCode;
14 pub const castTruncatedData = simple_panic.castTruncatedData;
15 pub const negativeToUnsigned = simple_panic.negativeToUnsigned;
16 pub const integerOverflow = simple_panic.integerOverflow;
17 pub const shlOverflow = simple_panic.shlOverflow;
18 pub const shrOverflow = simple_panic.shrOverflow;
19 pub const divideByZero = simple_panic.divideByZero;
20 pub const exactDivisionRemainder = simple_panic.exactDivisionRemainder;
21 pub const integerPartOutOfBounds = simple_panic.integerPartOutOfBounds;
22 pub const corruptSwitch = simple_panic.corruptSwitch;
23 pub const shiftRhsTooBig = simple_panic.shiftRhsTooBig;
24 pub const invalidEnumValue = simple_panic.invalidEnumValue;
25 pub const forLenMismatch = simple_panic.forLenMismatch;
26 pub const memcpyLenMismatch = simple_panic.memcpyLenMismatch;
27 pub const memcpyAlias = simple_panic.memcpyAlias;
28 pub const noreturnReturned = simple_panic.noreturnReturned;
29};
30
31export fn foo(arr: *const [2]u8) void {
32 @setRuntimeSafety(true);
33 _ = arr[0..1 :0];
34}
35
36const std = @import("std");
37
38// error
39//
40// :3:9: error: expected type 'fn (anytype, anytype) noreturn', found 'fn () void'
41// :3:9: note: non-generic function cannot cast into a generic function
test/cases/compile_errors/bad_panic_signature.zig deleted-28
...@@ -1,28 +0,0 @@
1pub const Panic = struct {
2 pub const call = badPanicSignature;
3 pub const sentinelMismatch = std.debug.FormattedPanic.sentinelMismatch;
4 pub const unwrapError = std.debug.FormattedPanic.unwrapError;
5 pub const outOfBounds = std.debug.FormattedPanic.outOfBounds;
6 pub const startGreaterThanEnd = std.debug.FormattedPanic.startGreaterThanEnd;
7 pub const inactiveUnionField = std.debug.FormattedPanic.inactiveUnionField;
8 pub const messages = std.debug.FormattedPanic.messages;
9};
10
11fn badPanicSignature(msg: []const u8, bad1: usize, bad2: void) noreturn {
12 _ = msg;
13 _ = bad1;
14 _ = bad2;
15 @trap();
16}
17
18export fn foo(a: u8) void {
19 @setRuntimeSafety(true);
20 _ = a + 1; // safety check to reference the panic handler
21}
22
23const std = @import("std");
24
25// error
26//
27// :2:9: error: expected type 'fn ([]const u8, ?*builtin.StackTrace, ?usize) noreturn', found 'fn ([]const u8, usize, void) noreturn'
28// :2:9: note: parameter 1 'usize' cannot cast into '?*builtin.StackTrace'
test/incremental/change_panic_handler+3-27
...@@ -9,15 +9,7 @@ pub fn main() !u8 {...@@ -9,15 +9,7 @@ pub fn main() !u8 {
9 _ = a + 1;9 _ = a + 1;
10 return 1;10 return 1;
11}11}
12pub const Panic = struct {12pub const panic = std.debug.FullPanic(myPanic);
13 pub const call = myPanic;
14 pub const sentinelMismatch = std.debug.FormattedPanic.sentinelMismatch;
15 pub const unwrapError = std.debug.FormattedPanic.unwrapError;
16 pub const outOfBounds = std.debug.FormattedPanic.outOfBounds;
17 pub const startGreaterThanEnd = std.debug.FormattedPanic.startGreaterThanEnd;
18 pub const inactiveUnionField = std.debug.FormattedPanic.inactiveUnionField;
19 pub const messages = std.debug.FormattedPanic.messages;
20};
21fn myPanic(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {13fn myPanic(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
22 std.io.getStdOut().writer().print("panic message: {s}\n", .{msg}) catch {};14 std.io.getStdOut().writer().print("panic message: {s}\n", .{msg}) catch {};
23 std.process.exit(0);15 std.process.exit(0);
...@@ -33,15 +25,7 @@ pub fn main() !u8 {...@@ -33,15 +25,7 @@ pub fn main() !u8 {
33 _ = a + 1;25 _ = a + 1;
34 return 1;26 return 1;
35}27}
36pub const Panic = struct {28pub const panic = std.debug.FullPanic(myPanic);
37 pub const call = myPanic;
38 pub const sentinelMismatch = std.debug.FormattedPanic.sentinelMismatch;
39 pub const unwrapError = std.debug.FormattedPanic.unwrapError;
40 pub const outOfBounds = std.debug.FormattedPanic.outOfBounds;
41 pub const startGreaterThanEnd = std.debug.FormattedPanic.startGreaterThanEnd;
42 pub const inactiveUnionField = std.debug.FormattedPanic.inactiveUnionField;
43 pub const messages = std.debug.FormattedPanic.messages;
44};
45fn myPanic(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {29fn myPanic(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
46 std.io.getStdOut().writer().print("new panic message: {s}\n", .{msg}) catch {};30 std.io.getStdOut().writer().print("new panic message: {s}\n", .{msg}) catch {};
47 std.process.exit(0);31 std.process.exit(0);
...@@ -57,15 +41,7 @@ pub fn main() !u8 {...@@ -57,15 +41,7 @@ pub fn main() !u8 {
57 _ = a + 1;41 _ = a + 1;
58 return 1;42 return 1;
59}43}
60pub const Panic = struct {44pub const panic = std.debug.FullPanic(myPanicNew);
61 pub const call = myPanicNew;
62 pub const sentinelMismatch = std.debug.FormattedPanic.sentinelMismatch;
63 pub const unwrapError = std.debug.FormattedPanic.unwrapError;
64 pub const outOfBounds = std.debug.FormattedPanic.outOfBounds;
65 pub const startGreaterThanEnd = std.debug.FormattedPanic.startGreaterThanEnd;
66 pub const inactiveUnionField = std.debug.FormattedPanic.inactiveUnionField;
67 pub const messages = std.debug.FormattedPanic.messages;
68};
69fn myPanicNew(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {45fn myPanicNew(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
70 std.io.getStdOut().writer().print("third panic message: {s}\n", .{msg}) catch {};46 std.io.getStdOut().writer().print("third panic message: {s}\n", .{msg}) catch {};
71 std.process.exit(0);47 std.process.exit(0);
test/incremental/change_panic_handler_explicit created+141
...@@ -0,0 +1,141 @@
1#target=x86_64-linux-selfhosted
2#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe
4#update=initial version
5#file=main.zig
6pub fn main() !u8 {
7 var a: u8 = undefined;
8 a = 255;
9 _ = a + 1;
10 return 1;
11}
12const no_panic = std.debug.no_panic;
13pub const panic = struct {
14 pub const call = myPanic;
15 pub fn integerOverflow() noreturn {
16 @panic("integer overflow");
17 }
18 pub const sentinelMismatch = no_panic.sentinelMismatch;
19 pub const unwrapError = no_panic.unwrapError;
20 pub const outOfBounds = no_panic.outOfBounds;
21 pub const startGreaterThanEnd = no_panic.startGreaterThanEnd;
22 pub const inactiveUnionField = no_panic.inactiveUnionField;
23 pub const reachedUnreachable = no_panic.reachedUnreachable;
24 pub const unwrapNull = no_panic.unwrapNull;
25 pub const castToNull = no_panic.castToNull;
26 pub const incorrectAlignment = no_panic.incorrectAlignment;
27 pub const invalidErrorCode = no_panic.invalidErrorCode;
28 pub const castTruncatedData = no_panic.castTruncatedData;
29 pub const negativeToUnsigned = no_panic.negativeToUnsigned;
30 pub const shlOverflow = no_panic.shlOverflow;
31 pub const shrOverflow = no_panic.shrOverflow;
32 pub const divideByZero = no_panic.divideByZero;
33 pub const exactDivisionRemainder = no_panic.exactDivisionRemainder;
34 pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds;
35 pub const corruptSwitch = no_panic.corruptSwitch;
36 pub const shiftRhsTooBig = no_panic.shiftRhsTooBig;
37 pub const invalidEnumValue = no_panic.invalidEnumValue;
38 pub const forLenMismatch = no_panic.forLenMismatch;
39 pub const memcpyLenMismatch = no_panic.memcpyLenMismatch;
40 pub const memcpyAlias = no_panic.memcpyAlias;
41 pub const noreturnReturned = no_panic.noreturnReturned;
42};
43fn myPanic(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
44 std.io.getStdOut().writer().print("panic message: {s}\n", .{msg}) catch {};
45 std.process.exit(0);
46}
47const std = @import("std");
48#expect_stdout="panic message: integer overflow\n"
49
50#update=change the panic handler body
51#file=main.zig
52pub fn main() !u8 {
53 var a: u8 = undefined;
54 a = 255;
55 _ = a + 1;
56 return 1;
57}
58const no_panic = std.debug.no_panic;
59pub const panic = struct {
60 pub const call = myPanic;
61 pub fn integerOverflow() noreturn {
62 @panic("integer overflow");
63 }
64 pub const sentinelMismatch = no_panic.sentinelMismatch;
65 pub const unwrapError = no_panic.unwrapError;
66 pub const outOfBounds = no_panic.outOfBounds;
67 pub const startGreaterThanEnd = no_panic.startGreaterThanEnd;
68 pub const inactiveUnionField = no_panic.inactiveUnionField;
69 pub const reachedUnreachable = no_panic.reachedUnreachable;
70 pub const unwrapNull = no_panic.unwrapNull;
71 pub const castToNull = no_panic.castToNull;
72 pub const incorrectAlignment = no_panic.incorrectAlignment;
73 pub const invalidErrorCode = no_panic.invalidErrorCode;
74 pub const castTruncatedData = no_panic.castTruncatedData;
75 pub const negativeToUnsigned = no_panic.negativeToUnsigned;
76 pub const shlOverflow = no_panic.shlOverflow;
77 pub const shrOverflow = no_panic.shrOverflow;
78 pub const divideByZero = no_panic.divideByZero;
79 pub const exactDivisionRemainder = no_panic.exactDivisionRemainder;
80 pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds;
81 pub const corruptSwitch = no_panic.corruptSwitch;
82 pub const shiftRhsTooBig = no_panic.shiftRhsTooBig;
83 pub const invalidEnumValue = no_panic.invalidEnumValue;
84 pub const forLenMismatch = no_panic.forLenMismatch;
85 pub const memcpyLenMismatch = no_panic.memcpyLenMismatch;
86 pub const memcpyAlias = no_panic.memcpyAlias;
87 pub const noreturnReturned = no_panic.noreturnReturned;
88};
89fn myPanic(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
90 std.io.getStdOut().writer().print("new panic message: {s}\n", .{msg}) catch {};
91 std.process.exit(0);
92}
93const std = @import("std");
94#expect_stdout="new panic message: integer overflow\n"
95
96#update=change the panic handler function value
97#file=main.zig
98pub fn main() !u8 {
99 var a: u8 = undefined;
100 a = 255;
101 _ = a + 1;
102 return 1;
103}
104const no_panic = std.debug.no_panic;
105pub const panic = struct {
106 pub const call = myPanicNew;
107 pub fn integerOverflow() noreturn {
108 @panic("integer overflow");
109 }
110 pub const sentinelMismatch = std.debug.no_panic.sentinelMismatch;
111 pub const unwrapError = std.debug.no_panic.unwrapError;
112 pub const outOfBounds = std.debug.no_panic.outOfBounds;
113 pub const startGreaterThanEnd = std.debug.no_panic.startGreaterThanEnd;
114 pub const inactiveUnionField = std.debug.no_panic.inactiveUnionField;
115 pub const messages = std.debug.no_panic.messages;
116 pub const reachedUnreachable = no_panic.reachedUnreachable;
117 pub const unwrapNull = no_panic.unwrapNull;
118 pub const castToNull = no_panic.castToNull;
119 pub const incorrectAlignment = no_panic.incorrectAlignment;
120 pub const invalidErrorCode = no_panic.invalidErrorCode;
121 pub const castTruncatedData = no_panic.castTruncatedData;
122 pub const negativeToUnsigned = no_panic.negativeToUnsigned;
123 pub const shlOverflow = no_panic.shlOverflow;
124 pub const shrOverflow = no_panic.shrOverflow;
125 pub const divideByZero = no_panic.divideByZero;
126 pub const exactDivisionRemainder = no_panic.exactDivisionRemainder;
127 pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds;
128 pub const corruptSwitch = no_panic.corruptSwitch;
129 pub const shiftRhsTooBig = no_panic.shiftRhsTooBig;
130 pub const invalidEnumValue = no_panic.invalidEnumValue;
131 pub const forLenMismatch = no_panic.forLenMismatch;
132 pub const memcpyLenMismatch = no_panic.memcpyLenMismatch;
133 pub const memcpyAlias = no_panic.memcpyAlias;
134 pub const noreturnReturned = no_panic.noreturnReturned;
135};
136fn myPanicNew(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
137 std.io.getStdOut().writer().print("third panic message: {s}\n", .{msg}) catch {};
138 std.process.exit(0);
139}
140const std = @import("std");
141#expect_stdout="third panic message: integer overflow\n"