authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-01-25 04:10:55+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-01-25 04:10:55+00:00
log8ba3812eeedec643dd045e0fecb8a6697f6253db
tree00c47f03ccef1a0398163b5af7063501860d18fe
parent921725427efeae591793f49291807a41112ccbf9
parentb6726913d31f9273317ab56c4d33096aee0a588f
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #22594 from mlugg/panic-stuff

compiler: yet more panic handler changes

23 files changed, 828 insertions(+), 543 deletions(-)

lib/compiler_rt/common.zig+1-10
...@@ -78,16 +78,7 @@ pub const want_sparc_abi = builtin.cpu.arch.isSPARC();...@@ -78,16 +78,7 @@ pub const want_sparc_abi = builtin.cpu.arch.isSPARC();
7878
79// Avoid dragging in the runtime safety mechanisms into this .o file, unless79// Avoid dragging in the runtime safety mechanisms into this .o file, unless
80// we're trying to test compiler-rt.80// we're trying to test compiler-rt.
81pub const Panic = if (builtin.is_test) std.debug.FormattedPanic else struct {};81pub const panic = if (builtin.is_test) std.debug.FullPanic(std.debug.defaultPanic) else std.debug.no_panic;
82
83/// To be deleted after zig1.wasm is updated.
84pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, ret_addr: ?usize) noreturn {
85 if (builtin.is_test) {
86 std.debug.defaultPanic(msg, error_return_trace, ret_addr orelse @returnAddress());
87 } else {
88 unreachable;
89 }
90}
9182
92/// AArch64 is the only ABI (at the moment) to support f16 arguments without the83/// AArch64 is the only ABI (at the moment) to support f16 arguments without the
93/// need for extending them to wider fp types.84/// need for extending them to wider fp types.
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+20-35
...@@ -1110,46 +1110,31 @@ pub const TestFn = struct {...@@ -1110,46 +1110,31 @@ 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 // Deprecated; make `panic` a namespace instead.
1124else if (builtin.zig_backend == .stage2_riscv64)1121 break :p std.debug.FullPanic(struct {
1125 std.debug.SimplePanic // https://github.com/ziglang/zig/issues/215191122 fn panic(msg: []const u8, ra: ?usize) noreturn {
1126else1123 root.panic(msg, @errorReturnTrace(), ra);
1127 std.debug.FormattedPanic;1124 }
11281125 }.panic);
1129/// To be deleted after 0.14.0 is released.1126 }
1130const DeprecatedPanic = struct {1127 break :p root.panic;
1131 pub const call = root.panic;1128 }
1132 pub const sentinelMismatch = std.debug.FormattedPanic.sentinelMismatch;1129 if (@hasDecl(root, "Panic")) {
1133 pub const unwrapError = std.debug.FormattedPanic.unwrapError;1130 break :p root.Panic; // Deprecated; use `panic` instead.
1134 pub const outOfBounds = std.debug.FormattedPanic.outOfBounds;1131 }
1135 pub const startGreaterThanEnd = std.debug.FormattedPanic.startGreaterThanEnd;1132 if (builtin.zig_backend == .stage2_riscv64) {
1136 pub const inactiveUnionField = std.debug.FormattedPanic.inactiveUnionField;1133 break :p std.debug.simple_panic;
1137 pub const messages = std.debug.FormattedPanic.messages;1134 }
1135 break :p std.debug.FullPanic(std.debug.defaultPanic);
1138};1136};
11391137
1140/// To be deleted after zig1.wasm is updated.
1141pub const panicSentinelMismatch = Panic.sentinelMismatch;
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;
1152
1153pub noinline fn returnError() void {1138pub noinline fn returnError() void {
1154 @branchHint(.unlikely);1139 @branchHint(.unlikely);
1155 @setRuntimeSafety(false);1140 @setRuntimeSafety(false);
lib/std/debug.zig+119-9
...@@ -21,9 +21,121 @@ pub const SelfInfo = @import("debug/SelfInfo.zig");...@@ -21,9 +21,121 @@ 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, ?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(@returnAddress(), "sentinel mismatch: expected {any}, found {any}", .{
36 expected, found,
37 });
38 }
39 pub fn unwrapError(err: anyerror) noreturn {
40 @branchHint(.cold);
41 std.debug.panicExtra(@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(@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(@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(@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", @returnAddress());
60 }
61 pub fn unwrapNull() noreturn {
62 @branchHint(.cold);
63 call("attempt to use null value", @returnAddress());
64 }
65 pub fn castToNull() noreturn {
66 @branchHint(.cold);
67 call("cast causes pointer to be null", @returnAddress());
68 }
69 pub fn incorrectAlignment() noreturn {
70 @branchHint(.cold);
71 call("incorrect alignment", @returnAddress());
72 }
73 pub fn invalidErrorCode() noreturn {
74 @branchHint(.cold);
75 call("invalid error code", @returnAddress());
76 }
77 pub fn castTruncatedData() noreturn {
78 @branchHint(.cold);
79 call("integer cast truncated bits", @returnAddress());
80 }
81 pub fn negativeToUnsigned() noreturn {
82 @branchHint(.cold);
83 call("attempt to cast negative value to unsigned integer", @returnAddress());
84 }
85 pub fn integerOverflow() noreturn {
86 @branchHint(.cold);
87 call("integer overflow", @returnAddress());
88 }
89 pub fn shlOverflow() noreturn {
90 @branchHint(.cold);
91 call("left shift overflowed bits", @returnAddress());
92 }
93 pub fn shrOverflow() noreturn {
94 @branchHint(.cold);
95 call("right shift overflowed bits", @returnAddress());
96 }
97 pub fn divideByZero() noreturn {
98 @branchHint(.cold);
99 call("division by zero", @returnAddress());
100 }
101 pub fn exactDivisionRemainder() noreturn {
102 @branchHint(.cold);
103 call("exact division produced remainder", @returnAddress());
104 }
105 pub fn integerPartOutOfBounds() noreturn {
106 @branchHint(.cold);
107 call("integer part of floating point value out of bounds", @returnAddress());
108 }
109 pub fn corruptSwitch() noreturn {
110 @branchHint(.cold);
111 call("switch on corrupt value", @returnAddress());
112 }
113 pub fn shiftRhsTooBig() noreturn {
114 @branchHint(.cold);
115 call("shift amount is greater than the type size", @returnAddress());
116 }
117 pub fn invalidEnumValue() noreturn {
118 @branchHint(.cold);
119 call("invalid enum value", @returnAddress());
120 }
121 pub fn forLenMismatch() noreturn {
122 @branchHint(.cold);
123 call("for loop over objects with non-equal lengths", @returnAddress());
124 }
125 pub fn memcpyLenMismatch() noreturn {
126 @branchHint(.cold);
127 call("@memcpy arguments have non-equal lengths", @returnAddress());
128 }
129 pub fn memcpyAlias() noreturn {
130 @branchHint(.cold);
131 call("@memcpy arguments alias", @returnAddress());
132 }
133 pub fn noreturnReturned() noreturn {
134 @branchHint(.cold);
135 call("'noreturn' function returned", @returnAddress());
136 }
137 };
138}
27139
28/// Unresolved source locations can be represented with a single `usize` that140/// Unresolved source locations can be represented with a single `usize` that
29/// corresponds to a virtual memory address of the program counter. Combined141/// corresponds to a virtual memory address of the program counter. Combined
...@@ -416,13 +528,12 @@ pub fn assertReadable(slice: []const volatile u8) void {...@@ -416,13 +528,12 @@ pub fn assertReadable(slice: []const volatile u8) void {
416/// Equivalent to `@panic` but with a formatted message.528/// Equivalent to `@panic` but with a formatted message.
417pub fn panic(comptime format: []const u8, args: anytype) noreturn {529pub fn panic(comptime format: []const u8, args: anytype) noreturn {
418 @branchHint(.cold);530 @branchHint(.cold);
419 panicExtra(@errorReturnTrace(), @returnAddress(), format, args);531 panicExtra(@returnAddress(), format, args);
420}532}
421533
422/// Equivalent to `@panic` but with a formatted message, and with an explicitly534/// Equivalent to `@panic` but with a formatted message, and with an explicitly
423/// provided `@errorReturnTrace` and return address.535/// provided return address.
424pub fn panicExtra(536pub fn panicExtra(
425 trace: ?*std.builtin.StackTrace,
426 ret_addr: ?usize,537 ret_addr: ?usize,
427 comptime format: []const u8,538 comptime format: []const u8,
428 args: anytype,539 args: anytype,
...@@ -441,7 +552,7 @@ pub fn panicExtra(...@@ -441,7 +552,7 @@ pub fn panicExtra(
441 break :blk &buf;552 break :blk &buf;
442 },553 },
443 };554 };
444 std.builtin.Panic.call(msg, trace, ret_addr);555 std.builtin.panic.call(msg, ret_addr);
445}556}
446557
447/// Non-zero whenever the program triggered a panic.558/// Non-zero whenever the program triggered a panic.
...@@ -455,7 +566,6 @@ threadlocal var panic_stage: usize = 0;...@@ -455,7 +566,6 @@ threadlocal var panic_stage: usize = 0;
455/// Dumps a stack trace to standard error, then aborts.566/// Dumps a stack trace to standard error, then aborts.
456pub fn defaultPanic(567pub fn defaultPanic(
457 msg: []const u8,568 msg: []const u8,
458 error_return_trace: ?*const std.builtin.StackTrace,
459 first_trace_addr: ?usize,569 first_trace_addr: ?usize,
460) noreturn {570) noreturn {
461 @branchHint(.cold);571 @branchHint(.cold);
...@@ -542,7 +652,7 @@ pub fn defaultPanic(...@@ -542,7 +652,7 @@ pub fn defaultPanic(
542 }652 }
543 stderr.print("{s}\n", .{msg}) catch posix.abort();653 stderr.print("{s}\n", .{msg}) catch posix.abort();
544654
545 if (error_return_trace) |t| dumpStackTrace(t.*);655 if (@errorReturnTrace()) |t| dumpStackTrace(t.*);
546 dumpCurrentStackTrace(first_trace_addr orelse @returnAddress());656 dumpCurrentStackTrace(first_trace_addr orelse @returnAddress());
547 }657 }
548658
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+136
...@@ -0,0 +1,136 @@
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, _: ?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(_: 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}
lib/std/debug/simple_panic.zig created+128
...@@ -0,0 +1,128 @@
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, ra: ?usize) noreturn {
15 @branchHint(.cold);
16 _ = ra;
17 std.debug.lockStdErr();
18 const stderr = std.io.getStdErr();
19 stderr.writeAll(msg) catch {};
20 @trap();
21}
22
23pub fn sentinelMismatch(expected: anytype, found: @TypeOf(expected)) noreturn {
24 _ = found;
25 call("sentinel mismatch", null);
26}
27
28pub fn unwrapError(err: anyerror) noreturn {
29 _ = &err;
30 call("attempt to unwrap error", null);
31}
32
33pub fn outOfBounds(index: usize, len: usize) noreturn {
34 _ = index;
35 _ = len;
36 call("index out of bounds", null);
37}
38
39pub fn startGreaterThanEnd(start: usize, end: usize) noreturn {
40 _ = start;
41 _ = end;
42 call("start index is larger than end index", null);
43}
44
45pub fn inactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn {
46 _ = accessed;
47 call("access of inactive union field", null);
48}
49
50pub fn reachedUnreachable() noreturn {
51 call("reached unreachable code", null);
52}
53
54pub fn unwrapNull() noreturn {
55 call("attempt to use null value", null);
56}
57
58pub fn castToNull() noreturn {
59 call("cast causes pointer to be null", null);
60}
61
62pub fn incorrectAlignment() noreturn {
63 call("incorrect alignment", null);
64}
65
66pub fn invalidErrorCode() noreturn {
67 call("invalid error code", null);
68}
69
70pub fn castTruncatedData() noreturn {
71 call("integer cast truncated bits", null);
72}
73
74pub fn negativeToUnsigned() noreturn {
75 call("attempt to cast negative value to unsigned integer", null);
76}
77
78pub fn integerOverflow() noreturn {
79 call("integer overflow", null);
80}
81
82pub fn shlOverflow() noreturn {
83 call("left shift overflowed bits", null);
84}
85
86pub fn shrOverflow() noreturn {
87 call("right shift overflowed bits", null);
88}
89
90pub fn divideByZero() noreturn {
91 call("division by zero", null);
92}
93
94pub fn exactDivisionRemainder() noreturn {
95 call("exact division produced remainder", null);
96}
97
98pub fn integerPartOutOfBounds() noreturn {
99 call("integer part of floating point value out of bounds", null);
100}
101
102pub fn corruptSwitch() noreturn {
103 call("switch on corrupt value", null);
104}
105
106pub fn shiftRhsTooBig() noreturn {
107 call("shift amount is greater than the type size", null);
108}
109
110pub fn invalidEnumValue() noreturn {
111 call("invalid enum value", null);
112}
113
114pub fn forLenMismatch() noreturn {
115 call("for loop over objects with non-equal lengths", null);
116}
117
118pub fn memcpyLenMismatch() noreturn {
119 call("@memcpy arguments have non-equal lengths", null);
120}
121
122pub fn memcpyAlias() noreturn {
123 call("@memcpy arguments alias", null);
124}
125
126pub fn noreturnReturned() noreturn {
127 call("'noreturn' function returned", null);
128}
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+94-102
...@@ -2584,7 +2584,7 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg...@@ -2584,7 +2584,7 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg
2584 std.debug.print("compile error during Sema:\n", .{});2584 std.debug.print("compile error during Sema:\n", .{});
2585 var error_bundle = wip_errors.toOwnedBundle("") catch @panic("out of memory");2585 var error_bundle = wip_errors.toOwnedBundle("") catch @panic("out of memory");
2586 error_bundle.renderToStdErr(.{ .ttyconf = .no_color });2586 error_bundle.renderToStdErr(.{ .ttyconf = .no_color });
2587 crash_report.compilerPanic("unexpected compile error occurred", null, null);2587 crash_report.compilerPanic("unexpected compile error occurred", null);
2588 }2588 }
25892589
2590 if (block) |start_block| {2590 if (block) |start_block| {
...@@ -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,22 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -5936,7 +5937,22 @@ 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
5950 const opt_usize_ty = try pt.optionalType(.usize_type);
5951 const null_ret_addr = Air.internedToRef((try pt.intern(.{ .opt = .{
5952 .ty = opt_usize_ty.toIntern(),
5953 .val = .none,
5954 } })));
5955 try sema.callBuiltin(block, src, panic_fn, .auto, &.{ coerced_msg, null_ret_addr }, .@"@panic");
5940}5956}
59415957
5942fn zirTrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {5958fn zirTrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
...@@ -13787,9 +13803,8 @@ fn maybeErrorUnwrap(...@@ -13787,9 +13803,8 @@ fn maybeErrorUnwrap(
13787 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;13803 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
13788 const msg_inst = try sema.resolveInst(inst_data.operand);13804 const msg_inst = try sema.resolveInst(inst_data.operand);
1378913805
13790 const panic_fn = try getBuiltin(sema, operand_src, .@"Panic.call");13806 const panic_fn = try getBuiltin(sema, operand_src, .@"panic.call");
13791 const err_return_trace = try sema.getErrorReturnTrace(block);13807 const args: [2]Air.Inst.Ref = .{ msg_inst, .null_value };
13792 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");13808 try sema.callBuiltin(block, operand_src, Air.internedToRef(panic_fn), .auto, &args, .@"safety check");
13794 return true;13809 return true;
13795 },13810 },
...@@ -27083,15 +27098,16 @@ fn explainWhyTypeIsNotPacked(...@@ -27083,15 +27098,16 @@ fn explainWhyTypeIsNotPacked(
27083/// Backends depend on panic decls being available when lowering safety-checked27098/// Backends depend on panic decls being available when lowering safety-checked
27084/// instructions. This function ensures the panic function will be available to27099/// instructions. This function ensures the panic function will be available to
27085/// be called during that time.27100/// be called during that time.
27086fn preparePanicId(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.PanicId) !InternPool.Index {27101fn preparePanicId(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) !InternPool.Index {
27087 const zcu = sema.pt.zcu;27102 const zcu = sema.pt.zcu;
27088 try sema.ensureMemoizedStateResolved(src, .panic);27103 try sema.ensureMemoizedStateResolved(src, .panic);
27089 try zcu.ensureFuncBodyAnalysisQueued(zcu.builtin_decl_values.get(.@"Panic.call"));27104 const panic_func = zcu.builtin_decl_values.get(panic_id.toBuiltin());
27105 try zcu.ensureFuncBodyAnalysisQueued(panic_func);
27090 switch (sema.owner.unwrap()) {27106 switch (sema.owner.unwrap()) {
27091 .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},27107 .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},
27092 .func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(owner_func, true),27108 .func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(owner_func, true),
27093 }27109 }
27094 return zcu.builtin_decl_values.get(panic_id.toBuiltin());27110 return panic_func;
27095}27111}
2709627112
27097fn addSafetyCheck(27113fn addSafetyCheck(
...@@ -27099,7 +27115,7 @@ fn addSafetyCheck(...@@ -27099,7 +27115,7 @@ fn addSafetyCheck(
27099 parent_block: *Block,27115 parent_block: *Block,
27100 src: LazySrcLoc,27116 src: LazySrcLoc,
27101 ok: Air.Inst.Ref,27117 ok: Air.Inst.Ref,
27102 panic_id: Zcu.PanicId,27118 panic_id: Zcu.SimplePanicId,
27103) !void {27119) !void {
27104 const gpa = sema.gpa;27120 const gpa = sema.gpa;
27105 assert(!parent_block.isComptime());27121 assert(!parent_block.isComptime());
...@@ -27186,29 +27202,6 @@ fn addSafetyCheckExtra(...@@ -27186,29 +27202,6 @@ fn addSafetyCheckExtra(
27186 parent_block.instructions.appendAssumeCapacity(block_inst);27202 parent_block.instructions.appendAssumeCapacity(block_inst);
27187}27203}
2718827204
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(27205fn addSafetyCheckUnwrapError(
27213 sema: *Sema,27206 sema: *Sema,
27214 parent_block: *Block,27207 parent_block: *Block,
...@@ -27246,10 +27239,8 @@ fn safetyPanicUnwrapError(sema: *Sema, block: *Block, src: LazySrcLoc, err: Air....@@ -27246,10 +27239,8 @@ fn safetyPanicUnwrapError(sema: *Sema, block: *Block, src: LazySrcLoc, err: Air.
27246 if (!zcu.backendSupportsFeature(.panic_fn)) {27239 if (!zcu.backendSupportsFeature(.panic_fn)) {
27247 _ = try block.addNoOp(.trap);27240 _ = try block.addNoOp(.trap);
27248 } else {27241 } else {
27249 const panic_fn = try getBuiltin(sema, src, .@"Panic.unwrapError");27242 const panic_fn = try getBuiltin(sema, src, .@"panic.unwrapError");
27250 const err_return_trace = try sema.getErrorReturnTrace(block);27243 try sema.callBuiltin(block, src, Air.internedToRef(panic_fn), .auto, &.{err}, .@"safety check");
27251 const args: [2]Air.Inst.Ref = .{ err_return_trace, err };
27252 try sema.callBuiltin(block, src, Air.internedToRef(panic_fn), .auto, &args, .@"safety check");
27253 }27244 }
27254}27245}
2725527246
...@@ -27263,7 +27254,7 @@ fn addSafetyCheckIndexOob(...@@ -27263,7 +27254,7 @@ fn addSafetyCheckIndexOob(
27263) !void {27254) !void {
27264 assert(!parent_block.isComptime());27255 assert(!parent_block.isComptime());
27265 const ok = try parent_block.addBinOp(cmp_op, index, len);27256 const ok = try parent_block.addBinOp(cmp_op, index, len);
27266 return addSafetyCheckCall(sema, parent_block, src, ok, .@"Panic.outOfBounds", &.{ index, len });27257 return addSafetyCheckCall(sema, parent_block, src, ok, .@"panic.outOfBounds", &.{ index, len });
27267}27258}
2726827259
27269fn addSafetyCheckInactiveUnionField(27260fn addSafetyCheckInactiveUnionField(
...@@ -27275,7 +27266,7 @@ fn addSafetyCheckInactiveUnionField(...@@ -27275,7 +27266,7 @@ fn addSafetyCheckInactiveUnionField(
27275) !void {27266) !void {
27276 assert(!parent_block.isComptime());27267 assert(!parent_block.isComptime());
27277 const ok = try parent_block.addBinOp(.cmp_eq, active_tag, wanted_tag);27268 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 });27269 return addSafetyCheckCall(sema, parent_block, src, ok, .@"panic.inactiveUnionField", &.{ active_tag, wanted_tag });
27279}27270}
2728027271
27281fn addSafetyCheckSentinelMismatch(27272fn addSafetyCheckSentinelMismatch(
...@@ -27316,7 +27307,7 @@ fn addSafetyCheckSentinelMismatch(...@@ -27316,7 +27307,7 @@ fn addSafetyCheckSentinelMismatch(
27316 break :ok try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel);27307 break :ok try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel);
27317 };27308 };
2731827309
27319 return addSafetyCheckCall(sema, parent_block, src, ok, .@"Panic.sentinelMismatch", &.{27310 return addSafetyCheckCall(sema, parent_block, src, ok, .@"panic.sentinelMismatch", &.{
27320 expected_sentinel, actual_sentinel,27311 expected_sentinel, actual_sentinel,
27321 });27312 });
27322}27313}
...@@ -27358,9 +27349,13 @@ fn addSafetyCheckCall(...@@ -27358,9 +27349,13 @@ fn addSafetyCheckCall(
27358}27349}
2735927350
27360/// This does not set `sema.branch_hint`.27351/// This does not set `sema.branch_hint`.
27361fn safetyPanic(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.PanicId) CompileError!void {27352fn safetyPanic(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) CompileError!void {
27362 const msg_val = try sema.preparePanicId(src, panic_id);27353 if (!sema.pt.zcu.backendSupportsFeature(.panic_fn)) {
27363 try sema.panicWithMsg(block, src, Air.internedToRef(msg_val), .@"safety check");27354 _ = try block.addNoOp(.trap);
27355 } else {
27356 const panic_fn = try sema.preparePanicId(src, panic_id);
27357 try sema.callBuiltin(block, src, Air.internedToRef(panic_fn), .auto, &.{}, .@"safety check");
27358 }
27364}27359}
2736527360
27366fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void {27361fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
...@@ -32818,7 +32813,7 @@ fn analyzeSlice(...@@ -32818,7 +32813,7 @@ fn analyzeSlice(
32818 assert(!block.isComptime());32813 assert(!block.isComptime());
32819 try sema.requireRuntimeBlock(block, src, runtime_src.?);32814 try sema.requireRuntimeBlock(block, src, runtime_src.?);
32820 const ok = try block.addBinOp(.cmp_lte, start, end);32815 const ok = try block.addBinOp(.cmp_lte, start, end);
32821 try sema.addSafetyCheckCall(block, src, ok, .@"Panic.startGreaterThanEnd", &.{ start, end });32816 try sema.addSafetyCheckCall(block, src, ok, .@"panic.startGreaterThanEnd", &.{ start, end });
32822 }32817 }
32823 const new_len = if (by_length)32818 const new_len = if (by_length)
32824 try sema.coerce(block, Type.usize, uncasted_end_opt, end_src)32819 try sema.coerce(block, Type.usize, uncasted_end_opt, end_src)
...@@ -38525,14 +38520,9 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc,...@@ -38525,14 +38520,9 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc,
38525 break :val uncoerced_val;38520 break :val uncoerced_val;
38526 },38521 },
38527 .func => val: {38522 .func => val: {
38528 if (try sema.getExpectedBuiltinFnType(src, builtin_decl)) |func_ty| {38523 const func_ty = try sema.getExpectedBuiltinFnType(builtin_decl);
38529 const coerced = try sema.coerce(block, func_ty, Air.internedToRef(uncoerced_val.toIntern()), src);38524 const coerced = try sema.coerce(block, func_ty, Air.internedToRef(uncoerced_val.toIntern()), src);
38530 break :val .fromInterned(coerced.toInterned().?);38525 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 },38526 },
38537 .string => val: {38527 .string => val: {
38538 const coerced = try sema.coerce(block, .slice_const_u8, Air.internedToRef(uncoerced_val.toIntern()), src);38528 const coerced = try sema.coerce(block, .slice_const_u8, Air.internedToRef(uncoerced_val.toIntern()), src);
...@@ -38549,75 +38539,77 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc,...@@ -38549,75 +38539,77 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc,
38549 }38539 }
38550 }38540 }
3855138541
38552 if (stage == .panic) {
38553 // We use `getBuiltinType` because this is from an earlier stage.
38554 const stack_trace_ty = try sema.getBuiltinType(simple_src, .StackTrace);
38555 const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty);
38556 const opt_ptr_stack_trace_ty = try pt.optionalType(ptr_stack_trace_ty.toIntern());
38557 const null_stack_trace = try pt.intern(.{ .opt = .{
38558 .ty = opt_ptr_stack_trace_ty.toIntern(),
38559 .val = .none,
38560 } });
38561 if (null_stack_trace != zcu.null_stack_trace) {
38562 zcu.null_stack_trace = null_stack_trace;
38563 any_changed = true;
38564 }
38565 }
38566
38567 return any_changed;38542 return any_changed;
38568}38543}
3856938544
38570/// Given that `decl.kind() == .func`, get the type expected of the function if necessary.38545/// 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`. In38546fn getExpectedBuiltinFnType(sema: *Sema, 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;38547 const pt = sema.pt;
38577 return switch (decl) {38548 return switch (decl) {
38578 // `fn ([]const u8, ?*StackTrace, ?usize) noreturn`38549 // `noinline fn () void`
38579 .@"Panic.call" => try pt.funcType(.{38550 .returnError => try pt.funcType(.{
38551 .param_types = &.{},
38552 .return_type = .void_type,
38553 .is_noinline = true,
38554 }),
38555
38556 // `fn ([]const u8, ?usize) noreturn`
38557 .@"panic.call" => try pt.funcType(.{
38580 .param_types = &.{38558 .param_types = &.{
38581 .slice_const_u8_type,38559 .slice_const_u8_type,
38582 (try pt.optionalType(
38583 (try pt.singleMutPtrType(
38584 try sema.getBuiltinType(src, .StackTrace),
38585 )).toIntern(),
38586 )).toIntern(),
38587 (try pt.optionalType(.usize_type)).toIntern(),38560 (try pt.optionalType(.usize_type)).toIntern(),
38588 },38561 },
38589 .return_type = .noreturn_type,38562 .return_type = .noreturn_type,
38590 }),38563 }),
3859138564
38592 // `fn (?*StackTrace, anyerror) noreturn`38565 // `fn (anytype, anytype) noreturn`
38593 .@"Panic.unwrapError" => try pt.funcType(.{38566 .@"panic.sentinelMismatch",
38594 .param_types = &.{38567 .@"panic.inactiveUnionField",
38595 (try pt.optionalType(38568 => try pt.funcType(.{
38596 (try pt.singleMutPtrType(38569 .param_types = &.{ .generic_poison_type, .generic_poison_type },
38597 try sema.getBuiltinType(src, .StackTrace),38570 .return_type = .noreturn_type,
38598 )).toIntern(),38571 .is_generic = true,
38599 )).toIntern(),38572 }),
38600 .anyerror_type,38573
38601 },38574 // `fn (anyerror) noreturn`
38575 .@"panic.unwrapError" => try pt.funcType(.{
38576 .param_types = &.{.anyerror_type},
38602 .return_type = .noreturn_type,38577 .return_type = .noreturn_type,
38603 }),38578 }),
3860438579
38605 // `fn (usize, usize) noreturn`38580 // `fn (usize, usize) noreturn`
38606 .@"Panic.outOfBounds",38581 .@"panic.outOfBounds",
38607 .@"Panic.startGreaterThanEnd",38582 .@"panic.startGreaterThanEnd",
38608 => try pt.funcType(.{38583 => try pt.funcType(.{
38609 .param_types = &.{ .usize_type, .usize_type },38584 .param_types = &.{ .usize_type, .usize_type },
38610 .return_type = .noreturn_type,38585 .return_type = .noreturn_type,
38611 }),38586 }),
3861238587
38613 // Generic functions, so calls are necessarily validated by Sema38588 // `fn () noreturn`
38614 .@"Panic.sentinelMismatch",38589 .@"panic.reachedUnreachable",
38615 .@"Panic.inactiveUnionField",38590 .@"panic.unwrapNull",
38616 => null,38591 .@"panic.castToNull",
3861738592 .@"panic.incorrectAlignment",
38618 // Other functions called exclusively by Sema38593 .@"panic.invalidErrorCode",
38619 .returnError,38594 .@"panic.castTruncatedData",
38620 => null,38595 .@"panic.negativeToUnsigned",
38596 .@"panic.integerOverflow",
38597 .@"panic.shlOverflow",
38598 .@"panic.shrOverflow",
38599 .@"panic.divideByZero",
38600 .@"panic.exactDivisionRemainder",
38601 .@"panic.integerPartOutOfBounds",
38602 .@"panic.corruptSwitch",
38603 .@"panic.shiftRhsTooBig",
38604 .@"panic.invalidEnumValue",
38605 .@"panic.forLenMismatch",
38606 .@"panic.memcpyLenMismatch",
38607 .@"panic.memcpyAlias",
38608 .@"panic.noreturnReturned",
38609 => try pt.funcType(.{
38610 .param_types = &.{},
38611 .return_type = .noreturn_type,
38612 }),
3862138613
38622 else => unreachable,38614 else => unreachable,
38623 };38615 };
src/Zcu.zig+81-76
...@@ -219,8 +219,6 @@ free_type_references: std.ArrayListUnmanaged(u32) = .empty,...@@ -219,8 +219,6 @@ free_type_references: std.ArrayListUnmanaged(u32) = .empty,
219219
220/// Populated by analysis of `AnalUnit.wrap(.{ .memoized_state = s })`, where `s` depends on the element.220/// Populated by analysis of `AnalUnit.wrap(.{ .memoized_state = s })`, where `s` depends on the element.
221builtin_decl_values: BuiltinDecl.Memoized = .initFill(.none),221builtin_decl_values: BuiltinDecl.Memoized = .initFill(.none),
222/// Populated by analysis of `AnalUnit.wrap(.{ .memoized_state = .panic })`.
223null_stack_trace: InternPool.Index = .none,
224222
225generation: u32 = 0,223generation: u32 = 0,
226224
...@@ -269,34 +267,33 @@ pub const BuiltinDecl = enum {...@@ -269,34 +267,33 @@ pub const BuiltinDecl = enum {
269 @"Type.Opaque",267 @"Type.Opaque",
270 @"Type.Declaration",268 @"Type.Declaration",
271269
272 Panic,270 panic,
273 @"Panic.call",271 @"panic.call",
274 @"Panic.sentinelMismatch",272 @"panic.sentinelMismatch",
275 @"Panic.unwrapError",273 @"panic.unwrapError",
276 @"Panic.outOfBounds",274 @"panic.outOfBounds",
277 @"Panic.startGreaterThanEnd",275 @"panic.startGreaterThanEnd",
278 @"Panic.inactiveUnionField",276 @"panic.inactiveUnionField",
279 @"Panic.messages",277 @"panic.reachedUnreachable",
280 @"Panic.messages.reached_unreachable",278 @"panic.unwrapNull",
281 @"Panic.messages.unwrap_null",279 @"panic.castToNull",
282 @"Panic.messages.cast_to_null",280 @"panic.incorrectAlignment",
283 @"Panic.messages.incorrect_alignment",281 @"panic.invalidErrorCode",
284 @"Panic.messages.invalid_error_code",282 @"panic.castTruncatedData",
285 @"Panic.messages.cast_truncated_data",283 @"panic.negativeToUnsigned",
286 @"Panic.messages.negative_to_unsigned",284 @"panic.integerOverflow",
287 @"Panic.messages.integer_overflow",285 @"panic.shlOverflow",
288 @"Panic.messages.shl_overflow",286 @"panic.shrOverflow",
289 @"Panic.messages.shr_overflow",287 @"panic.divideByZero",
290 @"Panic.messages.divide_by_zero",288 @"panic.exactDivisionRemainder",
291 @"Panic.messages.exact_division_remainder",289 @"panic.integerPartOutOfBounds",
292 @"Panic.messages.integer_part_out_of_bounds",290 @"panic.corruptSwitch",
293 @"Panic.messages.corrupt_switch",291 @"panic.shiftRhsTooBig",
294 @"Panic.messages.shift_rhs_too_big",292 @"panic.invalidEnumValue",
295 @"Panic.messages.invalid_enum_value",293 @"panic.forLenMismatch",
296 @"Panic.messages.for_len_mismatch",294 @"panic.memcpyLenMismatch",
297 @"Panic.messages.memcpy_len_mismatch",295 @"panic.memcpyAlias",
298 @"Panic.messages.memcpy_alias",296 @"panic.noreturnReturned",
299 @"Panic.messages.noreturn_returned",
300297
301 VaList,298 VaList,
302299
...@@ -345,39 +342,35 @@ pub const BuiltinDecl = enum {...@@ -345,39 +342,35 @@ pub const BuiltinDecl = enum {
345 .@"Type.Declaration",342 .@"Type.Declaration",
346 => .type,343 => .type,
347344
348 .Panic => .type,345 .panic => .type,
349346
350 .@"Panic.call",347 .@"panic.call",
351 .@"Panic.sentinelMismatch",348 .@"panic.sentinelMismatch",
352 .@"Panic.unwrapError",349 .@"panic.unwrapError",
353 .@"Panic.outOfBounds",350 .@"panic.outOfBounds",
354 .@"Panic.startGreaterThanEnd",351 .@"panic.startGreaterThanEnd",
355 .@"Panic.inactiveUnionField",352 .@"panic.inactiveUnionField",
353 .@"panic.reachedUnreachable",
354 .@"panic.unwrapNull",
355 .@"panic.castToNull",
356 .@"panic.incorrectAlignment",
357 .@"panic.invalidErrorCode",
358 .@"panic.castTruncatedData",
359 .@"panic.negativeToUnsigned",
360 .@"panic.integerOverflow",
361 .@"panic.shlOverflow",
362 .@"panic.shrOverflow",
363 .@"panic.divideByZero",
364 .@"panic.exactDivisionRemainder",
365 .@"panic.integerPartOutOfBounds",
366 .@"panic.corruptSwitch",
367 .@"panic.shiftRhsTooBig",
368 .@"panic.invalidEnumValue",
369 .@"panic.forLenMismatch",
370 .@"panic.memcpyLenMismatch",
371 .@"panic.memcpyAlias",
372 .@"panic.noreturnReturned",
356 => .func,373 => .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 };374 };
382 }375 }
383376
...@@ -423,7 +416,7 @@ pub const BuiltinDecl = enum {...@@ -423,7 +416,7 @@ pub const BuiltinDecl = enum {
423 const Memoized = std.enums.EnumArray(BuiltinDecl, InternPool.Index);416 const Memoized = std.enums.EnumArray(BuiltinDecl, InternPool.Index);
424};417};
425418
426pub const PanicId = enum {419pub const SimplePanicId = enum {
427 reached_unreachable,420 reached_unreachable,
428 unwrap_null,421 unwrap_null,
429 cast_to_null,422 cast_to_null,
...@@ -445,19 +438,31 @@ pub const PanicId = enum {...@@ -445,19 +438,31 @@ pub const PanicId = enum {
445 memcpy_alias,438 memcpy_alias,
446 noreturn_returned,439 noreturn_returned,
447440
448 pub fn toBuiltin(id: PanicId) BuiltinDecl {441 pub fn toBuiltin(id: SimplePanicId) BuiltinDecl {
449 const first_msg: PanicId = @enumFromInt(0);442 return switch (id) {
450 const first_decl = @field(BuiltinDecl, "Panic.messages." ++ @tagName(first_msg));443 // zig fmt: off
451 comptime {444 .reached_unreachable => .@"panic.reachedUnreachable",
452 // Ensure that the messages are ordered the same in `BuiltinDecl` as they are here.445 .unwrap_null => .@"panic.unwrapNull",
453 for (@typeInfo(PanicId).@"enum".fields) |panic_field| {446 .cast_to_null => .@"panic.castToNull",
454 const expect_name = "Panic.messages." ++ panic_field.name;447 .incorrect_alignment => .@"panic.incorrectAlignment",
455 const expect_idx = @intFromEnum(first_decl) + panic_field.value;448 .invalid_error_code => .@"panic.invalidErrorCode",
456 const actual_idx = @intFromEnum(@field(BuiltinDecl, expect_name));449 .cast_truncated_data => .@"panic.castTruncatedData",
457 assert(expect_idx == actual_idx);450 .negative_to_unsigned => .@"panic.negativeToUnsigned",
458 }451 .integer_overflow => .@"panic.integerOverflow",
459 }452 .shl_overflow => .@"panic.shlOverflow",
460 return @enumFromInt(@intFromEnum(first_decl) + @intFromEnum(id));453 .shr_overflow => .@"panic.shrOverflow",
454 .divide_by_zero => .@"panic.divideByZero",
455 .exact_division_remainder => .@"panic.exactDivisionRemainder",
456 .integer_part_out_of_bounds => .@"panic.integerPartOutOfBounds",
457 .corrupt_switch => .@"panic.corruptSwitch",
458 .shift_rhs_too_big => .@"panic.shiftRhsTooBig",
459 .invalid_enum_value => .@"panic.invalidEnumValue",
460 .for_len_mismatch => .@"panic.forLenMismatch",
461 .memcpy_len_mismatch => .@"panic.memcpyLenMismatch",
462 .memcpy_alias => .@"panic.memcpyAlias",
463 .noreturn_returned => .@"panic.noreturnReturned",
464 // zig fmt: on
465 };
461 }466 }
462};467};
463468
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+7-13
...@@ -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 {
...@@ -164,12 +158,12 @@ fn writeFilePath(file: *Zcu.File, writer: anytype) !void {...@@ -164,12 +158,12 @@ fn writeFilePath(file: *Zcu.File, writer: anytype) !void {
164 try writer.writeAll(file.sub_file_path);158 try writer.writeAll(file.sub_file_path);
165}159}
166160
167pub fn compilerPanic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, maybe_ret_addr: ?usize) noreturn {161pub fn compilerPanic(msg: []const u8, maybe_ret_addr: ?usize) noreturn {
168 @branchHint(.cold);162 @branchHint(.cold);
169 PanicSwitch.preDispatch();163 PanicSwitch.preDispatch();
170 const ret_addr = maybe_ret_addr orelse @returnAddress();164 const ret_addr = maybe_ret_addr orelse @returnAddress();
171 const stack_ctx: StackContext = .{ .current = .{ .ret_addr = ret_addr } };165 const stack_ctx: StackContext = .{ .current = .{ .ret_addr = ret_addr } };
172 PanicSwitch.dispatch(error_return_trace, stack_ctx, msg);166 PanicSwitch.dispatch(@errorReturnTrace(), stack_ctx, msg);
173}167}
174168
175/// Attaches a global SIGSEGV handler169/// Attaches a global SIGSEGV handler
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 {
stage1/zig1.wasm
Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ
test/cases/compile_errors/bad_panic_call_signature.zig created+45
...@@ -0,0 +1,45 @@
1const simple_panic = std.debug.simple_panic;
2pub const panic = struct {
3 pub fn call(msg: []const u8, bad: usize) noreturn {
4 _ = msg;
5 _ = bad;
6 @trap();
7 }
8 pub const sentinelMismatch = simple_panic.sentinelMismatch;
9 pub const unwrapError = simple_panic.unwrapError;
10 pub const outOfBounds = simple_panic.outOfBounds;
11 pub const startGreaterThanEnd = simple_panic.startGreaterThanEnd;
12 pub const inactiveUnionField = simple_panic.inactiveUnionField;
13 pub const reachedUnreachable = simple_panic.reachedUnreachable;
14 pub const unwrapNull = simple_panic.unwrapNull;
15 pub const castToNull = simple_panic.castToNull;
16 pub const incorrectAlignment = simple_panic.incorrectAlignment;
17 pub const invalidErrorCode = simple_panic.invalidErrorCode;
18 pub const castTruncatedData = simple_panic.castTruncatedData;
19 pub const negativeToUnsigned = simple_panic.negativeToUnsigned;
20 pub const integerOverflow = simple_panic.integerOverflow;
21 pub const shlOverflow = simple_panic.shlOverflow;
22 pub const shrOverflow = simple_panic.shrOverflow;
23 pub const divideByZero = simple_panic.divideByZero;
24 pub const exactDivisionRemainder = simple_panic.exactDivisionRemainder;
25 pub const integerPartOutOfBounds = simple_panic.integerPartOutOfBounds;
26 pub const corruptSwitch = simple_panic.corruptSwitch;
27 pub const shiftRhsTooBig = simple_panic.shiftRhsTooBig;
28 pub const invalidEnumValue = simple_panic.invalidEnumValue;
29 pub const forLenMismatch = simple_panic.forLenMismatch;
30 pub const memcpyLenMismatch = simple_panic.memcpyLenMismatch;
31 pub const memcpyAlias = simple_panic.memcpyAlias;
32 pub const noreturnReturned = simple_panic.noreturnReturned;
33};
34
35export fn foo(a: u8) void {
36 @setRuntimeSafety(true);
37 _ = a + 1; // safety check to reference the panic handler
38}
39
40const std = @import("std");
41
42// error
43//
44// :3:9: error: expected type 'fn ([]const u8, ?usize) noreturn', found 'fn ([]const u8, usize) noreturn'
45// :3:9: note: parameter 1 'usize' cannot cast into '?usize'
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+6-30
...@@ -9,16 +9,8 @@ pub fn main() !u8 {...@@ -9,16 +9,8 @@ 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;13fn myPanic(msg: []const u8, _: ?usize) noreturn {
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 {
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);
24}16}
...@@ -33,16 +25,8 @@ pub fn main() !u8 {...@@ -33,16 +25,8 @@ 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;29fn myPanic(msg: []const u8, _: ?usize) noreturn {
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 {
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);
48}32}
...@@ -57,16 +41,8 @@ pub fn main() !u8 {...@@ -57,16 +41,8 @@ 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;45fn myPanicNew(msg: []const u8, _: ?usize) noreturn {
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 {
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);
72}48}
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, _: ?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, _: ?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, _: ?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"
test/src/Cases.zig-1
...@@ -358,7 +358,6 @@ pub fn addFromDir(ctx: *Cases, dir: std.fs.Dir, b: *std.Build) void {...@@ -358,7 +358,6 @@ pub fn addFromDir(ctx: *Cases, dir: std.fs.Dir, b: *std.Build) void {
358 var current_file: []const u8 = "none";358 var current_file: []const u8 = "none";
359 ctx.addFromDirInner(dir, &current_file, b) catch |err| {359 ctx.addFromDirInner(dir, &current_file, b) catch |err| {
360 std.debug.panicExtra(360 std.debug.panicExtra(
361 @errorReturnTrace(),
362 @returnAddress(),361 @returnAddress(),
363 "test harness failed to process file '{s}': {s}\n",362 "test harness failed to process file '{s}': {s}\n",
364 .{ current_file, @errorName(err) },363 .{ current_file, @errorName(err) },