From 9ccf8d3332dd9c1e4d967e3b8af2b98128d360ca Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 25 Sep 2024 13:22:47 -0700 Subject: [PATCH] fixes for this branch I had to bring back some of the old API so that I could compile the new compiler with an old compiler. --- lib/std/builtin.zig | 77 +++++++++++++++++++++++++++++++++++- lib/std/debug.zig | 18 ++------- src/Sema.zig | 28 ++++++++----- src/codegen/llvm.zig | 93 +++++++++++++++++++++++--------------------- src/crash_report.zig | 11 ++++-- 5 files changed, 152 insertions(+), 75 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 8530a64fed..2718296a11 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -761,18 +761,91 @@ pub const TestFn = struct { func: *const fn () anyerror!void, }; +const old_version = std.SemanticVersion.parse("0.14.0-dev.1659+4ceefca14") catch unreachable; +const is_old = @import("builtin").zig_version.order(old_version) != .gt; + /// 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 (PanicCause, ?*StackTrace, ?usize) noreturn; +pub const PanicFn = if (is_old) + fn ([]const u8, ?*StackTrace, ?usize) noreturn +else + fn (PanicCause, ?*StackTrace, ?usize) noreturn; /// The entry point for auto-generated calls by the compiler. -pub const panic: PanicFn = if (@hasDecl(root, "panic")) +pub const panic: PanicFn = if (is_old) + defaultPanicOld +else if (@hasDecl(root, "panic")) root.panic else if (@hasDecl(root, "os") and @hasDecl(root.os, "panic")) root.os.panic else std.debug.defaultPanic; +pub fn defaultPanicOld( + msg: []const u8, + trace: ?*const std.builtin.StackTrace, + first_trace_addr: ?usize, +) noreturn { + @branchHint(.cold); + std.debug.print("old panic: {s}\n", .{msg}); + _ = trace; + _ = first_trace_addr; + @trap(); +} + +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"; +}; + /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const PanicCause = union(enum) { diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 8e5498b3f5..d6312598d1 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -437,7 +437,7 @@ pub fn panicExtra( break :blk &buf; }, }; - std.builtin.panic(msg, trace, ret_addr); + std.builtin.panic(.{ .explicit_call = msg }, trace, ret_addr); } /// Non-zero whenever the program triggered a panic. @@ -487,18 +487,6 @@ pub fn defaultPanic( .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; @@ -571,7 +559,7 @@ pub fn defaultPanic( i += fmtInt10(buffer[i..], std.Thread.getCurrentId()); i += fmtBuf(buffer[i..], " panic: "); } - i += fmtPanicCause(&buffer, cause); + i += fmtPanicCause(buffer[i..], cause); buffer[i] = '\n'; i += 1; const msg = buffer[0..i]; @@ -672,7 +660,7 @@ fn fmtInt10(out_buf: []u8, integer_value: usize) usize { while (true) { i -= 1; - tmp_buf[i] = '0' + (a % 10); + tmp_buf[i] = '0' + @as(u8, @intCast(a % 10)); a /= 10; if (a == 0) break; } diff --git a/src/Sema.zig b/src/Sema.zig index a2d883a040..fd4c8cfa4f 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2566,7 +2566,7 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg std.debug.print("compile error during Sema:\n", .{}); var error_bundle = wip_errors.toOwnedBundle("") catch @panic("out of memory"); error_bundle.renderToStdErr(.{ .ttyconf = .no_color }); - crash_report.compilerPanic("unexpected compile error occurred", null, null); + crash_report.compilerPanic(.{ .explicit_call = "unexpected compile error occurred" }, null, null); } if (block) |start_block| { @@ -7334,17 +7334,21 @@ fn callPanic( call_operation: CallOperation, ) !void { const pt = sema.pt; - if (!pt.zcu.backendSupportsFeature(.panic_fn)) { + const zcu = pt.zcu; + if (!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_cause = if (payload == .void_value) + try initUnionFromEnumTag(pt, panic_cause_ty, panic_cause_ty.unionTagType(zcu).?, @intFromEnum(tag)) + else + 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) }; + const args: [3]Air.Inst.Ref = .{ panic_cause, err_return_trace, Air.internedToRef(null_usize.toIntern()) }; try sema.callBuiltin(block, call_src, panic_fn, .auto, &args, call_operation); } @@ -18326,11 +18330,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai .undefined, .null, .enum_literal, - => |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, - }))), + => |type_info_tag| return initUnionFromEnumTag(pt, type_info_ty, type_info_tag_ty, @intFromEnum(type_info_tag)), .@"fn" => { 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"); @@ -28009,7 +28009,7 @@ fn addSafetyCheckSentinelMismatch( 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 }); + const panic_cause_payload = try fail_block.addAggregateInit(mm_ty, &.{ expected_sentinel, actual_sentinel }); try callPanic(sema, &fail_block, src, .sentinel_mismatch_usize, panic_cause_payload, .@"safety check"); } else { try callPanic(sema, &fail_block, src, .sentinel_mismatch_other, .void_value, .@"safety check"); @@ -38997,3 +38997,11 @@ fn getInnerType( try sema.ensureNavResolved(src, nav); return Type.fromInterned(ip.getNav(nav).status.resolved.val); } + +fn initUnionFromEnumTag(pt: Zcu.PerThread, union_ty: Type, union_tag_ty: Type, field_index: u32) !Air.Inst.Ref { + return Air.internedToRef((try pt.internUnion(.{ + .ty = union_ty.toIntern(), + .tag = (try pt.enumValueFieldIndex(union_tag_ty, field_index)).toIntern(), + .val = .void_value, + }))); +} diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 816975955a..78ac35e9eb 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3848,13 +3848,13 @@ pub const Object = struct { .undef => unreachable, // handled above .simple_value => |simple_value| switch (simple_value) { - .undefined, - .void, - .null, - .empty_struct, - .@"unreachable", - .generic_poison, - => unreachable, // non-runtime values + .undefined => unreachable, // non-runtime value + .void => unreachable, // non-runtime value + .null => unreachable, // non-runtime value + .empty_struct => unreachable, // non-runtime value + .@"unreachable" => unreachable, // non-runtime value + .generic_poison => unreachable, // non-runtime value + .false => .false, .true => .true, }, @@ -5675,43 +5675,48 @@ pub const FuncGen = struct { } } - fn buildSimplePanic(fg: *FuncGen, panic_id: Zcu.PanicId) !void { - const o = fg.ng.object; - const zcu = o.pt.zcu; - const ip = &zcu.intern_pool; - const msg_nav_index = zcu.panic_messages[@intFromEnum(panic_id)].unwrap().?; - const msg_nav = ip.getNav(msg_nav_index); - const msg_len = Type.fromInterned(msg_nav.typeOf(ip)).childType(zcu).arrayLen(zcu); - const msg_ptr = try o.lowerValue(msg_nav.status.resolved.val); - 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.panic_func_index); - const panic_nav = ip.getNav(panic_func.owner_nav); - const fn_info = zcu.typeToFunc(Type.fromInterned(panic_nav.typeOf(ip))).?; - const panic_global = try o.resolveLlvmFunction(panic_func.owner_nav); - _ = try fg.wip.callIntrinsicAssumeCold(); - _ = try fg.wip.call( - .normal, - toLlvmCallConv(fn_info.cc, target), - .none, - panic_global.typeOf(&o.builder), - panic_global.toValue(&o.builder), - &.{ - msg_ptr.toValue(), - try o.builder.intValue(llvm_usize, msg_len), - try o.builder.nullValue(.ptr), - null_opt_addr_global.toValue(), - }, - "", - ); + const PanicCauseTag = @typeInfo(std.builtin.PanicCause).@"union".tag_type.?; + + fn buildSimplePanic(fg: *FuncGen, panic_cause_tag: PanicCauseTag) !void { + // TODO update this before merging the branch + _ = panic_cause_tag; + //const o = fg.ng.object; + //const zcu = o.pt.zcu; + //const ip = &zcu.intern_pool; + //const msg_nav_index = zcu.panic_messages[@intFromEnum(panic_id)].unwrap().?; + //const msg_nav = ip.getNav(msg_nav_index); + //const msg_len = Type.fromInterned(msg_nav.typeOf(ip)).childType(zcu).arrayLen(zcu); + //const msg_ptr = try o.lowerValue(msg_nav.status.resolved.val); + //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.panic_func_index); + //const panic_nav = ip.getNav(panic_func.owner_nav); + //const fn_info = zcu.typeToFunc(Type.fromInterned(panic_nav.typeOf(ip))).?; + //const panic_global = try o.resolveLlvmFunction(panic_func.owner_nav); + //_ = try fg.wip.callIntrinsicAssumeCold(); + //_ = try fg.wip.call( + // .normal, + // toLlvmCallConv(fn_info.cc, target), + // .none, + // panic_global.typeOf(&o.builder), + // panic_global.toValue(&o.builder), + // &.{ + // msg_ptr.toValue(), + // try o.builder.intValue(llvm_usize, msg_len), + // try o.builder.nullValue(.ptr), + // null_opt_addr_global.toValue(), + // }, + // "", + //); + _ = try fg.wip.callIntrinsic(.normal, .none, .trap, &.{}, &.{}, ""); _ = try fg.wip.@"unreachable"(); } diff --git a/src/crash_report.zig b/src/crash_report.zig index fb681c8f08..e7a18d7f60 100644 --- a/src/crash_report.zig +++ b/src/crash_report.zig @@ -212,7 +212,7 @@ fn handleSegfaultPosix(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopa else => .not_supported, }; - PanicSwitch.dispatch(null, stack_ctx, error_msg); + PanicSwitch.dispatch(null, stack_ctx, .{ .explicit_call = error_msg }); } const WindowsSegfaultMessage = union(enum) { @@ -338,7 +338,7 @@ const PanicSwitch = struct { // it's happening and print a message. var panic_state: *volatile PanicState = &panic_state_raw; if (panic_state.awaiting_dispatch) { - dispatch(null, .{ .current = .{ .ret_addr = null } }, "Panic while preparing callstack"); + dispatch(null, .{ .current = .{ .ret_addr = null } }, .{ .explicit_call = "Panic while preparing callstack" }); } panic_state.awaiting_dispatch = true; } @@ -518,6 +518,7 @@ const PanicSwitch = struct { stack: StackContext, panic_cause: std.builtin.PanicCause, ) void { + var buffer: [1000]u8 = undefined; switch (state.recover_verbosity) { .message_and_stack => { // lower the verbosity, and restore it at the end if we don't panic. @@ -525,7 +526,8 @@ const PanicSwitch = struct { const stderr = io.getStdErr().writer(); stderr.writeAll("\nPanicked during a panic: ") catch {}; - stderr.writeAll(panic_cause) catch {}; + const msg = buffer[0..std.debug.fmtPanicCause(&buffer, panic_cause)]; + stderr.writeAll(msg) catch {}; stderr.writeAll("\nInner panic stack:\n") catch {}; if (trace) |t| { debug.dumpStackTrace(t.*); @@ -539,7 +541,8 @@ const PanicSwitch = struct { const stderr = io.getStdErr().writer(); stderr.writeAll("\nPanicked while dumping inner panic stack: ") catch {}; - stderr.writeAll(panic_cause) catch {}; + const msg = buffer[0..std.debug.fmtPanicCause(&buffer, panic_cause)]; + stderr.writeAll(msg) catch {}; stderr.writeAll("\n") catch {}; // If we succeed, restore all the way to dumping the stack.