| author | |
| committer | |
| log | 83991efe10d92c4b920d7b7fc75be98ed7854ad7 |
| tree | 7137ee5eb01517aede1c5503c29a2003fca71f80 |
| parent | b3d9b0e3f6bab5d662ec385cf754872f8a90607f |
| signature |
* `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 -> full20 files changed, 864 insertions(+), 482 deletions(-)
lib/std/Target.zig+1-1| ... | ... | @@ -370,7 +370,7 @@ pub const Os = struct { |
| 370 | 370 | range: std.SemanticVersion.Range, |
| 371 | 371 | glibc: std.SemanticVersion, |
| 372 | 372 | /// Android API level. |
| 373 | android: u32 = 14, // This default value is to be deleted after zig1.wasm is updated. | |
| 373 | android: u32, | |
| 374 | 374 | |
| 375 | 375 | pub inline fn includesVersion(range: LinuxVersionRange, ver: std.SemanticVersion) bool { |
| 376 | 376 | return range.range.includesVersion(ver); |
lib/std/builtin.zig+16-33| ... | ... | @@ -1110,45 +1110,28 @@ pub const TestFn = struct { |
| 1110 | 1110 | /// Deprecated, use the `Panic` namespace instead. |
| 1111 | 1111 | /// To be deleted after 0.14.0 is released. |
| 1112 | 1112 | pub 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. | |
| 1115 | pub const panic: PanicFn = Panic.call; | |
| 1116 | 1113 | |
| 1117 | 1114 | /// 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 the | |
| 1115 | /// panics. These can be overridden by making a public `panic` namespace in the | |
| 1119 | 1116 | /// root source file. |
| 1120 | pub const Panic: type = if (@hasDecl(root, "Panic")) | |
| 1121 | root.Panic | |
| 1122 | else if (@hasDecl(root, "panic")) // Deprecated, use `Panic` instead. | |
| 1123 | DeprecatedPanic | |
| 1124 | else if (builtin.zig_backend == .stage2_riscv64) | |
| 1125 | std.debug.SimplePanic // https://github.com/ziglang/zig/issues/21519 | |
| 1126 | else | |
| 1127 | std.debug.FormattedPanic; | |
| 1128 | ||
| 1129 | /// To be deleted after 0.14.0 is released. | |
| 1130 | const DeprecatedPanic = struct { | |
| 1131 | pub const call = root.panic; | |
| 1132 | pub const sentinelMismatch = std.debug.FormattedPanic.sentinelMismatch; | |
| 1133 | pub const unwrapError = std.debug.FormattedPanic.unwrapError; | |
| 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; | |
| 1117 | pub const panic: type = p: { | |
| 1118 | if (@hasDecl(root, "panic")) { | |
| 1119 | if (@TypeOf(root.panic) != type) { | |
| 1120 | break :p std.debug.FullPanic(root.panic); // Deprecated; make `panic` a namespace instead. | |
| 1121 | } | |
| 1122 | break :p root.panic; | |
| 1123 | } | |
| 1124 | if (@hasDecl(root, "Panic")) { | |
| 1125 | break :p root.Panic; // Deprecated; use `panic` instead. | |
| 1126 | } | |
| 1127 | if (builtin.zig_backend == .stage2_riscv64) { | |
| 1128 | break :p std.debug.simple_panic; | |
| 1129 | } | |
| 1130 | break :p std.debug.FullPanic(std.debug.defaultPanic); | |
| 1138 | 1131 | }; |
| 1139 | 1132 | |
| 1140 | 1133 | /// To be deleted after zig1.wasm is updated. |
| 1141 | pub const panicSentinelMismatch = Panic.sentinelMismatch; | |
| 1142 | /// To be deleted after zig1.wasm is updated. | |
| 1143 | pub const panicUnwrapError = Panic.unwrapError; | |
| 1144 | /// To be deleted after zig1.wasm is updated. | |
| 1145 | pub const panicOutOfBounds = Panic.outOfBounds; | |
| 1146 | /// To be deleted after zig1.wasm is updated. | |
| 1147 | pub const panicStartGreaterThanEnd = Panic.startGreaterThanEnd; | |
| 1148 | /// To be deleted after zig1.wasm is updated. | |
| 1149 | pub const panicInactiveUnionField = Panic.inactiveUnionField; | |
| 1150 | /// To be deleted after zig1.wasm is updated. | |
| 1151 | pub const panic_messages = Panic.messages; | |
| 1134 | pub const Panic = panic; | |
| 1152 | 1135 | |
| 1153 | 1136 | pub noinline fn returnError() void { |
| 1154 | 1137 | @branchHint(.unlikely); |
lib/std/debug.zig+119-4| ... | ... | @@ -21,9 +21,124 @@ pub const SelfInfo = @import("debug/SelfInfo.zig"); |
| 21 | 21 | pub const Info = @import("debug/Info.zig"); |
| 22 | 22 | pub const Coverage = @import("debug/Coverage.zig"); |
| 23 | 23 | |
| 24 | pub const FormattedPanic = @import("debug/FormattedPanic.zig"); | |
| 25 | pub const SimplePanic = @import("debug/SimplePanic.zig"); | |
| 26 | pub const NoPanic = @import("debug/NoPanic.zig"); | |
| 24 | pub const simple_panic = @import("debug/simple_panic.zig"); | |
| 25 | pub const no_panic = @import("debug/no_panic.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`. | |
| 30 | pub 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 | } | |
| 27 | 142 | |
| 28 | 143 | /// Unresolved source locations can be represented with a single `usize` that |
| 29 | 144 | /// corresponds to a virtual memory address of the program counter. Combined |
| ... | ... | @@ -441,7 +556,7 @@ pub fn panicExtra( |
| 441 | 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 | } |
| 446 | 561 | |
| 447 | 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 | ||
| 9 | const 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. | |
| 14 | pub const call: fn ([]const u8, ?*std.builtin.StackTrace, ?usize) noreturn = std.debug.defaultPanic; | |
| 15 | ||
| 16 | pub 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 | ||
| 23 | pub 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 | ||
| 28 | pub 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 | ||
| 33 | pub 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 | ||
| 38 | pub 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 | ||
| 45 | pub 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 | ||
| 6 | const std = @import("../std.zig"); | |
| 7 | ||
| 8 | pub fn call(_: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { | |
| 9 | @branchHint(.cold); | |
| 10 | @trap(); | |
| 11 | } | |
| 12 | ||
| 13 | pub fn sentinelMismatch(_: anytype, _: anytype) noreturn { | |
| 14 | @branchHint(.cold); | |
| 15 | @trap(); | |
| 16 | } | |
| 17 | ||
| 18 | pub fn unwrapError(_: ?*std.builtin.StackTrace, _: anyerror) noreturn { | |
| 19 | @branchHint(.cold); | |
| 20 | @trap(); | |
| 21 | } | |
| 22 | ||
| 23 | pub fn outOfBounds(_: usize, _: usize) noreturn { | |
| 24 | @branchHint(.cold); | |
| 25 | @trap(); | |
| 26 | } | |
| 27 | ||
| 28 | pub fn startGreaterThanEnd(_: usize, _: usize) noreturn { | |
| 29 | @branchHint(.cold); | |
| 30 | @trap(); | |
| 31 | } | |
| 32 | ||
| 33 | pub fn inactiveUnionField(_: anytype, _: anytype) noreturn { | |
| 34 | @branchHint(.cold); | |
| 35 | @trap(); | |
| 36 | } | |
| 37 | ||
| 38 | pub 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 | ||
| 9 | const 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. | |
| 14 | pub 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 | ||
| 24 | pub fn sentinelMismatch(expected: anytype, found: @TypeOf(expected)) noreturn { | |
| 25 | _ = found; | |
| 26 | call("sentinel mismatch", null, null); | |
| 27 | } | |
| 28 | ||
| 29 | pub fn unwrapError(ert: ?*std.builtin.StackTrace, err: anyerror) noreturn { | |
| 30 | _ = ert; | |
| 31 | _ = &err; | |
| 32 | call("attempt to unwrap error", null, null); | |
| 33 | } | |
| 34 | ||
| 35 | pub fn outOfBounds(index: usize, len: usize) noreturn { | |
| 36 | _ = index; | |
| 37 | _ = len; | |
| 38 | call("index out of bounds", null, null); | |
| 39 | } | |
| 40 | ||
| 41 | pub fn startGreaterThanEnd(start: usize, end: usize) noreturn { | |
| 42 | _ = start; | |
| 43 | _ = end; | |
| 44 | call("start index is larger than end index", null, null); | |
| 45 | } | |
| 46 | ||
| 47 | pub fn inactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn { | |
| 48 | _ = accessed; | |
| 49 | call("access of inactive union field", null, null); | |
| 50 | } | |
| 51 | ||
| 52 | pub 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 | ||
| 6 | const std = @import("../std.zig"); | |
| 7 | ||
| 8 | pub fn call(_: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { | |
| 9 | @branchHint(.cold); | |
| 10 | @trap(); | |
| 11 | } | |
| 12 | ||
| 13 | pub fn sentinelMismatch(_: anytype, _: anytype) noreturn { | |
| 14 | @branchHint(.cold); | |
| 15 | @trap(); | |
| 16 | } | |
| 17 | ||
| 18 | pub fn unwrapError(_: ?*std.builtin.StackTrace, _: anyerror) noreturn { | |
| 19 | @branchHint(.cold); | |
| 20 | @trap(); | |
| 21 | } | |
| 22 | ||
| 23 | pub fn outOfBounds(_: usize, _: usize) noreturn { | |
| 24 | @branchHint(.cold); | |
| 25 | @trap(); | |
| 26 | } | |
| 27 | ||
| 28 | pub fn startGreaterThanEnd(_: usize, _: usize) noreturn { | |
| 29 | @branchHint(.cold); | |
| 30 | @trap(); | |
| 31 | } | |
| 32 | ||
| 33 | pub fn inactiveUnionField(_: anytype, _: anytype) noreturn { | |
| 34 | @branchHint(.cold); | |
| 35 | @trap(); | |
| 36 | } | |
| 37 | ||
| 38 | pub fn reachedUnreachable() noreturn { | |
| 39 | @branchHint(.cold); | |
| 40 | @trap(); | |
| 41 | } | |
| 42 | ||
| 43 | pub fn unwrapNull() noreturn { | |
| 44 | @branchHint(.cold); | |
| 45 | @trap(); | |
| 46 | } | |
| 47 | ||
| 48 | pub fn castToNull() noreturn { | |
| 49 | @branchHint(.cold); | |
| 50 | @trap(); | |
| 51 | } | |
| 52 | ||
| 53 | pub fn incorrectAlignment() noreturn { | |
| 54 | @branchHint(.cold); | |
| 55 | @trap(); | |
| 56 | } | |
| 57 | ||
| 58 | pub fn invalidErrorCode() noreturn { | |
| 59 | @branchHint(.cold); | |
| 60 | @trap(); | |
| 61 | } | |
| 62 | ||
| 63 | pub fn castTruncatedData() noreturn { | |
| 64 | @branchHint(.cold); | |
| 65 | @trap(); | |
| 66 | } | |
| 67 | ||
| 68 | pub fn negativeToUnsigned() noreturn { | |
| 69 | @branchHint(.cold); | |
| 70 | @trap(); | |
| 71 | } | |
| 72 | ||
| 73 | pub fn integerOverflow() noreturn { | |
| 74 | @branchHint(.cold); | |
| 75 | @trap(); | |
| 76 | } | |
| 77 | ||
| 78 | pub fn shlOverflow() noreturn { | |
| 79 | @branchHint(.cold); | |
| 80 | @trap(); | |
| 81 | } | |
| 82 | ||
| 83 | pub fn shrOverflow() noreturn { | |
| 84 | @branchHint(.cold); | |
| 85 | @trap(); | |
| 86 | } | |
| 87 | ||
| 88 | pub fn divideByZero() noreturn { | |
| 89 | @branchHint(.cold); | |
| 90 | @trap(); | |
| 91 | } | |
| 92 | ||
| 93 | pub fn exactDivisionRemainder() noreturn { | |
| 94 | @branchHint(.cold); | |
| 95 | @trap(); | |
| 96 | } | |
| 97 | ||
| 98 | pub fn integerPartOutOfBounds() noreturn { | |
| 99 | @branchHint(.cold); | |
| 100 | @trap(); | |
| 101 | } | |
| 102 | ||
| 103 | pub fn corruptSwitch() noreturn { | |
| 104 | @branchHint(.cold); | |
| 105 | @trap(); | |
| 106 | } | |
| 107 | ||
| 108 | pub fn shiftRhsTooBig() noreturn { | |
| 109 | @branchHint(.cold); | |
| 110 | @trap(); | |
| 111 | } | |
| 112 | ||
| 113 | pub fn invalidEnumValue() noreturn { | |
| 114 | @branchHint(.cold); | |
| 115 | @trap(); | |
| 116 | } | |
| 117 | ||
| 118 | pub fn forLenMismatch() noreturn { | |
| 119 | @branchHint(.cold); | |
| 120 | @trap(); | |
| 121 | } | |
| 122 | ||
| 123 | pub fn memcpyLenMismatch() noreturn { | |
| 124 | @branchHint(.cold); | |
| 125 | @trap(); | |
| 126 | } | |
| 127 | ||
| 128 | pub fn memcpyAlias() noreturn { | |
| 129 | @branchHint(.cold); | |
| 130 | @trap(); | |
| 131 | } | |
| 132 | ||
| 133 | pub fn noreturnReturned() noreturn { | |
| 134 | @branchHint(.cold); | |
| 135 | @trap(); | |
| 136 | } | |
| 137 | ||
| 138 | /// To be deleted after zig1.wasm update. | |
| 139 | pub 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 | ||
| 9 | const 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. | |
| 14 | pub 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 | ||
| 24 | pub fn sentinelMismatch(expected: anytype, found: @TypeOf(expected)) noreturn { | |
| 25 | _ = found; | |
| 26 | call("sentinel mismatch", null, null); | |
| 27 | } | |
| 28 | ||
| 29 | pub fn unwrapError(ert: ?*std.builtin.StackTrace, err: anyerror) noreturn { | |
| 30 | _ = ert; | |
| 31 | _ = &err; | |
| 32 | call("attempt to unwrap error", null, null); | |
| 33 | } | |
| 34 | ||
| 35 | pub fn outOfBounds(index: usize, len: usize) noreturn { | |
| 36 | _ = index; | |
| 37 | _ = len; | |
| 38 | call("index out of bounds", null, null); | |
| 39 | } | |
| 40 | ||
| 41 | pub fn startGreaterThanEnd(start: usize, end: usize) noreturn { | |
| 42 | _ = start; | |
| 43 | _ = end; | |
| 44 | call("start index is larger than end index", null, null); | |
| 45 | } | |
| 46 | ||
| 47 | pub fn inactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn { | |
| 48 | _ = accessed; | |
| 49 | call("access of inactive union field", null, null); | |
| 50 | } | |
| 51 | ||
| 52 | pub fn reachedUnreachable() noreturn { | |
| 53 | call("reached unreachable code", null, null); | |
| 54 | } | |
| 55 | ||
| 56 | pub fn unwrapNull() noreturn { | |
| 57 | call("attempt to use null value", null, null); | |
| 58 | } | |
| 59 | ||
| 60 | pub fn castToNull() noreturn { | |
| 61 | call("cast causes pointer to be null", null, null); | |
| 62 | } | |
| 63 | ||
| 64 | pub fn incorrectAlignment() noreturn { | |
| 65 | call("incorrect alignment", null, null); | |
| 66 | } | |
| 67 | ||
| 68 | pub fn invalidErrorCode() noreturn { | |
| 69 | call("invalid error code", null, null); | |
| 70 | } | |
| 71 | ||
| 72 | pub fn castTruncatedData() noreturn { | |
| 73 | call("integer cast truncated bits", null, null); | |
| 74 | } | |
| 75 | ||
| 76 | pub fn negativeToUnsigned() noreturn { | |
| 77 | call("attempt to cast negative value to unsigned integer", null, null); | |
| 78 | } | |
| 79 | ||
| 80 | pub fn integerOverflow() noreturn { | |
| 81 | call("integer overflow", null, null); | |
| 82 | } | |
| 83 | ||
| 84 | pub fn shlOverflow() noreturn { | |
| 85 | call("left shift overflowed bits", null, null); | |
| 86 | } | |
| 87 | ||
| 88 | pub fn shrOverflow() noreturn { | |
| 89 | call("right shift overflowed bits", null, null); | |
| 90 | } | |
| 91 | ||
| 92 | pub fn divideByZero() noreturn { | |
| 93 | call("division by zero", null, null); | |
| 94 | } | |
| 95 | ||
| 96 | pub fn exactDivisionRemainder() noreturn { | |
| 97 | call("exact division produced remainder", null, null); | |
| 98 | } | |
| 99 | ||
| 100 | pub fn integerPartOutOfBounds() noreturn { | |
| 101 | call("integer part of floating point value out of bounds", null, null); | |
| 102 | } | |
| 103 | ||
| 104 | pub fn corruptSwitch() noreturn { | |
| 105 | call("switch on corrupt value", null, null); | |
| 106 | } | |
| 107 | ||
| 108 | pub fn shiftRhsTooBig() noreturn { | |
| 109 | call("shift amount is greater than the type size", null, null); | |
| 110 | } | |
| 111 | ||
| 112 | pub fn invalidEnumValue() noreturn { | |
| 113 | call("invalid enum value", null, null); | |
| 114 | } | |
| 115 | ||
| 116 | pub fn forLenMismatch() noreturn { | |
| 117 | call("for loop over objects with non-equal lengths", null, null); | |
| 118 | } | |
| 119 | ||
| 120 | pub fn memcpyLenMismatch() noreturn { | |
| 121 | call("@memcpy arguments have non-equal lengths", null, null); | |
| 122 | } | |
| 123 | ||
| 124 | pub fn memcpyAlias() noreturn { | |
| 125 | call("@memcpy arguments alias", null, null); | |
| 126 | } | |
| 127 | ||
| 128 | pub fn noreturnReturned() noreturn { | |
| 129 | call("'noreturn' function returned", null, null); | |
| 130 | } | |
| 131 | ||
| 132 | /// To be deleted after zig1.wasm update. | |
| 133 | pub 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 | 448 | return comptime blk: { |
| 449 | 449 | const fieldInfos = fields(T); |
| 450 | 450 | var names: [fieldInfos.len][:0]const u8 = undefined; |
| 451 | // This concat can be removed with the next zig1 update. | |
| 452 | for (&names, fieldInfos) |*name, field| name.* = field.name ++ ""; | |
| 451 | for (&names, fieldInfos) |*name, field| name.* = field.name; | |
| 453 | 452 | const final = names; |
| 454 | 453 | break :blk &final; |
| 455 | 454 | }; |
src/Sema.zig+89-66| ... | ... | @@ -5918,13 +5918,14 @@ fn zirCompileLog( |
| 5918 | 5918 | } |
| 5919 | 5919 | |
| 5920 | 5920 | fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |
| 5921 | const pt = sema.pt; | |
| 5922 | const zcu = pt.zcu; | |
| 5923 | ||
| 5921 | 5924 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 5922 | 5925 | const src = block.nodeOffset(inst_data.src_node); |
| 5923 | 5926 | const msg_inst = try sema.resolveInst(inst_data.operand); |
| 5924 | 5927 | |
| 5925 | // `panicWithMsg` would perform this coercion for us, but we can get a better | |
| 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)); | |
| 5928 | const coerced_msg = try sema.coerce(block, .slice_const_u8, msg_inst, block.builtinCallArgSrc(inst_data.src_node, 0)); | |
| 5928 | 5929 | |
| 5929 | 5930 | if (block.isComptime()) { |
| 5930 | 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 | 5937 | sema.branch_hint = .cold; |
| 5937 | 5938 | } |
| 5938 | 5939 | |
| 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 | } |
| 5941 | 5958 | |
| 5942 | 5959 | fn zirTrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |
| ... | ... | @@ -13787,7 +13804,7 @@ fn maybeErrorUnwrap( |
| 13787 | 13804 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 13788 | 13805 | const msg_inst = try sema.resolveInst(inst_data.operand); |
| 13789 | 13806 | |
| 13790 | const panic_fn = try getBuiltin(sema, operand_src, .@"Panic.call"); | |
| 13807 | const panic_fn = try getBuiltin(sema, operand_src, .@"panic.call"); | |
| 13791 | 13808 | const err_return_trace = try sema.getErrorReturnTrace(block); |
| 13792 | 13809 | const args: [3]Air.Inst.Ref = .{ msg_inst, err_return_trace, .null_value }; |
| 13793 | 13810 | try sema.callBuiltin(block, operand_src, Air.internedToRef(panic_fn), .auto, &args, .@"safety check"); |
| ... | ... | @@ -27083,15 +27100,16 @@ fn explainWhyTypeIsNotPacked( |
| 27083 | 27100 | /// Backends depend on panic decls being available when lowering safety-checked |
| 27084 | 27101 | /// instructions. This function ensures the panic function will be available to |
| 27085 | 27102 | /// be called during that time. |
| 27086 | fn preparePanicId(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.PanicId) !InternPool.Index { | |
| 27103 | fn preparePanicId(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) !InternPool.Index { | |
| 27087 | 27104 | const zcu = sema.pt.zcu; |
| 27088 | 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 | 27108 | switch (sema.owner.unwrap()) { |
| 27091 | 27109 | .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {}, |
| 27092 | 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 | } |
| 27096 | 27114 | |
| 27097 | 27115 | fn addSafetyCheck( |
| ... | ... | @@ -27099,7 +27117,7 @@ fn addSafetyCheck( |
| 27099 | 27117 | parent_block: *Block, |
| 27100 | 27118 | src: LazySrcLoc, |
| 27101 | 27119 | ok: Air.Inst.Ref, |
| 27102 | panic_id: Zcu.PanicId, | |
| 27120 | panic_id: Zcu.SimplePanicId, | |
| 27103 | 27121 | ) !void { |
| 27104 | 27122 | const gpa = sema.gpa; |
| 27105 | 27123 | assert(!parent_block.isComptime()); |
| ... | ... | @@ -27186,29 +27204,6 @@ fn addSafetyCheckExtra( |
| 27186 | 27204 | parent_block.instructions.appendAssumeCapacity(block_inst); |
| 27187 | 27205 | } |
| 27188 | 27206 | |
| 27189 | fn 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 | ||
| 27212 | 27207 | fn addSafetyCheckUnwrapError( |
| 27213 | 27208 | sema: *Sema, |
| 27214 | 27209 | parent_block: *Block, |
| ... | ... | @@ -27246,7 +27241,7 @@ fn safetyPanicUnwrapError(sema: *Sema, block: *Block, src: LazySrcLoc, err: Air. |
| 27246 | 27241 | if (!zcu.backendSupportsFeature(.panic_fn)) { |
| 27247 | 27242 | _ = try block.addNoOp(.trap); |
| 27248 | 27243 | } else { |
| 27249 | const panic_fn = try getBuiltin(sema, src, .@"Panic.unwrapError"); | |
| 27244 | const panic_fn = try getBuiltin(sema, src, .@"panic.unwrapError"); | |
| 27250 | 27245 | const err_return_trace = try sema.getErrorReturnTrace(block); |
| 27251 | 27246 | const args: [2]Air.Inst.Ref = .{ err_return_trace, err }; |
| 27252 | 27247 | try sema.callBuiltin(block, src, Air.internedToRef(panic_fn), .auto, &args, .@"safety check"); |
| ... | ... | @@ -27263,7 +27258,7 @@ fn addSafetyCheckIndexOob( |
| 27263 | 27258 | ) !void { |
| 27264 | 27259 | assert(!parent_block.isComptime()); |
| 27265 | 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 | } |
| 27268 | 27263 | |
| 27269 | 27264 | fn addSafetyCheckInactiveUnionField( |
| ... | ... | @@ -27275,7 +27270,7 @@ fn addSafetyCheckInactiveUnionField( |
| 27275 | 27270 | ) !void { |
| 27276 | 27271 | assert(!parent_block.isComptime()); |
| 27277 | 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 | } |
| 27280 | 27275 | |
| 27281 | 27276 | fn addSafetyCheckSentinelMismatch( |
| ... | ... | @@ -27316,7 +27311,7 @@ fn addSafetyCheckSentinelMismatch( |
| 27316 | 27311 | break :ok try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel); |
| 27317 | 27312 | }; |
| 27318 | 27313 | |
| 27319 | return addSafetyCheckCall(sema, parent_block, src, ok, .@"Panic.sentinelMismatch", &.{ | |
| 27314 | return addSafetyCheckCall(sema, parent_block, src, ok, .@"panic.sentinelMismatch", &.{ | |
| 27320 | 27315 | expected_sentinel, actual_sentinel, |
| 27321 | 27316 | }); |
| 27322 | 27317 | } |
| ... | ... | @@ -27358,9 +27353,13 @@ fn addSafetyCheckCall( |
| 27358 | 27353 | } |
| 27359 | 27354 | |
| 27360 | 27355 | /// This does not set `sema.branch_hint`. |
| 27361 | fn safetyPanic(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.PanicId) CompileError!void { | |
| 27362 | const msg_val = try sema.preparePanicId(src, panic_id); | |
| 27363 | try sema.panicWithMsg(block, src, Air.internedToRef(msg_val), .@"safety check"); | |
| 27356 | fn safetyPanic(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) CompileError!void { | |
| 27357 | if (!sema.pt.zcu.backendSupportsFeature(.panic_fn)) { | |
| 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 | } |
| 27365 | 27364 | |
| 27366 | 27365 | fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void { |
| ... | ... | @@ -32818,7 +32817,7 @@ fn analyzeSlice( |
| 32818 | 32817 | assert(!block.isComptime()); |
| 32819 | 32818 | try sema.requireRuntimeBlock(block, src, runtime_src.?); |
| 32820 | 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 | 32822 | const new_len = if (by_length) |
| 32824 | 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 | 38524 | break :val uncoerced_val; |
| 38526 | 38525 | }, |
| 38527 | 38526 | .func => val: { |
| 38528 | if (try sema.getExpectedBuiltinFnType(src, builtin_decl)) |func_ty| { | |
| 38529 | const coerced = try sema.coerce(block, func_ty, Air.internedToRef(uncoerced_val.toIntern()), src); | |
| 38530 | 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; | |
| 38527 | const func_ty = try sema.getExpectedBuiltinFnType(src, builtin_decl); | |
| 38528 | const coerced = try sema.coerce(block, func_ty, Air.internedToRef(uncoerced_val.toIntern()), src); | |
| 38529 | break :val .fromInterned(coerced.toInterned().?); | |
| 38536 | 38530 | }, |
| 38537 | 38531 | .string => val: { |
| 38538 | 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 | 38561 | return any_changed; |
| 38568 | 38562 | } |
| 38569 | 38563 | |
| 38570 | /// Given that `decl.kind() == .func`, get the type expected of the function if necessary. | |
| 38571 | /// If this will be type checked by `Sema` anyway, this function may return `null`. In | |
| 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. | |
| 38575 | fn getExpectedBuiltinFnType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) CompileError!?Type { | |
| 38564 | /// Given that `decl.kind() == .func`, get the type expected of the function. | |
| 38565 | fn getExpectedBuiltinFnType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) CompileError!Type { | |
| 38576 | 38566 | const pt = sema.pt; |
| 38577 | 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 | 38575 | // `fn ([]const u8, ?*StackTrace, ?usize) noreturn` |
| 38579 | .@"Panic.call" => try pt.funcType(.{ | |
| 38576 | .@"panic.call" => try pt.funcType(.{ | |
| 38580 | 38577 | .param_types = &.{ |
| 38581 | 38578 | .slice_const_u8_type, |
| 38582 | 38579 | (try pt.optionalType( |
| ... | ... | @@ -38589,8 +38586,17 @@ fn getExpectedBuiltinFnType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) |
| 38589 | 38586 | .return_type = .noreturn_type, |
| 38590 | 38587 | }), |
| 38591 | 38588 | |
| 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 | 38598 | // `fn (?*StackTrace, anyerror) noreturn` |
| 38593 | .@"Panic.unwrapError" => try pt.funcType(.{ | |
| 38599 | .@"panic.unwrapError" => try pt.funcType(.{ | |
| 38594 | 38600 | .param_types = &.{ |
| 38595 | 38601 | (try pt.optionalType( |
| 38596 | 38602 | (try pt.singleMutPtrType( |
| ... | ... | @@ -38603,21 +38609,38 @@ fn getExpectedBuiltinFnType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) |
| 38603 | 38609 | }), |
| 38604 | 38610 | |
| 38605 | 38611 | // `fn (usize, usize) noreturn` |
| 38606 | .@"Panic.outOfBounds", | |
| 38607 | .@"Panic.startGreaterThanEnd", | |
| 38612 | .@"panic.outOfBounds", | |
| 38613 | .@"panic.startGreaterThanEnd", | |
| 38608 | 38614 | => try pt.funcType(.{ |
| 38609 | 38615 | .param_types = &.{ .usize_type, .usize_type }, |
| 38610 | 38616 | .return_type = .noreturn_type, |
| 38611 | 38617 | }), |
| 38612 | 38618 | |
| 38613 | // Generic functions, so calls are necessarily validated by Sema | |
| 38614 | .@"Panic.sentinelMismatch", | |
| 38615 | .@"Panic.inactiveUnionField", | |
| 38616 | => null, | |
| 38617 | ||
| 38618 | // Other functions called exclusively by Sema | |
| 38619 | .returnError, | |
| 38620 | => null, | |
| 38619 | // `fn () noreturn` | |
| 38620 | .@"panic.reachedUnreachable", | |
| 38621 | .@"panic.unwrapNull", | |
| 38622 | .@"panic.castToNull", | |
| 38623 | .@"panic.incorrectAlignment", | |
| 38624 | .@"panic.invalidErrorCode", | |
| 38625 | .@"panic.castTruncatedData", | |
| 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 | }), | |
| 38621 | 38644 | |
| 38622 | 38645 | else => unreachable, |
| 38623 | 38646 | }; |
src/Zcu.zig+81-74| ... | ... | @@ -269,34 +269,33 @@ pub const BuiltinDecl = enum { |
| 269 | 269 | @"Type.Opaque", |
| 270 | 270 | @"Type.Declaration", |
| 271 | 271 | |
| 272 | Panic, | |
| 273 | @"Panic.call", | |
| 274 | @"Panic.sentinelMismatch", | |
| 275 | @"Panic.unwrapError", | |
| 276 | @"Panic.outOfBounds", | |
| 277 | @"Panic.startGreaterThanEnd", | |
| 278 | @"Panic.inactiveUnionField", | |
| 279 | @"Panic.messages", | |
| 280 | @"Panic.messages.reached_unreachable", | |
| 281 | @"Panic.messages.unwrap_null", | |
| 282 | @"Panic.messages.cast_to_null", | |
| 283 | @"Panic.messages.incorrect_alignment", | |
| 284 | @"Panic.messages.invalid_error_code", | |
| 285 | @"Panic.messages.cast_truncated_data", | |
| 286 | @"Panic.messages.negative_to_unsigned", | |
| 287 | @"Panic.messages.integer_overflow", | |
| 288 | @"Panic.messages.shl_overflow", | |
| 289 | @"Panic.messages.shr_overflow", | |
| 290 | @"Panic.messages.divide_by_zero", | |
| 291 | @"Panic.messages.exact_division_remainder", | |
| 292 | @"Panic.messages.integer_part_out_of_bounds", | |
| 293 | @"Panic.messages.corrupt_switch", | |
| 294 | @"Panic.messages.shift_rhs_too_big", | |
| 295 | @"Panic.messages.invalid_enum_value", | |
| 296 | @"Panic.messages.for_len_mismatch", | |
| 297 | @"Panic.messages.memcpy_len_mismatch", | |
| 298 | @"Panic.messages.memcpy_alias", | |
| 299 | @"Panic.messages.noreturn_returned", | |
| 272 | panic, | |
| 273 | @"panic.call", | |
| 274 | @"panic.sentinelMismatch", | |
| 275 | @"panic.unwrapError", | |
| 276 | @"panic.outOfBounds", | |
| 277 | @"panic.startGreaterThanEnd", | |
| 278 | @"panic.inactiveUnionField", | |
| 279 | @"panic.reachedUnreachable", | |
| 280 | @"panic.unwrapNull", | |
| 281 | @"panic.castToNull", | |
| 282 | @"panic.incorrectAlignment", | |
| 283 | @"panic.invalidErrorCode", | |
| 284 | @"panic.castTruncatedData", | |
| 285 | @"panic.negativeToUnsigned", | |
| 286 | @"panic.integerOverflow", | |
| 287 | @"panic.shlOverflow", | |
| 288 | @"panic.shrOverflow", | |
| 289 | @"panic.divideByZero", | |
| 290 | @"panic.exactDivisionRemainder", | |
| 291 | @"panic.integerPartOutOfBounds", | |
| 292 | @"panic.corruptSwitch", | |
| 293 | @"panic.shiftRhsTooBig", | |
| 294 | @"panic.invalidEnumValue", | |
| 295 | @"panic.forLenMismatch", | |
| 296 | @"panic.memcpyLenMismatch", | |
| 297 | @"panic.memcpyAlias", | |
| 298 | @"panic.noreturnReturned", | |
| 300 | 299 | |
| 301 | 300 | VaList, |
| 302 | 301 | |
| ... | ... | @@ -345,39 +344,35 @@ pub const BuiltinDecl = enum { |
| 345 | 344 | .@"Type.Declaration", |
| 346 | 345 | => .type, |
| 347 | 346 | |
| 348 | .Panic => .type, | |
| 349 | ||
| 350 | .@"Panic.call", | |
| 351 | .@"Panic.sentinelMismatch", | |
| 352 | .@"Panic.unwrapError", | |
| 353 | .@"Panic.outOfBounds", | |
| 354 | .@"Panic.startGreaterThanEnd", | |
| 355 | .@"Panic.inactiveUnionField", | |
| 347 | .panic => .type, | |
| 348 | ||
| 349 | .@"panic.call", | |
| 350 | .@"panic.sentinelMismatch", | |
| 351 | .@"panic.unwrapError", | |
| 352 | .@"panic.outOfBounds", | |
| 353 | .@"panic.startGreaterThanEnd", | |
| 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 | 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 | } |
| 383 | 378 | |
| ... | ... | @@ -423,7 +418,7 @@ pub const BuiltinDecl = enum { |
| 423 | 418 | const Memoized = std.enums.EnumArray(BuiltinDecl, InternPool.Index); |
| 424 | 419 | }; |
| 425 | 420 | |
| 426 | pub const PanicId = enum { | |
| 421 | pub const SimplePanicId = enum { | |
| 427 | 422 | reached_unreachable, |
| 428 | 423 | unwrap_null, |
| 429 | 424 | cast_to_null, |
| ... | ... | @@ -445,19 +440,31 @@ pub const PanicId = enum { |
| 445 | 440 | memcpy_alias, |
| 446 | 441 | noreturn_returned, |
| 447 | 442 | |
| 448 | pub fn toBuiltin(id: PanicId) BuiltinDecl { | |
| 449 | const first_msg: PanicId = @enumFromInt(0); | |
| 450 | const first_decl = @field(BuiltinDecl, "Panic.messages." ++ @tagName(first_msg)); | |
| 451 | comptime { | |
| 452 | // Ensure that the messages are ordered the same in `BuiltinDecl` as they are here. | |
| 453 | for (@typeInfo(PanicId).@"enum".fields) |panic_field| { | |
| 454 | const expect_name = "Panic.messages." ++ panic_field.name; | |
| 455 | const expect_idx = @intFromEnum(first_decl) + panic_field.value; | |
| 456 | const actual_idx = @intFromEnum(@field(BuiltinDecl, expect_name)); | |
| 457 | assert(expect_idx == actual_idx); | |
| 458 | } | |
| 459 | } | |
| 460 | return @enumFromInt(@intFromEnum(first_decl) + @intFromEnum(id)); | |
| 443 | pub fn toBuiltin(id: SimplePanicId) BuiltinDecl { | |
| 444 | return switch (id) { | |
| 445 | // zig fmt: off | |
| 446 | .reached_unreachable => .@"panic.reachedUnreachable", | |
| 447 | .unwrap_null => .@"panic.unwrapNull", | |
| 448 | .cast_to_null => .@"panic.castToNull", | |
| 449 | .incorrect_alignment => .@"panic.incorrectAlignment", | |
| 450 | .invalid_error_code => .@"panic.invalidErrorCode", | |
| 451 | .cast_truncated_data => .@"panic.castTruncatedData", | |
| 452 | .negative_to_unsigned => .@"panic.negativeToUnsigned", | |
| 453 | .integer_overflow => .@"panic.integerOverflow", | |
| 454 | .shl_overflow => .@"panic.shlOverflow", | |
| 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 | }; |
| 463 | 470 |
src/Zcu/PerThread.zig+1-1| ... | ... | @@ -605,7 +605,7 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized |
| 605 | 605 | // We use an arbitrary element to check if the state has been resolved yet. |
| 606 | 606 | const to_check: Zcu.BuiltinDecl = switch (stage) { |
| 607 | 607 | .main => .Type, |
| 608 | .panic => .Panic, | |
| 608 | .panic => .panic, | |
| 609 | 609 | .va_list => .VaList, |
| 610 | 610 | }; |
| 611 | 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 | 5019 | ); |
| 5020 | 5020 | } |
| 5021 | 5021 | |
| 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 | 5022 | fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air.CoveragePoint) Error!void { |
| 5035 | 5023 | const o = self.ng.object; |
| 5036 | 5024 | const zcu = o.pt.zcu; |
| ... | ... | @@ -5732,30 +5720,14 @@ pub const FuncGen = struct { |
| 5732 | 5720 | } |
| 5733 | 5721 | } |
| 5734 | 5722 | |
| 5735 | fn buildSimplePanic(fg: *FuncGen, panic_id: Zcu.PanicId) !void { | |
| 5723 | fn buildSimplePanic(fg: *FuncGen, panic_id: Zcu.SimplePanicId) !void { | |
| 5736 | 5724 | const o = fg.ng.object; |
| 5737 | 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 | 5726 | const target = zcu.getTarget(); |
| 5747 | const llvm_usize = try o.lowerType(Type.usize); | |
| 5748 | // example: | |
| 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))).?; | |
| 5727 | const panic_func = zcu.funcInfo(zcu.builtin_decl_values.get(panic_id.toBuiltin())); | |
| 5728 | const fn_info = zcu.typeToFunc(.fromInterned(panic_func.ty)).?; | |
| 5758 | 5729 | const panic_global = try o.resolveLlvmFunction(panic_func.owner_nav); |
| 5730 | ||
| 5759 | 5731 | const has_err_trace = zcu.comp.config.any_error_tracing and fn_info.cc == .auto; |
| 5760 | 5732 | if (has_err_trace) assert(fg.err_ret_trace != .none); |
| 5761 | 5733 | _ = try fg.wip.callIntrinsicAssumeCold(); |
| ... | ... | @@ -5765,18 +5737,7 @@ pub const FuncGen = struct { |
| 5765 | 5737 | .none, |
| 5766 | 5738 | panic_global.typeOf(&o.builder), |
| 5767 | 5739 | panic_global.toValue(&o.builder), |
| 5768 | if (has_err_trace) &.{ | |
| 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 | }, | |
| 5740 | if (has_err_trace) &.{fg.err_ret_trace} else &.{}, | |
| 5780 | 5741 | "", |
| 5781 | 5742 | ); |
| 5782 | 5743 | _ = try fg.wip.@"unreachable"(); |
src/crash_report.zig+5-11| ... | ... | @@ -18,18 +18,12 @@ const dev = @import("dev.zig"); |
| 18 | 18 | /// To use these crash report diagnostics, publish this panic in your main file |
| 19 | 19 | /// and add `pub const enable_segfault_handler = false;` to your `std_options`. |
| 20 | 20 | /// You will also need to call initialize() on startup, preferably as the very first operation in your program. |
| 21 | pub const Panic = if (build_options.enable_debug_extensions) struct { | |
| 22 | pub const call = compilerPanic; | |
| 23 | pub const sentinelMismatch = std.debug.FormattedPanic.sentinelMismatch; | |
| 24 | pub const unwrapError = std.debug.FormattedPanic.unwrapError; | |
| 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 | |
| 21 | pub const panic = if (build_options.enable_debug_extensions) | |
| 22 | std.debug.FullPanic(compilerPanic) | |
| 23 | else if (dev.env == .bootstrap) | |
| 24 | std.debug.simple_panic | |
| 31 | 25 | else |
| 32 | std.debug.FormattedPanic; | |
| 26 | std.debug.FullPanic(std.debug.defaultPanic); | |
| 33 | 27 | |
| 34 | 28 | /// Install signal handlers to identify crashes and report diagnostics. |
| 35 | 29 | pub fn initialize() void { |
src/main.zig+1-1| ... | ... | @@ -56,7 +56,7 @@ pub const std_options: std.Options = .{ |
| 56 | 56 | }, |
| 57 | 57 | }; |
| 58 | 58 | |
| 59 | pub const Panic = crash_report.Panic; | |
| 59 | pub const panic = crash_report.panic; | |
| 60 | 60 | |
| 61 | 61 | var wasi_preopens: fs.wasi.Preopens = undefined; |
| 62 | 62 | pub fn wasi_cwd() std.os.wasi.fd_t { |
test/cases/compile_errors/bad_panic_call_signature.zig created+46| ... | ... | @@ -0,0 +1,46 @@ |
| 1 | const simple_panic = std.debug.simple_panic; | |
| 2 | pub 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 | ||
| 36 | export fn foo(a: u8) void { | |
| 37 | @setRuntimeSafety(true); | |
| 38 | _ = a + 1; // safety check to reference the panic handler | |
| 39 | } | |
| 40 | ||
| 41 | const 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 @@ |
| 1 | const simple_panic = std.debug.simple_panic; | |
| 2 | pub 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 | ||
| 31 | export fn foo(arr: *const [2]u8) void { | |
| 32 | @setRuntimeSafety(true); | |
| 33 | _ = arr[0..1 :0]; | |
| 34 | } | |
| 35 | ||
| 36 | const 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 @@ |
| 1 | pub 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 | ||
| 11 | fn badPanicSignature(msg: []const u8, bad1: usize, bad2: void) noreturn { | |
| 12 | _ = msg; | |
| 13 | _ = bad1; | |
| 14 | _ = bad2; | |
| 15 | @trap(); | |
| 16 | } | |
| 17 | ||
| 18 | export fn foo(a: u8) void { | |
| 19 | @setRuntimeSafety(true); | |
| 20 | _ = a + 1; // safety check to reference the panic handler | |
| 21 | } | |
| 22 | ||
| 23 | const 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 | 9 | _ = a + 1; |
| 10 | 10 | return 1; |
| 11 | 11 | } |
| 12 | pub const Panic = struct { | |
| 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 | }; | |
| 12 | pub const panic = std.debug.FullPanic(myPanic); | |
| 21 | 13 | fn myPanic(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { |
| 22 | 14 | std.io.getStdOut().writer().print("panic message: {s}\n", .{msg}) catch {}; |
| 23 | 15 | std.process.exit(0); |
| ... | ... | @@ -33,15 +25,7 @@ pub fn main() !u8 { |
| 33 | 25 | _ = a + 1; |
| 34 | 26 | return 1; |
| 35 | 27 | } |
| 36 | pub const Panic = struct { | |
| 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 | }; | |
| 28 | pub const panic = std.debug.FullPanic(myPanic); | |
| 45 | 29 | fn myPanic(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { |
| 46 | 30 | std.io.getStdOut().writer().print("new panic message: {s}\n", .{msg}) catch {}; |
| 47 | 31 | std.process.exit(0); |
| ... | ... | @@ -57,15 +41,7 @@ pub fn main() !u8 { |
| 57 | 41 | _ = a + 1; |
| 58 | 42 | return 1; |
| 59 | 43 | } |
| 60 | pub const Panic = struct { | |
| 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 | }; | |
| 44 | pub const panic = std.debug.FullPanic(myPanicNew); | |
| 69 | 45 | fn myPanicNew(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn { |
| 70 | 46 | std.io.getStdOut().writer().print("third panic message: {s}\n", .{msg}) catch {}; |
| 71 | 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 | |
| 6 | pub fn main() !u8 { | |
| 7 | var a: u8 = undefined; | |
| 8 | a = 255; | |
| 9 | _ = a + 1; | |
| 10 | return 1; | |
| 11 | } | |
| 12 | const no_panic = std.debug.no_panic; | |
| 13 | pub 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 | }; | |
| 43 | fn 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 | } | |
| 47 | const std = @import("std"); | |
| 48 | #expect_stdout="panic message: integer overflow\n" | |
| 49 | ||
| 50 | #update=change the panic handler body | |
| 51 | #file=main.zig | |
| 52 | pub fn main() !u8 { | |
| 53 | var a: u8 = undefined; | |
| 54 | a = 255; | |
| 55 | _ = a + 1; | |
| 56 | return 1; | |
| 57 | } | |
| 58 | const no_panic = std.debug.no_panic; | |
| 59 | pub 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 | }; | |
| 89 | fn 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 | } | |
| 93 | const 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 | |
| 98 | pub fn main() !u8 { | |
| 99 | var a: u8 = undefined; | |
| 100 | a = 255; | |
| 101 | _ = a + 1; | |
| 102 | return 1; | |
| 103 | } | |
| 104 | const no_panic = std.debug.no_panic; | |
| 105 | pub 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 | }; | |
| 136 | fn 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 | } | |
| 140 | const std = @import("std"); | |
| 141 | #expect_stdout="third panic message: integer overflow\n" |