From 4f8d244e7ea47a8cdb41496d51961ef4ba3ec2af Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 25 Sep 2024 11:11:48 -0700 Subject: [PATCH] remove formatted panics implements #17969 --- lib/compiler_rt/common.zig | 6 +- lib/std/builtin.zig | 211 +++------- lib/std/debug.zig | 292 ++++++++++--- lib/std/fmt.zig | 12 +- src/Compilation.zig | 8 - src/InternPool.zig | 34 +- src/Sema.zig | 658 ++++++++++++------------------ src/Sema/bitcast.zig | 12 +- src/Type.zig | 4 +- src/Value.zig | 12 +- src/Zcu.zig | 40 +- src/Zcu/PerThread.zig | 12 +- src/crash_report.zig | 48 ++- src/main.zig | 8 +- src/mutable_value.zig | 4 +- src/target.zig | 8 - test/cases/safety/unreachable.zig | 3 +- 17 files changed, 631 insertions(+), 741 deletions(-) diff --git a/lib/compiler_rt/common.zig b/lib/compiler_rt/common.zig index a6fd953379..8a1055267d 100644 --- a/lib/compiler_rt/common.zig +++ b/lib/compiler_rt/common.zig @@ -77,11 +77,9 @@ pub const want_sparc_abi = builtin.cpu.arch.isSPARC(); // Avoid dragging in the runtime safety mechanisms into this .o file, // unless we're trying to test compiler-rt. -pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { - _ = error_return_trace; +pub fn panic(cause: std.builtin.PanicCause, error_return_trace: ?*std.builtin.StackTrace, ret_addr: ?usize) noreturn { if (builtin.is_test) { - @branchHint(.cold); - std.debug.panic("{s}", .{msg}); + std.debug.defaultPanic(cause, error_return_trace, ret_addr orelse @returnAddress()); } else { unreachable; } diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index abbdf89c0a..8530a64fed 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -763,181 +763,66 @@ pub const TestFn = struct { /// This function type is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. -pub const PanicFn = fn ([]const u8, ?*StackTrace, ?usize) noreturn; +pub const PanicFn = fn (PanicCause, ?*StackTrace, ?usize) noreturn; -/// This function is used by the Zig language code generation and -/// therefore must be kept in sync with the compiler implementation. +/// The entry point for auto-generated calls by the compiler. pub const panic: PanicFn = if (@hasDecl(root, "panic")) root.panic else if (@hasDecl(root, "os") and @hasDecl(root.os, "panic")) root.os.panic else - default_panic; + std.debug.defaultPanic; -/// This function is used by the Zig language code generation and +/// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. -pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr: ?usize) noreturn { - @branchHint(.cold); +pub const PanicCause = union(enum) { + reached_unreachable, + unwrap_null, + cast_to_null, + incorrect_alignment, + invalid_error_code, + cast_truncated_data, + negative_to_unsigned, + integer_overflow, + shl_overflow, + shr_overflow, + divide_by_zero, + exact_division_remainder, + inactive_union_field: InactiveUnionField, + integer_part_out_of_bounds, + corrupt_switch, + shift_rhs_too_big, + invalid_enum_value, + sentinel_mismatch_usize: SentinelMismatchUsize, + sentinel_mismatch_other, + unwrap_error: anyerror, + index_out_of_bounds: IndexOutOfBounds, + start_index_greater_than_end: StartIndexGreaterThanEnd, + for_len_mismatch, + memcpy_len_mismatch, + memcpy_alias, + noreturn_returned, + explicit_call: []const u8, - // For backends that cannot handle the language features depended on by the - // default panic handler, we have a simpler panic handler: - if (builtin.zig_backend == .stage2_wasm or - builtin.zig_backend == .stage2_arm or - builtin.zig_backend == .stage2_aarch64 or - builtin.zig_backend == .stage2_x86 or - (builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf and builtin.target.ofmt != .macho)) or - builtin.zig_backend == .stage2_sparc64 or - builtin.zig_backend == .stage2_spirv64) - { - while (true) { - @breakpoint(); - } - } + pub const IndexOutOfBounds = struct { + index: usize, + len: usize, + }; - if (builtin.zig_backend == .stage2_riscv64) { - std.debug.print("panic: {s}\n", .{msg}); - @breakpoint(); - std.posix.exit(127); - } + pub const StartIndexGreaterThanEnd = struct { + start: usize, + end: usize, + }; - switch (builtin.os.tag) { - .freestanding => { - while (true) { - @breakpoint(); - } - }, - .wasi => { - std.debug.print("{s}", .{msg}); - std.posix.abort(); - }, - .uefi => { - const uefi = std.os.uefi; + pub const SentinelMismatchUsize = struct { + expected: usize, + found: usize, + }; - const Formatter = struct { - pub fn fmt(exit_msg: []const u8, out: []u16) ![:0]u16 { - var u8_buf: [256]u8 = undefined; - const slice = try std.fmt.bufPrint(&u8_buf, "err: {s}\r\n", .{exit_msg}); - // We pass len - 1 because we need to add a null terminator after - const len = try std.unicode.utf8ToUtf16Le(out[0 .. out.len - 1], slice); - - out[len] = 0; - - return out[0..len :0]; - } - }; - - const ExitData = struct { - pub fn create_exit_data(exit_msg: [:0]u16, exit_size: *usize) ![*:0]u16 { - // Need boot services for pool allocation - if (uefi.system_table.boot_services == null) { - return error.BootServicesUnavailable; - } - - // ExitData buffer must be allocated using boot_services.allocatePool (spec: page 220) - const exit_data: []u16 = try uefi.raw_pool_allocator.alloc(u16, exit_msg.len + 1); - - @memcpy(exit_data[0 .. exit_msg.len + 1], exit_msg[0 .. exit_msg.len + 1]); - exit_size.* = exit_msg.len + 1; - - return @as([*:0]u16, @ptrCast(exit_data.ptr)); - } - }; - - var buf: [256]u16 = undefined; - const utf16 = Formatter.fmt(msg, &buf) catch null; - - var exit_size: usize = 0; - const exit_data = if (utf16) |u| - ExitData.create_exit_data(u, &exit_size) catch null - else - null; - - if (utf16) |str| { - // Output to both std_err and con_out, as std_err is easier - // to read in stuff like QEMU at times, but, unlike con_out, - // isn't visible on actual hardware if directly booted into - inline for ([_]?*uefi.protocol.SimpleTextOutput{ uefi.system_table.std_err, uefi.system_table.con_out }) |o| { - if (o) |out| { - _ = out.setAttribute(uefi.protocol.SimpleTextOutput.red); - _ = out.outputString(str); - _ = out.setAttribute(uefi.protocol.SimpleTextOutput.white); - } - } - } - - if (uefi.system_table.boot_services) |bs| { - _ = bs.exit(uefi.handle, .Aborted, exit_size, exit_data); - } - - // Didn't have boot_services, just fallback to whatever. - std.posix.abort(); - }, - .cuda, .amdhsa => std.posix.abort(), - .plan9 => { - var status: [std.os.plan9.ERRMAX]u8 = undefined; - const len = @min(msg.len, status.len - 1); - @memcpy(status[0..len], msg[0..len]); - status[len] = 0; - std.os.plan9.exits(status[0..len :0]); - }, - else => { - const first_trace_addr = ret_addr orelse @returnAddress(); - std.debug.panicImpl(error_return_trace, first_trace_addr, msg); - }, - } -} - -pub fn panicSentinelMismatch(expected: anytype, actual: @TypeOf(expected)) noreturn { - @branchHint(.cold); - std.debug.panicExtra(null, @returnAddress(), "sentinel mismatch: expected {any}, found {any}", .{ expected, actual }); -} - -pub fn panicUnwrapError(st: ?*StackTrace, err: anyerror) noreturn { - @branchHint(.cold); - std.debug.panicExtra(st, @returnAddress(), "attempt to unwrap error: {s}", .{@errorName(err)}); -} - -pub fn panicOutOfBounds(index: usize, len: usize) noreturn { - @branchHint(.cold); - std.debug.panicExtra(null, @returnAddress(), "index out of bounds: index {d}, len {d}", .{ index, len }); -} - -pub fn panicStartGreaterThanEnd(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 panicInactiveUnionField(active: anytype, wanted: @TypeOf(active)) noreturn { - @branchHint(.cold); - std.debug.panicExtra(null, @returnAddress(), "access of union field '{s}' while field '{s}' is active", .{ @tagName(wanted), @tagName(active) }); -} - -pub const panic_messages = struct { - pub const unreach = "reached unreachable code"; - pub const unwrap_null = "attempt to use null value"; - pub const cast_to_null = "cast causes pointer to be null"; - pub const incorrect_alignment = "incorrect alignment"; - pub const invalid_error_code = "invalid error code"; - pub const cast_truncated_data = "integer cast truncated bits"; - pub const negative_to_unsigned = "attempt to cast negative value to unsigned integer"; - pub const integer_overflow = "integer overflow"; - pub const shl_overflow = "left shift overflowed bits"; - pub const shr_overflow = "right shift overflowed bits"; - pub const divide_by_zero = "division by zero"; - pub const exact_division_remainder = "exact division produced remainder"; - pub const inactive_union_field = "access of inactive union field"; - pub const integer_part_out_of_bounds = "integer part of floating point value out of bounds"; - pub const corrupt_switch = "switch on corrupt value"; - pub const shift_rhs_too_big = "shift amount is greater than the type size"; - pub const invalid_enum_value = "invalid enum value"; - pub const sentinel_mismatch = "sentinel mismatch"; - pub const unwrap_error = "attempt to unwrap error"; - pub const index_out_of_bounds = "index out of bounds"; - pub const start_index_greater_than_end = "start index is larger than end index"; - pub const for_len_mismatch = "for loop over objects with non-equal lengths"; - 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"; + pub const InactiveUnionField = struct { + active: []const u8, + accessed: []const u8, + }; }; pub noinline fn returnError(st: *StackTrace) void { diff --git a/lib/std/debug.zig b/lib/std/debug.zig index fd6676504f..8e5498b3f5 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -408,14 +408,15 @@ pub fn assertReadable(slice: []const volatile u8) void { for (slice) |*byte| _ = byte.*; } +/// Equivalent to `@panic` but with a formatted message. pub fn panic(comptime format: []const u8, args: anytype) noreturn { @branchHint(.cold); panicExtra(@errorReturnTrace(), @returnAddress(), format, args); } -/// `panicExtra` is useful when you want to print out an `@errorReturnTrace` -/// and also print out some values. +/// Equivalent to `@panic` but with a formatted message, and with an explicitly +/// provided `@errorReturnTrace` and return address. pub fn panicExtra( trace: ?*std.builtin.StackTrace, ret_addr: ?usize, @@ -447,11 +448,104 @@ var panicking = std.atomic.Value(u8).init(0); /// This is used to catch and handle panics triggered by the panic handler. threadlocal var panic_stage: usize = 0; -// `panicImpl` could be useful in implementing a custom panic handler which -// calls the default handler (on supported platforms) -pub fn panicImpl(trace: ?*const std.builtin.StackTrace, first_trace_addr: ?usize, msg: []const u8) noreturn { +// Dumps a stack trace to standard error, then aborts. +// +// This function avoids a dependency on formatted printing. +pub fn defaultPanic( + cause: std.builtin.PanicCause, + trace: ?*const std.builtin.StackTrace, + first_trace_addr: ?usize, +) noreturn { @branchHint(.cold); + // For backends that cannot handle the language features depended on by the + // default panic handler, we have a simpler panic handler: + if (builtin.zig_backend == .stage2_wasm or + builtin.zig_backend == .stage2_arm or + builtin.zig_backend == .stage2_aarch64 or + builtin.zig_backend == .stage2_x86 or + (builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf and builtin.target.ofmt != .macho)) or + builtin.zig_backend == .stage2_sparc64 or + builtin.zig_backend == .stage2_spirv64) + { + @trap(); + } + + if (builtin.zig_backend == .stage2_riscv64) { + var buffer: [1000]u8 = undefined; + var i: usize = 0; + i += fmtPanicCause(buffer[i..], cause); + buffer[i] = '\n'; + i += 1; + const msg = buffer[0..i]; + lockStdErr(); + io.getStdErr().writeAll(msg) catch {}; + @trap(); + } + + switch (builtin.os.tag) { + .freestanding => { + @trap(); + }, + .wasi => { + // TODO: before merging my branch, unify this logic with the main panic logic + var buffer: [1000]u8 = undefined; + var i: usize = 0; + i += fmtPanicCause(buffer[i..], cause); + buffer[i] = '\n'; + i += 1; + const msg = buffer[0..i]; + lockStdErr(); + io.getStdErr().writeAll(msg) catch {}; + @trap(); + }, + .uefi => { + const uefi = std.os.uefi; + + var buffer: [1000]u8 = undefined; + var i: usize = 0; + i += fmtBuf(buffer[i..], "panic: "); + i += fmtPanicCause(buffer[i..], cause); + i += fmtBuf(buffer[i..], "\r\n\x00"); + + var utf16_buffer: [1000]u16 = undefined; + const len = std.unicode.utf8ToUtf16Le(&utf16_buffer, buffer[0..i]) catch 0; + const exit_msg = utf16_buffer[0 .. len - 1 :0]; + + // Output to both std_err and con_out, as std_err is easier + // to read in stuff like QEMU at times, but, unlike con_out, + // isn't visible on actual hardware if directly booted into + inline for ([_]?*uefi.protocol.SimpleTextOutput{ uefi.system_table.std_err, uefi.system_table.con_out }) |o| { + if (o) |out| { + _ = out.setAttribute(uefi.protocol.SimpleTextOutput.red); + _ = out.outputString(exit_msg); + _ = out.setAttribute(uefi.protocol.SimpleTextOutput.white); + } + } + + if (uefi.system_table.boot_services) |bs| { + // ExitData buffer must be allocated using boot_services.allocatePool (spec: page 220) + const exit_data: []u16 = uefi.raw_pool_allocator.alloc(u16, exit_msg.len + 1) catch @trap(); + @memcpy(exit_data, exit_msg[0..exit_data.len]); // Includes null terminator. + _ = bs.exit(uefi.handle, .Aborted, exit_msg.len + 1, exit_data); + } + @trap(); + }, + .cuda, .amdhsa => std.posix.abort(), + .plan9 => { + var buffer: [1000]u8 = undefined; + comptime assert(buffer.len > std.os.plan9.ERRMAX); + var i: usize = 0; + i += fmtPanicCause(buffer[i..], cause); + buffer[i] = '\n'; + i += 1; + const len = @min(i, std.os.plan9.ERRMAX - 1); + buffer[len] = 0; + std.os.plan9.exits(buffer[0..len :0]); + }, + else => {}, + } + if (enable_segfault_handler) { // If a segfault happens while panicking, we want it to actually segfault, not trigger // the handler. @@ -465,23 +559,29 @@ pub fn panicImpl(trace: ?*const std.builtin.StackTrace, first_trace_addr: ?usize _ = panicking.fetchAdd(1, .seq_cst); - // Make sure to release the mutex when done { + // This code avoids a dependency on formatted printing, the writer interface, + // and limits to only 1 syscall made to print the panic message to stderr. + var buffer: [0x1000]u8 = undefined; + var i: usize = 0; + if (builtin.single_threaded) { + i += fmtBuf(buffer[i..], "panic: "); + } else { + i += fmtBuf(buffer[i..], "thread "); + i += fmtInt10(buffer[i..], std.Thread.getCurrentId()); + i += fmtBuf(buffer[i..], " panic: "); + } + i += fmtPanicCause(&buffer, cause); + buffer[i] = '\n'; + i += 1; + const msg = buffer[0..i]; + lockStdErr(); defer unlockStdErr(); - const stderr = io.getStdErr().writer(); - if (builtin.single_threaded) { - stderr.print("panic: ", .{}) catch posix.abort(); - } else { - const current_thread_id = std.Thread.getCurrentId(); - stderr.print("thread {} panic: ", .{current_thread_id}) catch posix.abort(); - } - stderr.print("{s}\n", .{msg}) catch posix.abort(); - if (trace) |t| { - dumpStackTrace(t.*); - } - dumpCurrentStackTrace(first_trace_addr); + io.getStdErr().writeAll(msg) catch posix.abort(); + if (trace) |t| dumpStackTrace(t.*); + dumpCurrentStackTrace(first_trace_addr orelse @returnAddress()); } waitForOtherThreadToFinishPanicking(); @@ -489,20 +589,99 @@ pub fn panicImpl(trace: ?*const std.builtin.StackTrace, first_trace_addr: ?usize 1 => { panic_stage = 2; - // A panic happened while trying to print a previous panic message, - // we're still holding the mutex but that's fine as we're going to - // call abort() - const stderr = io.getStdErr().writer(); - stderr.print("Panicked during a panic. Aborting.\n", .{}) catch posix.abort(); - }, - else => { - // Panicked while printing "Panicked during a panic." + // A panic happened while trying to print a previous panic message. + // We're still holding the mutex but that's fine as we're going to + // call abort(). + io.getStdErr().writeAll("aborting due to recursive panic\n") catch {}; }, + else => {}, // Panicked while printing the recursive panic message. }; posix.abort(); } +pub fn fmtPanicCause(buffer: []u8, cause: std.builtin.PanicCause) usize { + var i: usize = 0; + + switch (cause) { + .reached_unreachable => i += fmtBuf(buffer[i..], "reached unreachable code"), + .unwrap_null => i += fmtBuf(buffer[i..], "attempt to use null value"), + .cast_to_null => i += fmtBuf(buffer[i..], "cast causes pointer to be null"), + .incorrect_alignment => i += fmtBuf(buffer[i..], "incorrect alignment"), + .invalid_error_code => i += fmtBuf(buffer[i..], "invalid error code"), + .cast_truncated_data => i += fmtBuf(buffer[i..], "integer cast truncated bits"), + .negative_to_unsigned => i += fmtBuf(buffer[i..], "attempt to cast negative value to unsigned integer"), + .integer_overflow => i += fmtBuf(buffer[i..], "integer overflow"), + .shl_overflow => i += fmtBuf(buffer[i..], "left shift overflowed bits"), + .shr_overflow => i += fmtBuf(buffer[i..], "right shift overflowed bits"), + .divide_by_zero => i += fmtBuf(buffer[i..], "division by zero"), + .exact_division_remainder => i += fmtBuf(buffer[i..], "exact division produced remainder"), + .inactive_union_field => |info| { + i += fmtBuf(buffer[i..], "access of union field '"); + i += fmtBuf(buffer[i..], info.accessed); + i += fmtBuf(buffer[i..], "' while field '"); + i += fmtBuf(buffer[i..], info.active); + i += fmtBuf(buffer[i..], "' is active"); + }, + .integer_part_out_of_bounds => i += fmtBuf(buffer[i..], "integer part of floating point value out of bounds"), + .corrupt_switch => i += fmtBuf(buffer[i..], "switch on corrupt value"), + .shift_rhs_too_big => i += fmtBuf(buffer[i..], "shift amount is greater than the type size"), + .invalid_enum_value => i += fmtBuf(buffer[i..], "invalid enum value"), + .sentinel_mismatch_usize => |mm| { + i += fmtBuf(buffer[i..], "sentinel mismatch: expected "); + i += fmtInt10(buffer[i..], mm.expected); + i += fmtBuf(buffer[i..], ", found "); + i += fmtInt10(buffer[i..], mm.found); + }, + .sentinel_mismatch_other => i += fmtBuf(buffer[i..], "sentinel mismatch"), + .unwrap_error => |err| { + i += fmtBuf(buffer[i..], "attempt to unwrap error: "); + i += fmtBuf(buffer[i..], @errorName(err)); + }, + .index_out_of_bounds => |oob| { + i += fmtBuf(buffer[i..], "index "); + i += fmtInt10(buffer[i..], oob.index); + i += fmtBuf(buffer[i..], " exceeds length "); + i += fmtInt10(buffer[i..], oob.len); + }, + .start_index_greater_than_end => |oob| { + i += fmtBuf(buffer[i..], "start index "); + i += fmtInt10(buffer[i..], oob.start); + i += fmtBuf(buffer[i..], " exceeds end index "); + i += fmtInt10(buffer[i..], oob.end); + }, + .for_len_mismatch => i += fmtBuf(buffer[i..], "for loop over objects with non-equal lengths"), + .memcpy_len_mismatch => i += fmtBuf(buffer[i..], "@memcpy arguments have non-equal lengths"), + .memcpy_alias => i += fmtBuf(buffer[i..], "@memcpy arguments alias"), + .noreturn_returned => i += fmtBuf(buffer[i..], "'noreturn' function returned"), + .explicit_call => |msg| i += fmtBuf(buffer[i..], msg), + } + + return i; +} + +fn fmtBuf(out_buf: []u8, s: []const u8) usize { + @memcpy(out_buf[0..s.len], s); + return s.len; +} + +fn fmtInt10(out_buf: []u8, integer_value: usize) usize { + var tmp_buf: [50]u8 = undefined; + var i: usize = tmp_buf.len; + var a: usize = integer_value; + + while (true) { + i -= 1; + tmp_buf[i] = '0' + (a % 10); + a /= 10; + if (a == 0) break; + } + + const result = tmp_buf[i..]; + @memcpy(out_buf[0..result.len], result); + return result.len; +} + /// Must be called only after adding 1 to `panicking`. There are three callsites. fn waitForOtherThreadToFinishPanicking() void { if (panicking.fetchSub(1, .seq_cst) != 1) { @@ -1157,7 +1336,7 @@ pub const default_enable_segfault_handler = runtime_safety and have_segfault_han pub fn maybeEnableSegfaultHandler() void { if (enable_segfault_handler) { - std.debug.attachSegfaultHandler(); + attachSegfaultHandler(); } } @@ -1289,46 +1468,29 @@ fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) callconv(windows.WIN } } -fn handleSegfaultWindowsExtra( - info: *windows.EXCEPTION_POINTERS, - msg: u8, - label: ?[]const u8, -) noreturn { - const exception_address = @intFromPtr(info.ExceptionRecord.ExceptionAddress); - if (windows.CONTEXT != void) { - nosuspend switch (panic_stage) { - 0 => { - panic_stage = 1; - _ = panicking.fetchAdd(1, .seq_cst); +fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[]const u8) noreturn { + comptime assert(windows.CONTEXT != void); + nosuspend switch (panic_stage) { + 0 => { + panic_stage = 1; + _ = panicking.fetchAdd(1, .seq_cst); - { - lockStdErr(); - defer unlockStdErr(); + { + lockStdErr(); + defer unlockStdErr(); - dumpSegfaultInfoWindows(info, msg, label); - } - - waitForOtherThreadToFinishPanicking(); - }, - else => { - // panic mutex already locked dumpSegfaultInfoWindows(info, msg, label); - }, - }; - posix.abort(); - } else { - switch (msg) { - 0 => panicImpl(null, exception_address, "{s}", label.?), - 1 => { - const format_item = "Segmentation fault at address 0x{x}"; - var buf: [format_item.len + 64]u8 = undefined; // 64 is arbitrary, but sufficiently large - const to_print = std.fmt.bufPrint(buf[0..buf.len], format_item, .{info.ExceptionRecord.ExceptionInformation[1]}) catch unreachable; - panicImpl(null, exception_address, to_print); - }, - 2 => panicImpl(null, exception_address, "Illegal Instruction"), - else => unreachable, - } - } + } + + waitForOtherThreadToFinishPanicking(); + }, + 1 => { + panic_stage = 2; + io.getStdErr().writeAll("aborting due to recursive panic\n") catch {}; + }, + else => {}, + }; + posix.abort(); } fn dumpSegfaultInfoWindows(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[]const u8) void { @@ -1347,7 +1509,7 @@ pub fn dumpStackPointerAddr(prefix: []const u8) void { const sp = asm ("" : [argc] "={rsp}" (-> usize), ); - std.debug.print("{s} sp = 0x{x}\n", .{ prefix, sp }); + print("{s} sp = 0x{x}\n", .{ prefix, sp }); } test "manage resources correctly" { diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 12504b6872..123122fd56 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -1197,7 +1197,7 @@ pub fn formatInt( if (base == 10) { while (a >= 100) : (a = @divTrunc(a, 100)) { index -= 2; - buf[index..][0..2].* = digits2(@as(usize, @intCast(a % 100))); + buf[index..][0..2].* = digits2(@intCast(a % 100)); } if (a < 10) { @@ -1205,13 +1205,13 @@ pub fn formatInt( buf[index] = '0' + @as(u8, @intCast(a)); } else { index -= 2; - buf[index..][0..2].* = digits2(@as(usize, @intCast(a))); + buf[index..][0..2].* = digits2(@intCast(a)); } } else { while (true) { const digit = a % base; index -= 1; - buf[index] = digitToChar(@as(u8, @intCast(digit)), case); + buf[index] = digitToChar(@intCast(digit), case); a /= base; if (a == 0) break; } @@ -1242,11 +1242,7 @@ pub fn formatIntBuf(out_buf: []u8, value: anytype, base: u8, case: Case, options // Converts values in the range [0, 100) to a string. pub fn digits2(value: usize) [2]u8 { - return ("0001020304050607080910111213141516171819" ++ - "2021222324252627282930313233343536373839" ++ - "4041424344454647484950515253545556575859" ++ - "6061626364656667686970717273747576777879" ++ - "8081828384858687888990919293949596979899")[value * 2 ..][0..2].*; + return "00010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899"[value * 2 ..][0..2].*; } const FormatDurationData = struct { diff --git a/src/Compilation.zig b/src/Compilation.zig index 3ca4d376e9..227b6e67ef 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -195,7 +195,6 @@ job_queued_compiler_rt_obj: bool = false, job_queued_fuzzer_lib: bool = false, job_queued_update_builtin_zig: bool, alloc_failure_occurred: bool = false, -formatted_panics: bool = false, last_update_was_cache_hit: bool = false, c_source_files: []const CSourceFile, @@ -1088,7 +1087,6 @@ pub const CreateOptions = struct { /// executable this field is ignored. want_compiler_rt: ?bool = null, want_lto: ?bool = null, - formatted_panics: ?bool = null, function_sections: bool = false, data_sections: bool = false, no_builtin: bool = false, @@ -1357,9 +1355,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil } } - // TODO: https://github.com/ziglang/zig/issues/17969 - const formatted_panics = options.formatted_panics orelse (options.root_mod.optimize_mode == .Debug); - const error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1); // We put everything into the cache hash that *cannot be modified @@ -1520,7 +1515,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil .verbose_link = options.verbose_link, .disable_c_depfile = options.disable_c_depfile, .reference_trace = options.reference_trace, - .formatted_panics = formatted_panics, .time_report = options.time_report, .stack_report = options.stack_report, .test_filters = options.test_filters, @@ -1638,7 +1632,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil hash.addListOfBytes(options.test_filters); hash.addOptionalBytes(options.test_name_prefix); hash.add(options.skip_linker_dependencies); - hash.add(formatted_panics); hash.add(options.emit_h != null); hash.add(error_limit); @@ -2564,7 +2557,6 @@ fn addNonIncrementalStuffToCacheManifest( man.hash.addListOfBytes(comp.test_filters); man.hash.addOptionalBytes(comp.test_name_prefix); man.hash.add(comp.skip_linker_dependencies); - man.hash.add(comp.formatted_panics); //man.hash.add(mod.emit_h != null); man.hash.add(mod.error_limit); } else { diff --git a/src/InternPool.zig b/src/InternPool.zig index 6b20f79561..f41f780e0a 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -7353,6 +7353,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All .func_type => unreachable, // use getFuncType() instead .@"extern" => unreachable, // use getExtern() instead .func => unreachable, // use getFuncInstance() or getFuncDecl() instead + .un => unreachable, // use getUnion instead .variable => |variable| { const has_init = variable.init != .none; @@ -7968,15 +7969,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All if (sentinel != .none) extra.appendAssumeCapacity(.{@intFromEnum(sentinel)}); }, - .un => |un| { - assert(un.ty != .none); - assert(un.val != .none); - items.appendAssumeCapacity(.{ - .tag = .union_value, - .data = try addExtra(extra, un), - }); - }, - .memoized_call => |memoized_call| { for (memoized_call.arg_values) |arg| assert(arg != .none); try extra.ensureUnusedCapacity(@typeInfo(MemoizedCall).@"struct".fields.len + @@ -7996,6 +7988,30 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All return gop.put(); } +pub fn getUnion( + ip: *InternPool, + gpa: Allocator, + tid: Zcu.PerThread.Id, + un: Key.Union, +) Allocator.Error!Index { + var gop = try ip.getOrPutKey(gpa, tid, .{ .un = un }); + defer gop.deinit(); + if (gop == .existing) return gop.existing; + const local = ip.getLocal(tid); + const items = local.getMutableItems(gpa); + const extra = local.getMutableExtra(gpa); + try items.ensureUnusedCapacity(1); + + assert(un.ty != .none); + assert(un.val != .none); + items.appendAssumeCapacity(.{ + .tag = .union_value, + .data = try addExtra(extra, un), + }); + + return gop.put(); +} + pub const UnionTypeInit = struct { flags: packed struct { runtime_tag: LoadedUnionType.RuntimeTag, diff --git a/src/Sema.zig b/src/Sema.zig index 406dbebc31..a2d883a040 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -4854,11 +4854,11 @@ fn validateUnionInit( } block.instructions.shrinkRetainingCapacity(block_index); - const union_val = try pt.intern(.{ .un = .{ + const union_val = try pt.internUnion(.{ .ty = union_ty.toIntern(), .tag = tag_val.toIntern(), .val = val.toIntern(), - } }); + }); const union_init = Air.internedToRef(union_val); try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store); return; @@ -5830,8 +5830,6 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void 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)); if (block.is_comptime) { @@ -5844,7 +5842,7 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void sema.branch_hint = .cold; } - try sema.panicWithMsg(block, src, coerced_msg, .@"@panic"); + try callPanic(sema, block, src, .explicit_call, coerced_msg, .@"@panic"); } fn zirTrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { @@ -7325,6 +7323,31 @@ fn callBuiltin( ); } +const PanicCauseTag = @typeInfo(std.builtin.PanicCause).@"union".tag_type.?; + +fn callPanic( + sema: *Sema, + block: *Block, + call_src: LazySrcLoc, + tag: PanicCauseTag, + payload: Air.Inst.Ref, + call_operation: CallOperation, +) !void { + const pt = sema.pt; + if (!pt.zcu.backendSupportsFeature(.panic_fn)) { + _ = try block.addNoOp(.trap); + return; + } + const panic_cause_ty = try pt.getBuiltinType("PanicCause"); + const panic_cause = try block.addUnionInit(panic_cause_ty, @intFromEnum(tag), payload); + const panic_fn = try pt.getBuiltin("panic"); + const err_return_trace = try sema.getErrorReturnTrace(block); + const opt_usize_ty = try pt.optionalType(.usize_type); + const null_usize = try pt.nullValue(opt_usize_ty); + const args: [3]Air.Inst.Ref = .{ panic_cause, err_return_trace, Air.internedToRef(null_usize) }; + try sema.callBuiltin(block, call_src, panic_fn, .auto, &args, call_operation); +} + const CallOperation = enum { call, @"@call", @@ -9327,7 +9350,7 @@ fn analyzeErrUnionPayload( if (safety_check and block.wantSafety() and !err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) { - try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err, .is_non_err); + try sema.addSafetyCheckUnwrapError(block, src, operand, .unwrap_errunion_err, .is_non_err); } return block.addTyOp(.unwrap_errunion_payload, payload_ty, operand); @@ -9411,7 +9434,7 @@ fn analyzeErrUnionPayloadPtr( if (safety_check and block.wantSafety() and !err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) { - try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr); + try sema.addSafetyCheckUnwrapError(block, src, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr); } if (initializing) { @@ -14190,7 +14213,6 @@ fn maybeErrorUnwrap( ) !bool { const pt = sema.pt; const zcu = pt.zcu; - if (!zcu.backendSupportsFeature(.panic_unwrap_error)) return false; const tags = sema.code.instructions.items(.tag); for (body) |inst| { @@ -14223,25 +14245,13 @@ fn maybeErrorUnwrap( .as_node => try sema.zirAsNode(block, inst), .field_val => try sema.zirFieldVal(block, inst), .@"unreachable" => { - if (!zcu.comp.formatted_panics) { - try sema.safetyPanic(block, operand_src, .unwrap_error); - return true; - } - - const panic_fn = try pt.getBuiltin("panicUnwrapError"); - const err_return_trace = try sema.getErrorReturnTrace(block); - const args: [2]Air.Inst.Ref = .{ err_return_trace, operand }; - try sema.callBuiltin(block, operand_src, panic_fn, .auto, &args, .@"safety check"); + try callPanic(sema, block, operand_src, .unwrap_error, operand, .@"safety check"); return true; }, .panic => { 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 pt.getBuiltin("panic"); - 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, panic_fn, .auto, &args, .@"safety check"); + try callPanic(sema, block, operand_src, .explicit_call, msg_inst, .@"@panic"); return true; }, else => unreachable, @@ -17388,9 +17398,6 @@ fn analyzeArithmetic( if (block.wantSafety() and want_safety and scalar_tag == .int) { if (zcu.backendSupportsFeature(.safety_checked_instructions)) { - if (air_tag != air_tag_safe) { - _ = try sema.preparePanicId(block, src, .integer_overflow); - } return block.addBinOp(air_tag_safe, casted_lhs, casted_rhs); } else { const maybe_op_ov: ?Air.Inst.Tag = switch (air_tag) { @@ -18319,29 +18326,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .undefined, .null, .enum_literal, - => |type_info_tag| return Air.internedToRef((try pt.intern(.{ .un = .{ + => |type_info_tag| return Air.internedToRef((try pt.internUnion(.{ .ty = type_info_ty.toIntern(), .tag = (try pt.enumValueFieldIndex(type_info_tag_ty, @intFromEnum(type_info_tag))).toIntern(), .val = .void_value, - } }))), + }))), .@"fn" => { - const fn_info_nav = try sema.namespaceLookup( - block, - src, - type_info_ty.getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "Fn", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, fn_info_nav); - const fn_info_ty = Type.fromInterned(ip.getNav(fn_info_nav).status.resolved.val); - - const param_info_nav = try sema.namespaceLookup( - block, - src, - fn_info_ty.getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "Param", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, param_info_nav); - const param_info_ty = Type.fromInterned(ip.getNav(param_info_nav).status.resolved.val); + const fn_info_ty = try getInnerType(sema, block, src, type_info_ty, "Fn"); + const param_info_ty = try getInnerType(sema, block, src, fn_info_ty, "Param"); const func_ty_info = zcu.typeToFunc(ty).?; const param_vals = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len); @@ -18425,25 +18417,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // args: []const Fn.Param, args_val, }; - return Air.internedToRef((try pt.intern(.{ .un = .{ + return Air.internedToRef((try pt.internUnion(.{ .ty = type_info_ty.toIntern(), .tag = (try pt.enumValueFieldIndex(type_info_tag_ty, @intFromEnum(std.builtin.TypeId.@"fn"))).toIntern(), .val = try pt.intern(.{ .aggregate = .{ .ty = fn_info_ty.toIntern(), .storage = .{ .elems = &field_values }, } }), - } }))); + }))); }, .int => { - const int_info_nav = try sema.namespaceLookup( - block, - src, - type_info_ty.getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "Int", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, int_info_nav); - const int_info_ty = Type.fromInterned(ip.getNav(int_info_nav).status.resolved.val); - + const int_info_ty = try getInnerType(sema, block, src, type_info_ty, "Int"); const signedness_ty = try pt.getBuiltinType("Signedness"); const info = ty.intInfo(zcu); const field_values = .{ @@ -18452,37 +18436,30 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // bits: u16, (try pt.intValue(Type.u16, info.bits)).toIntern(), }; - return Air.internedToRef((try pt.intern(.{ .un = .{ + return Air.internedToRef((try pt.internUnion(.{ .ty = type_info_ty.toIntern(), .tag = (try pt.enumValueFieldIndex(type_info_tag_ty, @intFromEnum(std.builtin.TypeId.int))).toIntern(), .val = try pt.intern(.{ .aggregate = .{ .ty = int_info_ty.toIntern(), .storage = .{ .elems = &field_values }, } }), - } }))); + }))); }, .float => { - const float_info_nav = try sema.namespaceLookup( - block, - src, - type_info_ty.getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "Float", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, float_info_nav); - const float_info_ty = Type.fromInterned(ip.getNav(float_info_nav).status.resolved.val); + const float_info_ty = try getInnerType(sema, block, src, type_info_ty, "Float"); const field_vals = .{ // bits: u16, (try pt.intValue(Type.u16, ty.bitSize(zcu))).toIntern(), }; - return Air.internedToRef((try pt.intern(.{ .un = .{ + return Air.internedToRef((try pt.internUnion(.{ .ty = type_info_ty.toIntern(), .tag = (try pt.enumValueFieldIndex(type_info_tag_ty, @intFromEnum(std.builtin.TypeId.float))).toIntern(), .val = try pt.intern(.{ .aggregate = .{ .ty = float_info_ty.toIntern(), .storage = .{ .elems = &field_vals }, } }), - } }))); + }))); }, .pointer => { const info = ty.ptrInfo(zcu); @@ -18492,26 +18469,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai try Type.fromInterned(info.child).lazyAbiAlignment(pt); const addrspace_ty = try pt.getBuiltinType("AddressSpace"); - const pointer_ty = t: { - const nav = try sema.namespaceLookup( - block, - src, - (try pt.getBuiltinType("Type")).getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "Pointer", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, nav); - break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); - }; - const ptr_size_ty = t: { - const nav = try sema.namespaceLookup( - block, - src, - pointer_ty.getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "Size", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, nav); - break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); - }; + const pointer_ty = try getInnerType(sema, block, src, type_info_ty, "Pointer"); + const ptr_size_ty = try getInnerType(sema, block, src, pointer_ty, "Size"); const field_values = .{ // size: Size, @@ -18534,26 +18493,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai else => Value.fromInterned(info.sentinel), })).toIntern(), }; - return Air.internedToRef((try pt.intern(.{ .un = .{ + return Air.internedToRef((try pt.internUnion(.{ .ty = type_info_ty.toIntern(), .tag = (try pt.enumValueFieldIndex(type_info_tag_ty, @intFromEnum(std.builtin.TypeId.pointer))).toIntern(), .val = try pt.intern(.{ .aggregate = .{ .ty = pointer_ty.toIntern(), .storage = .{ .elems = &field_values }, } }), - } }))); + }))); }, .array => { - const array_field_ty = t: { - const nav = try sema.namespaceLookup( - block, - src, - type_info_ty.getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "Array", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, nav); - break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); - }; + const array_field_ty = try getInnerType(sema, block, src, type_info_ty, "Array"); const info = ty.arrayInfo(zcu); const field_values = .{ @@ -18564,26 +18514,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // sentinel: ?*const anyopaque, (try sema.optRefValue(info.sentinel)).toIntern(), }; - return Air.internedToRef((try pt.intern(.{ .un = .{ + return Air.internedToRef((try pt.internUnion(.{ .ty = type_info_ty.toIntern(), .tag = (try pt.enumValueFieldIndex(type_info_tag_ty, @intFromEnum(std.builtin.TypeId.array))).toIntern(), .val = try pt.intern(.{ .aggregate = .{ .ty = array_field_ty.toIntern(), .storage = .{ .elems = &field_values }, } }), - } }))); + }))); }, .vector => { - const vector_field_ty = t: { - const nav = try sema.namespaceLookup( - block, - src, - type_info_ty.getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "Vector", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, nav); - break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); - }; + const vector_field_ty = try getInnerType(sema, block, src, type_info_ty, "Vector"); const info = ty.arrayInfo(zcu); const field_values = .{ @@ -18592,52 +18533,34 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // child: type, info.elem_type.toIntern(), }; - return Air.internedToRef((try pt.intern(.{ .un = .{ + return Air.internedToRef((try pt.internUnion(.{ .ty = type_info_ty.toIntern(), .tag = (try pt.enumValueFieldIndex(type_info_tag_ty, @intFromEnum(std.builtin.TypeId.vector))).toIntern(), .val = try pt.intern(.{ .aggregate = .{ .ty = vector_field_ty.toIntern(), .storage = .{ .elems = &field_values }, } }), - } }))); + }))); }, .optional => { - const optional_field_ty = t: { - const nav = try sema.namespaceLookup( - block, - src, - type_info_ty.getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "Optional", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, nav); - break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); - }; + const optional_field_ty = try getInnerType(sema, block, src, type_info_ty, "Optional"); const field_values = .{ // child: type, ty.optionalChild(zcu).toIntern(), }; - return Air.internedToRef((try pt.intern(.{ .un = .{ + return Air.internedToRef((try pt.internUnion(.{ .ty = type_info_ty.toIntern(), .tag = (try pt.enumValueFieldIndex(type_info_tag_ty, @intFromEnum(std.builtin.TypeId.optional))).toIntern(), .val = try pt.intern(.{ .aggregate = .{ .ty = optional_field_ty.toIntern(), .storage = .{ .elems = &field_values }, } }), - } }))); + }))); }, .error_set => { // Get the Error type - const error_field_ty = t: { - const nav = try sema.namespaceLookup( - block, - src, - type_info_ty.getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "Error", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, nav); - break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); - }; + const error_field_ty = try getInnerType(sema, block, src, type_info_ty, "Error"); // Build our list of Error values // Optional value is only null if anyerror @@ -18726,23 +18649,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }); // Construct Type{ .error_set = errors_val } - return Air.internedToRef((try pt.intern(.{ .un = .{ + return Air.internedToRef((try pt.internUnion(.{ .ty = type_info_ty.toIntern(), .tag = (try pt.enumValueFieldIndex(type_info_tag_ty, @intFromEnum(std.builtin.TypeId.error_set))).toIntern(), .val = errors_val, - } }))); + }))); }, .error_union => { - const error_union_field_ty = t: { - const nav = try sema.namespaceLookup( - block, - src, - type_info_ty.getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "ErrorUnion", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, nav); - break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); - }; + const error_union_field_ty = try getInnerType(sema, block, src, type_info_ty, "ErrorUnion"); const field_values = .{ // error_set: type, @@ -18750,28 +18664,19 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // payload: type, ty.errorUnionPayload(zcu).toIntern(), }; - return Air.internedToRef((try pt.intern(.{ .un = .{ + return Air.internedToRef((try pt.internUnion(.{ .ty = type_info_ty.toIntern(), .tag = (try pt.enumValueFieldIndex(type_info_tag_ty, @intFromEnum(std.builtin.TypeId.error_union))).toIntern(), .val = try pt.intern(.{ .aggregate = .{ .ty = error_union_field_ty.toIntern(), .storage = .{ .elems = &field_values }, } }), - } }))); + }))); }, .@"enum" => { const is_exhaustive = Value.makeBool(ip.loadEnumType(ty.toIntern()).tag_mode != .nonexhaustive); - const enum_field_ty = t: { - const nav = try sema.namespaceLookup( - block, - src, - type_info_ty.getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "EnumField", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, nav); - break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); - }; + const enum_field_ty = try getInnerType(sema, block, src, type_info_ty, "EnumField"); const enum_field_vals = try sema.arena.alloc(InternPool.Index, ip.loadEnumType(ty.toIntern()).names.len); for (enum_field_vals, 0..) |*field_val, tag_index| { @@ -18858,16 +18763,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ip.loadEnumType(ty.toIntern()).namespace.toOptional()); - const type_enum_ty = t: { - const nav = try sema.namespaceLookup( - block, - src, - type_info_ty.getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "Enum", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, nav); - break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); - }; + const type_enum_ty = try getInnerType(sema, block, src, type_info_ty, "Enum"); const field_values = .{ // tag_type: type, @@ -18879,37 +18775,18 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // is_exhaustive: bool, is_exhaustive.toIntern(), }; - return Air.internedToRef((try pt.intern(.{ .un = .{ + return Air.internedToRef((try pt.internUnion(.{ .ty = type_info_ty.toIntern(), .tag = (try pt.enumValueFieldIndex(type_info_tag_ty, @intFromEnum(std.builtin.TypeId.@"enum"))).toIntern(), .val = try pt.intern(.{ .aggregate = .{ .ty = type_enum_ty.toIntern(), .storage = .{ .elems = &field_values }, } }), - } }))); + }))); }, .@"union" => { - const type_union_ty = t: { - const nav = try sema.namespaceLookup( - block, - src, - type_info_ty.getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "Union", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, nav); - break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); - }; - - const union_field_ty = t: { - const nav = try sema.namespaceLookup( - block, - src, - type_info_ty.getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "UnionField", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, nav); - break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); - }; + const type_union_ty = try getInnerType(sema, block, src, type_info_ty, "Union"); + const union_field_ty = try getInnerType(sema, block, src, type_info_ty, "UnionField"); try ty.resolveLayout(pt); // Getting alignment requires type layout const union_obj = zcu.typeToUnion(ty).?; @@ -19004,16 +18881,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .val = if (ty.unionTagType(zcu)) |tag_ty| tag_ty.toIntern() else .none, } }); - const container_layout_ty = t: { - const nav = try sema.namespaceLookup( - block, - src, - (try pt.getBuiltinType("Type")).getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "ContainerLayout", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, nav); - break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); - }; + const container_layout_ty = try getBuiltinInnerType(sema, block, src, "Type", "ContainerLayout"); const field_values = .{ // layout: ContainerLayout, @@ -19026,37 +18894,18 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // decls: []const Declaration, decls_val, }; - return Air.internedToRef((try pt.intern(.{ .un = .{ + return Air.internedToRef((try pt.internUnion(.{ .ty = type_info_ty.toIntern(), .tag = (try pt.enumValueFieldIndex(type_info_tag_ty, @intFromEnum(std.builtin.TypeId.@"union"))).toIntern(), .val = try pt.intern(.{ .aggregate = .{ .ty = type_union_ty.toIntern(), .storage = .{ .elems = &field_values }, } }), - } }))); + }))); }, .@"struct" => { - const type_struct_ty = t: { - const nav = try sema.namespaceLookup( - block, - src, - type_info_ty.getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "Struct", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, nav); - break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); - }; - - const struct_field_ty = t: { - const nav = try sema.namespaceLookup( - block, - src, - type_info_ty.getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "StructField", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, nav); - break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); - }; + const type_struct_ty = try getInnerType(sema, block, src, type_info_ty, "Struct"); + const struct_field_ty = try getInnerType(sema, block, src, type_info_ty, "StructField"); try ty.resolveLayout(pt); // Getting alignment requires type layout @@ -19233,16 +19082,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } else .none, } }); - const container_layout_ty = t: { - const nav = try sema.namespaceLookup( - block, - src, - (try pt.getBuiltinType("Type")).getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "ContainerLayout", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, nav); - break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); - }; + const container_layout_ty = try getInnerType(sema, block, src, type_info_ty, "ContainerLayout"); const layout = ty.containerLayout(zcu); @@ -19258,26 +19098,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // is_tuple: bool, Value.makeBool(ty.isTuple(zcu)).toIntern(), }; - return Air.internedToRef((try pt.intern(.{ .un = .{ + return Air.internedToRef((try pt.internUnion(.{ .ty = type_info_ty.toIntern(), .tag = (try pt.enumValueFieldIndex(type_info_tag_ty, @intFromEnum(std.builtin.TypeId.@"struct"))).toIntern(), .val = try pt.intern(.{ .aggregate = .{ .ty = type_struct_ty.toIntern(), .storage = .{ .elems = &field_values }, } }), - } }))); + }))); }, .@"opaque" => { - const type_opaque_ty = t: { - const nav = try sema.namespaceLookup( - block, - src, - type_info_ty.getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "Opaque", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, nav); - break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); - }; + const type_opaque_ty = try getInnerType(sema, block, src, type_info_ty, "Opaque"); try ty.resolveFields(pt); const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespace(zcu)); @@ -19286,14 +19117,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai // decls: []const Declaration, decls_val, }; - return Air.internedToRef((try pt.intern(.{ .un = .{ + return Air.internedToRef((try pt.internUnion(.{ .ty = type_info_ty.toIntern(), .tag = (try pt.enumValueFieldIndex(type_info_tag_ty, @intFromEnum(std.builtin.TypeId.@"opaque"))).toIntern(), .val = try pt.intern(.{ .aggregate = .{ .ty = type_opaque_ty.toIntern(), .storage = .{ .elems = &field_values }, } }), - } }))); + }))); }, .frame => return sema.failWithUseOfAsync(block, src), .@"anyframe" => return sema.failWithUseOfAsync(block, src), @@ -19309,19 +19140,9 @@ fn typeInfoDecls( ) CompileError!InternPool.Index { const pt = sema.pt; const zcu = pt.zcu; - const ip = &zcu.intern_pool; const gpa = sema.gpa; - const declaration_ty = t: { - const nav = try sema.namespaceLookup( - block, - src, - type_info_ty.getNamespaceIndex(zcu), - try ip.getOrPutString(gpa, pt.tid, "Declaration", .no_embedded_nulls), - ) orelse @panic("std.builtin.Type is corrupt"); - try sema.ensureNavResolved(src, nav); - break :t Type.fromInterned(ip.getNav(nav).status.resolved.val); - }; + const declaration_ty = try getInnerType(sema, block, src, type_info_ty, "Declaration"); var decl_vals = std.ArrayList(InternPool.Index).init(gpa); defer decl_vals.deinit(); @@ -20809,11 +20630,11 @@ fn unionInit( if (try sema.resolveValue(init)) |init_val| { const tag_ty = union_ty.unionTagTypeHypothetical(zcu); const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index); - return Air.internedToRef((try pt.intern(.{ .un = .{ + return Air.internedToRef((try pt.internUnion(.{ .ty = union_ty.toIntern(), .tag = tag_val.toIntern(), .val = init_val.toIntern(), - } }))); + }))); } try sema.requireRuntimeBlock(block, init_src, null); @@ -20949,11 +20770,11 @@ fn zirStructInit( const init_inst = try sema.coerce(block, field_ty, uncoerced_init_inst, field_src); if (try sema.resolveValue(init_inst)) |val| { - const struct_val = Value.fromInterned(try pt.intern(.{ .un = .{ + const struct_val = Value.fromInterned(try pt.internUnion(.{ .ty = resolved_ty.toIntern(), .tag = tag_val.toIntern(), .val = val.toIntern(), - } })); + })); const final_val_inst = try sema.coerce(block, result_ty, Air.internedToRef(struct_val.toIntern()), src); const final_val = (try sema.resolveValue(final_val_inst)).?; return sema.addConstantMaybeRef(final_val.toIntern(), is_ref); @@ -21869,11 +21690,20 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0); const src = block.nodeOffset(inst_data.src_node); const operand = try sema.resolveInst(inst_data.operand); + return analyzeTagName(sema, block, src, operand_src, operand); +} + +fn analyzeTagName( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + operand_src: LazySrcLoc, + operand: Air.Inst.Ref, +) CompileError!Air.Inst.Ref { const operand_ty = sema.typeOf(operand); const pt = sema.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; - try operand_ty.resolveLayout(pt); const enum_ty = switch (operand_ty.zigTypeTag(zcu)) { .enum_literal => { @@ -27840,7 +27670,7 @@ fn explainWhyTypeIsNotPacked( } } -fn prepareSimplePanic(sema: *Sema, block: *Block, src: LazySrcLoc) !void { +fn preparePanic(sema: *Sema, block: *Block, src: LazySrcLoc) !void { const pt = sema.pt; const zcu = pt.zcu; @@ -27871,33 +27701,12 @@ fn prepareSimplePanic(sema: *Sema, block: *Block, src: LazySrcLoc) !void { .val = .none, } }); } -} -/// 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, block: *Block, src: LazySrcLoc, panic_id: Zcu.PanicId) !InternPool.Nav.Index { - const pt = sema.pt; - const zcu = pt.zcu; - const gpa = sema.gpa; - if (zcu.panic_messages[@intFromEnum(panic_id)].unwrap()) |x| return x; - - try sema.prepareSimplePanic(block, src); - - const panic_messages_ty = try pt.getBuiltinType("panic_messages"); - const msg_nav_index = (sema.namespaceLookup( - block, - LazySrcLoc.unneeded, - panic_messages_ty.getNamespaceIndex(zcu), - try zcu.intern_pool.getOrPutString(gpa, pt.tid, @tagName(panic_id), .no_embedded_nulls), - ) catch |err| switch (err) { - error.AnalysisFail => @panic("std.builtin.panic_messages is corrupt"), - error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, - error.OutOfMemory => |e| return e, - }).?; - try sema.ensureNavResolved(src, msg_nav_index); - zcu.panic_messages[@intFromEnum(panic_id)] = msg_nav_index.toOptional(); - return msg_nav_index; + if (zcu.panic_cause_type == .none) { + const panic_cause_ty = try pt.getBuiltinType("PanicCause"); + try panic_cause_ty.resolveFields(pt); + zcu.panic_cause_type = panic_cause_ty.toIntern(); + } } fn addSafetyCheck( @@ -27905,7 +27714,7 @@ fn addSafetyCheck( parent_block: *Block, src: LazySrcLoc, ok: Air.Inst.Ref, - panic_id: Zcu.PanicId, + panic_cause_tag: PanicCauseTag, ) !void { const gpa = sema.gpa; assert(!parent_block.is_comptime); @@ -27923,7 +27732,7 @@ fn addSafetyCheck( defer fail_block.instructions.deinit(gpa); - try sema.safetyPanic(&fail_block, src, panic_id); + try sema.safetyPanic(&fail_block, src, panic_cause_tag); try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); } @@ -27992,30 +27801,7 @@ 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.prepareSimplePanic(block, src); - - const panic_func = zcu.funcInfo(zcu.panic_func_index); - const panic_fn = try sema.analyzeNavVal(block, src, panic_func.owner_nav); - 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 panicUnwrapError( +fn addSafetyCheckUnwrapError( sema: *Sema, parent_block: *Block, src: LazySrcLoc, @@ -28023,12 +27809,8 @@ fn panicUnwrapError( unwrap_err_tag: Air.Inst.Tag, is_non_err_tag: Air.Inst.Tag, ) !void { - const pt = sema.pt; assert(!parent_block.is_comptime); const ok = try parent_block.addUnOp(is_non_err_tag, operand); - if (!pt.zcu.comp.formatted_panics) { - return sema.addSafetyCheck(parent_block, src, ok, .unwrap_error); - } const gpa = sema.gpa; var fail_block: Block = .{ @@ -28044,21 +27826,13 @@ fn panicUnwrapError( defer fail_block.instructions.deinit(gpa); - { - if (!pt.zcu.backendSupportsFeature(.panic_unwrap_error)) { - _ = try fail_block.addNoOp(.trap); - } else { - const panic_fn = try sema.pt.getBuiltin("panicUnwrapError"); - const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand); - const err_return_trace = try sema.getErrorReturnTrace(&fail_block); - const args: [2]Air.Inst.Ref = .{ err_return_trace, err }; - try sema.callBuiltin(&fail_block, src, panic_fn, .auto, &args, .@"safety check"); - } - } + const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand); + try callPanic(sema, &fail_block, src, .unwrap_error, err, .@"safety check"); + try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); } -fn panicIndexOutOfBounds( +fn addSafetyCheckIndexOob( sema: *Sema, parent_block: *Block, src: LazySrcLoc, @@ -28067,14 +27841,71 @@ fn panicIndexOutOfBounds( cmp_op: Air.Inst.Tag, ) !void { assert(!parent_block.is_comptime); + const gpa = sema.gpa; const ok = try parent_block.addBinOp(cmp_op, index, len); - if (!sema.pt.zcu.comp.formatted_panics) { - return sema.addSafetyCheck(parent_block, src, ok, .index_out_of_bounds); + + var fail_block: Block = .{ + .parent = parent_block, + .sema = sema, + .namespace = parent_block.namespace, + .instructions = .{}, + .inlining = parent_block.inlining, + .is_comptime = false, + .src_base_inst = parent_block.src_base_inst, + .type_name_ctx = parent_block.type_name_ctx, + }; + + defer fail_block.instructions.deinit(gpa); + + const oob_ty = try getBuiltinInnerType(sema, &fail_block, src, "PanicCause", "IndexOutOfBounds"); + comptime { + const fields = @typeInfo(std.builtin.PanicCause.IndexOutOfBounds).@"struct".fields; + assert(std.mem.eql(u8, fields[0].name, "index")); + assert(std.mem.eql(u8, fields[1].name, "len")); + assert(fields.len == 2); } - try sema.safetyCheckFormatted(parent_block, src, ok, "panicOutOfBounds", &.{ index, len }); + const panic_cause_payload = try fail_block.addAggregateInit(oob_ty, &.{ index, len }); + try callPanic(sema, &fail_block, src, .index_out_of_bounds, panic_cause_payload, .@"safety check"); + try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); } -fn panicInactiveUnionField( +fn addSafetyCheckStartGreaterThanEnd( + sema: *Sema, + parent_block: *Block, + src: LazySrcLoc, + start: Air.Inst.Ref, + end: Air.Inst.Ref, +) !void { + assert(!parent_block.is_comptime); + const gpa = sema.gpa; + const ok = try parent_block.addBinOp(.cmp_lte, start, end); + + var fail_block: Block = .{ + .parent = parent_block, + .sema = sema, + .namespace = parent_block.namespace, + .instructions = .{}, + .inlining = parent_block.inlining, + .is_comptime = false, + .src_base_inst = parent_block.src_base_inst, + .type_name_ctx = parent_block.type_name_ctx, + }; + + defer fail_block.instructions.deinit(gpa); + + const oob_ty = try getBuiltinInnerType(sema, &fail_block, src, "PanicCause", "StartIndexGreaterThanEnd"); + comptime { + const fields = @typeInfo(std.builtin.PanicCause.StartIndexGreaterThanEnd).@"struct".fields; + assert(std.mem.eql(u8, fields[0].name, "start")); + assert(std.mem.eql(u8, fields[1].name, "end")); + assert(fields.len == 2); + } + const panic_cause_payload = try fail_block.addAggregateInit(oob_ty, &.{ start, end }); + try callPanic(sema, &fail_block, src, .start_index_greater_than_end, panic_cause_payload, .@"safety check"); + try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); +} + +fn addSafetyCheckInactiveUnionField( sema: *Sema, parent_block: *Block, src: LazySrcLoc, @@ -28082,14 +27913,39 @@ fn panicInactiveUnionField( wanted_tag: Air.Inst.Ref, ) !void { assert(!parent_block.is_comptime); + const gpa = sema.gpa; const ok = try parent_block.addBinOp(.cmp_eq, active_tag, wanted_tag); - if (!sema.pt.zcu.comp.formatted_panics) { - return sema.addSafetyCheck(parent_block, src, ok, .inactive_union_field); + + var fail_block: Block = .{ + .parent = parent_block, + .sema = sema, + .namespace = parent_block.namespace, + .instructions = .{}, + .inlining = parent_block.inlining, + .is_comptime = false, + .src_base_inst = parent_block.src_base_inst, + .type_name_ctx = parent_block.type_name_ctx, + }; + + defer fail_block.instructions.deinit(gpa); + + const payload_ty = try getBuiltinInnerType(sema, &fail_block, src, "PanicCause", "InactiveUnionField"); + comptime { + const fields = @typeInfo(std.builtin.PanicCause.InactiveUnionField).@"struct".fields; + assert(std.mem.eql(u8, fields[0].name, "active")); + assert(std.mem.eql(u8, fields[1].name, "accessed")); + assert(fields.len == 2); } - try sema.safetyCheckFormatted(parent_block, src, ok, "panicInactiveUnionField", &.{ active_tag, wanted_tag }); + // TODO: before merging the branch, check how many safety checks end up being emitted + // for union field accesses and avoid extraneous ones. + const active_str = try analyzeTagName(sema, &fail_block, src, src, active_tag); + const accessed_str = try analyzeTagName(sema, &fail_block, src, src, wanted_tag); + const panic_cause_payload = try fail_block.addAggregateInit(payload_ty, &.{ active_str, accessed_str }); + try callPanic(sema, &fail_block, src, .inactive_union_field, panic_cause_payload, .@"safety check"); + try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); } -fn panicSentinelMismatch( +fn addSafetyCheckSentinelMismatch( sema: *Sema, parent_block: *Block, src: LazySrcLoc, @@ -28099,6 +27955,7 @@ fn panicSentinelMismatch( sentinel_index: Air.Inst.Ref, ) !void { assert(!parent_block.is_comptime); + const gpa = sema.gpa; const pt = sema.pt; const zcu = pt.zcu; const expected_sentinel_val = maybe_sentinel orelse return; @@ -28114,8 +27971,7 @@ fn panicSentinelMismatch( }; const ok = if (sentinel_ty.zigTypeTag(zcu) == .vector) ok: { - const eql = - try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq); + const eql = try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq); break :ok try parent_block.addInst(.{ .tag = .reduce, .data = .{ .reduce = .{ @@ -28128,25 +27984,6 @@ fn panicSentinelMismatch( break :ok try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel); }; - if (!pt.zcu.comp.formatted_panics) { - return sema.addSafetyCheck(parent_block, src, ok, .sentinel_mismatch); - } - try sema.safetyCheckFormatted(parent_block, src, ok, "panicSentinelMismatch", &.{ expected_sentinel, actual_sentinel }); -} - -fn safetyCheckFormatted( - sema: *Sema, - parent_block: *Block, - src: LazySrcLoc, - ok: Air.Inst.Ref, - func: []const u8, - args: []const Air.Inst.Ref, -) CompileError!void { - const pt = sema.pt; - const zcu = pt.zcu; - assert(zcu.comp.formatted_panics); - const gpa = sema.gpa; - var fail_block: Block = .{ .parent = parent_block, .sema = sema, @@ -28160,20 +27997,29 @@ fn safetyCheckFormatted( defer fail_block.instructions.deinit(gpa); - if (!zcu.backendSupportsFeature(.safety_check_formatted)) { - _ = try fail_block.addNoOp(.trap); + // A different PanicCause tag must be used depending on what payload type it can be fit into. + // If it cannot fit into any, the "other" tag can be used, which does not try to carry the + // sentinel value data. + + if (sentinel_ty.isUnsignedInt(zcu) and sentinel_ty.intInfo(zcu).bits <= Type.usize.intInfo(zcu).bits) { + const mm_ty = try getBuiltinInnerType(sema, &fail_block, src, "PanicCause", "SentinelMismatchUsize"); + comptime { + const fields = @typeInfo(std.builtin.PanicCause.SentinelMismatchUsize).@"struct".fields; + assert(std.mem.eql(u8, fields[0].name, "expected")); + assert(std.mem.eql(u8, fields[1].name, "found")); + assert(fields.len == 2); + } + const panic_cause_payload = &fail_block.addAggregateInit(mm_ty, &.{ expected_sentinel, actual_sentinel }); + try callPanic(sema, &fail_block, src, .sentinel_mismatch_usize, panic_cause_payload, .@"safety check"); } else { - const panic_fn = try pt.getBuiltin(func); - try sema.callBuiltin(&fail_block, src, panic_fn, .auto, args, .@"safety check"); + try callPanic(sema, &fail_block, src, .sentinel_mismatch_other, .void_value, .@"safety check"); } try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); } /// This does not set `sema.branch_hint`. -fn safetyPanic(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.PanicId) CompileError!void { - const msg_nav_index = try sema.preparePanicId(block, src, panic_id); - const msg_inst = try sema.analyzeNavVal(block, src, msg_nav_index); - try sema.panicWithMsg(block, src, msg_inst, .@"safety check"); +fn safetyPanic(sema: *Sema, block: *Block, src: LazySrcLoc, panic_cause_tag: PanicCauseTag) CompileError!void { + try callPanic(sema, block, src, panic_cause_tag, .void_value, .@"safety check"); } fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void { @@ -29229,7 +29075,7 @@ fn unionFieldPtr( // TODO would it be better if get_union_tag supported pointers to unions? const union_val = try block.addTyOp(.load, union_ty, union_ptr); const active_tag = try block.addTyOp(.get_union_tag, Type.fromInterned(union_obj.enum_tag_ty), union_val); - try sema.panicInactiveUnionField(block, src, active_tag, wanted_tag); + try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, wanted_tag); } if (field_ty.zigTypeTag(zcu) == .noreturn) { _ = try block.addNoOp(.unreach); @@ -29304,7 +29150,7 @@ fn unionFieldVal( const wanted_tag_val = try pt.enumValueFieldIndex(Type.fromInterned(union_obj.enum_tag_ty), enum_field_index); const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern()); const active_tag = try block.addTyOp(.get_union_tag, Type.fromInterned(union_obj.enum_tag_ty), union_byval); - try sema.panicInactiveUnionField(block, src, active_tag, wanted_tag); + try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, wanted_tag); } if (field_ty.zigTypeTag(zcu) == .noreturn) { _ = try block.addNoOp(.unreach); @@ -29668,11 +29514,11 @@ fn elemValArray( const runtime_src = if (maybe_undef_array_val != null) elem_index_src else array_src; if (oob_safety and block.wantSafety()) { - // Runtime check is only needed if unable to comptime check + // Runtime check is only needed if unable to comptime check. if (maybe_index_val == null) { const len_inst = try pt.intRef(Type.usize, array_len); const cmp_op: Air.Inst.Tag = if (array_sent != null) .cmp_lte else .cmp_lt; - try sema.panicIndexOutOfBounds(block, src, elem_index, len_inst, cmp_op); + try sema.addSafetyCheckIndexOob(block, src, elem_index, len_inst, cmp_op); } } @@ -29740,7 +29586,7 @@ fn elemPtrArray( if (oob_safety and block.wantSafety() and offset == null) { const len_inst = try pt.intRef(Type.usize, array_len); const cmp_op: Air.Inst.Tag = if (array_sent) .cmp_lte else .cmp_lt; - try sema.panicIndexOutOfBounds(block, src, elem_index, len_inst, cmp_op); + try sema.addSafetyCheckIndexOob(block, src, elem_index, len_inst, cmp_op); } return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty); @@ -29799,7 +29645,7 @@ fn elemValSlice( else try block.addTyOp(.slice_len, Type.usize, slice); const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; - try sema.panicIndexOutOfBounds(block, src, elem_index, len_inst, cmp_op); + try sema.addSafetyCheckIndexOob(block, src, elem_index, len_inst, cmp_op); } return block.addBinOp(.slice_elem_val, slice, elem_index); } @@ -29859,7 +29705,7 @@ fn elemPtrSlice( break :len try block.addTyOp(.slice_len, Type.usize, slice); }; const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; - try sema.panicIndexOutOfBounds(block, src, elem_index, len_inst, cmp_op); + try sema.addSafetyCheckIndexOob(block, src, elem_index, len_inst, cmp_op); } return block.addSliceElemPtr(slice, elem_index, elem_ptr_ty); } @@ -33666,12 +33512,7 @@ fn analyzeSlice( // requirement: start <= end assert(!block.is_comptime); try sema.requireRuntimeBlock(block, src, runtime_src.?); - const ok = try block.addBinOp(.cmp_lte, start, end); - if (!pt.zcu.comp.formatted_panics) { - try sema.addSafetyCheck(block, src, ok, .start_index_greater_than_end); - } else { - try sema.safetyCheckFormatted(block, src, ok, "panicStartGreaterThanEnd", &.{ start, end }); - } + try sema.addSafetyCheckStartGreaterThanEnd(block, src, start, end); } const new_len = if (by_length) try sema.coerce(block, Type.usize, uncasted_end_opt, end_src) @@ -33726,11 +33567,11 @@ fn analyzeSlice( else end; - try sema.panicIndexOutOfBounds(block, src, actual_end, actual_len, .cmp_lte); + try sema.addSafetyCheckIndexOob(block, src, actual_end, actual_len, .cmp_lte); } // requirement: result[new_len] == slice_sentinel - try sema.panicSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len); + try sema.addSafetyCheckSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len); } return result; }; @@ -33789,11 +33630,11 @@ fn analyzeSlice( try sema.analyzeArithmetic(block, .add, end, .one, src, end_src, end_src, true) else end; - try sema.panicIndexOutOfBounds(block, src, actual_end, len_inst, .cmp_lte); + try sema.addSafetyCheckIndexOob(block, src, actual_end, len_inst, .cmp_lte); } // requirement: start <= end - try sema.panicIndexOutOfBounds(block, src, start, end, .cmp_lte); + try sema.addSafetyCheckIndexOob(block, src, start, end, .cmp_lte); } const result = try block.addInst(.{ .tag = .slice, @@ -33807,7 +33648,7 @@ fn analyzeSlice( }); if (block.wantSafety()) { // requirement: result[new_len] == slice_sentinel - try sema.panicSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len); + try sema.addSafetyCheckSentinelMismatch(block, src, slice_sentinel, elem_ty, result, new_len); } return result; } @@ -37688,11 +37529,11 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { const only_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[0]); const val_val = (try sema.typeHasOnePossibleValue(only_field_ty)) orelse return null; - const only = try pt.intern(.{ .un = .{ + const only = try pt.internUnion(.{ .ty = ty.toIntern(), .tag = tag_val.toIntern(), .val = val_val.toIntern(), - } }); + }); return Value.fromInterned(only); }, @@ -38849,7 +38690,7 @@ fn analyzeUnreachable(sema: *Sema, block: *Block, src: LazySrcLoc, safety_check: sema.branch_hint = .cold; } - try sema.safetyPanic(block, src, .unreach); + try sema.safetyPanic(block, src, .reached_unreachable); } else { _ = try block.addNoOp(.unreach); } @@ -39123,3 +38964,36 @@ const loadComptimePtr = @import("Sema/comptime_ptr_access.zig").loadComptimePtr; const ComptimeLoadResult = @import("Sema/comptime_ptr_access.zig").ComptimeLoadResult; const storeComptimePtr = @import("Sema/comptime_ptr_access.zig").storeComptimePtr; const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStoreResult; + +/// Convenience function that looks 2 levels deep into `std.builtin`. +fn getBuiltinInnerType( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + outer_name: []const u8, + inner_name: []const u8, +) !Type { + const outer_ty = try sema.pt.getBuiltinType(outer_name); + return getInnerType(sema, block, src, outer_ty, inner_name); +} + +fn getInnerType( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + outer_ty: Type, + inner_name: []const u8, +) !Type { + const pt = sema.pt; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; + const gpa = sema.gpa; + const nav = try sema.namespaceLookup( + block, + src, + outer_ty.getNamespaceIndex(zcu), + try ip.getOrPutString(gpa, pt.tid, inner_name, .no_embedded_nulls), + ) orelse return sema.fail(block, src, "std.builtin missing {s}", .{inner_name}); + try sema.ensureNavResolved(src, nav); + return Type.fromInterned(ip.getNav(nav).status.resolved.val); +} diff --git a/src/Sema/bitcast.zig b/src/Sema/bitcast.zig index d3adbe7eb8..25955b113f 100644 --- a/src/Sema/bitcast.zig +++ b/src/Sema/bitcast.zig @@ -613,11 +613,11 @@ const PackValueBits = struct { pack.bit_offset = prev_bit_offset; break :backing; } - return Value.fromInterned(try pt.intern(.{ .un = .{ + return Value.fromInterned(try pt.internUnion(.{ .ty = ty.toIntern(), .tag = .none, .val = backing_val.toIntern(), - } })); + })); } const field_order = try pack.arena.alloc(u32, ty.unionTagTypeHypothetical(zcu).enumFieldCount(zcu)); @@ -658,21 +658,21 @@ const PackValueBits = struct { continue; } const tag_val = try pt.enumValueFieldIndex(ty.unionTagTypeHypothetical(zcu), field_idx); - return Value.fromInterned(try pt.intern(.{ .un = .{ + return Value.fromInterned(try pt.internUnion(.{ .ty = ty.toIntern(), .tag = tag_val.toIntern(), .val = field_val.toIntern(), - } })); + })); } // No field could represent the value. Just do whatever happens when we try to read // the backing type - either `undefined` or `error.ReinterpretDeclRef`. const backing_val = try pack.get(backing_ty); - return Value.fromInterned(try pt.intern(.{ .un = .{ + return Value.fromInterned(try pt.internUnion(.{ .ty = ty.toIntern(), .tag = .none, .val = backing_val.toIntern(), - } })); + })); }, else => return pack.primitive(ty), } diff --git a/src/Type.zig b/src/Type.zig index e4c7f7ab7a..19ddf6dfed 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -2677,11 +2677,11 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value { const only_field_ty = union_obj.field_types.get(ip)[0]; const val_val = (try Type.fromInterned(only_field_ty).onePossibleValue(pt)) orelse return null; - const only = try pt.intern(.{ .un = .{ + const only = try pt.internUnion(.{ .ty = ty.toIntern(), .tag = tag_val.toIntern(), .val = val_val.toIntern(), - } }); + }); return Value.fromInterned(only); }, .opaque_type => return null, diff --git a/src/Value.zig b/src/Value.zig index d6e533429a..157f47bc7e 100644 --- a/src/Value.zig +++ b/src/Value.zig @@ -713,11 +713,11 @@ pub fn readFromMemory( const union_size = ty.abiSize(zcu); const array_ty = try zcu.arrayType(.{ .len = union_size, .child = .u8_type }); const val = (try readFromMemory(array_ty, zcu, buffer, arena)).toIntern(); - return Value.fromInterned(try pt.intern(.{ .un = .{ + return Value.fromInterned(try pt.internUnion(.{ .ty = ty.toIntern(), .tag = .none, .val = val, - } })); + })); }, .@"packed" => { const byte_count = (@as(usize, @intCast(ty.bitSize(zcu))) + 7) / 8; @@ -860,11 +860,11 @@ pub fn readFromPackedMemory( .@"packed" => { const backing_ty = try ty.unionBackingType(pt); const val = (try readFromPackedMemory(backing_ty, pt, buffer, bit_offset, arena)).toIntern(); - return Value.fromInterned(try pt.intern(.{ .un = .{ + return Value.fromInterned(try pt.internUnion(.{ .ty = ty.toIntern(), .tag = .none, .val = val, - } })); + })); }, }, .pointer => { @@ -4481,11 +4481,11 @@ pub fn resolveLazy( return if (resolved_tag == un.tag and resolved_val == un.val) val else - Value.fromInterned(try pt.intern(.{ .un = .{ + Value.fromInterned(try pt.internUnion(.{ .ty = un.ty, .tag = resolved_tag, .val = resolved_val, - } })); + })); }, else => return val, } diff --git a/src/Zcu.zig b/src/Zcu.zig index e71e7fae9d..f5f433ed9c 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -210,45 +210,15 @@ all_type_references: std.ArrayListUnmanaged(TypeReference) = .empty, /// Freelist of indices in `all_type_references`. free_type_references: std.ArrayListUnmanaged(u32) = .empty, -panic_messages: [PanicId.len]InternPool.Nav.Index.Optional = .{.none} ** PanicId.len, /// The panic function body. panic_func_index: InternPool.Index = .none, null_stack_trace: InternPool.Index = .none, +panic_cause_type: InternPool.Index = .none, generation: u32 = 0, pub const PerThread = @import("Zcu/PerThread.zig"); -pub const PanicId = enum { - unreach, - unwrap_null, - cast_to_null, - incorrect_alignment, - invalid_error_code, - cast_truncated_data, - negative_to_unsigned, - integer_overflow, - shl_overflow, - shr_overflow, - divide_by_zero, - exact_division_remainder, - inactive_union_field, - integer_part_out_of_bounds, - corrupt_switch, - shift_rhs_too_big, - invalid_enum_value, - sentinel_mismatch, - unwrap_error, - index_out_of_bounds, - start_index_greater_than_end, - for_len_mismatch, - memcpy_len_mismatch, - memcpy_alias, - noreturn_returned, - - pub const len = @typeInfo(PanicId).@"enum".fields.len; -}; - pub const GlobalErrorSet = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void); pub const CImportError = struct { @@ -2926,14 +2896,6 @@ pub const Feature = enum { /// When this feature is enabled, Sema will emit calls to `std.builtin.panic` /// for things like safety checks and unreachables. Otherwise traps will be emitted. panic_fn, - /// When this feature is enabled, Sema will emit calls to `std.builtin.panicUnwrapError`. - /// This error message requires more advanced formatting, hence it being seperate from `panic_fn`. - /// Otherwise traps will be emitted. - panic_unwrap_error, - /// When this feature is enabled, Sema will emit calls to the more complex panic functions - /// that use formatting to add detail to error messages. Similar to `panic_unwrap_error`. - /// Otherwise traps will be emitted. - safety_check_formatted, /// When this feature is enabled, Sema will insert tracer functions for gathering a stack /// trace for error returns. error_return_trace, diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index a11910302d..a0e90e60bd 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -2697,11 +2697,16 @@ pub fn reportRetryableFileError( gop.value_ptr.* = err_msg; } -///Shortcut for calling `intern_pool.get`. +/// Shortcut for calling `intern_pool.get`. pub fn intern(pt: Zcu.PerThread, key: InternPool.Key) Allocator.Error!InternPool.Index { return pt.zcu.intern_pool.get(pt.zcu.gpa, pt.tid, key); } +/// Shortcut for calling `intern_pool.getUnion`. +pub fn internUnion(pt: Zcu.PerThread, un: InternPool.Key.Union) Allocator.Error!InternPool.Index { + return pt.zcu.intern_pool.getUnion(pt.zcu.gpa, pt.tid, un); +} + /// Essentially a shortcut for calling `intern_pool.getCoerced`. /// However, this function also allows coercing `extern`s. The `InternPool` function can't do /// this because it requires potentially pushing to the job queue. @@ -2949,11 +2954,12 @@ pub fn intValue_i64(pt: Zcu.PerThread, ty: Type, x: i64) Allocator.Error!Value { } pub fn unionValue(pt: Zcu.PerThread, union_ty: Type, tag: Value, val: Value) Allocator.Error!Value { - return Value.fromInterned(try pt.intern(.{ .un = .{ + const zcu = pt.zcu; + return Value.fromInterned(try zcu.intern_pool.getUnion(zcu.gpa, pt.tid, .{ .ty = union_ty.toIntern(), .tag = tag.toIntern(), .val = val.toIntern(), - } })); + })); } /// This function casts the float representation down to the representation of the type, potentially diff --git a/src/crash_report.zig b/src/crash_report.zig index c0a90d8705..fb681c8f08 100644 --- a/src/crash_report.zig +++ b/src/crash_report.zig @@ -17,7 +17,7 @@ const Decl = Zcu.Decl; /// 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) compilerPanic else std.builtin.default_panic; +pub const panic = if (build_options.enable_debug_extensions) compilerPanic else std.debug.defaultPanic; /// Install signal handlers to identify crashes and report diagnostics. pub fn initialize() void { @@ -152,12 +152,16 @@ fn writeFilePath(file: *Zcu.File, writer: anytype) !void { try writer.writeAll(file.sub_file_path); } -pub fn compilerPanic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, maybe_ret_addr: ?usize) noreturn { +pub fn compilerPanic( + cause: std.builtin.PanicCause, + error_return_trace: ?*std.builtin.StackTrace, + maybe_ret_addr: ?usize, +) noreturn { @branchHint(.cold); PanicSwitch.preDispatch(); const ret_addr = maybe_ret_addr orelse @returnAddress(); const stack_ctx: StackContext = .{ .current = .{ .ret_addr = ret_addr } }; - PanicSwitch.dispatch(error_return_trace, stack_ctx, msg); + PanicSwitch.dispatch(error_return_trace, stack_ctx, cause); } /// Attaches a global SIGSEGV handler @@ -354,17 +358,17 @@ const PanicSwitch = struct { pub fn dispatch( trace: ?*const std.builtin.StackTrace, stack_ctx: StackContext, - msg: []const u8, + panic_cause: std.builtin.PanicCause, ) noreturn { var panic_state: *volatile PanicState = &panic_state_raw; debug.assert(panic_state.awaiting_dispatch); panic_state.awaiting_dispatch = false; nosuspend switch (panic_state.recover_stage) { - .initialize => goTo(initPanic, .{ panic_state, trace, stack_ctx, msg }), - .report_stack => goTo(recoverReportStack, .{ panic_state, trace, stack_ctx, msg }), - .release_mutex => goTo(recoverReleaseMutex, .{ panic_state, trace, stack_ctx, msg }), - .release_ref_count => goTo(recoverReleaseRefCount, .{ panic_state, trace, stack_ctx, msg }), - .abort => goTo(recoverAbort, .{ panic_state, trace, stack_ctx, msg }), + .initialize => goTo(initPanic, .{ panic_state, trace, stack_ctx, panic_cause }), + .report_stack => goTo(recoverReportStack, .{ panic_state, trace, stack_ctx, panic_cause }), + .release_mutex => goTo(recoverReleaseMutex, .{ panic_state, trace, stack_ctx, panic_cause }), + .release_ref_count => goTo(recoverReleaseRefCount, .{ panic_state, trace, stack_ctx, panic_cause }), + .abort => goTo(recoverAbort, .{ panic_state, trace, stack_ctx, panic_cause }), .silent_abort => goTo(abort, .{}), }; } @@ -373,7 +377,7 @@ const PanicSwitch = struct { state: *volatile PanicState, trace: ?*const std.builtin.StackTrace, stack: StackContext, - msg: []const u8, + panic_cause: std.builtin.PanicCause, ) noreturn { // use a temporary so there's only one volatile store const new_state = PanicState{ @@ -398,6 +402,8 @@ const PanicSwitch = struct { const current_thread_id = std.Thread.getCurrentId(); stderr.print("thread {} panic: ", .{current_thread_id}) catch goTo(releaseMutex, .{state}); } + var buffer: [1000]u8 = undefined; + const msg = buffer[0..std.debug.fmtPanicCause(&buffer, panic_cause)]; stderr.print("{s}\n", .{msg}) catch goTo(releaseMutex, .{state}); state.recover_stage = .report_stack; @@ -413,9 +419,9 @@ const PanicSwitch = struct { state: *volatile PanicState, trace: ?*const std.builtin.StackTrace, stack: StackContext, - msg: []const u8, + panic_cause: std.builtin.PanicCause, ) noreturn { - recover(state, trace, stack, msg); + recover(state, trace, stack, panic_cause); state.recover_stage = .release_mutex; const stderr = io.getStdErr().writer(); @@ -438,9 +444,9 @@ const PanicSwitch = struct { state: *volatile PanicState, trace: ?*const std.builtin.StackTrace, stack: StackContext, - msg: []const u8, + panic_cause: std.builtin.PanicCause, ) noreturn { - recover(state, trace, stack, msg); + recover(state, trace, stack, panic_cause); goTo(releaseMutex, .{state}); } @@ -456,9 +462,9 @@ const PanicSwitch = struct { state: *volatile PanicState, trace: ?*const std.builtin.StackTrace, stack: StackContext, - msg: []const u8, + panic_cause: std.builtin.PanicCause, ) noreturn { - recover(state, trace, stack, msg); + recover(state, trace, stack, panic_cause); goTo(releaseRefCount, .{state}); } @@ -484,9 +490,9 @@ const PanicSwitch = struct { state: *volatile PanicState, trace: ?*const std.builtin.StackTrace, stack: StackContext, - msg: []const u8, + panic_cause: std.builtin.PanicCause, ) noreturn { - recover(state, trace, stack, msg); + recover(state, trace, stack, panic_cause); state.recover_stage = .silent_abort; const stderr = io.getStdErr().writer(); @@ -510,7 +516,7 @@ const PanicSwitch = struct { state: *volatile PanicState, trace: ?*const std.builtin.StackTrace, stack: StackContext, - msg: []const u8, + panic_cause: std.builtin.PanicCause, ) void { switch (state.recover_verbosity) { .message_and_stack => { @@ -519,7 +525,7 @@ const PanicSwitch = struct { const stderr = io.getStdErr().writer(); stderr.writeAll("\nPanicked during a panic: ") catch {}; - stderr.writeAll(msg) catch {}; + stderr.writeAll(panic_cause) catch {}; stderr.writeAll("\nInner panic stack:\n") catch {}; if (trace) |t| { debug.dumpStackTrace(t.*); @@ -533,7 +539,7 @@ const PanicSwitch = struct { const stderr = io.getStdErr().writer(); stderr.writeAll("\nPanicked while dumping inner panic stack: ") catch {}; - stderr.writeAll(msg) catch {}; + stderr.writeAll(panic_cause) catch {}; stderr.writeAll("\n") catch {}; // If we succeed, restore all the way to dumping the stack. diff --git a/src/main.zig b/src/main.zig index 3e7813019e..b08acf568c 100644 --- a/src/main.zig +++ b/src/main.zig @@ -826,7 +826,6 @@ fn buildOutputType( var version: std.SemanticVersion = .{ .major = 0, .minor = 0, .patch = 0 }; var have_version = false; var compatibility_version: ?std.SemanticVersion = null; - var formatted_panics: ?bool = null; var function_sections = false; var data_sections = false; var no_builtin = false; @@ -1537,9 +1536,11 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "-gdwarf64")) { create_module.opts.debug_format = .{ .dwarf = .@"64" }; } else if (mem.eql(u8, arg, "-fformatted-panics")) { - formatted_panics = true; + // Remove this after 0.15.0 is tagged. + warn("-fformatted-panics is deprecated and does nothing", .{}); } else if (mem.eql(u8, arg, "-fno-formatted-panics")) { - formatted_panics = false; + // Remove this after 0.15.0 is tagged. + warn("-fno-formatted-panics is deprecated and does nothing", .{}); } else if (mem.eql(u8, arg, "-fsingle-threaded")) { mod_opts.single_threaded = true; } else if (mem.eql(u8, arg, "-fno-single-threaded")) { @@ -3405,7 +3406,6 @@ fn buildOutputType( .force_undefined_symbols = force_undefined_symbols, .stack_size = stack_size, .image_base = image_base, - .formatted_panics = formatted_panics, .function_sections = function_sections, .data_sections = data_sections, .no_builtin = no_builtin, diff --git a/src/mutable_value.zig b/src/mutable_value.zig index 49826c2fb2..9e63494d12 100644 --- a/src/mutable_value.zig +++ b/src/mutable_value.zig @@ -88,11 +88,11 @@ pub const MutableValue = union(enum) { .ptr = (try s.ptr.intern(pt, arena)).toIntern(), .len = (try s.len.intern(pt, arena)).toIntern(), } }), - .un => |u| try pt.intern(.{ .un = .{ + .un => |u| try pt.internUnion(.{ .ty = u.ty, .tag = u.tag, .val = (try u.payload.intern(pt, arena)).toIntern(), - } }), + }), }); } diff --git a/src/target.zig b/src/target.zig index d85981ec84..6348543f94 100644 --- a/src/target.zig +++ b/src/target.zig @@ -586,14 +586,6 @@ pub inline fn backendSupportsFeature(backend: std.builtin.CompilerBackend, compt => true, else => false, }, - .panic_unwrap_error => switch (backend) { - .stage2_c, .stage2_llvm => true, - else => false, - }, - .safety_check_formatted => switch (backend) { - .stage2_c, .stage2_llvm => true, - else => false, - }, .error_return_trace => switch (backend) { .stage2_llvm => true, else => false, diff --git a/test/cases/safety/unreachable.zig b/test/cases/safety/unreachable.zig index 492f7958b1..818d7e31a5 100644 --- a/test/cases/safety/unreachable.zig +++ b/test/cases/safety/unreachable.zig @@ -1,7 +1,8 @@ const std = @import("std"); -pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, ret_addr: ?usize) noreturn { _ = stack_trace; + _ = ret_addr; if (std.mem.eql(u8, message, "reached unreachable code")) { std.process.exit(0); }