authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-07 13:28:16-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-07 13:28:16-07:00
log8b2949e372e615886b9087b06187878452421724
tree69109053e156249712255bba6c292f3d7a2eb09c
parent0f1c478db329c4b91c3a34aed2d48e4cde059eff

simplify stack trace and error trace tests

by explicitly listing out the combinations of parameters we would like to check.

5 files changed, 337 insertions(+), 250 deletions(-)

test/error_traces.zig+41-2
......@@ -1,7 +1,10 @@
11const std = @import("std");
2const Context = @import("tests.zig").ErrorTracesContext;
23
3pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.Os.Tag) void {
4pub fn addCases(cases: *Context, params: *const Context.CaseParameters, target: *const std.Target) void {
45 cases.addCase(.{
6 .params = params,
7 .target = target,
58 .name = "return",
69 .source =
710 \\pub fn main() !void {
......@@ -17,6 +20,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
1720 });
1821
1922 cases.addCase(.{
23 .params = params,
24 .target = target,
2025 .name = "try return",
2126 .source =
2227 \\fn foo() !void {
......@@ -44,6 +49,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
4449 },
4550 });
4651 cases.addCase(.{
52 .params = params,
53 .target = target,
4754 .name = "non-error return pops error trace",
4855 .source =
4956 \\fn bar() !void {
......@@ -70,6 +77,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
7077 });
7178
7279 cases.addCase(.{
80 .params = params,
81 .target = target,
7382 .name = "continue in while loop",
7483 .source =
7584 \\fn foo() !void {
......@@ -93,6 +102,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
93102 });
94103
95104 cases.addCase(.{
105 .params = params,
106 .target = target,
96107 .name = "for loop pops error return trace",
97108 .source =
98109 \\fn foo() !void { return error.FooError; }
......@@ -123,6 +134,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
123134 });
124135
125136 cases.addCase(.{
137 .params = params,
138 .target = target,
126139 .name = "implicit continue in for loop pops stale error return trace",
127140 .source =
128141 \\fn foo() !void { return error.FooError; }
......@@ -154,6 +167,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
154167 });
155168
156169 cases.addCase(.{
170 .params = params,
171 .target = target,
157172 .name = "while loop pops error return trace",
158173 .source =
159174 \\fn foo() !void { return error.FooError; }
......@@ -186,6 +201,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
186201 });
187202
188203 cases.addCase(.{
204 .params = params,
205 .target = target,
189206 .name = "implicit continue in while loop pops stale error return trace",
190207 .source =
191208 \\fn foo() !void { return error.FooError; }
......@@ -219,6 +236,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
219236 });
220237
221238 cases.addCase(.{
239 .params = params,
240 .target = target,
222241 .name = "try return + handled catch/if-else",
223242 .source =
224243 \\fn foo() !void {
......@@ -251,6 +270,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
251270 });
252271
253272 cases.addCase(.{
273 .params = params,
274 .target = target,
254275 .name = "break from inline loop pops error return trace",
255276 .source =
256277 \\fn foo() !void { return error.FooBar; }
......@@ -276,6 +297,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
276297 });
277298
278299 cases.addCase(.{
300 .params = params,
301 .target = target,
279302 .name = "catch and re-throw error",
280303 .source =
281304 \\fn foo() !void {
......@@ -304,6 +327,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
304327 });
305328
306329 cases.addCase(.{
330 .params = params,
331 .target = target,
307332 .name = "errors stored in var do not contribute to error trace",
308333 .source =
309334 \\fn foo() !void {
......@@ -328,6 +353,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
328353 });
329354
330355 cases.addCase(.{
356 .params = params,
357 .target = target,
331358 .name = "error stored in const has trace preserved for duration of block",
332359 .source =
333360 \\fn foo() !void { return error.TheSkyIsFalling; }
......@@ -376,6 +403,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
376403 });
377404
378405 cases.addCase(.{
406 .params = params,
407 .target = target,
379408 .name = "error passed to function has its trace preserved for duration of the call",
380409 .source =
381410 \\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.
418447 });
419448
420449 cases.addCase(.{
450 .params = params,
451 .target = target,
421452 .name = "try return from within catch",
422453 .source =
423454 \\fn foo() !void {
......@@ -455,6 +486,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
455486 });
456487
457488 cases.addCase(.{
489 .params = params,
490 .target = target,
458491 .name = "try return from within if-else",
459492 .source =
460493 \\fn foo() !void {
......@@ -492,6 +525,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
492525 });
493526
494527 cases.addCase(.{
528 .params = params,
529 .target = target,
495530 .name = "try try return return",
496531 .source =
497532 \\fn foo() !void {
......@@ -534,6 +569,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
534569 });
535570
536571 cases.addCase(.{
572 .params = params,
573 .target = target,
537574 .name = "error union switch with call operand",
538575 .source =
539576 \\pub fn main() !void {
......@@ -579,6 +616,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
579616 });
580617
581618 cases.addCase(.{
619 .params = params,
620 .target = target,
582621 .name = "trace through inline call",
583622 // The main function has two inline calls to ensure
584623 // that inlinees in PDBs are properly deduplicated.
......@@ -595,7 +634,7 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
595634 \\}
596635 ,
597636 .expect_error = "ThisIsSoSad",
598 .expect_trace = switch (os) {
637 .expect_trace = switch (target.os.tag) {
599638 // LLVM doesn't emit column info in the binary annotations for inlinee callees in PDBs,
600639 // so our expected result is slightly different for Windows than on other operating
601640 // systems.
test/src/ErrorTrace.zig+117-52
......@@ -1,11 +1,81 @@
1const ErrorTrace = @This();
2
3const builtin = @import("builtin");
4
5const std = @import("std");
6const Step = std.Build.Step;
7const OptimizeMode = std.lang.Optimize;
8const mem = std.mem;
9
10const error_traces_cases = @import("../error_traces.zig");
11
112b: *std.Build,
213step: *Step,
314test_filters: []const []const u8,
4targets: []const std.Build.ResolvedTarget,
15skip_non_native: bool,
516optimize_modes: []const OptimizeMode,
617convert_exe: *std.Build.Step.Compile,
718
19pub const CaseParameters = @import("StackTrace.zig").CaseParameters;
20
21const param_sets = [_]CaseParameters{
22 .{},
23 .{
24 .link_libc = true,
25 },
26 .{
27 .use_llvm = true,
28 .use_lld = true,
29 },
30 .{
31 .pie = true,
32 },
33 .{
34 .target = .{
35 .cpu_arch = .aarch64,
36 .os_tag = .windows,
37 .abi = .msvc,
38 },
39 },
40 .{
41 .target = .{
42 .cpu_arch = .x86_64,
43 .os_tag = .windows,
44 .abi = .gnu,
45 },
46 },
47 .{
48 .target = .{
49 .cpu_arch = .x86,
50 .os_tag = .windows,
51 .abi = .msvc,
52 },
53 },
54 .{
55 .target = .{
56 .cpu_arch = .aarch64,
57 .os_tag = .macos,
58 },
59 },
60 .{
61 .target = .{
62 .cpu_arch = .s390x,
63 .os_tag = .linux,
64 .abi = .none,
65 },
66 },
67 .{
68 .target = .{
69 .cpu_arch = .loongarch32,
70 .os_tag = .linux,
71 .abi = .none,
72 },
73 },
74};
75
876pub const Case = struct {
77 params: *const CaseParameters,
78 target: *const std.Target,
979 name: []const u8,
1080 source: []const u8,
1181 expect_error: []const u8,
......@@ -22,50 +92,47 @@ pub const Case = struct {
2292 pub const Backend = enum { llvm, selfhosted };
2393};
2494
25pub fn addCase(self: *ErrorTrace, case: Case) void {
26 for (self.targets) |*target| {
27 const triple: ?[]const u8 = if (target.query.isNative()) null else t: {
28 break :t target.query.zigTriple(self.b.graph.arena) catch @panic("OOM");
29 };
30 for (self.optimize_modes) |optimize| {
31 self.addCaseConfig(case, target, triple, optimize, .llvm);
32 }
33 if (shouldTestNonLlvm(&target.result)) {
34 for (self.optimize_modes) |optimize| {
35 self.addCaseConfig(case, target, triple, optimize, .selfhosted);
36 }
95pub fn addCases(self: *ErrorTrace) void {
96 const b = self.b;
97
98 for (&param_sets) |*params| {
99 const resolved_target = b.resolveTargetQuery(params.target);
100
101 if (self.skip_non_native and !resolved_target.query.isNative()) continue;
102
103 // To avoid redundant testing, skip cross-compilation targets matching the host.
104 if (resolved_target.result.os.tag == builtin.target.os.tag and
105 resolved_target.result.cpu.arch == builtin.target.cpu.arch)
106 {
107 continue;
37108 }
38 }
39}
40109
41fn shouldTestNonLlvm(target: *const std.Target) bool {
42 if (comptime builtin.cpu.arch.endian() == .big) return false; // https://github.com/ziglang/zig/issues/25961
43 return switch (target.cpu.arch) {
44 .x86_64 => switch (target.ofmt) {
45 .elf => !target.os.tag.isBSD() and target.os.tag != .illumos,
46 else => false,
47 },
48 else => false,
49 };
110 for (self.optimize_modes) |optimize| {
111 if (optimize == params.optimize) break;
112 } else return;
113
114 error_traces_cases.addCases(self, params, &resolved_target.result);
115 }
50116}
51117
52fn addCaseConfig(
53 self: *ErrorTrace,
54 case: Case,
55 target: *const std.Build.ResolvedTarget,
56 triple: ?[]const u8,
57 optimize: OptimizeMode,
58 backend: Case.Backend,
59) void {
118/// Called from test/error_traces.zig
119pub fn addCase(self: *ErrorTrace, case: Case) void {
60120 const b = self.b;
121 const params = case.params;
122 const target = case.target;
123 const target_query = params.target;
124
125 const triple: ?[]const u8 = if (target_query.isNative()) null else t: {
126 break :t target_query.zigTriple(self.b.graph.arena) catch @panic("OOM");
127 };
61128
62129 const error_tracing: bool = tracing: {
63 if (optimize == .debug) break :tracing true;
64 if (backend != .llvm) break :tracing true;
65 if (optimize == .small) break :tracing false;
130 if (params.optimize == .debug) break :tracing true;
131 if (params.use_llvm == false) break :tracing true;
132 if (params.optimize == .small) break :tracing false;
66133 for (case.disable_trace_optimized) |disable| {
67134 const d_arch, const d_os = disable;
68 if (target.result.cpu.arch == d_arch and target.result.os.tag == d_os) {
135 if (target.cpu.arch == d_arch and target.os.tag == d_os) {
69136 // This particular configuration cannot do error tracing in optimized LLVM builds.
70137 break :tracing false;
71138 }
......@@ -73,12 +140,19 @@ fn addCaseConfig(
73140 break :tracing true;
74141 };
75142
76 const annotated_case_name = b.fmt("check {s} ({s}{s}{s} {s})", .{
143 const backend_string = if (params.use_llvm == true)
144 "-llvm"
145 else if (params.use_llvm == false)
146 "-selfhosted"
147 else
148 "";
149
150 const annotated_case_name = b.fmt("check {s} ({s}{s}{t}{s})", .{
77151 case.name,
78152 triple orelse "",
79153 if (triple != null) " " else "",
80 @tagName(optimize),
81 @tagName(backend),
154 params.optimize,
155 backend_string,
82156 });
83157 if (self.test_filters.len > 0) {
84158 for (self.test_filters) |test_filter| {
......@@ -92,15 +166,13 @@ fn addCaseConfig(
92166 .name = "test",
93167 .root_module = b.createModule(.{
94168 .root_source_file = source_zig,
95 .optimize = optimize,
96 .target = target.*,
169 .optimize = params.optimize,
170 .target = .{ .result = target.*, .query = target_query },
97171 .error_tracing = error_tracing,
98172 .strip = false,
99173 }),
100 .use_llvm = switch (backend) {
101 .llvm => true,
102 .selfhosted => false,
103 },
174 .use_llvm = params.use_llvm,
175 .use_lld = params.use_lld,
104176 });
105177 exe.bundle_ubsan_rt = false;
106178
......@@ -124,10 +196,3 @@ fn addCaseConfig(
124196
125197 self.step.dependOn(&check_run.step);
126198}
127
128const ErrorTrace = @This();
129const std = @import("std");
130const builtin = @import("builtin");
131const Step = std.Build.Step;
132const OptimizeMode = std.builtin.OptimizeMode;
133const mem = std.mem;
test/src/StackTrace.zig+146-86
......@@ -4,16 +4,88 @@ const builtin = @import("builtin");
44
55const std = @import("std");
66const Step = std.Build.Step;
7const OptimizeMode = std.lang.OptimizeMode;
7const OptimizeMode = std.lang.Optimize;
88const mem = std.mem;
99
10const stack_traces_cases = @import("../stack_traces.zig");
11
1012b: *std.Build,
1113step: *Step,
1214test_filters: []const []const u8,
13targets: []const std.Build.ResolvedTarget,
15skip_non_native: bool,
1416convert_exe: *std.Build.Step.Compile,
1517
18pub const CaseParameters = struct {
19 target: std.Target.Query = .{},
20 optimize: std.builtin.OptimizeMode = .debug,
21 link_libc: ?bool = null,
22 use_llvm: ?bool = null,
23 use_lld: ?bool = null,
24 pie: ?bool = null,
25 /// To enable this coverage, one of two things needs to happen:
26 /// * The compiler needs to gain the ability to strip only debug info (not symbols)
27 /// * `std.Build.Step.ObjCopy` needs to be un-regressed
28 strip: ?bool = false,
29};
30
31const param_sets = [_]CaseParameters{
32 .{},
33 .{
34 .link_libc = true,
35 },
36 .{
37 .use_llvm = true,
38 .use_lld = true,
39 },
40 .{
41 .pie = true,
42 },
43 .{
44 .target = .{
45 .cpu_arch = .aarch64,
46 .os_tag = .windows,
47 .abi = .msvc,
48 },
49 },
50 .{
51 .target = .{
52 .cpu_arch = .x86_64,
53 .os_tag = .windows,
54 .abi = .gnu,
55 },
56 },
57 .{
58 .target = .{
59 .cpu_arch = .x86,
60 .os_tag = .windows,
61 .abi = .msvc,
62 },
63 },
64 .{
65 .target = .{
66 .cpu_arch = .aarch64,
67 .os_tag = .macos,
68 },
69 },
70 .{
71 .target = .{
72 .cpu_arch = .s390x,
73 .os_tag = .linux,
74 .abi = .none,
75 },
76 },
77 .{
78 .target = .{
79 .cpu_arch = .loongarch32,
80 .os_tag = .linux,
81 .abi = .none,
82 },
83 },
84};
85
1686const Config = struct {
87 params: *const CaseParameters,
88 target: *const std.Target,
1789 name: []const u8,
1890 source: []const u8,
1991 /// Whether this test case expects to have unwind tables / frame pointers.
......@@ -35,42 +107,37 @@ const Config = struct {
35107 expect_strip: []const u8,
36108};
37109
38pub fn addCase(self: *StackTrace, config: Config) void {
39 for (self.targets) |*target| {
40 addCaseTarget(
41 self,
42 config,
43 target,
44 if (target.query.isNative()) null else t: {
45 break :t target.query.zigTriple(self.b.graph.arena) catch @panic("OOM");
46 },
47 );
110pub fn addCases(self: *StackTrace) void {
111 const b = self.b;
112
113 for (&param_sets) |*params| {
114 const resolved_target = b.resolveTargetQuery(params.target);
115
116 if (self.skip_non_native and !resolved_target.query.isNative()) continue;
117
118 // To avoid redundant testing, skip cross-compilation targets matching the host.
119 if (resolved_target.result.os.tag == builtin.target.os.tag and
120 resolved_target.result.cpu.arch == builtin.target.cpu.arch)
121 {
122 continue;
123 }
124
125 stack_traces_cases.addCases(self, params, &resolved_target.result);
48126 }
49127}
50fn addCaseTarget(
51 self: *StackTrace,
52 config: Config,
53 target: *const std.Build.ResolvedTarget,
54 triple: ?[]const u8,
55) void {
56 const both_backends = b: {
57 if (builtin.cpu.arch.endian() == .big) break :b false; // https://codeberg.org/ziglang/zig/issues/31522
58 break :b switch (target.result.cpu.arch) {
59 .x86_64 => switch (target.result.ofmt) {
60 .elf => !target.result.os.tag.isBSD() and target.result.os.tag != .illumos,
61 else => false,
62 },
63 else => false,
64 };
65 };
66 const both_pie = switch (target.result.os.tag) {
67 .fuchsia => false,
68 else => true,
128
129/// Called from test/stack_traces.zig
130pub fn addCase(self: *StackTrace, config: Config) void {
131 const params = config.params;
132 const target = config.target;
133 const target_query = config.params.target;
134
135 const triple: ?[]const u8 = if (target_query.isNative()) null else t: {
136 break :t target_query.zigTriple(self.b.graph.arena) catch @panic("OOM");
69137 };
70 const both_libc = !std.os.targetRequiresLibC(&target.result);
71138
72139 // See `std.debug.StackIterator.fp_usability` logic.
73 const fp_usability: enum { useless, unsafe, safe, ideal } = switch (target.result.cpu.arch) {
140 const fp_usability: enum { useless, unsafe, safe, ideal } = switch (target.cpu.arch) {
74141 .alpha,
75142 .csky,
76143 .microblaze,
......@@ -92,20 +159,15 @@ fn addCaseTarget(
92159 .sparc,
93160 .sparc64,
94161 => .ideal,
95 .aarch64 => if (target.result.os.tag.isDarwin()) .safe else .unsafe,
162 .aarch64 => if (target.os.tag.isDarwin()) .safe else .unsafe,
96163 else => .unsafe,
97164 };
98 const supports_unwind_tables = switch (target.result.os.tag) {
165 const supports_unwind_tables = switch (target.os.tag) {
99166 // x86-windows just has no way to do stack unwinding other then using frame pointers.
100 .windows => target.result.cpu.arch != .x86,
167 .windows => target.cpu.arch != .x86,
101168 else => true,
102169 };
103170
104 const use_llvm_vals: []const bool = if (both_backends) &.{ true, false } else &.{true};
105 const pie_vals: []const ?bool = if (both_pie) &.{ true, false } else &.{null};
106 const link_libc_vals: []const ?bool = if (both_libc) &.{ true, false } else &.{null};
107 const strip_debug_vals: []const bool = &.{ true, false };
108
109171 const UnwindInfo = packed struct(u2) {
110172 tables: bool,
111173 fp: bool,
......@@ -135,43 +197,33 @@ fn addCaseTarget(
135197 },
136198 };
137199
138 for (use_llvm_vals) |use_llvm| {
139 for (pie_vals) |pie| {
140 for (link_libc_vals) |link_libc| {
141 for (strip_debug_vals) |strip_debug| {
142 for (unwind_info_vals) |unwind_info| {
143 if (unwind_info.tables and !supports_unwind_tables) continue;
144 self.addCaseInstance(
145 target,
146 triple,
147 config.name,
148 config.source,
149 use_llvm,
150 pie,
151 link_libc,
152 strip_debug,
153 !unwind_info.tables and supports_unwind_tables,
154 !unwind_info.fp,
155 config.expect_panic,
156 if (strip_debug) config.expect_strip else config.expect,
157 );
158 }
159 }
160 }
161 }
200 for (unwind_info_vals) |unwind_info| {
201 if (unwind_info.tables and !supports_unwind_tables) continue;
202 const strip = params.strip orelse switch (params.optimize) {
203 .debug, .fast, .safe => false,
204 .small => true,
205 };
206 self.addCaseInstance(
207 .{ .result = target.*, .query = target_query },
208 triple,
209 config.name,
210 config.source,
211 params,
212 !unwind_info.tables and supports_unwind_tables,
213 !unwind_info.fp,
214 config.expect_panic,
215 if (strip) config.expect_strip else config.expect,
216 );
162217 }
163218}
164219
165220fn addCaseInstance(
166221 self: *StackTrace,
167 target: *const std.Build.ResolvedTarget,
222 resolved_target: std.Build.ResolvedTarget,
168223 triple: ?[]const u8,
169224 name: []const u8,
170225 source: []const u8,
171 use_llvm: bool,
172 pie: ?bool,
173 link_libc: ?bool,
174 strip_debug: bool,
226 params: *const CaseParameters,
175227 strip_unwind: bool,
176228 omit_frame_pointer: bool,
177229 expect_panic: bool,
......@@ -179,13 +231,6 @@ fn addCaseInstance(
179231) void {
180232 const b = self.b;
181233
182 if (strip_debug) {
183 // To enable this coverage, one of two things needs to happen:
184 // * The compiler needs to gain the ability to strip only debug info (not symbols)
185 // * `std.Build.Step.ObjCopy` needs to be un-regressed
186 return;
187 }
188
189234 if (strip_unwind) {
190235 // To enable this coverage, `std.Build.Step.ObjCopy` needs to be un-regressed and gain the
191236 // ability to remove individual sections. `-fno-unwind-tables` is insufficient because it
......@@ -196,14 +241,28 @@ fn addCaseInstance(
196241 return;
197242 }
198243
244 const backend_string = if (params.use_llvm == true)
245 " llvm"
246 else if (params.use_llvm == false)
247 " selfhosted"
248 else
249 "";
250
251 const strip_string = if (params.strip == true)
252 " strip"
253 else if (params.strip == false)
254 " unstripped"
255 else
256 "";
257
199258 const annotated_case_name = b.fmt("check {s} ({s}{s}{s}{s}{s}{s}{s}{s})", .{
200259 name,
201260 triple orelse "",
202261 if (triple != null) " " else "",
203 if (use_llvm) "llvm" else "selfhosted",
204 if (pie == true) " pie" else "",
205 if (link_libc == true) " libc" else "",
206 if (strip_debug) " strip" else "",
262 backend_string,
263 if (params.pie == true) " pie" else "",
264 if (params.link_libc == true) " libc" else "",
265 strip_string,
207266 if (strip_unwind) " no_unwind" else "",
208267 if (omit_frame_pointer) " no_fp" else "",
209268 });
......@@ -220,16 +279,17 @@ fn addCaseInstance(
220279 .root_module = b.createModule(.{
221280 .root_source_file = source_zig,
222281 .optimize = .Debug,
223 .target = target.*,
282 .target = resolved_target,
224283 .omit_frame_pointer = omit_frame_pointer,
225 .link_libc = link_libc,
284 .link_libc = params.link_libc,
226285 .unwind_tables = if (strip_unwind) .none else null,
227286 // make panics single-threaded so that they don't include a thread ID
228287 .single_threaded = expect_panic,
229288 }),
230 .use_llvm = use_llvm,
289 .use_llvm = params.use_llvm,
290 .use_lld = params.use_lld,
231291 });
232 exe.pie = pie;
292 exe.pie = params.pie;
233293 exe.bundle_ubsan_rt = false;
234294
235295 const run = b.addRunArtifact(exe);
......@@ -238,7 +298,7 @@ fn addCaseInstance(
238298 run.setEnvironmentVariable("NO_COLOR", "1");
239299 run.addCheck(.{ .expect_term = term: {
240300 if (!expect_panic) break :term .{ .exited = 0 };
241 if (target.result.os.tag == .windows) break :term .{ .exited = 3 };
301 if (resolved_target.result.os.tag == .windows) break :term .{ .exited = 3 };
242302 break :term .{ .signal = @fromBackingInt(@intCast(6)) };
243303 } });
244304 run.expectStdOutEqual("");
test/stack_traces.zig+24-5
......@@ -1,7 +1,10 @@
11const std = @import("std");
2const Context = @import("tests.zig").StackTracesContext;
23
3pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.Os.Tag) void {
4pub fn addCases(cases: *Context, params: *const Context.CaseParameters, target: *const std.Target) void {
45 cases.addCase(.{
6 .params = params,
7 .target = target,
58 .name = "simple panic",
69 .source =
710 \\pub fn main() void {
......@@ -33,6 +36,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
3336 });
3437
3538 cases.addCase(.{
39 .params = params,
40 .target = target,
3641 .name = "simple panic with no unwind strategy",
3742 .source =
3843 \\pub fn main() void {
......@@ -50,6 +55,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
5055 });
5156
5257 cases.addCase(.{
58 .params = params,
59 .target = target,
5360 .name = "dump current trace",
5461 .source =
5562 \\pub fn main() void {
......@@ -89,6 +96,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
8996 });
9097
9198 cases.addCase(.{
99 .params = params,
100 .target = target,
92101 .name = "dump current trace with no unwind strategy",
93102 .source =
94103 \\pub fn main() void {
......@@ -114,6 +123,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
114123 });
115124
116125 cases.addCase(.{
126 .params = params,
127 .target = target,
117128 .name = "dump captured trace",
118129 .source =
119130 \\pub fn main() void {
......@@ -155,6 +166,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
155166 });
156167
157168 cases.addCase(.{
169 .params = params,
170 .target = target,
158171 .name = "dump captured trace with no unwind strategy",
159172 .source =
160173 \\pub fn main() void {
......@@ -180,6 +193,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
180193 });
181194
182195 cases.addCase(.{
196 .params = params,
197 .target = target,
183198 .name = "dump captured trace on thread",
184199 .source =
185200 \\pub fn main() !void {
......@@ -225,6 +240,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
225240 });
226241
227242 cases.addCase(.{
243 .params = params,
244 .target = target,
228245 .name = "simple inline panic",
229246 // The main function has two inline calls to ensure
230247 // that inlinees in PDBs are properly deduplicated.
......@@ -240,7 +257,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
240257 ,
241258 .unwind = .any,
242259 .expect_panic = true,
243 .expect = switch (os) {
260 .expect = switch (target.os.tag) {
244261 // LLVM doesn't emit column info in the binary annotations for inlinee callees in PDBs,
245262 // so the first location has only a row.
246263 .windows =>
......@@ -262,7 +279,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
262279 \\ ^
263280 ,
264281 },
265 .expect_strip = switch (os) {
282 .expect_strip = switch (target.os.tag) {
266283 .windows =>
267284 \\panic: oh no
268285 \\???:?:?: [address] in source.foo
......@@ -279,6 +296,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
279296
280297 // Make sure all inline calls are resolved and in the right order!
281298 cases.addCase(.{
299 .params = params,
300 .target = target,
282301 .name = "nested inline panic",
283302 .source =
284303 \\pub fn main() void {
......@@ -298,7 +317,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
298317 .unwind = .any,
299318 .expect_panic = true,
300319 // This switch serves a similar purpose as in "inline panic".
301 .expect = switch (os) {
320 .expect = switch (target.os.tag) {
302321 .windows =>
303322 \\panic: oh no
304323 \\source.zig:11: [address] in baz
......@@ -322,7 +341,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
322341 \\ ^
323342 ,
324343 },
325 .expect_strip = switch (os) {
344 .expect_strip = switch (target.os.tag) {
326345 .windows =>
327346 \\panic: oh no
328347 \\???:?:?: [address] in baz
test/tests.zig+9-105
......@@ -6,8 +6,6 @@ const OptimizeMode = std.builtin.OptimizeMode;
66const Step = std.Build.Step;
77
88// Cases
9const error_traces = @import("error_traces.zig");
10const stack_traces = @import("stack_traces.zig");
119const llvm_ir = @import("llvm_ir.zig");
1210const libc = @import("libc.zig");
1311const link = @import("link.zig");
......@@ -2381,59 +2379,7 @@ pub fn isNative(actual_target: *const std.Build.ResolvedTarget, host: *const std
23812379 return true;
23822380}
23832381
2384/// For stack trace tests, we only test native by default, because external executors are pretty
2385/// unreliable at stack tracing. However, if there's a 32-bit equivalent target which the host can
2386/// trivially run, we may as well at least test that!
2387fn nativeAndCompatible32bit(b: *std.Build, skip_non_native: bool) []const std.Build.ResolvedTarget {
2388 const host = b.graph.host.result;
2389 const only_native = (&b.graph.host)[0..1];
2390 if (skip_non_native) return only_native;
2391 const arch32 = compatible32bitArch(&b.graph.host.result) orelse return only_native;
2392 return b.graph.arena.dupe(std.Build.ResolvedTarget, &.{
2393 b.graph.host,
2394 b.resolveTargetQuery(.{ .cpu_arch = arch32, .os_tag = host.os.tag }),
2395 }) catch @panic("OOM");
2396}
2397
2398fn wineAndCompatible32bit(b: *std.Build, skip_non_native: bool) []const std.Build.ResolvedTarget {
2399 var targets: std.ArrayList(std.Build.ResolvedTarget) = .empty;
2400
2401 const host = b.graph.host.result;
2402
2403 targets.append(b.graph.arena, b.resolveTargetQuery(.{
2404 .cpu_arch = host.cpu.arch,
2405 .os_tag = .windows,
2406 })) catch @panic("OOM");
2407 if (!skip_non_native) {
2408 if (compatible32bitArch(&b.graph.host.result)) |arch| {
2409 targets.append(b.graph.arena, b.resolveTargetQuery(.{
2410 .cpu_arch = arch,
2411 .os_tag = .windows,
2412 })) catch @panic("OOM");
2413 }
2414 }
2415
2416 return targets.toOwnedSlice(b.graph.arena) catch @panic("OOM");
2417}
2418
2419fn darlingTargets(b: *std.Build) []const std.Build.ResolvedTarget {
2420 var targets: std.ArrayList(std.Build.ResolvedTarget) = .empty;
2421
2422 const host = b.graph.host.result;
2423
2424 targets.append(b.graph.arena, b.resolveTargetQuery(.{
2425 .cpu_arch = host.cpu.arch,
2426 .os_tag = .macos,
2427 })) catch @panic("OOM");
2428
2429 return targets.toOwnedSlice(b.graph.arena) catch @panic("OOM");
2430}
2431
2432pub fn addStackTraceTests(
2433 b: *std.Build,
2434 test_filters: []const []const u8,
2435 skip_non_native: bool,
2436) *Step {
2382pub fn addStackTraceTests(b: *std.Build, test_filters: []const []const u8, skip_non_native: bool) *Step {
24372383 const step = b.step("test-stack-traces", "Run the stack trace tests");
24382384
24392385 const convert_exe = b.addExecutable(.{
......@@ -2445,35 +2391,15 @@ pub fn addStackTraceTests(
24452391 }),
24462392 });
24472393
2448 const host_cases = b.allocator.create(StackTracesContext) catch @panic("OOM");
2449 host_cases.* = .{
2394 const stack_traces_context = b.allocator.create(StackTracesContext) catch @panic("OOM");
2395 stack_traces_context.* = .{
24502396 .b = b,
24512397 .step = step,
24522398 .test_filters = test_filters,
2453 .targets = nativeAndCompatible32bit(b, skip_non_native),
2399 .skip_non_native = skip_non_native,
24542400 .convert_exe = convert_exe,
24552401 };
2456 stack_traces.addCases(host_cases, b.graph.host.result.os.tag);
2457
2458 const wine_cases = b.allocator.create(StackTracesContext) catch @panic("OOM");
2459 wine_cases.* = .{
2460 .b = b,
2461 .step = step,
2462 .test_filters = test_filters,
2463 .targets = wineAndCompatible32bit(b, skip_non_native),
2464 .convert_exe = convert_exe,
2465 };
2466 stack_traces.addCases(wine_cases, .windows);
2467
2468 const darling_cases = b.allocator.create(StackTracesContext) catch @panic("OOM");
2469 darling_cases.* = .{
2470 .b = b,
2471 .step = step,
2472 .test_filters = test_filters,
2473 .targets = darlingTargets(b),
2474 .convert_exe = convert_exe,
2475 };
2476 stack_traces.addCases(darling_cases, .macos);
2402 stack_traces_context.addCases();
24772403
24782404 return step;
24792405}
......@@ -2495,38 +2421,16 @@ pub fn addErrorTraceTests(
24952421 }),
24962422 });
24972423
2498 const host_cases = b.allocator.create(ErrorTracesContext) catch @panic("OOM");
2499 host_cases.* = .{
2500 .b = b,
2501 .step = step,
2502 .test_filters = test_filters,
2503 .targets = nativeAndCompatible32bit(b, skip_non_native),
2504 .optimize_modes = optimize_modes,
2505 .convert_exe = convert_exe,
2506 };
2507 error_traces.addCases(host_cases, b.graph.host.result.os.tag);
2508
2509 const wine_cases = b.allocator.create(ErrorTracesContext) catch @panic("OOM");
2510 wine_cases.* = .{
2511 .b = b,
2512 .step = step,
2513 .test_filters = test_filters,
2514 .targets = wineAndCompatible32bit(b, skip_non_native),
2515 .optimize_modes = optimize_modes,
2516 .convert_exe = convert_exe,
2517 };
2518 error_traces.addCases(wine_cases, .windows);
2519
2520 const darling_cases = b.allocator.create(ErrorTracesContext) catch @panic("OOM");
2521 darling_cases.* = .{
2424 const error_traces_context = b.allocator.create(ErrorTracesContext) catch @panic("OOM");
2425 error_traces_context.* = .{
25222426 .b = b,
25232427 .step = step,
25242428 .test_filters = test_filters,
2525 .targets = darlingTargets(b),
2429 .skip_non_native = skip_non_native,
25262430 .optimize_modes = optimize_modes,
25272431 .convert_exe = convert_exe,
25282432 };
2529 error_traces.addCases(darling_cases, .macos);
2433 error_traces_context.addCases();
25302434
25312435 return step;
25322436}