compiler: yet more panic handler changes

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

Also, add some missing type checks to Sema.

Resolves: #22584

formatted -> full
This commit is contained in:
mlugg 2025-01-24 02:19:28 +00:00
parent b3d9b0e3f6
commit 83991efe10
No known key found for this signature in database
GPG Key ID: 3F5B7DCCBF4AF02E
19 changed files with 792 additions and 410 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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.

View File

@ -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;

View File

@ -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 = "";
};

160
lib/std/debug/no_panic.zig Normal file
View File

@ -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 = "";
};

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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,
};

View File

@ -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 => .type,
.@"Panic.call",
.@"Panic.sentinelMismatch",
.@"Panic.unwrapError",
.@"Panic.outOfBounds",
.@"Panic.startGreaterThanEnd",
.@"Panic.inactiveUnionField",
.@"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
};
}
};

View File

@ -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;

View File

@ -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"();

View File

@ -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 {

View File

@ -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 {

View File

@ -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'

View File

@ -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

View File

@ -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'

View File

@ -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);

View File

@ -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"