Commit 83991efe10
Changed files (19)
lib
src
test
lib/std/debug/FormattedPanic.zig
@@ -1,45 +0,0 @@
-//! This namespace is the default one used by the Zig compiler to emit various
-//! kinds of safety panics, due to the logic in `std.builtin.Panic`.
-//!
-//! Since Zig does not have interfaces, this file serves as an example template
-//! for users to provide their own alternative panic handling.
-//!
-//! As an alternative, see `std.debug.SimplePanic`.
-
-const std = @import("../std.zig");
-
-/// Dumps a stack trace to standard error, then aborts.
-///
-/// Explicit calls to `@panic` lower to calling this function.
-pub const call: fn ([]const u8, ?*std.builtin.StackTrace, ?usize) noreturn = std.debug.defaultPanic;
-
-pub fn sentinelMismatch(expected: anytype, found: @TypeOf(expected)) noreturn {
- @branchHint(.cold);
- std.debug.panicExtra(null, @returnAddress(), "sentinel mismatch: expected {any}, found {any}", .{
- expected, found,
- });
-}
-
-pub fn unwrapError(ert: ?*std.builtin.StackTrace, err: anyerror) noreturn {
- @branchHint(.cold);
- std.debug.panicExtra(ert, @returnAddress(), "attempt to unwrap error: {s}", .{@errorName(err)});
-}
-
-pub fn outOfBounds(index: usize, len: usize) noreturn {
- @branchHint(.cold);
- std.debug.panicExtra(null, @returnAddress(), "index out of bounds: index {d}, len {d}", .{ index, len });
-}
-
-pub fn startGreaterThanEnd(start: usize, end: usize) noreturn {
- @branchHint(.cold);
- std.debug.panicExtra(null, @returnAddress(), "start index {d} is larger than end index {d}", .{ start, end });
-}
-
-pub fn inactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn {
- @branchHint(.cold);
- std.debug.panicExtra(null, @returnAddress(), "access of union field '{s}' while field '{s}' is active", .{
- @tagName(accessed), @tagName(active),
- });
-}
-
-pub const messages = std.debug.SimplePanic.messages;
lib/std/debug/no_panic.zig
@@ -0,0 +1,160 @@
+//! This namespace can be used with `pub const panic = std.debug.no_panic;` in the root file.
+//! It emits as little code as possible, for testing purposes.
+//!
+//! For a functional alternative, see `std.debug.FullPanic`.
+
+const std = @import("../std.zig");
+
+pub fn call(_: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn sentinelMismatch(_: anytype, _: anytype) noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn unwrapError(_: ?*std.builtin.StackTrace, _: anyerror) noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn outOfBounds(_: usize, _: usize) noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn startGreaterThanEnd(_: usize, _: usize) noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn inactiveUnionField(_: anytype, _: anytype) noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn reachedUnreachable() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn unwrapNull() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn castToNull() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn incorrectAlignment() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn invalidErrorCode() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn castTruncatedData() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn negativeToUnsigned() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn integerOverflow() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn shlOverflow() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn shrOverflow() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn divideByZero() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn exactDivisionRemainder() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn integerPartOutOfBounds() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn corruptSwitch() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn shiftRhsTooBig() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn invalidEnumValue() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn forLenMismatch() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn memcpyLenMismatch() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn memcpyAlias() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+pub fn noreturnReturned() noreturn {
+ @branchHint(.cold);
+ @trap();
+}
+
+/// To be deleted after zig1.wasm update.
+pub const messages = struct {
+ pub const reached_unreachable = "";
+ pub const unwrap_null = "";
+ pub const cast_to_null = "";
+ pub const incorrect_alignment = "";
+ pub const invalid_error_code = "";
+ pub const cast_truncated_data = "";
+ pub const negative_to_unsigned = "";
+ pub const integer_overflow = "";
+ pub const shl_overflow = "";
+ pub const shr_overflow = "";
+ pub const divide_by_zero = "";
+ pub const exact_division_remainder = "";
+ pub const integer_part_out_of_bounds = "";
+ pub const corrupt_switch = "";
+ pub const shift_rhs_too_big = "";
+ pub const invalid_enum_value = "";
+ pub const for_len_mismatch = "";
+ pub const memcpy_len_mismatch = "";
+ pub const memcpy_alias = "";
+ pub const noreturn_returned = "";
+};
lib/std/debug/NoPanic.zig
@@ -1,59 +0,0 @@
-//! This namespace can be used with `pub const Panic = std.debug.NoPanic;` in the root file.
-//! It emits as little code as possible, for testing purposes.
-//!
-//! For a functional alternative, see `std.debug.FormattedPanic`.
-
-const std = @import("../std.zig");
-
-pub fn call(_: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
- @branchHint(.cold);
- @trap();
-}
-
-pub fn sentinelMismatch(_: anytype, _: anytype) noreturn {
- @branchHint(.cold);
- @trap();
-}
-
-pub fn unwrapError(_: ?*std.builtin.StackTrace, _: anyerror) noreturn {
- @branchHint(.cold);
- @trap();
-}
-
-pub fn outOfBounds(_: usize, _: usize) noreturn {
- @branchHint(.cold);
- @trap();
-}
-
-pub fn startGreaterThanEnd(_: usize, _: usize) noreturn {
- @branchHint(.cold);
- @trap();
-}
-
-pub fn inactiveUnionField(_: anytype, _: anytype) noreturn {
- @branchHint(.cold);
- @trap();
-}
-
-pub const messages = struct {
- pub const reached_unreachable = "";
- pub const unwrap_null = "";
- pub const cast_to_null = "";
- pub const incorrect_alignment = "";
- pub const invalid_error_code = "";
- pub const cast_truncated_data = "";
- pub const negative_to_unsigned = "";
- pub const integer_overflow = "";
- pub const shl_overflow = "";
- pub const shr_overflow = "";
- pub const divide_by_zero = "";
- pub const exact_division_remainder = "";
- pub const integer_part_out_of_bounds = "";
- pub const corrupt_switch = "";
- pub const shift_rhs_too_big = "";
- pub const invalid_enum_value = "";
- pub const for_len_mismatch = "";
- pub const memcpy_len_mismatch = "";
- pub const memcpy_alias = "";
- pub const noreturn_returned = "";
-};
lib/std/debug/SimplePanic.zig → lib/std/debug/simple_panic.zig
@@ -1,10 +1,10 @@
//! This namespace is the default one used by the Zig compiler to emit various
-//! kinds of safety panics, due to the logic in `std.builtin.Panic`.
+//! kinds of safety panics, due to the logic in `std.builtin.panic`.
//!
//! Since Zig does not have interfaces, this file serves as an example template
//! for users to provide their own alternative panic handling.
//!
-//! As an alternative, see `std.debug.FormattedPanic`.
+//! As an alternative, see `std.debug.FullPanic`.
const std = @import("../std.zig");
@@ -49,6 +49,87 @@ pub fn inactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn {
call("access of inactive union field", null, null);
}
+pub fn reachedUnreachable() noreturn {
+ call("reached unreachable code", null, null);
+}
+
+pub fn unwrapNull() noreturn {
+ call("attempt to use null value", null, null);
+}
+
+pub fn castToNull() noreturn {
+ call("cast causes pointer to be null", null, null);
+}
+
+pub fn incorrectAlignment() noreturn {
+ call("incorrect alignment", null, null);
+}
+
+pub fn invalidErrorCode() noreturn {
+ call("invalid error code", null, null);
+}
+
+pub fn castTruncatedData() noreturn {
+ call("integer cast truncated bits", null, null);
+}
+
+pub fn negativeToUnsigned() noreturn {
+ call("attempt to cast negative value to unsigned integer", null, null);
+}
+
+pub fn integerOverflow() noreturn {
+ call("integer overflow", null, null);
+}
+
+pub fn shlOverflow() noreturn {
+ call("left shift overflowed bits", null, null);
+}
+
+pub fn shrOverflow() noreturn {
+ call("right shift overflowed bits", null, null);
+}
+
+pub fn divideByZero() noreturn {
+ call("division by zero", null, null);
+}
+
+pub fn exactDivisionRemainder() noreturn {
+ call("exact division produced remainder", null, null);
+}
+
+pub fn integerPartOutOfBounds() noreturn {
+ call("integer part of floating point value out of bounds", null, null);
+}
+
+pub fn corruptSwitch() noreturn {
+ call("switch on corrupt value", null, null);
+}
+
+pub fn shiftRhsTooBig() noreturn {
+ call("shift amount is greater than the type size", null, null);
+}
+
+pub fn invalidEnumValue() noreturn {
+ call("invalid enum value", null, null);
+}
+
+pub fn forLenMismatch() noreturn {
+ call("for loop over objects with non-equal lengths", null, null);
+}
+
+pub fn memcpyLenMismatch() noreturn {
+ call("@memcpy arguments have non-equal lengths", null, null);
+}
+
+pub fn memcpyAlias() noreturn {
+ call("@memcpy arguments alias", null, null);
+}
+
+pub fn noreturnReturned() noreturn {
+ call("'noreturn' function returned", null, null);
+}
+
+/// To be deleted after zig1.wasm update.
pub const messages = struct {
pub const reached_unreachable = "reached unreachable code";
pub const unwrap_null = "attempt to use null value";
@@ -70,17 +151,4 @@ pub const messages = struct {
pub const memcpy_len_mismatch = "@memcpy arguments have non-equal lengths";
pub const memcpy_alias = "@memcpy arguments alias";
pub const noreturn_returned = "'noreturn' function returned";
-
- /// To be deleted after zig1.wasm is updated.
- pub const inactive_union_field = "access of inactive union field";
- /// To be deleted after zig1.wasm is updated.
- pub const sentinel_mismatch = "sentinel mismatch";
- /// To be deleted after zig1.wasm is updated.
- pub const unwrap_error = "attempt to unwrap error";
- /// To be deleted after zig1.wasm is updated.
- pub const index_out_of_bounds = "index out of bounds";
- /// To be deleted after zig1.wasm is updated.
- pub const start_index_greater_than_end = "start index is larger than end index";
- /// To be deleted after zig1.wasm is updated.
- pub const unreach = reached_unreachable;
};
lib/std/builtin.zig
@@ -1110,45 +1110,28 @@ pub const TestFn = struct {
/// Deprecated, use the `Panic` namespace instead.
/// To be deleted after 0.14.0 is released.
pub const PanicFn = fn ([]const u8, ?*StackTrace, ?usize) noreturn;
-/// Deprecated, use the `Panic` namespace instead.
-/// To be deleted after 0.14.0 is released.
-pub const panic: PanicFn = Panic.call;
/// This namespace is used by the Zig compiler to emit various kinds of safety
-/// panics. These can be overridden by making a public `Panic` namespace in the
+/// panics. These can be overridden by making a public `panic` namespace in the
/// root source file.
-pub const Panic: type = if (@hasDecl(root, "Panic"))
- root.Panic
-else if (@hasDecl(root, "panic")) // Deprecated, use `Panic` instead.
- DeprecatedPanic
-else if (builtin.zig_backend == .stage2_riscv64)
- std.debug.SimplePanic // https://github.com/ziglang/zig/issues/21519
-else
- std.debug.FormattedPanic;
-
-/// To be deleted after 0.14.0 is released.
-const DeprecatedPanic = struct {
- pub const call = root.panic;
- pub const sentinelMismatch = std.debug.FormattedPanic.sentinelMismatch;
- pub const unwrapError = std.debug.FormattedPanic.unwrapError;
- pub const outOfBounds = std.debug.FormattedPanic.outOfBounds;
- pub const startGreaterThanEnd = std.debug.FormattedPanic.startGreaterThanEnd;
- pub const inactiveUnionField = std.debug.FormattedPanic.inactiveUnionField;
- pub const messages = std.debug.FormattedPanic.messages;
+pub const panic: type = p: {
+ if (@hasDecl(root, "panic")) {
+ if (@TypeOf(root.panic) != type) {
+ break :p std.debug.FullPanic(root.panic); // Deprecated; make `panic` a namespace instead.
+ }
+ break :p root.panic;
+ }
+ if (@hasDecl(root, "Panic")) {
+ break :p root.Panic; // Deprecated; use `panic` instead.
+ }
+ if (builtin.zig_backend == .stage2_riscv64) {
+ break :p std.debug.simple_panic;
+ }
+ break :p std.debug.FullPanic(std.debug.defaultPanic);
};
/// To be deleted after zig1.wasm is updated.
-pub const panicSentinelMismatch = Panic.sentinelMismatch;
-/// To be deleted after zig1.wasm is updated.
-pub const panicUnwrapError = Panic.unwrapError;
-/// To be deleted after zig1.wasm is updated.
-pub const panicOutOfBounds = Panic.outOfBounds;
-/// To be deleted after zig1.wasm is updated.
-pub const panicStartGreaterThanEnd = Panic.startGreaterThanEnd;
-/// To be deleted after zig1.wasm is updated.
-pub const panicInactiveUnionField = Panic.inactiveUnionField;
-/// To be deleted after zig1.wasm is updated.
-pub const panic_messages = Panic.messages;
+pub const Panic = panic;
pub noinline fn returnError() void {
@branchHint(.unlikely);
lib/std/debug.zig
@@ -21,9 +21,124 @@ pub const SelfInfo = @import("debug/SelfInfo.zig");
pub const Info = @import("debug/Info.zig");
pub const Coverage = @import("debug/Coverage.zig");
-pub const FormattedPanic = @import("debug/FormattedPanic.zig");
-pub const SimplePanic = @import("debug/SimplePanic.zig");
-pub const NoPanic = @import("debug/NoPanic.zig");
+pub const simple_panic = @import("debug/simple_panic.zig");
+pub const no_panic = @import("debug/no_panic.zig");
+
+/// A fully-featured panic handler namespace which lowers all panics to calls to `panicFn`.
+/// Safety panics will use formatted printing to provide a meaningful error message.
+/// The signature of `panicFn` should match that of `defaultPanic`.
+pub fn FullPanic(comptime panicFn: fn ([]const u8, ?*std.builtin.StackTrace, ?usize) noreturn) type {
+ return struct {
+ pub const call = panicFn;
+ pub fn sentinelMismatch(expected: anytype, found: @TypeOf(expected)) noreturn {
+ @branchHint(.cold);
+ std.debug.panicExtra(null, @returnAddress(), "sentinel mismatch: expected {any}, found {any}", .{
+ expected, found,
+ });
+ }
+ pub fn unwrapError(ert: ?*std.builtin.StackTrace, err: anyerror) noreturn {
+ @branchHint(.cold);
+ std.debug.panicExtra(ert, @returnAddress(), "attempt to unwrap error: {s}", .{@errorName(err)});
+ }
+ pub fn outOfBounds(index: usize, len: usize) noreturn {
+ @branchHint(.cold);
+ std.debug.panicExtra(null, @returnAddress(), "index out of bounds: index {d}, len {d}", .{ index, len });
+ }
+ pub fn startGreaterThanEnd(start: usize, end: usize) noreturn {
+ @branchHint(.cold);
+ std.debug.panicExtra(null, @returnAddress(), "start index {d} is larger than end index {d}", .{ start, end });
+ }
+ pub fn inactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn {
+ @branchHint(.cold);
+ std.debug.panicExtra(null, @returnAddress(), "access of union field '{s}' while field '{s}' is active", .{
+ @tagName(accessed), @tagName(active),
+ });
+ }
+ pub fn reachedUnreachable() noreturn {
+ @branchHint(.cold);
+ call("reached unreachable code", null, @returnAddress());
+ }
+ pub fn unwrapNull() noreturn {
+ @branchHint(.cold);
+ call("attempt to use null value", null, @returnAddress());
+ }
+ pub fn castToNull() noreturn {
+ @branchHint(.cold);
+ call("cast causes pointer to be null", null, @returnAddress());
+ }
+ pub fn incorrectAlignment() noreturn {
+ @branchHint(.cold);
+ call("incorrect alignment", null, @returnAddress());
+ }
+ pub fn invalidErrorCode() noreturn {
+ @branchHint(.cold);
+ call("invalid error code", null, @returnAddress());
+ }
+ pub fn castTruncatedData() noreturn {
+ @branchHint(.cold);
+ call("integer cast truncated bits", null, @returnAddress());
+ }
+ pub fn negativeToUnsigned() noreturn {
+ @branchHint(.cold);
+ call("attempt to cast negative value to unsigned integer", null, @returnAddress());
+ }
+ pub fn integerOverflow() noreturn {
+ @branchHint(.cold);
+ call("integer overflow", null, @returnAddress());
+ }
+ pub fn shlOverflow() noreturn {
+ @branchHint(.cold);
+ call("left shift overflowed bits", null, @returnAddress());
+ }
+ pub fn shrOverflow() noreturn {
+ @branchHint(.cold);
+ call("right shift overflowed bits", null, @returnAddress());
+ }
+ pub fn divideByZero() noreturn {
+ @branchHint(.cold);
+ call("division by zero", null, @returnAddress());
+ }
+ pub fn exactDivisionRemainder() noreturn {
+ @branchHint(.cold);
+ call("exact division produced remainder", null, @returnAddress());
+ }
+ pub fn integerPartOutOfBounds() noreturn {
+ @branchHint(.cold);
+ call("integer part of floating point value out of bounds", null, @returnAddress());
+ }
+ pub fn corruptSwitch() noreturn {
+ @branchHint(.cold);
+ call("switch on corrupt value", null, @returnAddress());
+ }
+ pub fn shiftRhsTooBig() noreturn {
+ @branchHint(.cold);
+ call("shift amount is greater than the type size", null, @returnAddress());
+ }
+ pub fn invalidEnumValue() noreturn {
+ @branchHint(.cold);
+ call("invalid enum value", null, @returnAddress());
+ }
+ pub fn forLenMismatch() noreturn {
+ @branchHint(.cold);
+ call("for loop over objects with non-equal lengths", null, @returnAddress());
+ }
+ pub fn memcpyLenMismatch() noreturn {
+ @branchHint(.cold);
+ call("@memcpy arguments have non-equal lengths", null, @returnAddress());
+ }
+ pub fn memcpyAlias() noreturn {
+ @branchHint(.cold);
+ call("@memcpy arguments alias", null, @returnAddress());
+ }
+ pub fn noreturnReturned() noreturn {
+ @branchHint(.cold);
+ call("'noreturn' function returned", null, @returnAddress());
+ }
+
+ /// To be deleted after zig1.wasm update.
+ pub const messages = simple_panic.messages;
+ };
+}
/// Unresolved source locations can be represented with a single `usize` that
/// corresponds to a virtual memory address of the program counter. Combined
@@ -441,7 +556,7 @@ pub fn panicExtra(
break :blk &buf;
},
};
- std.builtin.Panic.call(msg, trace, ret_addr);
+ std.builtin.panic.call(msg, trace, ret_addr);
}
/// Non-zero whenever the program triggered a panic.
lib/std/meta.zig
@@ -448,8 +448,7 @@ pub fn fieldNames(comptime T: type) *const [fields(T).len][:0]const u8 {
return comptime blk: {
const fieldInfos = fields(T);
var names: [fieldInfos.len][:0]const u8 = undefined;
- // This concat can be removed with the next zig1 update.
- for (&names, fieldInfos) |*name, field| name.* = field.name ++ "";
+ for (&names, fieldInfos) |*name, field| name.* = field.name;
const final = names;
break :blk &final;
};
lib/std/Target.zig
@@ -370,7 +370,7 @@ pub const Os = struct {
range: std.SemanticVersion.Range,
glibc: std.SemanticVersion,
/// Android API level.
- android: u32 = 14, // This default value is to be deleted after zig1.wasm is updated.
+ android: u32,
pub inline fn includesVersion(range: LinuxVersionRange, ver: std.SemanticVersion) bool {
return range.range.includesVersion(ver);
src/codegen/llvm.zig
@@ -5019,18 +5019,6 @@ pub const FuncGen = struct {
);
}
- fn resolveNullOptUsize(self: *FuncGen) Error!Builder.Constant {
- const o = self.ng.object;
- const pt = o.pt;
- if (o.null_opt_usize == .no_init) {
- o.null_opt_usize = try self.resolveValue(Value.fromInterned(try pt.intern(.{ .opt = .{
- .ty = try pt.intern(.{ .opt_type = .usize_type }),
- .val = .none,
- } })));
- }
- return o.null_opt_usize;
- }
-
fn genBody(self: *FuncGen, body: []const Air.Inst.Index, coverage_point: Air.CoveragePoint) Error!void {
const o = self.ng.object;
const zcu = o.pt.zcu;
@@ -5732,30 +5720,14 @@ pub const FuncGen = struct {
}
}
- fn buildSimplePanic(fg: *FuncGen, panic_id: Zcu.PanicId) !void {
+ fn buildSimplePanic(fg: *FuncGen, panic_id: Zcu.SimplePanicId) !void {
const o = fg.ng.object;
const zcu = o.pt.zcu;
- const ip = &zcu.intern_pool;
- const msg_len: u64, const msg_ptr: Builder.Constant = msg: {
- const str_val = zcu.builtin_decl_values.get(panic_id.toBuiltin());
- assert(str_val != .none);
- const slice = ip.indexToKey(str_val).slice;
- break :msg .{ Value.fromInterned(slice.len).toUnsignedInt(zcu), try o.lowerValue(slice.ptr) };
- };
- const null_opt_addr_global = try fg.resolveNullOptUsize();
const target = zcu.getTarget();
- const llvm_usize = try o.lowerType(Type.usize);
- // example:
- // call fastcc void @test2.panic(
- // ptr @builtin.panic_messages.integer_overflow__anon_987, ; msg.ptr
- // i64 16, ; msg.len
- // ptr null, ; stack trace
- // ptr @2, ; addr (null ?usize)
- // )
- const panic_func = zcu.funcInfo(zcu.builtin_decl_values.get(.@"Panic.call"));
- const panic_nav = ip.getNav(panic_func.owner_nav);
- const fn_info = zcu.typeToFunc(Type.fromInterned(panic_nav.typeOf(ip))).?;
+ const panic_func = zcu.funcInfo(zcu.builtin_decl_values.get(panic_id.toBuiltin()));
+ const fn_info = zcu.typeToFunc(.fromInterned(panic_func.ty)).?;
const panic_global = try o.resolveLlvmFunction(panic_func.owner_nav);
+
const has_err_trace = zcu.comp.config.any_error_tracing and fn_info.cc == .auto;
if (has_err_trace) assert(fg.err_ret_trace != .none);
_ = try fg.wip.callIntrinsicAssumeCold();
@@ -5765,18 +5737,7 @@ pub const FuncGen = struct {
.none,
panic_global.typeOf(&o.builder),
panic_global.toValue(&o.builder),
- if (has_err_trace) &.{
- fg.err_ret_trace,
- msg_ptr.toValue(),
- try o.builder.intValue(llvm_usize, msg_len),
- try o.builder.nullValue(.ptr),
- null_opt_addr_global.toValue(),
- } else &.{
- msg_ptr.toValue(),
- try o.builder.intValue(llvm_usize, msg_len),
- try o.builder.nullValue(.ptr),
- null_opt_addr_global.toValue(),
- },
+ if (has_err_trace) &.{fg.err_ret_trace} else &.{},
"",
);
_ = try fg.wip.@"unreachable"();
src/Zcu/PerThread.zig
@@ -605,7 +605,7 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized
// We use an arbitrary element to check if the state has been resolved yet.
const to_check: Zcu.BuiltinDecl = switch (stage) {
.main => .Type,
- .panic => .Panic,
+ .panic => .panic,
.va_list => .VaList,
};
if (zcu.builtin_decl_values.get(to_check) != .none) return;
src/crash_report.zig
@@ -18,18 +18,12 @@ const dev = @import("dev.zig");
/// To use these crash report diagnostics, publish this panic in your main file
/// and add `pub const enable_segfault_handler = false;` to your `std_options`.
/// You will also need to call initialize() on startup, preferably as the very first operation in your program.
-pub const Panic = if (build_options.enable_debug_extensions) struct {
- pub const call = compilerPanic;
- pub const sentinelMismatch = std.debug.FormattedPanic.sentinelMismatch;
- pub const unwrapError = std.debug.FormattedPanic.unwrapError;
- pub const outOfBounds = std.debug.FormattedPanic.outOfBounds;
- pub const startGreaterThanEnd = std.debug.FormattedPanic.startGreaterThanEnd;
- pub const inactiveUnionField = std.debug.FormattedPanic.inactiveUnionField;
- pub const messages = std.debug.FormattedPanic.messages;
-} else if (dev.env == .bootstrap)
- std.debug.SimplePanic
+pub const panic = if (build_options.enable_debug_extensions)
+ std.debug.FullPanic(compilerPanic)
+else if (dev.env == .bootstrap)
+ std.debug.simple_panic
else
- std.debug.FormattedPanic;
+ std.debug.FullPanic(std.debug.defaultPanic);
/// Install signal handlers to identify crashes and report diagnostics.
pub fn initialize() void {
src/main.zig
@@ -56,7 +56,7 @@ pub const std_options: std.Options = .{
},
};
-pub const Panic = crash_report.Panic;
+pub const panic = crash_report.panic;
var wasi_preopens: fs.wasi.Preopens = undefined;
pub fn wasi_cwd() std.os.wasi.fd_t {
src/Sema.zig
@@ -5918,13 +5918,14 @@ fn zirCompileLog(
}
fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
const msg_inst = try sema.resolveInst(inst_data.operand);
- // `panicWithMsg` would perform this coercion for us, but we can get a better
- // source location if we do it here.
- const coerced_msg = try sema.coerce(block, Type.slice_const_u8, msg_inst, block.builtinCallArgSrc(inst_data.src_node, 0));
+ const coerced_msg = try sema.coerce(block, .slice_const_u8, msg_inst, block.builtinCallArgSrc(inst_data.src_node, 0));
if (block.isComptime()) {
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
sema.branch_hint = .cold;
}
- try sema.panicWithMsg(block, src, coerced_msg, .@"@panic");
+ if (!zcu.backendSupportsFeature(.panic_fn)) {
+ _ = try block.addNoOp(.trap);
+ return;
+ }
+
+ try sema.ensureMemoizedStateResolved(src, .panic);
+ try zcu.ensureFuncBodyAnalysisQueued(zcu.builtin_decl_values.get(.@"panic.call"));
+
+ const panic_fn = Air.internedToRef(zcu.builtin_decl_values.get(.@"panic.call"));
+ const null_stack_trace = Air.internedToRef(zcu.null_stack_trace);
+
+ const opt_usize_ty = try pt.optionalType(.usize_type);
+ const null_ret_addr = Air.internedToRef((try pt.intern(.{ .opt = .{
+ .ty = opt_usize_ty.toIntern(),
+ .val = .none,
+ } })));
+ try sema.callBuiltin(block, src, panic_fn, .auto, &.{ coerced_msg, null_stack_trace, null_ret_addr }, .@"@panic");
}
fn zirTrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
@@ -13787,7 +13804,7 @@ fn maybeErrorUnwrap(
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const msg_inst = try sema.resolveInst(inst_data.operand);
- const panic_fn = try getBuiltin(sema, operand_src, .@"Panic.call");
+ const panic_fn = try getBuiltin(sema, operand_src, .@"panic.call");
const err_return_trace = try sema.getErrorReturnTrace(block);
const args: [3]Air.Inst.Ref = .{ msg_inst, err_return_trace, .null_value };
try sema.callBuiltin(block, operand_src, Air.internedToRef(panic_fn), .auto, &args, .@"safety check");
@@ -27083,15 +27100,16 @@ fn explainWhyTypeIsNotPacked(
/// Backends depend on panic decls being available when lowering safety-checked
/// instructions. This function ensures the panic function will be available to
/// be called during that time.
-fn preparePanicId(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.PanicId) !InternPool.Index {
+fn preparePanicId(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) !InternPool.Index {
const zcu = sema.pt.zcu;
try sema.ensureMemoizedStateResolved(src, .panic);
- try zcu.ensureFuncBodyAnalysisQueued(zcu.builtin_decl_values.get(.@"Panic.call"));
+ const panic_func = zcu.builtin_decl_values.get(panic_id.toBuiltin());
+ try zcu.ensureFuncBodyAnalysisQueued(panic_func);
switch (sema.owner.unwrap()) {
.@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},
.func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(owner_func, true),
}
- return zcu.builtin_decl_values.get(panic_id.toBuiltin());
+ return panic_func;
}
fn addSafetyCheck(
@@ -27099,7 +27117,7 @@ fn addSafetyCheck(
parent_block: *Block,
src: LazySrcLoc,
ok: Air.Inst.Ref,
- panic_id: Zcu.PanicId,
+ panic_id: Zcu.SimplePanicId,
) !void {
const gpa = sema.gpa;
assert(!parent_block.isComptime());
@@ -27186,29 +27204,6 @@ fn addSafetyCheckExtra(
parent_block.instructions.appendAssumeCapacity(block_inst);
}
-fn panicWithMsg(sema: *Sema, block: *Block, src: LazySrcLoc, msg_inst: Air.Inst.Ref, operation: CallOperation) !void {
- const pt = sema.pt;
- const zcu = pt.zcu;
-
- if (!zcu.backendSupportsFeature(.panic_fn)) {
- _ = try block.addNoOp(.trap);
- return;
- }
-
- try sema.ensureMemoizedStateResolved(src, .panic);
- try zcu.ensureFuncBodyAnalysisQueued(zcu.builtin_decl_values.get(.@"Panic.call"));
-
- const panic_fn = Air.internedToRef(zcu.builtin_decl_values.get(.@"Panic.call"));
- const null_stack_trace = Air.internedToRef(zcu.null_stack_trace);
-
- const opt_usize_ty = try pt.optionalType(.usize_type);
- const null_ret_addr = Air.internedToRef((try pt.intern(.{ .opt = .{
- .ty = opt_usize_ty.toIntern(),
- .val = .none,
- } })));
- try sema.callBuiltin(block, src, panic_fn, .auto, &.{ msg_inst, null_stack_trace, null_ret_addr }, operation);
-}
-
fn addSafetyCheckUnwrapError(
sema: *Sema,
parent_block: *Block,
@@ -27246,7 +27241,7 @@ fn safetyPanicUnwrapError(sema: *Sema, block: *Block, src: LazySrcLoc, err: Air.
if (!zcu.backendSupportsFeature(.panic_fn)) {
_ = try block.addNoOp(.trap);
} else {
- const panic_fn = try getBuiltin(sema, src, .@"Panic.unwrapError");
+ const panic_fn = try getBuiltin(sema, src, .@"panic.unwrapError");
const err_return_trace = try sema.getErrorReturnTrace(block);
const args: [2]Air.Inst.Ref = .{ err_return_trace, err };
try sema.callBuiltin(block, src, Air.internedToRef(panic_fn), .auto, &args, .@"safety check");
@@ -27263,7 +27258,7 @@ fn addSafetyCheckIndexOob(
) !void {
assert(!parent_block.isComptime());
const ok = try parent_block.addBinOp(cmp_op, index, len);
- return addSafetyCheckCall(sema, parent_block, src, ok, .@"Panic.outOfBounds", &.{ index, len });
+ return addSafetyCheckCall(sema, parent_block, src, ok, .@"panic.outOfBounds", &.{ index, len });
}
fn addSafetyCheckInactiveUnionField(
@@ -27275,7 +27270,7 @@ fn addSafetyCheckInactiveUnionField(
) !void {
assert(!parent_block.isComptime());
const ok = try parent_block.addBinOp(.cmp_eq, active_tag, wanted_tag);
- return addSafetyCheckCall(sema, parent_block, src, ok, .@"Panic.inactiveUnionField", &.{ active_tag, wanted_tag });
+ return addSafetyCheckCall(sema, parent_block, src, ok, .@"panic.inactiveUnionField", &.{ active_tag, wanted_tag });
}
fn addSafetyCheckSentinelMismatch(
@@ -27316,7 +27311,7 @@ fn addSafetyCheckSentinelMismatch(
break :ok try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel);
};
- return addSafetyCheckCall(sema, parent_block, src, ok, .@"Panic.sentinelMismatch", &.{
+ return addSafetyCheckCall(sema, parent_block, src, ok, .@"panic.sentinelMismatch", &.{
expected_sentinel, actual_sentinel,
});
}
@@ -27358,9 +27353,13 @@ fn addSafetyCheckCall(
}
/// This does not set `sema.branch_hint`.
-fn safetyPanic(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.PanicId) CompileError!void {
- const msg_val = try sema.preparePanicId(src, panic_id);
- try sema.panicWithMsg(block, src, Air.internedToRef(msg_val), .@"safety check");
+fn safetyPanic(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) CompileError!void {
+ if (!sema.pt.zcu.backendSupportsFeature(.panic_fn)) {
+ _ = try block.addNoOp(.trap);
+ } else {
+ const panic_fn = try sema.preparePanicId(src, panic_id);
+ try sema.callBuiltin(block, src, Air.internedToRef(panic_fn), .auto, &.{}, .@"safety check");
+ }
}
fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
@@ -32818,7 +32817,7 @@ fn analyzeSlice(
assert(!block.isComptime());
try sema.requireRuntimeBlock(block, src, runtime_src.?);
const ok = try block.addBinOp(.cmp_lte, start, end);
- try sema.addSafetyCheckCall(block, src, ok, .@"Panic.startGreaterThanEnd", &.{ start, end });
+ try sema.addSafetyCheckCall(block, src, ok, .@"panic.startGreaterThanEnd", &.{ start, end });
}
const new_len = if (by_length)
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,
break :val uncoerced_val;
},
.func => val: {
- if (try sema.getExpectedBuiltinFnType(src, builtin_decl)) |func_ty| {
- const coerced = try sema.coerce(block, func_ty, Air.internedToRef(uncoerced_val.toIntern()), src);
- break :val .fromInterned(coerced.toInterned().?);
- }
- if (uncoerced_val.typeOf(zcu).zigTypeTag(zcu) != .@"fn") {
- return sema.fail(block, src, "{s}.{s} is not a function", .{ parent_name, name });
- }
- break :val uncoerced_val;
+ const func_ty = try sema.getExpectedBuiltinFnType(src, builtin_decl);
+ const coerced = try sema.coerce(block, func_ty, Air.internedToRef(uncoerced_val.toIntern()), src);
+ break :val .fromInterned(coerced.toInterned().?);
},
.string => val: {
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,
return any_changed;
}
-/// Given that `decl.kind() == .func`, get the type expected of the function if necessary.
-/// If this will be type checked by `Sema` anyway, this function may return `null`. In
-/// particular, generic functions should return `null`, as `Sema` will necessarily check
-/// them at instantiation time. Returning non-null is necessary only when backends can emit
-/// calls to the function, as is the case with the panic handler.
-fn getExpectedBuiltinFnType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) CompileError!?Type {
+/// Given that `decl.kind() == .func`, get the type expected of the function.
+fn getExpectedBuiltinFnType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) CompileError!Type {
const pt = sema.pt;
return switch (decl) {
+ // `noinline fn () void`
+ .returnError => try pt.funcType(.{
+ .param_types = &.{},
+ .return_type = .void_type,
+ .is_noinline = true,
+ }),
+
// `fn ([]const u8, ?*StackTrace, ?usize) noreturn`
- .@"Panic.call" => try pt.funcType(.{
+ .@"panic.call" => try pt.funcType(.{
.param_types = &.{
.slice_const_u8_type,
(try pt.optionalType(
@@ -38589,8 +38586,17 @@ fn getExpectedBuiltinFnType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl)
.return_type = .noreturn_type,
}),
+ // `fn (anytype, anytype) noreturn`
+ .@"panic.sentinelMismatch",
+ .@"panic.inactiveUnionField",
+ => try pt.funcType(.{
+ .param_types = &.{ .generic_poison_type, .generic_poison_type },
+ .return_type = .noreturn_type,
+ .is_generic = true,
+ }),
+
// `fn (?*StackTrace, anyerror) noreturn`
- .@"Panic.unwrapError" => try pt.funcType(.{
+ .@"panic.unwrapError" => try pt.funcType(.{
.param_types = &.{
(try pt.optionalType(
(try pt.singleMutPtrType(
@@ -38603,21 +38609,38 @@ fn getExpectedBuiltinFnType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl)
}),
// `fn (usize, usize) noreturn`
- .@"Panic.outOfBounds",
- .@"Panic.startGreaterThanEnd",
+ .@"panic.outOfBounds",
+ .@"panic.startGreaterThanEnd",
=> try pt.funcType(.{
.param_types = &.{ .usize_type, .usize_type },
.return_type = .noreturn_type,
}),
- // Generic functions, so calls are necessarily validated by Sema
- .@"Panic.sentinelMismatch",
- .@"Panic.inactiveUnionField",
- => null,
-
- // Other functions called exclusively by Sema
- .returnError,
- => null,
+ // `fn () noreturn`
+ .@"panic.reachedUnreachable",
+ .@"panic.unwrapNull",
+ .@"panic.castToNull",
+ .@"panic.incorrectAlignment",
+ .@"panic.invalidErrorCode",
+ .@"panic.castTruncatedData",
+ .@"panic.negativeToUnsigned",
+ .@"panic.integerOverflow",
+ .@"panic.shlOverflow",
+ .@"panic.shrOverflow",
+ .@"panic.divideByZero",
+ .@"panic.exactDivisionRemainder",
+ .@"panic.integerPartOutOfBounds",
+ .@"panic.corruptSwitch",
+ .@"panic.shiftRhsTooBig",
+ .@"panic.invalidEnumValue",
+ .@"panic.forLenMismatch",
+ .@"panic.memcpyLenMismatch",
+ .@"panic.memcpyAlias",
+ .@"panic.noreturnReturned",
+ => try pt.funcType(.{
+ .param_types = &.{},
+ .return_type = .noreturn_type,
+ }),
else => unreachable,
};
src/Zcu.zig
@@ -269,34 +269,33 @@ pub const BuiltinDecl = enum {
@"Type.Opaque",
@"Type.Declaration",
- Panic,
- @"Panic.call",
- @"Panic.sentinelMismatch",
- @"Panic.unwrapError",
- @"Panic.outOfBounds",
- @"Panic.startGreaterThanEnd",
- @"Panic.inactiveUnionField",
- @"Panic.messages",
- @"Panic.messages.reached_unreachable",
- @"Panic.messages.unwrap_null",
- @"Panic.messages.cast_to_null",
- @"Panic.messages.incorrect_alignment",
- @"Panic.messages.invalid_error_code",
- @"Panic.messages.cast_truncated_data",
- @"Panic.messages.negative_to_unsigned",
- @"Panic.messages.integer_overflow",
- @"Panic.messages.shl_overflow",
- @"Panic.messages.shr_overflow",
- @"Panic.messages.divide_by_zero",
- @"Panic.messages.exact_division_remainder",
- @"Panic.messages.integer_part_out_of_bounds",
- @"Panic.messages.corrupt_switch",
- @"Panic.messages.shift_rhs_too_big",
- @"Panic.messages.invalid_enum_value",
- @"Panic.messages.for_len_mismatch",
- @"Panic.messages.memcpy_len_mismatch",
- @"Panic.messages.memcpy_alias",
- @"Panic.messages.noreturn_returned",
+ panic,
+ @"panic.call",
+ @"panic.sentinelMismatch",
+ @"panic.unwrapError",
+ @"panic.outOfBounds",
+ @"panic.startGreaterThanEnd",
+ @"panic.inactiveUnionField",
+ @"panic.reachedUnreachable",
+ @"panic.unwrapNull",
+ @"panic.castToNull",
+ @"panic.incorrectAlignment",
+ @"panic.invalidErrorCode",
+ @"panic.castTruncatedData",
+ @"panic.negativeToUnsigned",
+ @"panic.integerOverflow",
+ @"panic.shlOverflow",
+ @"panic.shrOverflow",
+ @"panic.divideByZero",
+ @"panic.exactDivisionRemainder",
+ @"panic.integerPartOutOfBounds",
+ @"panic.corruptSwitch",
+ @"panic.shiftRhsTooBig",
+ @"panic.invalidEnumValue",
+ @"panic.forLenMismatch",
+ @"panic.memcpyLenMismatch",
+ @"panic.memcpyAlias",
+ @"panic.noreturnReturned",
VaList,
@@ -345,39 +344,35 @@ pub const BuiltinDecl = enum {
.@"Type.Declaration",
=> .type,
- .Panic => .type,
-
- .@"Panic.call",
- .@"Panic.sentinelMismatch",
- .@"Panic.unwrapError",
- .@"Panic.outOfBounds",
- .@"Panic.startGreaterThanEnd",
- .@"Panic.inactiveUnionField",
+ .panic => .type,
+
+ .@"panic.call",
+ .@"panic.sentinelMismatch",
+ .@"panic.unwrapError",
+ .@"panic.outOfBounds",
+ .@"panic.startGreaterThanEnd",
+ .@"panic.inactiveUnionField",
+ .@"panic.reachedUnreachable",
+ .@"panic.unwrapNull",
+ .@"panic.castToNull",
+ .@"panic.incorrectAlignment",
+ .@"panic.invalidErrorCode",
+ .@"panic.castTruncatedData",
+ .@"panic.negativeToUnsigned",
+ .@"panic.integerOverflow",
+ .@"panic.shlOverflow",
+ .@"panic.shrOverflow",
+ .@"panic.divideByZero",
+ .@"panic.exactDivisionRemainder",
+ .@"panic.integerPartOutOfBounds",
+ .@"panic.corruptSwitch",
+ .@"panic.shiftRhsTooBig",
+ .@"panic.invalidEnumValue",
+ .@"panic.forLenMismatch",
+ .@"panic.memcpyLenMismatch",
+ .@"panic.memcpyAlias",
+ .@"panic.noreturnReturned",
=> .func,
-
- .@"Panic.messages" => .type,
-
- .@"Panic.messages.reached_unreachable",
- .@"Panic.messages.unwrap_null",
- .@"Panic.messages.cast_to_null",
- .@"Panic.messages.incorrect_alignment",
- .@"Panic.messages.invalid_error_code",
- .@"Panic.messages.cast_truncated_data",
- .@"Panic.messages.negative_to_unsigned",
- .@"Panic.messages.integer_overflow",
- .@"Panic.messages.shl_overflow",
- .@"Panic.messages.shr_overflow",
- .@"Panic.messages.divide_by_zero",
- .@"Panic.messages.exact_division_remainder",
- .@"Panic.messages.integer_part_out_of_bounds",
- .@"Panic.messages.corrupt_switch",
- .@"Panic.messages.shift_rhs_too_big",
- .@"Panic.messages.invalid_enum_value",
- .@"Panic.messages.for_len_mismatch",
- .@"Panic.messages.memcpy_len_mismatch",
- .@"Panic.messages.memcpy_alias",
- .@"Panic.messages.noreturn_returned",
- => .string,
};
}
@@ -423,7 +418,7 @@ pub const BuiltinDecl = enum {
const Memoized = std.enums.EnumArray(BuiltinDecl, InternPool.Index);
};
-pub const PanicId = enum {
+pub const SimplePanicId = enum {
reached_unreachable,
unwrap_null,
cast_to_null,
@@ -445,19 +440,31 @@ pub const PanicId = enum {
memcpy_alias,
noreturn_returned,
- pub fn toBuiltin(id: PanicId) BuiltinDecl {
- const first_msg: PanicId = @enumFromInt(0);
- const first_decl = @field(BuiltinDecl, "Panic.messages." ++ @tagName(first_msg));
- comptime {
- // Ensure that the messages are ordered the same in `BuiltinDecl` as they are here.
- for (@typeInfo(PanicId).@"enum".fields) |panic_field| {
- const expect_name = "Panic.messages." ++ panic_field.name;
- const expect_idx = @intFromEnum(first_decl) + panic_field.value;
- const actual_idx = @intFromEnum(@field(BuiltinDecl, expect_name));
- assert(expect_idx == actual_idx);
- }
- }
- return @enumFromInt(@intFromEnum(first_decl) + @intFromEnum(id));
+ pub fn toBuiltin(id: SimplePanicId) BuiltinDecl {
+ return switch (id) {
+ // zig fmt: off
+ .reached_unreachable => .@"panic.reachedUnreachable",
+ .unwrap_null => .@"panic.unwrapNull",
+ .cast_to_null => .@"panic.castToNull",
+ .incorrect_alignment => .@"panic.incorrectAlignment",
+ .invalid_error_code => .@"panic.invalidErrorCode",
+ .cast_truncated_data => .@"panic.castTruncatedData",
+ .negative_to_unsigned => .@"panic.negativeToUnsigned",
+ .integer_overflow => .@"panic.integerOverflow",
+ .shl_overflow => .@"panic.shlOverflow",
+ .shr_overflow => .@"panic.shrOverflow",
+ .divide_by_zero => .@"panic.divideByZero",
+ .exact_division_remainder => .@"panic.exactDivisionRemainder",
+ .integer_part_out_of_bounds => .@"panic.integerPartOutOfBounds",
+ .corrupt_switch => .@"panic.corruptSwitch",
+ .shift_rhs_too_big => .@"panic.shiftRhsTooBig",
+ .invalid_enum_value => .@"panic.invalidEnumValue",
+ .for_len_mismatch => .@"panic.forLenMismatch",
+ .memcpy_len_mismatch => .@"panic.memcpyLenMismatch",
+ .memcpy_alias => .@"panic.memcpyAlias",
+ .noreturn_returned => .@"panic.noreturnReturned",
+ // zig fmt: on
+ };
}
};
test/cases/compile_errors/bad_panic_call_signature.zig
@@ -0,0 +1,46 @@
+const simple_panic = std.debug.simple_panic;
+pub const panic = struct {
+ pub fn call(msg: []const u8, bad1: usize, bad2: void) noreturn {
+ _ = msg;
+ _ = bad1;
+ _ = bad2;
+ @trap();
+ }
+ pub const sentinelMismatch = simple_panic.sentinelMismatch;
+ pub const unwrapError = simple_panic.unwrapError;
+ pub const outOfBounds = simple_panic.outOfBounds;
+ pub const startGreaterThanEnd = simple_panic.startGreaterThanEnd;
+ pub const inactiveUnionField = simple_panic.inactiveUnionField;
+ pub const reachedUnreachable = simple_panic.reachedUnreachable;
+ pub const unwrapNull = simple_panic.unwrapNull;
+ pub const castToNull = simple_panic.castToNull;
+ pub const incorrectAlignment = simple_panic.incorrectAlignment;
+ pub const invalidErrorCode = simple_panic.invalidErrorCode;
+ pub const castTruncatedData = simple_panic.castTruncatedData;
+ pub const negativeToUnsigned = simple_panic.negativeToUnsigned;
+ pub const integerOverflow = simple_panic.integerOverflow;
+ pub const shlOverflow = simple_panic.shlOverflow;
+ pub const shrOverflow = simple_panic.shrOverflow;
+ pub const divideByZero = simple_panic.divideByZero;
+ pub const exactDivisionRemainder = simple_panic.exactDivisionRemainder;
+ pub const integerPartOutOfBounds = simple_panic.integerPartOutOfBounds;
+ pub const corruptSwitch = simple_panic.corruptSwitch;
+ pub const shiftRhsTooBig = simple_panic.shiftRhsTooBig;
+ pub const invalidEnumValue = simple_panic.invalidEnumValue;
+ pub const forLenMismatch = simple_panic.forLenMismatch;
+ pub const memcpyLenMismatch = simple_panic.memcpyLenMismatch;
+ pub const memcpyAlias = simple_panic.memcpyAlias;
+ pub const noreturnReturned = simple_panic.noreturnReturned;
+};
+
+export fn foo(a: u8) void {
+ @setRuntimeSafety(true);
+ _ = a + 1; // safety check to reference the panic handler
+}
+
+const std = @import("std");
+
+// error
+//
+// :3:9: error: expected type 'fn ([]const u8, ?*builtin.StackTrace, ?usize) noreturn', found 'fn ([]const u8, usize, void) noreturn'
+// :3:9: note: parameter 1 'usize' cannot cast into '?*builtin.StackTrace'
test/cases/compile_errors/bad_panic_generic_signature.zig
@@ -0,0 +1,41 @@
+const simple_panic = std.debug.simple_panic;
+pub const panic = struct {
+ pub fn sentinelMismatch() void {} // invalid
+ pub const call = simple_panic.call;
+ pub const unwrapError = simple_panic.unwrapError;
+ pub const outOfBounds = simple_panic.outOfBounds;
+ pub const startGreaterThanEnd = simple_panic.startGreaterThanEnd;
+ pub const inactiveUnionField = simple_panic.inactiveUnionField;
+ pub const reachedUnreachable = simple_panic.reachedUnreachable;
+ pub const unwrapNull = simple_panic.unwrapNull;
+ pub const castToNull = simple_panic.castToNull;
+ pub const incorrectAlignment = simple_panic.incorrectAlignment;
+ pub const invalidErrorCode = simple_panic.invalidErrorCode;
+ pub const castTruncatedData = simple_panic.castTruncatedData;
+ pub const negativeToUnsigned = simple_panic.negativeToUnsigned;
+ pub const integerOverflow = simple_panic.integerOverflow;
+ pub const shlOverflow = simple_panic.shlOverflow;
+ pub const shrOverflow = simple_panic.shrOverflow;
+ pub const divideByZero = simple_panic.divideByZero;
+ pub const exactDivisionRemainder = simple_panic.exactDivisionRemainder;
+ pub const integerPartOutOfBounds = simple_panic.integerPartOutOfBounds;
+ pub const corruptSwitch = simple_panic.corruptSwitch;
+ pub const shiftRhsTooBig = simple_panic.shiftRhsTooBig;
+ pub const invalidEnumValue = simple_panic.invalidEnumValue;
+ pub const forLenMismatch = simple_panic.forLenMismatch;
+ pub const memcpyLenMismatch = simple_panic.memcpyLenMismatch;
+ pub const memcpyAlias = simple_panic.memcpyAlias;
+ pub const noreturnReturned = simple_panic.noreturnReturned;
+};
+
+export fn foo(arr: *const [2]u8) void {
+ @setRuntimeSafety(true);
+ _ = arr[0..1 :0];
+}
+
+const std = @import("std");
+
+// error
+//
+// :3:9: error: expected type 'fn (anytype, anytype) noreturn', found 'fn () void'
+// :3:9: note: non-generic function cannot cast into a generic function
test/cases/compile_errors/bad_panic_signature.zig
@@ -1,28 +0,0 @@
-pub const Panic = struct {
- pub const call = badPanicSignature;
- pub const sentinelMismatch = std.debug.FormattedPanic.sentinelMismatch;
- pub const unwrapError = std.debug.FormattedPanic.unwrapError;
- pub const outOfBounds = std.debug.FormattedPanic.outOfBounds;
- pub const startGreaterThanEnd = std.debug.FormattedPanic.startGreaterThanEnd;
- pub const inactiveUnionField = std.debug.FormattedPanic.inactiveUnionField;
- pub const messages = std.debug.FormattedPanic.messages;
-};
-
-fn badPanicSignature(msg: []const u8, bad1: usize, bad2: void) noreturn {
- _ = msg;
- _ = bad1;
- _ = bad2;
- @trap();
-}
-
-export fn foo(a: u8) void {
- @setRuntimeSafety(true);
- _ = a + 1; // safety check to reference the panic handler
-}
-
-const std = @import("std");
-
-// error
-//
-// :2:9: error: expected type 'fn ([]const u8, ?*builtin.StackTrace, ?usize) noreturn', found 'fn ([]const u8, usize, void) noreturn'
-// :2:9: note: parameter 1 'usize' cannot cast into '?*builtin.StackTrace'
test/incremental/change_panic_handler
@@ -9,15 +9,7 @@ pub fn main() !u8 {
_ = a + 1;
return 1;
}
-pub const Panic = struct {
- pub const call = myPanic;
- pub const sentinelMismatch = std.debug.FormattedPanic.sentinelMismatch;
- pub const unwrapError = std.debug.FormattedPanic.unwrapError;
- pub const outOfBounds = std.debug.FormattedPanic.outOfBounds;
- pub const startGreaterThanEnd = std.debug.FormattedPanic.startGreaterThanEnd;
- pub const inactiveUnionField = std.debug.FormattedPanic.inactiveUnionField;
- pub const messages = std.debug.FormattedPanic.messages;
-};
+pub const panic = std.debug.FullPanic(myPanic);
fn myPanic(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
std.io.getStdOut().writer().print("panic message: {s}\n", .{msg}) catch {};
std.process.exit(0);
@@ -33,15 +25,7 @@ pub fn main() !u8 {
_ = a + 1;
return 1;
}
-pub const Panic = struct {
- pub const call = myPanic;
- pub const sentinelMismatch = std.debug.FormattedPanic.sentinelMismatch;
- pub const unwrapError = std.debug.FormattedPanic.unwrapError;
- pub const outOfBounds = std.debug.FormattedPanic.outOfBounds;
- pub const startGreaterThanEnd = std.debug.FormattedPanic.startGreaterThanEnd;
- pub const inactiveUnionField = std.debug.FormattedPanic.inactiveUnionField;
- pub const messages = std.debug.FormattedPanic.messages;
-};
+pub const panic = std.debug.FullPanic(myPanic);
fn myPanic(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
std.io.getStdOut().writer().print("new panic message: {s}\n", .{msg}) catch {};
std.process.exit(0);
@@ -57,15 +41,7 @@ pub fn main() !u8 {
_ = a + 1;
return 1;
}
-pub const Panic = struct {
- pub const call = myPanicNew;
- pub const sentinelMismatch = std.debug.FormattedPanic.sentinelMismatch;
- pub const unwrapError = std.debug.FormattedPanic.unwrapError;
- pub const outOfBounds = std.debug.FormattedPanic.outOfBounds;
- pub const startGreaterThanEnd = std.debug.FormattedPanic.startGreaterThanEnd;
- pub const inactiveUnionField = std.debug.FormattedPanic.inactiveUnionField;
- pub const messages = std.debug.FormattedPanic.messages;
-};
+pub const panic = std.debug.FullPanic(myPanicNew);
fn myPanicNew(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
std.io.getStdOut().writer().print("third panic message: {s}\n", .{msg}) catch {};
std.process.exit(0);
test/incremental/change_panic_handler_explicit
@@ -0,0 +1,141 @@
+#target=x86_64-linux-selfhosted
+#target=x86_64-linux-cbe
+#target=x86_64-windows-cbe
+#update=initial version
+#file=main.zig
+pub fn main() !u8 {
+ var a: u8 = undefined;
+ a = 255;
+ _ = a + 1;
+ return 1;
+}
+const no_panic = std.debug.no_panic;
+pub const panic = struct {
+ pub const call = myPanic;
+ pub fn integerOverflow() noreturn {
+ @panic("integer overflow");
+ }
+ pub const sentinelMismatch = no_panic.sentinelMismatch;
+ pub const unwrapError = no_panic.unwrapError;
+ pub const outOfBounds = no_panic.outOfBounds;
+ pub const startGreaterThanEnd = no_panic.startGreaterThanEnd;
+ pub const inactiveUnionField = no_panic.inactiveUnionField;
+ pub const reachedUnreachable = no_panic.reachedUnreachable;
+ pub const unwrapNull = no_panic.unwrapNull;
+ pub const castToNull = no_panic.castToNull;
+ pub const incorrectAlignment = no_panic.incorrectAlignment;
+ pub const invalidErrorCode = no_panic.invalidErrorCode;
+ pub const castTruncatedData = no_panic.castTruncatedData;
+ pub const negativeToUnsigned = no_panic.negativeToUnsigned;
+ pub const shlOverflow = no_panic.shlOverflow;
+ pub const shrOverflow = no_panic.shrOverflow;
+ pub const divideByZero = no_panic.divideByZero;
+ pub const exactDivisionRemainder = no_panic.exactDivisionRemainder;
+ pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds;
+ pub const corruptSwitch = no_panic.corruptSwitch;
+ pub const shiftRhsTooBig = no_panic.shiftRhsTooBig;
+ pub const invalidEnumValue = no_panic.invalidEnumValue;
+ pub const forLenMismatch = no_panic.forLenMismatch;
+ pub const memcpyLenMismatch = no_panic.memcpyLenMismatch;
+ pub const memcpyAlias = no_panic.memcpyAlias;
+ pub const noreturnReturned = no_panic.noreturnReturned;
+};
+fn myPanic(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
+ std.io.getStdOut().writer().print("panic message: {s}\n", .{msg}) catch {};
+ std.process.exit(0);
+}
+const std = @import("std");
+#expect_stdout="panic message: integer overflow\n"
+
+#update=change the panic handler body
+#file=main.zig
+pub fn main() !u8 {
+ var a: u8 = undefined;
+ a = 255;
+ _ = a + 1;
+ return 1;
+}
+const no_panic = std.debug.no_panic;
+pub const panic = struct {
+ pub const call = myPanic;
+ pub fn integerOverflow() noreturn {
+ @panic("integer overflow");
+ }
+ pub const sentinelMismatch = no_panic.sentinelMismatch;
+ pub const unwrapError = no_panic.unwrapError;
+ pub const outOfBounds = no_panic.outOfBounds;
+ pub const startGreaterThanEnd = no_panic.startGreaterThanEnd;
+ pub const inactiveUnionField = no_panic.inactiveUnionField;
+ pub const reachedUnreachable = no_panic.reachedUnreachable;
+ pub const unwrapNull = no_panic.unwrapNull;
+ pub const castToNull = no_panic.castToNull;
+ pub const incorrectAlignment = no_panic.incorrectAlignment;
+ pub const invalidErrorCode = no_panic.invalidErrorCode;
+ pub const castTruncatedData = no_panic.castTruncatedData;
+ pub const negativeToUnsigned = no_panic.negativeToUnsigned;
+ pub const shlOverflow = no_panic.shlOverflow;
+ pub const shrOverflow = no_panic.shrOverflow;
+ pub const divideByZero = no_panic.divideByZero;
+ pub const exactDivisionRemainder = no_panic.exactDivisionRemainder;
+ pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds;
+ pub const corruptSwitch = no_panic.corruptSwitch;
+ pub const shiftRhsTooBig = no_panic.shiftRhsTooBig;
+ pub const invalidEnumValue = no_panic.invalidEnumValue;
+ pub const forLenMismatch = no_panic.forLenMismatch;
+ pub const memcpyLenMismatch = no_panic.memcpyLenMismatch;
+ pub const memcpyAlias = no_panic.memcpyAlias;
+ pub const noreturnReturned = no_panic.noreturnReturned;
+};
+fn myPanic(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
+ std.io.getStdOut().writer().print("new panic message: {s}\n", .{msg}) catch {};
+ std.process.exit(0);
+}
+const std = @import("std");
+#expect_stdout="new panic message: integer overflow\n"
+
+#update=change the panic handler function value
+#file=main.zig
+pub fn main() !u8 {
+ var a: u8 = undefined;
+ a = 255;
+ _ = a + 1;
+ return 1;
+}
+const no_panic = std.debug.no_panic;
+pub const panic = struct {
+ pub const call = myPanicNew;
+ pub fn integerOverflow() noreturn {
+ @panic("integer overflow");
+ }
+ pub const sentinelMismatch = std.debug.no_panic.sentinelMismatch;
+ pub const unwrapError = std.debug.no_panic.unwrapError;
+ pub const outOfBounds = std.debug.no_panic.outOfBounds;
+ pub const startGreaterThanEnd = std.debug.no_panic.startGreaterThanEnd;
+ pub const inactiveUnionField = std.debug.no_panic.inactiveUnionField;
+ pub const messages = std.debug.no_panic.messages;
+ pub const reachedUnreachable = no_panic.reachedUnreachable;
+ pub const unwrapNull = no_panic.unwrapNull;
+ pub const castToNull = no_panic.castToNull;
+ pub const incorrectAlignment = no_panic.incorrectAlignment;
+ pub const invalidErrorCode = no_panic.invalidErrorCode;
+ pub const castTruncatedData = no_panic.castTruncatedData;
+ pub const negativeToUnsigned = no_panic.negativeToUnsigned;
+ pub const shlOverflow = no_panic.shlOverflow;
+ pub const shrOverflow = no_panic.shrOverflow;
+ pub const divideByZero = no_panic.divideByZero;
+ pub const exactDivisionRemainder = no_panic.exactDivisionRemainder;
+ pub const integerPartOutOfBounds = no_panic.integerPartOutOfBounds;
+ pub const corruptSwitch = no_panic.corruptSwitch;
+ pub const shiftRhsTooBig = no_panic.shiftRhsTooBig;
+ pub const invalidEnumValue = no_panic.invalidEnumValue;
+ pub const forLenMismatch = no_panic.forLenMismatch;
+ pub const memcpyLenMismatch = no_panic.memcpyLenMismatch;
+ pub const memcpyAlias = no_panic.memcpyAlias;
+ pub const noreturnReturned = no_panic.noreturnReturned;
+};
+fn myPanicNew(msg: []const u8, _: ?*std.builtin.StackTrace, _: ?usize) noreturn {
+ std.io.getStdOut().writer().print("third panic message: {s}\n", .{msg}) catch {};
+ std.process.exit(0);
+}
+const std = @import("std");
+#expect_stdout="third panic message: integer overflow\n"