From 8b2949e372e615886b9087b06187878452421724 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 7 Aug 2026 13:28:16 -0700 Subject: [PATCH] simplify stack trace and error trace tests by explicitly listing out the combinations of parameters we would like to check. --- test/error_traces.zig | 43 +++++++- test/src/ErrorTrace.zig | 169 ++++++++++++++++++++--------- test/src/StackTrace.zig | 234 +++++++++++++++++++++++++--------------- test/stack_traces.zig | 29 ++++- test/tests.zig | 114 ++------------------ 5 files changed, 338 insertions(+), 251 deletions(-) diff --git a/test/error_traces.zig b/test/error_traces.zig index 071e4e8df53b7f017f988f6759db5adc30cebef0..5f84202fcfa5268094a5b625c10e30cda2bc3725 100644 --- a/test/error_traces.zig +++ b/test/error_traces.zig @@ -1,7 +1,10 @@ const std = @import("std"); +const Context = @import("tests.zig").ErrorTracesContext; -pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.Os.Tag) void { +pub fn addCases(cases: *Context, params: *const Context.CaseParameters, target: *const std.Target) void { cases.addCase(.{ + .params = params, + .target = target, .name = "return", .source = \\pub fn main() !void { @@ -17,6 +20,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "try return", .source = \\fn foo() !void { @@ -44,6 +49,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }, }); cases.addCase(.{ + .params = params, + .target = target, .name = "non-error return pops error trace", .source = \\fn bar() !void { @@ -70,6 +77,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "continue in while loop", .source = \\fn foo() !void { @@ -93,6 +102,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "for loop pops error return trace", .source = \\fn foo() !void { return error.FooError; } @@ -123,6 +134,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "implicit continue in for loop pops stale error return trace", .source = \\fn foo() !void { return error.FooError; } @@ -154,6 +167,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "while loop pops error return trace", .source = \\fn foo() !void { return error.FooError; } @@ -186,6 +201,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "implicit continue in while loop pops stale error return trace", .source = \\fn foo() !void { return error.FooError; } @@ -219,6 +236,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "try return + handled catch/if-else", .source = \\fn foo() !void { @@ -251,6 +270,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "break from inline loop pops error return trace", .source = \\fn foo() !void { return error.FooBar; } @@ -276,6 +297,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "catch and re-throw error", .source = \\fn foo() !void { @@ -304,6 +327,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "errors stored in var do not contribute to error trace", .source = \\fn foo() !void { @@ -328,6 +353,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "error stored in const has trace preserved for duration of block", .source = \\fn foo() !void { return error.TheSkyIsFalling; } @@ -376,6 +403,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "error passed to function has its trace preserved for duration of the call", .source = \\pub fn expectError(expected_error: anyerror, actual_error: anyerror!void) !void { @@ -418,6 +447,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "try return from within catch", .source = \\fn foo() !void { @@ -455,6 +486,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "try return from within if-else", .source = \\fn foo() !void { @@ -492,6 +525,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "try try return return", .source = \\fn foo() !void { @@ -534,6 +569,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "error union switch with call operand", .source = \\pub fn main() !void { @@ -579,6 +616,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "trace through inline call", // The main function has two inline calls to ensure // that inlinees in PDBs are properly deduplicated. @@ -595,7 +634,7 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target. \\} , .expect_error = "ThisIsSoSad", - .expect_trace = switch (os) { + .expect_trace = switch (target.os.tag) { // LLVM doesn't emit column info in the binary annotations for inlinee callees in PDBs, // so our expected result is slightly different for Windows than on other operating // systems. diff --git a/test/src/ErrorTrace.zig b/test/src/ErrorTrace.zig index d570cf406ae4d248ff106c7b304cc77eb9097eef..7fda389dc6c295a6c950f95a6551945eab878643 100644 --- a/test/src/ErrorTrace.zig +++ b/test/src/ErrorTrace.zig @@ -1,11 +1,81 @@ +const ErrorTrace = @This(); + +const builtin = @import("builtin"); + +const std = @import("std"); +const Step = std.Build.Step; +const OptimizeMode = std.lang.Optimize; +const mem = std.mem; + +const error_traces_cases = @import("../error_traces.zig"); + b: *std.Build, step: *Step, test_filters: []const []const u8, -targets: []const std.Build.ResolvedTarget, +skip_non_native: bool, optimize_modes: []const OptimizeMode, convert_exe: *std.Build.Step.Compile, +pub const CaseParameters = @import("StackTrace.zig").CaseParameters; + +const param_sets = [_]CaseParameters{ + .{}, + .{ + .link_libc = true, + }, + .{ + .use_llvm = true, + .use_lld = true, + }, + .{ + .pie = true, + }, + .{ + .target = .{ + .cpu_arch = .aarch64, + .os_tag = .windows, + .abi = .msvc, + }, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .windows, + .abi = .gnu, + }, + }, + .{ + .target = .{ + .cpu_arch = .x86, + .os_tag = .windows, + .abi = .msvc, + }, + }, + .{ + .target = .{ + .cpu_arch = .aarch64, + .os_tag = .macos, + }, + }, + .{ + .target = .{ + .cpu_arch = .s390x, + .os_tag = .linux, + .abi = .none, + }, + }, + .{ + .target = .{ + .cpu_arch = .loongarch32, + .os_tag = .linux, + .abi = .none, + }, + }, +}; + pub const Case = struct { + params: *const CaseParameters, + target: *const std.Target, name: []const u8, source: []const u8, expect_error: []const u8, @@ -22,50 +92,47 @@ pub const Case = struct { pub const Backend = enum { llvm, selfhosted }; }; -pub fn addCase(self: *ErrorTrace, case: Case) void { - for (self.targets) |*target| { - const triple: ?[]const u8 = if (target.query.isNative()) null else t: { - break :t target.query.zigTriple(self.b.graph.arena) catch @panic("OOM"); - }; +pub fn addCases(self: *ErrorTrace) void { + const b = self.b; + + for (¶m_sets) |*params| { + const resolved_target = b.resolveTargetQuery(params.target); + + if (self.skip_non_native and !resolved_target.query.isNative()) continue; + + // To avoid redundant testing, skip cross-compilation targets matching the host. + if (resolved_target.result.os.tag == builtin.target.os.tag and + resolved_target.result.cpu.arch == builtin.target.cpu.arch) + { + continue; + } + for (self.optimize_modes) |optimize| { - self.addCaseConfig(case, target, triple, optimize, .llvm); - } - if (shouldTestNonLlvm(&target.result)) { - for (self.optimize_modes) |optimize| { - self.addCaseConfig(case, target, triple, optimize, .selfhosted); - } - } + if (optimize == params.optimize) break; + } else return; + + error_traces_cases.addCases(self, params, &resolved_target.result); } } -fn shouldTestNonLlvm(target: *const std.Target) bool { - if (comptime builtin.cpu.arch.endian() == .big) return false; // https://github.com/ziglang/zig/issues/25961 - return switch (target.cpu.arch) { - .x86_64 => switch (target.ofmt) { - .elf => !target.os.tag.isBSD() and target.os.tag != .illumos, - else => false, - }, - else => false, - }; -} - -fn addCaseConfig( - self: *ErrorTrace, - case: Case, - target: *const std.Build.ResolvedTarget, - triple: ?[]const u8, - optimize: OptimizeMode, - backend: Case.Backend, -) void { +/// Called from test/error_traces.zig +pub fn addCase(self: *ErrorTrace, case: Case) void { const b = self.b; + const params = case.params; + const target = case.target; + const target_query = params.target; + + const triple: ?[]const u8 = if (target_query.isNative()) null else t: { + break :t target_query.zigTriple(self.b.graph.arena) catch @panic("OOM"); + }; const error_tracing: bool = tracing: { - if (optimize == .debug) break :tracing true; - if (backend != .llvm) break :tracing true; - if (optimize == .small) break :tracing false; + if (params.optimize == .debug) break :tracing true; + if (params.use_llvm == false) break :tracing true; + if (params.optimize == .small) break :tracing false; for (case.disable_trace_optimized) |disable| { const d_arch, const d_os = disable; - if (target.result.cpu.arch == d_arch and target.result.os.tag == d_os) { + if (target.cpu.arch == d_arch and target.os.tag == d_os) { // This particular configuration cannot do error tracing in optimized LLVM builds. break :tracing false; } @@ -73,12 +140,19 @@ fn addCaseConfig( break :tracing true; }; - const annotated_case_name = b.fmt("check {s} ({s}{s}{s} {s})", .{ + const backend_string = if (params.use_llvm == true) + "-llvm" + else if (params.use_llvm == false) + "-selfhosted" + else + ""; + + const annotated_case_name = b.fmt("check {s} ({s}{s}{t}{s})", .{ case.name, triple orelse "", if (triple != null) " " else "", - @tagName(optimize), - @tagName(backend), + params.optimize, + backend_string, }); if (self.test_filters.len > 0) { for (self.test_filters) |test_filter| { @@ -92,15 +166,13 @@ fn addCaseConfig( .name = "test", .root_module = b.createModule(.{ .root_source_file = source_zig, - .optimize = optimize, - .target = target.*, + .optimize = params.optimize, + .target = .{ .result = target.*, .query = target_query }, .error_tracing = error_tracing, .strip = false, }), - .use_llvm = switch (backend) { - .llvm => true, - .selfhosted => false, - }, + .use_llvm = params.use_llvm, + .use_lld = params.use_lld, }); exe.bundle_ubsan_rt = false; @@ -124,10 +196,3 @@ fn addCaseConfig( self.step.dependOn(&check_run.step); } - -const ErrorTrace = @This(); -const std = @import("std"); -const builtin = @import("builtin"); -const Step = std.Build.Step; -const OptimizeMode = std.builtin.OptimizeMode; -const mem = std.mem; diff --git a/test/src/StackTrace.zig b/test/src/StackTrace.zig index 7270ef4cbbe51af44efab1f4950d660554889920..c4e4a5fe391a4141fe167681183b761c8fbf806b 100644 --- a/test/src/StackTrace.zig +++ b/test/src/StackTrace.zig @@ -4,16 +4,88 @@ const builtin = @import("builtin"); const std = @import("std"); const Step = std.Build.Step; -const OptimizeMode = std.lang.OptimizeMode; +const OptimizeMode = std.lang.Optimize; const mem = std.mem; +const stack_traces_cases = @import("../stack_traces.zig"); + b: *std.Build, step: *Step, test_filters: []const []const u8, -targets: []const std.Build.ResolvedTarget, +skip_non_native: bool, convert_exe: *std.Build.Step.Compile, +pub const CaseParameters = struct { + target: std.Target.Query = .{}, + optimize: std.builtin.OptimizeMode = .debug, + link_libc: ?bool = null, + use_llvm: ?bool = null, + use_lld: ?bool = null, + pie: ?bool = null, + /// To enable this coverage, one of two things needs to happen: + /// * The compiler needs to gain the ability to strip only debug info (not symbols) + /// * `std.Build.Step.ObjCopy` needs to be un-regressed + strip: ?bool = false, +}; + +const param_sets = [_]CaseParameters{ + .{}, + .{ + .link_libc = true, + }, + .{ + .use_llvm = true, + .use_lld = true, + }, + .{ + .pie = true, + }, + .{ + .target = .{ + .cpu_arch = .aarch64, + .os_tag = .windows, + .abi = .msvc, + }, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .windows, + .abi = .gnu, + }, + }, + .{ + .target = .{ + .cpu_arch = .x86, + .os_tag = .windows, + .abi = .msvc, + }, + }, + .{ + .target = .{ + .cpu_arch = .aarch64, + .os_tag = .macos, + }, + }, + .{ + .target = .{ + .cpu_arch = .s390x, + .os_tag = .linux, + .abi = .none, + }, + }, + .{ + .target = .{ + .cpu_arch = .loongarch32, + .os_tag = .linux, + .abi = .none, + }, + }, +}; + const Config = struct { + params: *const CaseParameters, + target: *const std.Target, name: []const u8, source: []const u8, /// Whether this test case expects to have unwind tables / frame pointers. @@ -35,42 +107,37 @@ const Config = struct { expect_strip: []const u8, }; +pub fn addCases(self: *StackTrace) void { + const b = self.b; + + for (¶m_sets) |*params| { + const resolved_target = b.resolveTargetQuery(params.target); + + if (self.skip_non_native and !resolved_target.query.isNative()) continue; + + // To avoid redundant testing, skip cross-compilation targets matching the host. + if (resolved_target.result.os.tag == builtin.target.os.tag and + resolved_target.result.cpu.arch == builtin.target.cpu.arch) + { + continue; + } + + stack_traces_cases.addCases(self, params, &resolved_target.result); + } +} + +/// Called from test/stack_traces.zig pub fn addCase(self: *StackTrace, config: Config) void { - for (self.targets) |*target| { - addCaseTarget( - self, - config, - target, - if (target.query.isNative()) null else t: { - break :t target.query.zigTriple(self.b.graph.arena) catch @panic("OOM"); - }, - ); - } -} -fn addCaseTarget( - self: *StackTrace, - config: Config, - target: *const std.Build.ResolvedTarget, - triple: ?[]const u8, -) void { - const both_backends = b: { - if (builtin.cpu.arch.endian() == .big) break :b false; // https://codeberg.org/ziglang/zig/issues/31522 - break :b switch (target.result.cpu.arch) { - .x86_64 => switch (target.result.ofmt) { - .elf => !target.result.os.tag.isBSD() and target.result.os.tag != .illumos, - else => false, - }, - else => false, - }; + const params = config.params; + const target = config.target; + const target_query = config.params.target; + + const triple: ?[]const u8 = if (target_query.isNative()) null else t: { + break :t target_query.zigTriple(self.b.graph.arena) catch @panic("OOM"); }; - const both_pie = switch (target.result.os.tag) { - .fuchsia => false, - else => true, - }; - const both_libc = !std.os.targetRequiresLibC(&target.result); // See `std.debug.StackIterator.fp_usability` logic. - const fp_usability: enum { useless, unsafe, safe, ideal } = switch (target.result.cpu.arch) { + const fp_usability: enum { useless, unsafe, safe, ideal } = switch (target.cpu.arch) { .alpha, .csky, .microblaze, @@ -92,20 +159,15 @@ fn addCaseTarget( .sparc, .sparc64, => .ideal, - .aarch64 => if (target.result.os.tag.isDarwin()) .safe else .unsafe, + .aarch64 => if (target.os.tag.isDarwin()) .safe else .unsafe, else => .unsafe, }; - const supports_unwind_tables = switch (target.result.os.tag) { + const supports_unwind_tables = switch (target.os.tag) { // x86-windows just has no way to do stack unwinding other then using frame pointers. - .windows => target.result.cpu.arch != .x86, + .windows => target.cpu.arch != .x86, else => true, }; - const use_llvm_vals: []const bool = if (both_backends) &.{ true, false } else &.{true}; - const pie_vals: []const ?bool = if (both_pie) &.{ true, false } else &.{null}; - const link_libc_vals: []const ?bool = if (both_libc) &.{ true, false } else &.{null}; - const strip_debug_vals: []const bool = &.{ true, false }; - const UnwindInfo = packed struct(u2) { tables: bool, fp: bool, @@ -135,43 +197,33 @@ fn addCaseTarget( }, }; - for (use_llvm_vals) |use_llvm| { - for (pie_vals) |pie| { - for (link_libc_vals) |link_libc| { - for (strip_debug_vals) |strip_debug| { - for (unwind_info_vals) |unwind_info| { - if (unwind_info.tables and !supports_unwind_tables) continue; - self.addCaseInstance( - target, - triple, - config.name, - config.source, - use_llvm, - pie, - link_libc, - strip_debug, - !unwind_info.tables and supports_unwind_tables, - !unwind_info.fp, - config.expect_panic, - if (strip_debug) config.expect_strip else config.expect, - ); - } - } - } - } + for (unwind_info_vals) |unwind_info| { + if (unwind_info.tables and !supports_unwind_tables) continue; + const strip = params.strip orelse switch (params.optimize) { + .debug, .fast, .safe => false, + .small => true, + }; + self.addCaseInstance( + .{ .result = target.*, .query = target_query }, + triple, + config.name, + config.source, + params, + !unwind_info.tables and supports_unwind_tables, + !unwind_info.fp, + config.expect_panic, + if (strip) config.expect_strip else config.expect, + ); } } fn addCaseInstance( self: *StackTrace, - target: *const std.Build.ResolvedTarget, + resolved_target: std.Build.ResolvedTarget, triple: ?[]const u8, name: []const u8, source: []const u8, - use_llvm: bool, - pie: ?bool, - link_libc: ?bool, - strip_debug: bool, + params: *const CaseParameters, strip_unwind: bool, omit_frame_pointer: bool, expect_panic: bool, @@ -179,13 +231,6 @@ fn addCaseInstance( ) void { const b = self.b; - if (strip_debug) { - // To enable this coverage, one of two things needs to happen: - // * The compiler needs to gain the ability to strip only debug info (not symbols) - // * `std.Build.Step.ObjCopy` needs to be un-regressed - return; - } - if (strip_unwind) { // To enable this coverage, `std.Build.Step.ObjCopy` needs to be un-regressed and gain the // ability to remove individual sections. `-fno-unwind-tables` is insufficient because it @@ -196,14 +241,28 @@ fn addCaseInstance( return; } + const backend_string = if (params.use_llvm == true) + " llvm" + else if (params.use_llvm == false) + " selfhosted" + else + ""; + + const strip_string = if (params.strip == true) + " strip" + else if (params.strip == false) + " unstripped" + else + ""; + const annotated_case_name = b.fmt("check {s} ({s}{s}{s}{s}{s}{s}{s}{s})", .{ name, triple orelse "", if (triple != null) " " else "", - if (use_llvm) "llvm" else "selfhosted", - if (pie == true) " pie" else "", - if (link_libc == true) " libc" else "", - if (strip_debug) " strip" else "", + backend_string, + if (params.pie == true) " pie" else "", + if (params.link_libc == true) " libc" else "", + strip_string, if (strip_unwind) " no_unwind" else "", if (omit_frame_pointer) " no_fp" else "", }); @@ -220,16 +279,17 @@ fn addCaseInstance( .root_module = b.createModule(.{ .root_source_file = source_zig, .optimize = .Debug, - .target = target.*, + .target = resolved_target, .omit_frame_pointer = omit_frame_pointer, - .link_libc = link_libc, + .link_libc = params.link_libc, .unwind_tables = if (strip_unwind) .none else null, // make panics single-threaded so that they don't include a thread ID .single_threaded = expect_panic, }), - .use_llvm = use_llvm, + .use_llvm = params.use_llvm, + .use_lld = params.use_lld, }); - exe.pie = pie; + exe.pie = params.pie; exe.bundle_ubsan_rt = false; const run = b.addRunArtifact(exe); @@ -238,7 +298,7 @@ fn addCaseInstance( run.setEnvironmentVariable("NO_COLOR", "1"); run.addCheck(.{ .expect_term = term: { if (!expect_panic) break :term .{ .exited = 0 }; - if (target.result.os.tag == .windows) break :term .{ .exited = 3 }; + if (resolved_target.result.os.tag == .windows) break :term .{ .exited = 3 }; break :term .{ .signal = @fromBackingInt(@intCast(6)) }; } }); run.expectStdOutEqual(""); diff --git a/test/stack_traces.zig b/test/stack_traces.zig index 82d7d67863c209f4a5e3825f0eeb2cb100e50ced..352950af2b307d0fb1d7a8027358c76fe064db56 100644 --- a/test/stack_traces.zig +++ b/test/stack_traces.zig @@ -1,7 +1,10 @@ const std = @import("std"); +const Context = @import("tests.zig").StackTracesContext; -pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.Os.Tag) void { +pub fn addCases(cases: *Context, params: *const Context.CaseParameters, target: *const std.Target) void { cases.addCase(.{ + .params = params, + .target = target, .name = "simple panic", .source = \\pub fn main() void { @@ -33,6 +36,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "simple panic with no unwind strategy", .source = \\pub fn main() void { @@ -50,6 +55,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "dump current trace", .source = \\pub fn main() void { @@ -89,6 +96,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "dump current trace with no unwind strategy", .source = \\pub fn main() void { @@ -114,6 +123,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "dump captured trace", .source = \\pub fn main() void { @@ -155,6 +166,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "dump captured trace with no unwind strategy", .source = \\pub fn main() void { @@ -180,6 +193,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "dump captured trace on thread", .source = \\pub fn main() !void { @@ -225,6 +240,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. }); cases.addCase(.{ + .params = params, + .target = target, .name = "simple inline panic", // The main function has two inline calls to ensure // that inlinees in PDBs are properly deduplicated. @@ -240,7 +257,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. , .unwind = .any, .expect_panic = true, - .expect = switch (os) { + .expect = switch (target.os.tag) { // LLVM doesn't emit column info in the binary annotations for inlinee callees in PDBs, // so the first location has only a row. .windows => @@ -262,7 +279,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. \\ ^ , }, - .expect_strip = switch (os) { + .expect_strip = switch (target.os.tag) { .windows => \\panic: oh no \\???:?:?: [address] in source.foo @@ -279,6 +296,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. // Make sure all inline calls are resolved and in the right order! cases.addCase(.{ + .params = params, + .target = target, .name = "nested inline panic", .source = \\pub fn main() void { @@ -298,7 +317,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. .unwind = .any, .expect_panic = true, // This switch serves a similar purpose as in "inline panic". - .expect = switch (os) { + .expect = switch (target.os.tag) { .windows => \\panic: oh no \\source.zig:11: [address] in baz @@ -322,7 +341,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target. \\ ^ , }, - .expect_strip = switch (os) { + .expect_strip = switch (target.os.tag) { .windows => \\panic: oh no \\???:?:?: [address] in baz diff --git a/test/tests.zig b/test/tests.zig index d165597131204537abc2c494a97885c3866a5e5f..fbb16c5a2fe759dd4840d4670670983898985276 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -6,8 +6,6 @@ const OptimizeMode = std.builtin.OptimizeMode; const Step = std.Build.Step; // Cases -const error_traces = @import("error_traces.zig"); -const stack_traces = @import("stack_traces.zig"); const llvm_ir = @import("llvm_ir.zig"); const libc = @import("libc.zig"); const link = @import("link.zig"); @@ -2381,59 +2379,7 @@ pub fn isNative(actual_target: *const std.Build.ResolvedTarget, host: *const std return true; } -/// For stack trace tests, we only test native by default, because external executors are pretty -/// unreliable at stack tracing. However, if there's a 32-bit equivalent target which the host can -/// trivially run, we may as well at least test that! -fn nativeAndCompatible32bit(b: *std.Build, skip_non_native: bool) []const std.Build.ResolvedTarget { - const host = b.graph.host.result; - const only_native = (&b.graph.host)[0..1]; - if (skip_non_native) return only_native; - const arch32 = compatible32bitArch(&b.graph.host.result) orelse return only_native; - return b.graph.arena.dupe(std.Build.ResolvedTarget, &.{ - b.graph.host, - b.resolveTargetQuery(.{ .cpu_arch = arch32, .os_tag = host.os.tag }), - }) catch @panic("OOM"); -} - -fn wineAndCompatible32bit(b: *std.Build, skip_non_native: bool) []const std.Build.ResolvedTarget { - var targets: std.ArrayList(std.Build.ResolvedTarget) = .empty; - - const host = b.graph.host.result; - - targets.append(b.graph.arena, b.resolveTargetQuery(.{ - .cpu_arch = host.cpu.arch, - .os_tag = .windows, - })) catch @panic("OOM"); - if (!skip_non_native) { - if (compatible32bitArch(&b.graph.host.result)) |arch| { - targets.append(b.graph.arena, b.resolveTargetQuery(.{ - .cpu_arch = arch, - .os_tag = .windows, - })) catch @panic("OOM"); - } - } - - return targets.toOwnedSlice(b.graph.arena) catch @panic("OOM"); -} - -fn darlingTargets(b: *std.Build) []const std.Build.ResolvedTarget { - var targets: std.ArrayList(std.Build.ResolvedTarget) = .empty; - - const host = b.graph.host.result; - - targets.append(b.graph.arena, b.resolveTargetQuery(.{ - .cpu_arch = host.cpu.arch, - .os_tag = .macos, - })) catch @panic("OOM"); - - return targets.toOwnedSlice(b.graph.arena) catch @panic("OOM"); -} - -pub fn addStackTraceTests( - b: *std.Build, - test_filters: []const []const u8, - skip_non_native: bool, -) *Step { +pub fn addStackTraceTests(b: *std.Build, test_filters: []const []const u8, skip_non_native: bool) *Step { const step = b.step("test-stack-traces", "Run the stack trace tests"); const convert_exe = b.addExecutable(.{ @@ -2445,35 +2391,15 @@ pub fn addStackTraceTests( }), }); - const host_cases = b.allocator.create(StackTracesContext) catch @panic("OOM"); - host_cases.* = .{ + const stack_traces_context = b.allocator.create(StackTracesContext) catch @panic("OOM"); + stack_traces_context.* = .{ .b = b, .step = step, .test_filters = test_filters, - .targets = nativeAndCompatible32bit(b, skip_non_native), + .skip_non_native = skip_non_native, .convert_exe = convert_exe, }; - stack_traces.addCases(host_cases, b.graph.host.result.os.tag); - - const wine_cases = b.allocator.create(StackTracesContext) catch @panic("OOM"); - wine_cases.* = .{ - .b = b, - .step = step, - .test_filters = test_filters, - .targets = wineAndCompatible32bit(b, skip_non_native), - .convert_exe = convert_exe, - }; - stack_traces.addCases(wine_cases, .windows); - - const darling_cases = b.allocator.create(StackTracesContext) catch @panic("OOM"); - darling_cases.* = .{ - .b = b, - .step = step, - .test_filters = test_filters, - .targets = darlingTargets(b), - .convert_exe = convert_exe, - }; - stack_traces.addCases(darling_cases, .macos); + stack_traces_context.addCases(); return step; } @@ -2495,38 +2421,16 @@ pub fn addErrorTraceTests( }), }); - const host_cases = b.allocator.create(ErrorTracesContext) catch @panic("OOM"); - host_cases.* = .{ + const error_traces_context = b.allocator.create(ErrorTracesContext) catch @panic("OOM"); + error_traces_context.* = .{ .b = b, .step = step, .test_filters = test_filters, - .targets = nativeAndCompatible32bit(b, skip_non_native), + .skip_non_native = skip_non_native, .optimize_modes = optimize_modes, .convert_exe = convert_exe, }; - error_traces.addCases(host_cases, b.graph.host.result.os.tag); - - const wine_cases = b.allocator.create(ErrorTracesContext) catch @panic("OOM"); - wine_cases.* = .{ - .b = b, - .step = step, - .test_filters = test_filters, - .targets = wineAndCompatible32bit(b, skip_non_native), - .optimize_modes = optimize_modes, - .convert_exe = convert_exe, - }; - error_traces.addCases(wine_cases, .windows); - - const darling_cases = b.allocator.create(ErrorTracesContext) catch @panic("OOM"); - darling_cases.* = .{ - .b = b, - .step = step, - .test_filters = test_filters, - .targets = darlingTargets(b), - .optimize_modes = optimize_modes, - .convert_exe = convert_exe, - }; - error_traces.addCases(darling_cases, .macos); + error_traces_context.addCases(); return step; } -- 2.54.0