diff options
| -rw-r--r-- | lib/std/builtin.zig | 4 | ||||
| -rw-r--r-- | src/Compilation.zig | 5 | ||||
| -rw-r--r-- | src/Sema.zig | 76 | ||||
| -rw-r--r-- | src/main.zig | 8 |
4 files changed, 64 insertions, 29 deletions
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index fcdf43bd31..8c8d0b37b7 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -891,6 +891,10 @@ pub const panic_messages = struct { 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 noinline fn returnError(st: *StackTrace) void { diff --git a/src/Compilation.zig b/src/Compilation.zig index 795eb493e2..dcd9ca5cf6 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -101,6 +101,7 @@ debug_compile_errors: bool, job_queued_compiler_rt_lib: bool = false, job_queued_compiler_rt_obj: bool = false, alloc_failure_occurred: bool = false, +formatted_panics: bool = false, c_source_files: []const CSourceFile, clang_argv: []const []const u8, @@ -937,6 +938,7 @@ pub const InitOptions = struct { use_stage1: ?bool = null, single_threaded: ?bool = null, strip: ?bool = null, + formatted_panics: ?bool = null, rdynamic: bool = false, function_sections: bool = false, no_builtin: bool = false, @@ -1457,6 +1459,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .Debug => @as(u8, 0), else => @as(u8, 3), }; + const formatted_panics = options.formatted_panics orelse (options.optimize_mode == .Debug); // We put everything into the cache hash that *cannot be modified // during an incremental update*. For example, one cannot change the @@ -1551,6 +1554,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { hash.addOptionalBytes(options.test_name_prefix); hash.add(options.skip_linker_dependencies); hash.add(options.parent_compilation_link_libc); + hash.add(formatted_panics); // In the case of incremental cache mode, this `zig_cache_artifact_directory` // is computed based on a hash of non-linker inputs, and it is where all @@ -1957,6 +1961,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .owned_link_dir = owned_link_dir, .color = options.color, .reference_trace = options.reference_trace, + .formatted_panics = formatted_panics, .time_report = options.time_report, .stack_report = options.stack_report, .unwind_tables = unwind_tables, diff --git a/src/Sema.zig b/src/Sema.zig index 6c87f7d4b9..686d9c11cb 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -667,9 +667,9 @@ pub const Block = struct { return result_index; } - fn addUnreachable(block: *Block, src: LazySrcLoc, safety_check: bool) !void { + fn addUnreachable(block: *Block, safety_check: bool) !void { if (safety_check and block.wantSafety()) { - _ = try block.sema.safetyPanic(block, src, .unreach); + try block.sema.safetyPanic(block, .unreach); } else { _ = try block.addNoOp(.unreach); } @@ -5003,7 +5003,8 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index, force_comptime: bo if (block.is_comptime or force_comptime) { return sema.fail(block, src, "encountered @panic at comptime", .{}); } - return sema.panicWithMsg(block, src, msg_inst); + try sema.panicWithMsg(block, src, msg_inst); + return always_noreturn; } fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -7962,7 +7963,7 @@ fn analyzeErrUnionPayload( if (safety_check and block.wantSafety() and !err_union_ty.errorUnionSet().errorSetIsEmpty()) { - try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err, .is_non_err); + try sema.panicUnwrapError(block, operand, .unwrap_errunion_err, .is_non_err); } return block.addTyOp(.unwrap_errunion_payload, payload_ty, operand); @@ -8047,7 +8048,7 @@ fn analyzeErrUnionPayloadPtr( if (safety_check and block.wantSafety() and !err_union_ty.errorUnionSet().errorSetIsEmpty()) { - try sema.panicUnwrapError(block, src, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr); + try sema.panicUnwrapError(block, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr); } const air_tag: Air.Inst.Tag = if (initializing) @@ -9542,7 +9543,7 @@ fn zirSwitchCapture( .ErrorSet => if (block.switch_else_err_ty) |some| { return sema.bitCast(block, some, operand, operand_src); } else { - try block.addUnreachable(operand_src, false); + try block.addUnreachable(false); return Air.Inst.Ref.unreachable_value; }, else => return operand, @@ -10975,7 +10976,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError // that it is unreachable. if (case_block.wantSafety()) { try sema.zirDbgStmt(&case_block, cond_dbg_node_index); - _ = try sema.safetyPanic(&case_block, src, .corrupt_switch); + try sema.safetyPanic(&case_block, .corrupt_switch); } else { _ = try case_block.addNoOp(.unreach); } @@ -11304,6 +11305,11 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable"; const src = inst_data.src(); + if (!sema.mod.comp.formatted_panics) { + try sema.safetyPanic(block, .unwrap_error); + return true; + } + const panic_fn = try sema.getBuiltin("panicUnwrapError"); const err_return_trace = try sema.getErrorReturnTrace(block); const args: [2]Air.Inst.Ref = .{ err_return_trace, operand }; @@ -16513,7 +16519,7 @@ fn zirUnreachable(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError return sema.fail(block, src, "reached unreachable code", .{}); } // TODO Add compile error for @optimizeFor occurring too late in a scope. - try block.addUnreachable(src, true); + try block.addUnreachable(true); return always_noreturn; } @@ -22128,6 +22134,10 @@ pub const PanicId = enum { corrupt_switch, shift_rhs_too_big, invalid_enum_value, + sentinel_mismatch, + unwrap_error, + index_out_of_bounds, + start_index_greater_than_end, }; fn addSafetyCheck( @@ -22152,12 +22162,7 @@ fn addSafetyCheck( defer fail_block.instructions.deinit(gpa); - // This function doesn't actually need a src location but if - // the panic function interface ever changes passing `.unneeded` here - // will cause confusing panics. - const src = sema.src; - _ = try sema.safetyPanic(&fail_block, src, panic_id); - + try sema.safetyPanic(&fail_block, panic_id); try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); } @@ -22221,7 +22226,7 @@ fn panicWithMsg( block: *Block, src: LazySrcLoc, msg_inst: Air.Inst.Ref, -) !Zir.Inst.Index { +) !void { const mod = sema.mod; const arena = sema.arena; @@ -22232,7 +22237,7 @@ fn panicWithMsg( // TODO implement this feature in all the backends and then delete this branch _ = try block.addNoOp(.breakpoint); _ = try block.addNoOp(.unreach); - return always_noreturn; + return; } const panic_fn = try sema.getBuiltin("panic"); const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); @@ -22248,19 +22253,20 @@ fn panicWithMsg( ); const args: [3]Air.Inst.Ref = .{ msg_inst, null_stack_trace, .null_value }; _ = try sema.analyzeCall(block, panic_fn, src, src, .auto, false, &args, null); - return always_noreturn; } fn panicUnwrapError( sema: *Sema, parent_block: *Block, - src: LazySrcLoc, operand: Air.Inst.Ref, unwrap_err_tag: Air.Inst.Tag, is_non_err_tag: Air.Inst.Tag, ) !void { assert(!parent_block.is_comptime); const ok = try parent_block.addUnOp(is_non_err_tag, operand); + if (!sema.mod.comp.formatted_panics) { + return sema.addSafetyCheck(parent_block, ok, .unwrap_error); + } const gpa = sema.gpa; var fail_block: Block = .{ @@ -22289,7 +22295,7 @@ fn 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.analyzeCall(&fail_block, panic_fn, src, src, .auto, false, &args, null); + _ = try sema.analyzeCall(&fail_block, panic_fn, sema.src, sema.src, .auto, false, &args, null); } } try sema.addSafetyCheckExtra(parent_block, ok, &fail_block); @@ -22304,7 +22310,10 @@ fn panicIndexOutOfBounds( ) !void { assert(!parent_block.is_comptime); const ok = try parent_block.addBinOp(cmp_op, index, len); - try sema.safetyPanicFormatted(parent_block, ok, "panicOutOfBounds", &.{ index, len }); + if (!sema.mod.comp.formatted_panics) { + return sema.addSafetyCheck(parent_block, ok, .index_out_of_bounds); + } + try sema.safetyCheckFormatted(parent_block, ok, "panicOutOfBounds", &.{ index, len }); } fn panicStartLargerThanEnd( @@ -22315,7 +22324,10 @@ fn panicStartLargerThanEnd( ) !void { assert(!parent_block.is_comptime); const ok = try parent_block.addBinOp(.cmp_lte, start, end); - try sema.safetyPanicFormatted(parent_block, ok, "panicStartGreaterThanEnd", &.{ start, end }); + if (!sema.mod.comp.formatted_panics) { + return sema.addSafetyCheck(parent_block, ok, .start_index_greater_than_end); + } + try sema.safetyCheckFormatted(parent_block, ok, "panicStartGreaterThanEnd", &.{ start, end }); } fn panicInactiveUnionField( @@ -22326,7 +22338,10 @@ fn panicInactiveUnionField( ) !void { assert(!parent_block.is_comptime); const ok = try parent_block.addBinOp(.cmp_eq, active_tag, wanted_tag); - try sema.safetyPanicFormatted(parent_block, ok, "panicInactiveUnionField", &.{ active_tag, wanted_tag }); + if (!sema.mod.comp.formatted_panics) { + return sema.addSafetyCheck(parent_block, ok, .inactive_union_field); + } + try sema.safetyCheckFormatted(parent_block, ok, "panicInactiveUnionField", &.{ active_tag, wanted_tag }); } fn panicSentinelMismatch( @@ -22369,16 +22384,20 @@ fn panicSentinelMismatch( return; }; - try sema.safetyPanicFormatted(parent_block, ok, "panicSentinelMismatch", &.{ expected_sentinel, actual_sentinel }); + if (!sema.mod.comp.formatted_panics) { + return sema.addSafetyCheck(parent_block, ok, .sentinel_mismatch); + } + try sema.safetyCheckFormatted(parent_block, ok, "panicSentinelMismatch", &.{ expected_sentinel, actual_sentinel }); } -fn safetyPanicFormatted( +fn safetyCheckFormatted( sema: *Sema, parent_block: *Block, ok: Air.Inst.Ref, func: []const u8, args: []const Air.Inst.Ref, ) CompileError!void { + assert(sema.mod.comp.formatted_panics); const gpa = sema.gpa; var fail_block: Block = .{ @@ -22413,19 +22432,18 @@ fn safetyPanicFormatted( fn safetyPanic( sema: *Sema, block: *Block, - src: LazySrcLoc, panic_id: PanicId, -) CompileError!Zir.Inst.Index { +) CompileError!void { const panic_messages_ty = try sema.getBuiltinType("panic_messages"); const msg_decl_index = (try sema.namespaceLookup( block, - src, + sema.src, panic_messages_ty.getNamespace().?, @tagName(panic_id), )).?; - const msg_inst = try sema.analyzeDeclVal(block, src, msg_decl_index); - return sema.panicWithMsg(block, src, msg_inst); + const msg_inst = try sema.analyzeDeclVal(block, sema.src, msg_decl_index); + try sema.panicWithMsg(block, sema.src, msg_inst); } fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void { diff --git a/src/main.zig b/src/main.zig index c372462365..e3721d1101 100644 --- a/src/main.zig +++ b/src/main.zig @@ -406,6 +406,8 @@ const usage_build_generic = \\ -fno-function-sections All functions go into same section \\ -fstrip Omit debug symbols \\ -fno-strip Keep debug symbols + \\ -fformatted-panics Enable formatted safety panics + \\ -fno-formatted-panics Disable formatted safety panics \\ -ofmt=[mode] Override target object format \\ elf Executable and Linking Format \\ c C source code @@ -632,6 +634,7 @@ fn buildOutputType( var have_version = false; var compatibility_version: ?std.builtin.Version = null; var strip: ?bool = null; + var formatted_panics: ?bool = null; var function_sections = false; var no_builtin = false; var watch = false; @@ -1242,6 +1245,10 @@ fn buildOutputType( strip = true; } else if (mem.eql(u8, arg, "-fno-strip")) { strip = false; + } else if (mem.eql(u8, arg, "-fformatted-panics")) { + formatted_panics = true; + } else if (mem.eql(u8, arg, "-fno-formatted-panics")) { + formatted_panics = false; } else if (mem.eql(u8, arg, "-fsingle-threaded")) { single_threaded = true; } else if (mem.eql(u8, arg, "-fno-single-threaded")) { @@ -2938,6 +2945,7 @@ fn buildOutputType( .stack_size_override = stack_size_override, .image_base_override = image_base_override, .strip = strip, + .formatted_panics = formatted_panics, .single_threaded = single_threaded, .function_sections = function_sections, .no_builtin = no_builtin, |
