diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index 0afb633c86..efe314095c 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -9,6 +9,10 @@ link_libunwind: bool, any_unwind_tables: bool, any_c_source_files: bool, any_non_single_threaded: bool, +/// This is true if any Module has error_tracing set to true. Function types +/// and function calling convention depend on this global value, however, other +/// kinds of error tracing are omitted depending on the per-Module setting. +any_error_tracing: bool, pie: bool, /// If this is true then linker code is responsible for making an LLVM IR /// Module, outputting it to an object file, and then linking that together @@ -34,6 +38,8 @@ is_test: bool, test_evented_io: bool, entry: ?[]const u8, debug_format: DebugFormat, +root_strip: bool, +root_error_tracing: bool, pub const CFrontend = enum { clang, aro }; @@ -51,6 +57,7 @@ pub const Options = struct { emit_bin: bool, root_optimize_mode: ?std.builtin.OptimizeMode = null, root_strip: ?bool = null, + root_error_tracing: ?bool = null, link_mode: ?std.builtin.LinkMode = null, ensure_libc_on_non_freestanding: bool = false, ensure_libcpp_on_non_freestanding: bool = false, @@ -60,6 +67,7 @@ pub const Options = struct { any_dyn_libs: bool = false, any_c_source_files: bool = false, any_non_stripped: bool = false, + any_error_tracing: bool = false, emit_llvm_ir: bool = false, emit_llvm_bc: bool = false, link_libc: ?bool = null, @@ -395,6 +403,17 @@ pub fn resolve(options: Options) !Config { }; }; + const root_error_tracing = b: { + if (options.root_error_tracing) |x| break :b x; + if (root_strip) break :b false; + break :b switch (root_optimize_mode) { + .Debug => true, + .ReleaseSafe, .ReleaseFast, .ReleaseSmall => false, + }; + }; + + const any_error_tracing = root_error_tracing or options.any_error_tracing; + return .{ .output_mode = options.output_mode, .have_zcu = options.have_zcu, @@ -407,6 +426,8 @@ pub fn resolve(options: Options) !Config { .any_unwind_tables = any_unwind_tables, .any_c_source_files = options.any_c_source_files, .any_non_single_threaded = options.any_non_single_threaded, + .any_error_tracing = any_error_tracing, + .root_error_tracing = root_error_tracing, .pie = pie, .lto = lto, .import_memory = import_memory, @@ -419,6 +440,7 @@ pub fn resolve(options: Options) !Config { .entry = entry, .wasi_exec_model = wasi_exec_model, .debug_format = debug_format, + .root_strip = root_strip, }; } diff --git a/src/Package/Module.zig b/src/Package/Module.zig index 051303ca26..5e786a6fa2 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -114,9 +114,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { const strip = b: { if (options.inherited.strip) |x| break :b x; if (options.parent) |p| break :b p.strip; - if (optimize_mode == .ReleaseSmall) break :b true; - if (!target_util.hasDebugInfo(target)) break :b true; - break :b false; + break :b options.global.root_strip; }; const valgrind = b: { @@ -156,11 +154,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { const error_tracing = b: { if (options.inherited.error_tracing) |x| break :b x; if (options.parent) |p| break :b p.error_tracing; - if (strip) break :b false; - break :b switch (optimize_mode) { - .Debug => true, - .ReleaseSafe, .ReleaseFast, .ReleaseSmall => false, - }; + break :b options.global.root_error_tracing; }; const pic = b: { diff --git a/src/Sema.zig b/src/Sema.zig index 2d46faf435..6d14deb095 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1329,13 +1329,13 @@ fn analyzeBodyInner( }, .dbg_block_begin => { dbg_block_begins += 1; - try sema.zirDbgBlockBegin(block); + try zirDbgBlockBegin(block); i += 1; continue; }, .dbg_block_end => { dbg_block_begins -= 1; - try sema.zirDbgBlockEnd(block); + try zirDbgBlockEnd(block); i += 1; continue; }, @@ -1830,17 +1830,17 @@ fn analyzeBodyInner( }; // balance out dbg_block_begins in case of early noreturn - const noreturn_inst = block.instructions.popOrNull(); - while (dbg_block_begins > 0) { - dbg_block_begins -= 1; - if (block.is_comptime or mod.comp.bin_file.options.strip) continue; - - _ = try block.addInst(.{ - .tag = .dbg_block_end, - .data = undefined, - }); + if (!block.is_comptime and !block.ownerModule().strip) { + const noreturn_inst = block.instructions.popOrNull(); + while (dbg_block_begins > 0) { + dbg_block_begins -= 1; + _ = try block.addInst(.{ + .tag = .dbg_block_end, + .data = undefined, + }); + } + if (noreturn_inst) |some| try block.instructions.append(sema.gpa, some); } - if (noreturn_inst) |some| try block.instructions.append(sema.gpa, some); // We may have overwritten the capture scope due to a `repeat` instruction where // the body had a capture; restore it now. @@ -6272,7 +6272,7 @@ fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi // ZIR code that possibly will need to generate runtime code. So error messages // and other source locations must not rely on sema.src being set from dbg_stmt // instructions. - if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; + if (block.is_comptime or block.ownerModule().strip) return; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt; @@ -6297,8 +6297,8 @@ fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi }); } -fn zirDbgBlockBegin(sema: *Sema, block: *Block) CompileError!void { - if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; +fn zirDbgBlockBegin(block: *Block) CompileError!void { + if (block.is_comptime or block.ownerModule().strip) return; _ = try block.addInst(.{ .tag = .dbg_block_begin, @@ -6306,8 +6306,8 @@ fn zirDbgBlockBegin(sema: *Sema, block: *Block) CompileError!void { }); } -fn zirDbgBlockEnd(sema: *Sema, block: *Block) CompileError!void { - if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; +fn zirDbgBlockEnd(block: *Block) CompileError!void { + if (block.is_comptime or block.ownerModule().strip) return; _ = try block.addInst(.{ .tag = .dbg_block_end, @@ -6321,7 +6321,7 @@ fn zirDbgVar( inst: Zir.Inst.Index, air_tag: Air.Inst.Tag, ) CompileError!void { - if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; + if (block.is_comptime or block.ownerModule().strip) return; const str_op = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_op; const operand = try sema.resolveInst(str_op.operand); @@ -6519,7 +6519,7 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref const src = sema.src; if (!mod.backendSupportsFeature(.error_return_trace)) return .none; - if (!mod.comp.bin_file.options.error_return_tracing) return .none; + if (!block.ownerModule().error_tracing) return .none; if (block.is_comptime) return .none; @@ -6703,7 +6703,7 @@ fn zirCall( input_is_error = false; } - if (mod.backendSupportsFeature(.error_return_trace) and mod.comp.bin_file.options.error_return_tracing and + if (mod.backendSupportsFeature(.error_return_trace) and block.ownerModule().error_tracing and !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace)) { const return_ty = sema.typeOf(call_inst); @@ -7456,7 +7456,7 @@ fn analyzeCall( new_fn_info.return_type = sema.fn_ret_ty.toIntern(); const new_func_resolved_ty = try mod.funcType(new_fn_info); if (!is_comptime_call and !block.is_typeof) { - try sema.emitDbgInline(block, prev_fn_index, module_fn_index, new_func_resolved_ty, .dbg_inline_begin); + try emitDbgInline(block, prev_fn_index, module_fn_index, new_func_resolved_ty, .dbg_inline_begin); const zir_tags = sema.code.instructions.items(.tag); for (fn_info.param_body) |param| switch (zir_tags[@intFromEnum(param)]) { @@ -7494,7 +7494,7 @@ fn analyzeCall( if (!is_comptime_call and !block.is_typeof and sema.typeOf(result).zigTypeTag(mod) != .NoReturn) { - try sema.emitDbgInline( + try emitDbgInline( block, module_fn_index, prev_fn_index, @@ -8067,15 +8067,13 @@ fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) } fn emitDbgInline( - sema: *Sema, block: *Block, old_func: InternPool.Index, new_func: InternPool.Index, new_func_ty: Type, tag: Air.Inst.Tag, ) CompileError!void { - const mod = sema.mod; - if (mod.comp.bin_file.options.strip) return; + if (block.ownerModule().strip) return; // Recursive inline call; no dbg_inline needed. if (old_func == new_func) return; @@ -9109,7 +9107,7 @@ fn handleExternLibName( ); break :blk; } - if (!target.isWasm() and !comp.bin_file.options.pic) { + if (!target.isWasm() and !block.ownerModule().pic) { return sema.fail( block, src_loc, @@ -18738,16 +18736,16 @@ fn wantErrorReturnTracing(sema: *Sema, fn_ret_ty: Type) bool { const mod = sema.mod; if (!mod.backendSupportsFeature(.error_return_trace)) return false; - return fn_ret_ty.isError(mod) and - mod.comp.bin_file.options.error_return_tracing; + return fn_ret_ty.isError(mod) and mod.comp.config.any_error_tracing; } fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { const mod = sema.mod; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].save_err_ret_index; + // TODO: replace all of these checks with logic in module creation if (!mod.backendSupportsFeature(.error_return_trace)) return; - if (!mod.comp.bin_file.options.error_return_tracing) return; + if (!block.ownerModule().error_tracing) return; // This is only relevant at runtime. if (block.is_comptime or block.is_typeof) return; @@ -18774,7 +18772,7 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) if (!mod.backendSupportsFeature(.error_return_trace)) return; if (!ip.funcAnalysis(sema.owner_func_index).calls_or_awaits_errorable_fn) return; - if (!mod.comp.bin_file.options.error_return_tracing) return; + if (!start_block.ownerModule().error_tracing) return; const tracy = trace(@src()); defer tracy.end(); @@ -20045,7 +20043,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { if (sema.owner_func_index != .none and ip.funcAnalysis(sema.owner_func_index).calls_or_awaits_errorable_fn and - mod.comp.bin_file.options.error_return_tracing and + mod.ownerModule().error_tracing and mod.backendSupportsFeature(.error_return_trace)) { return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); @@ -34504,7 +34502,9 @@ pub fn resolveFnTypes(sema: *Sema, fn_ty: Type) CompileError!void { try sema.resolveTypeFully(Type.fromInterned(fn_ty_info.return_type)); - if (mod.comp.bin_file.options.error_return_tracing and Type.fromInterned(fn_ty_info.return_type).isError(mod)) { + if (mod.comp.config.any_error_tracing and + Type.fromInterned(fn_ty_info.return_type).isError(mod)) + { // Ensure the type exists so that backends can assume that. _ = try sema.getBuiltinType("StackTrace"); } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 6545f84f9d..75fb373d9b 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1398,7 +1398,7 @@ pub const Object = struct { }; const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(mod) and - mod.comp.bin_file.options.error_return_tracing; + mod.comp.config.any_error_tracing; const err_ret_trace: Builder.Value = if (err_return_tracing) param: { const param = wip.arg(llvm_arg_i); @@ -2820,7 +2820,7 @@ pub const Object = struct { } if (Type.fromInterned(fn_info.return_type).isError(mod) and - o.module.comp.bin_file.options.error_return_tracing) + o.module.comp.config.any_error_tracing) { const ptr_ty = try mod.singleMutPtrType(try o.getStackTraceType()); try param_di_types.append(try o.lowerDebugType(ptr_ty, .full)); @@ -2988,7 +2988,7 @@ pub const Object = struct { } const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(mod) and - mod.comp.bin_file.options.error_return_tracing; + mod.comp.config.any_error_tracing; if (err_return_tracing) { try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder); @@ -3677,7 +3677,7 @@ pub const Object = struct { } if (Type.fromInterned(fn_info.return_type).isError(mod) and - mod.comp.bin_file.options.error_return_tracing) + mod.comp.config.any_error_tracing) { const ptr_ty = try mod.singleMutPtrType(try o.getStackTraceType()); try llvm_params.append(o.gpa, try o.lowerType(ptr_ty)); @@ -5142,7 +5142,7 @@ pub const FuncGen = struct { }; const err_return_tracing = return_type.isError(mod) and - o.module.comp.bin_file.options.error_return_tracing; + o.module.comp.config.any_error_tracing; if (err_return_tracing) { assert(self.err_ret_trace != .none); try llvm_args.append(self.err_ret_trace); diff --git a/src/main.zig b/src/main.zig index dbd9759015..b73023e5b3 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1055,6 +1055,8 @@ fn buildOutputType( create_module.opts.any_unwind_tables = true; if (mod_opts.strip == false) create_module.opts.any_non_stripped = true; + if (mod_opts.error_tracing == true) + create_module.opts.any_error_tracing = true; const root_src = try introspect.resolvePath(arena, root_src_orig); try create_module.modules.put(arena, mod_name, .{ @@ -2535,6 +2537,8 @@ fn buildOutputType( create_module.opts.any_unwind_tables = true; if (mod_opts.strip == false) create_module.opts.any_non_stripped = true; + if (mod_opts.error_tracing == true) + create_module.opts.any_error_tracing = true; const src_path = try introspect.resolvePath(arena, unresolved_src_path); try create_module.modules.put(arena, "main", .{ @@ -3741,6 +3745,7 @@ fn createModule( create_module.opts.resolved_target = resolved_target; create_module.opts.root_optimize_mode = cli_mod.inherited.optimize_mode; create_module.opts.root_strip = cli_mod.inherited.strip; + create_module.opts.root_error_tracing = cli_mod.inherited.error_tracing; const target = resolved_target.result; // First, remove libc, libc++, and compiler_rt libraries from the system libraries list.