| author | |
| committer | |
| log | 8ba3812eeedec643dd045e0fecb8a6697f6253db |
| tree | 00c47f03ccef1a0398163b5af7063501860d18fe |
| parent | 921725427efeae591793f49291807a41112ccbf9 |
| parent | b6726913d31f9273317ab56c4d33096aee0a588f |
| signature |
compiler: yet more panic handler changes23 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(); |
| 78 | 78 | ||
| 79 | // Avoid dragging in the runtime safety mechanisms into this .o file, unless | 79 | // 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. |
| 81 | pub const Panic = if (builtin.is_test) std.debug.FormattedPanic else struct {}; | 81 | pub 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. | ||
| 84 | pub 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 | } | ||
| 91 | 82 | ||
| 92 | /// AArch64 is the only ABI (at the moment) to support f16 arguments without the | 83 | /// 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, |
| 374 | 374 | ||
| 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. |
| 1112 | pub const PanicFn = fn ([]const u8, ?*StackTrace, ?usize) noreturn; | 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 | /// This namespace is used by the Zig compiler to emit various kinds of safety | 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 | /// root source file. | 1116 | /// root source file. |
| 1120 | pub const Panic: type = if (@hasDecl(root, "Panic")) | 1117 | pub const panic: type = p: { |
| 1121 | root.Panic | 1118 | if (@hasDecl(root, "panic")) { |
| 1122 | else if (@hasDecl(root, "panic")) // Deprecated, use `Panic` instead. | 1119 | if (@TypeOf(root.panic) != type) { |
| 1123 | DeprecatedPanic | 1120 | // Deprecated; make `panic` a namespace instead. |
| 1124 | else if (builtin.zig_backend == .stage2_riscv64) | 1121 | break :p std.debug.FullPanic(struct { |
| 1125 | std.debug.SimplePanic // https://github.com/ziglang/zig/issues/21519 | 1122 | fn panic(msg: []const u8, ra: ?usize) noreturn { |
| 1126 | else | 1123 | root.panic(msg, @errorReturnTrace(), ra); |
| 1127 | std.debug.FormattedPanic; | 1124 | } |
| 1128 | 1125 | }.panic); | |
| 1129 | /// To be deleted after 0.14.0 is released. | 1126 | } |
| 1130 | const 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 | }; |
| 1139 | 1137 | ||
| 1140 | /// 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; | ||
| 1152 | |||
| 1153 | pub noinline fn returnError() void { | 1138 | pub 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"); |
| 21 | pub const Info = @import("debug/Info.zig"); | 21 | pub const Info = @import("debug/Info.zig"); |
| 22 | pub const Coverage = @import("debug/Coverage.zig"); | 22 | pub const Coverage = @import("debug/Coverage.zig"); |
| 23 | 23 | ||
| 24 | pub const FormattedPanic = @import("debug/FormattedPanic.zig"); | 24 | pub const simple_panic = @import("debug/simple_panic.zig"); |
| 25 | pub const SimplePanic = @import("debug/SimplePanic.zig"); | 25 | pub const no_panic = @import("debug/no_panic.zig"); |
| 26 | pub 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`. | ||
| 30 | pub 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 | } | ||
| 27 | 139 | ||
| 28 | /// Unresolved source locations can be represented with a single `usize` that | 140 | /// Unresolved source locations can be represented with a single `usize` that |
| 29 | /// corresponds to a virtual memory address of the program counter. Combined | 141 | /// 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. |
| 417 | pub fn panic(comptime format: []const u8, args: anytype) noreturn { | 529 | pub 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 | } |
| 421 | 533 | ||
| 422 | /// Equivalent to `@panic` but with a formatted message, and with an explicitly | 534 | /// Equivalent to `@panic` but with a formatted message, and with an explicitly |
| 423 | /// provided `@errorReturnTrace` and return address. | 535 | /// provided return address. |
| 424 | pub fn panicExtra( | 536 | pub 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 | } |
| 446 | 557 | ||
| 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. |
| 456 | pub fn defaultPanic( | 567 | pub 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(); |
| 544 | 654 | ||
| 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 | } |
| 548 | 658 |
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+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 | |||
| 6 | const std = @import("../std.zig"); | ||
| 7 | |||
| 8 | pub fn call(_: []const u8, _: ?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(_: 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 | } | ||
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 | |||
| 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, 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 | |||
| 23 | pub fn sentinelMismatch(expected: anytype, found: @TypeOf(expected)) noreturn { | ||
| 24 | _ = found; | ||
| 25 | call("sentinel mismatch", null); | ||
| 26 | } | ||
| 27 | |||
| 28 | pub fn unwrapError(err: anyerror) noreturn { | ||
| 29 | _ = &err; | ||
| 30 | call("attempt to unwrap error", null); | ||
| 31 | } | ||
| 32 | |||
| 33 | pub fn outOfBounds(index: usize, len: usize) noreturn { | ||
| 34 | _ = index; | ||
| 35 | _ = len; | ||
| 36 | call("index out of bounds", null); | ||
| 37 | } | ||
| 38 | |||
| 39 | pub fn startGreaterThanEnd(start: usize, end: usize) noreturn { | ||
| 40 | _ = start; | ||
| 41 | _ = end; | ||
| 42 | call("start index is larger than end index", null); | ||
| 43 | } | ||
| 44 | |||
| 45 | pub fn inactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn { | ||
| 46 | _ = accessed; | ||
| 47 | call("access of inactive union field", null); | ||
| 48 | } | ||
| 49 | |||
| 50 | pub fn reachedUnreachable() noreturn { | ||
| 51 | call("reached unreachable code", null); | ||
| 52 | } | ||
| 53 | |||
| 54 | pub fn unwrapNull() noreturn { | ||
| 55 | call("attempt to use null value", null); | ||
| 56 | } | ||
| 57 | |||
| 58 | pub fn castToNull() noreturn { | ||
| 59 | call("cast causes pointer to be null", null); | ||
| 60 | } | ||
| 61 | |||
| 62 | pub fn incorrectAlignment() noreturn { | ||
| 63 | call("incorrect alignment", null); | ||
| 64 | } | ||
| 65 | |||
| 66 | pub fn invalidErrorCode() noreturn { | ||
| 67 | call("invalid error code", null); | ||
| 68 | } | ||
| 69 | |||
| 70 | pub fn castTruncatedData() noreturn { | ||
| 71 | call("integer cast truncated bits", null); | ||
| 72 | } | ||
| 73 | |||
| 74 | pub fn negativeToUnsigned() noreturn { | ||
| 75 | call("attempt to cast negative value to unsigned integer", null); | ||
| 76 | } | ||
| 77 | |||
| 78 | pub fn integerOverflow() noreturn { | ||
| 79 | call("integer overflow", null); | ||
| 80 | } | ||
| 81 | |||
| 82 | pub fn shlOverflow() noreturn { | ||
| 83 | call("left shift overflowed bits", null); | ||
| 84 | } | ||
| 85 | |||
| 86 | pub fn shrOverflow() noreturn { | ||
| 87 | call("right shift overflowed bits", null); | ||
| 88 | } | ||
| 89 | |||
| 90 | pub fn divideByZero() noreturn { | ||
| 91 | call("division by zero", null); | ||
| 92 | } | ||
| 93 | |||
| 94 | pub fn exactDivisionRemainder() noreturn { | ||
| 95 | call("exact division produced remainder", null); | ||
| 96 | } | ||
| 97 | |||
| 98 | pub fn integerPartOutOfBounds() noreturn { | ||
| 99 | call("integer part of floating point value out of bounds", null); | ||
| 100 | } | ||
| 101 | |||
| 102 | pub fn corruptSwitch() noreturn { | ||
| 103 | call("switch on corrupt value", null); | ||
| 104 | } | ||
| 105 | |||
| 106 | pub fn shiftRhsTooBig() noreturn { | ||
| 107 | call("shift amount is greater than the type size", null); | ||
| 108 | } | ||
| 109 | |||
| 110 | pub fn invalidEnumValue() noreturn { | ||
| 111 | call("invalid enum value", null); | ||
| 112 | } | ||
| 113 | |||
| 114 | pub fn forLenMismatch() noreturn { | ||
| 115 | call("for loop over objects with non-equal lengths", null); | ||
| 116 | } | ||
| 117 | |||
| 118 | pub fn memcpyLenMismatch() noreturn { | ||
| 119 | call("@memcpy arguments have non-equal lengths", null); | ||
| 120 | } | ||
| 121 | |||
| 122 | pub fn memcpyAlias() noreturn { | ||
| 123 | call("@memcpy arguments alias", null); | ||
| 124 | } | ||
| 125 | |||
| 126 | pub 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 | } |
| 2589 | 2589 | ||
| 2590 | if (block) |start_block| { | 2590 | if (block) |start_block| { |
| ... | @@ -5918,13 +5918,14 @@ fn zirCompileLog( | ... | @@ -5918,13 +5918,14 @@ fn zirCompileLog( |
| 5918 | } | 5918 | } |
| 5919 | 5919 | ||
| 5920 | fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { | 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 | 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); |
| 5924 | 5927 | ||
| 5925 | // `panicWithMsg` would perform this coercion for us, but we can get a better | 5928 | 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)); | ||
| 5928 | 5929 | ||
| 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 | } |
| 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 | |||
| 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 | } |
| 5941 | 5957 | ||
| 5942 | fn zirTrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { | 5958 | fn 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); |
| 13789 | 13805 | ||
| 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-checked | 27098 | /// Backends depend on panic decls being available when lowering safety-checked |
| 27084 | /// instructions. This function ensures the panic function will be available to | 27099 | /// instructions. This function ensures the panic function will be available to |
| 27085 | /// be called during that time. | 27100 | /// be called during that time. |
| 27086 | fn preparePanicId(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.PanicId) !InternPool.Index { | 27101 | fn 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 | } |
| 27096 | 27112 | ||
| 27097 | fn addSafetyCheck( | 27113 | fn 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 | } |
| 27188 | 27204 | ||
| 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 | fn addSafetyCheckUnwrapError( | 27205 | fn 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 | } |
| 27255 | 27246 | ||
| ... | @@ -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 | } |
| 27268 | 27259 | ||
| 27269 | fn addSafetyCheckInactiveUnionField( | 27260 | fn 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 | } |
| 27280 | 27271 | ||
| 27281 | fn addSafetyCheckSentinelMismatch( | 27272 | fn 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 | }; |
| 27318 | 27309 | ||
| 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 | } |
| 27359 | 27350 | ||
| 27360 | /// This does not set `sema.branch_hint`. | 27351 | /// This does not set `sema.branch_hint`. |
| 27361 | fn safetyPanic(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.PanicId) CompileError!void { | 27352 | fn 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 | } |
| 27365 | 27360 | ||
| 27366 | fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void { | 27361 | fn 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 | } |
| 38551 | 38541 | ||
| 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 | } |
| 38569 | 38544 | ||
| 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`. In | 38546 | fn 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. | ||
| 38575 | fn 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 | }), |
| 38591 | 38564 | ||
| 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 | }), |
| 38604 | 38579 | ||
| 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 | }), |
| 38612 | 38587 | ||
| 38613 | // Generic functions, so calls are necessarily validated by Sema | 38588 | // `fn () noreturn` |
| 38614 | .@"Panic.sentinelMismatch", | 38589 | .@"panic.reachedUnreachable", |
| 38615 | .@"Panic.inactiveUnionField", | 38590 | .@"panic.unwrapNull", |
| 38616 | => null, | 38591 | .@"panic.castToNull", |
| 38617 | 38592 | .@"panic.incorrectAlignment", | |
| 38618 | // Other functions called exclusively by Sema | 38593 | .@"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 | }), | ||
| 38621 | 38613 | ||
| 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, |
| 219 | 219 | ||
| 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. |
| 221 | builtin_decl_values: BuiltinDecl.Memoized = .initFill(.none), | 221 | builtin_decl_values: BuiltinDecl.Memoized = .initFill(.none), |
| 222 | /// Populated by analysis of `AnalUnit.wrap(.{ .memoized_state = .panic })`. | ||
| 223 | null_stack_trace: InternPool.Index = .none, | ||
| 224 | 222 | ||
| 225 | generation: u32 = 0, | 223 | generation: u32 = 0, |
| 226 | 224 | ||
| ... | @@ -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", |
| 271 | 269 | ||
| 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", | ||
| 300 | 297 | ||
| 301 | VaList, | 298 | VaList, |
| 302 | 299 | ||
| ... | @@ -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, |
| 347 | 344 | ||
| 348 | .Panic => .type, | 345 | .panic => .type, |
| 349 | 346 | ||
| 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 | } |
| 383 | 376 | ||
| ... | @@ -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 | }; |
| 425 | 418 | ||
| 426 | pub const PanicId = enum { | 419 | pub 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, |
| 447 | 440 | ||
| 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 | }; |
| 463 | 468 |
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 | } |
| 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 | 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 | } |
| 5734 | 5722 | ||
| 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 file | 18 | /// 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. |
| 21 | pub const Panic = if (build_options.enable_debug_extensions) struct { | 21 | pub 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; | 23 | else 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 | ||
| 31 | else | 25 | else |
| 32 | std.debug.FormattedPanic; | 26 | std.debug.FullPanic(std.debug.defaultPanic); |
| 33 | 27 | ||
| 34 | /// Install signal handlers to identify crashes and report diagnostics. | 28 | /// Install signal handlers to identify crashes and report diagnostics. |
| 35 | pub fn initialize() void { | 29 | pub 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 | } |
| 166 | 160 | ||
| 167 | pub fn compilerPanic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, maybe_ret_addr: ?usize) noreturn { | 161 | pub 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 | } |
| 174 | 168 | ||
| 175 | /// Attaches a global SIGSEGV handler | 169 | /// 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 | }; |
| 58 | 58 | ||
| 59 | pub const Panic = crash_report.Panic; | 59 | pub const panic = crash_report.panic; |
| 60 | 60 | ||
| 61 | var wasi_preopens: fs.wasi.Preopens = undefined; | 61 | var wasi_preopens: fs.wasi.Preopens = undefined; |
| 62 | pub fn wasi_cwd() std.os.wasi.fd_t { | 62 | pub 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 @@ | ||
| 1 | const simple_panic = std.debug.simple_panic; | ||
| 2 | pub 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 | |||
| 35 | export fn foo(a: u8) void { | ||
| 36 | @setRuntimeSafety(true); | ||
| 37 | _ = a + 1; // safety check to reference the panic handler | ||
| 38 | } | ||
| 39 | |||
| 40 | const 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 @@ | ||
| 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+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 | } |
| 12 | pub const Panic = struct { | 12 | pub const panic = std.debug.FullPanic(myPanic); |
| 13 | pub const call = myPanic; | 13 | fn 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 | }; | ||
| 21 | fn 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 | } |
| 36 | pub const Panic = struct { | 28 | pub const panic = std.debug.FullPanic(myPanic); |
| 37 | pub const call = myPanic; | 29 | fn 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 | }; | ||
| 45 | fn 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 | } |
| 60 | pub const Panic = struct { | 44 | pub const panic = std.debug.FullPanic(myPanicNew); |
| 61 | pub const call = myPanicNew; | 45 | fn 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 | }; | ||
| 69 | fn 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 | ||
| 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, _: ?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, _: ?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, _: ?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" | ||
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) }, |