| ... | @@ -1,11 +1,12 @@ | ... | @@ -1,11 +1,12 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const fatal = std.process.fatal; | | |
| 3 | const Allocator = std.mem.Allocator; | 2 | const Allocator = std.mem.Allocator; |
| 4 | const Cache = std.Build.Cache; | 3 | const Cache = std.Build.Cache; |
| 5 | | 4 | |
| 6 | const usage = "usage: incr-check <zig binary path> <input file> [--zig-lib-dir lib] [--debug-zcu] [--debug-link] [--zig-cc-binary /path/to/zig]"; | 5 | const usage = "usage: incr-check <zig binary path> <input file> [--zig-lib-dir lib] [--debug-zcu] [--debug-link] [--preserve-tmp] [--zig-cc-binary /path/to/zig]"; |
| 7 | | 6 | |
| 8 | pub fn main() !void { | 7 | pub fn main() !void { |
| | 8 | const fatal = std.process.fatal; |
| | 9 | |
| 9 | var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); | 10 | var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); |
| 10 | defer arena_instance.deinit(); | 11 | defer arena_instance.deinit(); |
| 11 | const arena = arena_instance.allocator(); | 12 | const arena = arena_instance.allocator(); |
| ... | @@ -16,6 +17,7 @@ pub fn main() !void { | ... | @@ -16,6 +17,7 @@ pub fn main() !void { |
| 16 | var opt_cc_zig: ?[]const u8 = null; | 17 | var opt_cc_zig: ?[]const u8 = null; |
| 17 | var debug_zcu = false; | 18 | var debug_zcu = false; |
| 18 | var debug_link = false; | 19 | var debug_link = false; |
| | 20 | var preserve_tmp = false; |
| 19 | | 21 | |
| 20 | var arg_it = try std.process.argsWithAllocator(arena); | 22 | var arg_it = try std.process.argsWithAllocator(arena); |
| 21 | _ = arg_it.skip(); | 23 | _ = arg_it.skip(); |
| ... | @@ -27,6 +29,8 @@ pub fn main() !void { | ... | @@ -27,6 +29,8 @@ pub fn main() !void { |
| 27 | debug_zcu = true; | 29 | debug_zcu = true; |
| 28 | } else if (std.mem.eql(u8, arg, "--debug-link")) { | 30 | } else if (std.mem.eql(u8, arg, "--debug-link")) { |
| 29 | debug_link = true; | 31 | debug_link = true; |
| | 32 | } else if (std.mem.eql(u8, arg, "--preserve-tmp")) { |
| | 33 | preserve_tmp = true; |
| 30 | } else if (std.mem.eql(u8, arg, "--zig-cc-binary")) { | 34 | } else if (std.mem.eql(u8, arg, "--zig-cc-binary")) { |
| 31 | opt_cc_zig = arg_it.next() orelse fatal("expect arg after '--zig-cc-binary'\n{s}", .{usage}); | 35 | opt_cc_zig = arg_it.next() orelse fatal("expect arg after '--zig-cc-binary'\n{s}", .{usage}); |
| 32 | } else { | 36 | } else { |
| ... | @@ -48,12 +52,29 @@ pub fn main() !void { | ... | @@ -48,12 +52,29 @@ pub fn main() !void { |
| 48 | const input_file_bytes = try std.fs.cwd().readFileAlloc(arena, input_file_name, std.math.maxInt(u32)); | 52 | const input_file_bytes = try std.fs.cwd().readFileAlloc(arena, input_file_name, std.math.maxInt(u32)); |
| 49 | const case = try Case.parse(arena, input_file_bytes); | 53 | const case = try Case.parse(arena, input_file_bytes); |
| 50 | | 54 | |
| | 55 | // Check now: if there are any targets using the `cbe` backend, we need the lib dir. |
| | 56 | if (opt_lib_dir == null) { |
| | 57 | for (case.targets) |target| { |
| | 58 | if (target.backend == .cbe) { |
| | 59 | fatal("'--zig-lib-dir' requried when using backend 'cbe'", .{}); |
| | 60 | } |
| | 61 | } |
| | 62 | } |
| | 63 | |
| 51 | const prog_node = std.Progress.start(.{}); | 64 | const prog_node = std.Progress.start(.{}); |
| 52 | defer prog_node.end(); | 65 | defer prog_node.end(); |
| 53 | | 66 | |
| 54 | const rand_int = std.crypto.random.int(u64); | 67 | const rand_int = std.crypto.random.int(u64); |
| 55 | const tmp_dir_path = "tmp_" ++ std.fmt.hex(rand_int); | 68 | const tmp_dir_path = "tmp_" ++ std.fmt.hex(rand_int); |
| 56 | const tmp_dir = try std.fs.cwd().makeOpenPath(tmp_dir_path, .{}); | 69 | var tmp_dir = try std.fs.cwd().makeOpenPath(tmp_dir_path, .{}); |
| | 70 | defer { |
| | 71 | tmp_dir.close(); |
| | 72 | if (!preserve_tmp) { |
| | 73 | std.fs.cwd().deleteTree(tmp_dir_path) catch |err| { |
| | 74 | std.log.warn("failed to delete tree '{s}': {s}", .{ tmp_dir_path, @errorName(err) }); |
| | 75 | }; |
| | 76 | } |
| | 77 | } |
| 57 | | 78 | |
| 58 | // Convert paths to be relative to the cwd of the subprocess. | 79 | // Convert paths to be relative to the cwd of the subprocess. |
| 59 | const resolved_zig_exe = try std.fs.path.relative(arena, tmp_dir_path, zig_exe); | 80 | const resolved_zig_exe = try std.fs.path.relative(arena, tmp_dir_path, zig_exe); |
| ... | @@ -132,7 +153,7 @@ pub fn main() !void { | ... | @@ -132,7 +153,7 @@ pub fn main() !void { |
| 132 | "-target", | 153 | "-target", |
| 133 | target.query, | 154 | target.query, |
| 134 | "-I", | 155 | "-I", |
| 135 | opt_resolved_lib_dir orelse fatal("'--zig-lib-dir' required when using backend 'cbe'", .{}), | 156 | opt_resolved_lib_dir.?, // verified earlier |
| 136 | "-o", | 157 | "-o", |
| 137 | }); | 158 | }); |
| 138 | } | 159 | } |
| ... | @@ -146,6 +167,7 @@ pub fn main() !void { | ... | @@ -146,6 +167,7 @@ pub fn main() !void { |
| 146 | .tmp_dir_path = tmp_dir_path, | 167 | .tmp_dir_path = tmp_dir_path, |
| 147 | .child = &child, | 168 | .child = &child, |
| 148 | .allow_stderr = debug_log_verbose, | 169 | .allow_stderr = debug_log_verbose, |
| | 170 | .preserve_tmp_on_fatal = preserve_tmp, |
| 149 | .cc_child_args = &cc_child_args, | 171 | .cc_child_args = &cc_child_args, |
| 150 | }; | 172 | }; |
| 151 | | 173 | |
| ... | @@ -172,7 +194,7 @@ pub fn main() !void { | ... | @@ -172,7 +194,7 @@ pub fn main() !void { |
| 172 | | 194 | |
| 173 | try eval.end(&poller); | 195 | try eval.end(&poller); |
| 174 | | 196 | |
| 175 | waitChild(&child); | 197 | waitChild(&child, &eval); |
| 176 | } | 198 | } |
| 177 | } | 199 | } |
| 178 | | 200 | |
| ... | @@ -185,6 +207,7 @@ const Eval = struct { | ... | @@ -185,6 +207,7 @@ const Eval = struct { |
| 185 | tmp_dir_path: []const u8, | 207 | tmp_dir_path: []const u8, |
| 186 | child: *std.process.Child, | 208 | child: *std.process.Child, |
| 187 | allow_stderr: bool, | 209 | allow_stderr: bool, |
| | 210 | preserve_tmp_on_fatal: bool, |
| 188 | /// When `target.backend == .cbe`, this contains the first few arguments to `zig cc` to build the generated binary. | 211 | /// When `target.backend == .cbe`, this contains the first few arguments to `zig cc` to build the generated binary. |
| 189 | /// The arguments `out.c in.c` must be appended before spawning the subprocess. | 212 | /// The arguments `out.c in.c` must be appended before spawning the subprocess. |
| 190 | cc_child_args: *std.ArrayListUnmanaged([]const u8), | 213 | cc_child_args: *std.ArrayListUnmanaged([]const u8), |
| ... | @@ -199,12 +222,12 @@ const Eval = struct { | ... | @@ -199,12 +222,12 @@ const Eval = struct { |
| 199 | .sub_path = full_contents.name, | 222 | .sub_path = full_contents.name, |
| 200 | .data = full_contents.bytes, | 223 | .data = full_contents.bytes, |
| 201 | }) catch |err| { | 224 | }) catch |err| { |
| 202 | fatal("failed to update '{s}': {s}", .{ full_contents.name, @errorName(err) }); | 225 | eval.fatal("failed to update '{s}': {s}", .{ full_contents.name, @errorName(err) }); |
| 203 | }; | 226 | }; |
| 204 | } | 227 | } |
| 205 | for (update.deletes) |doomed_name| { | 228 | for (update.deletes) |doomed_name| { |
| 206 | eval.tmp_dir.deleteFile(doomed_name) catch |err| { | 229 | eval.tmp_dir.deleteFile(doomed_name) catch |err| { |
| 207 | fatal("failed to delete '{s}': {s}", .{ doomed_name, @errorName(err) }); | 230 | eval.fatal("failed to delete '{s}': {s}", .{ doomed_name, @errorName(err) }); |
| 208 | }; | 231 | }; |
| 209 | } | 232 | } |
| 210 | } | 233 | } |
| ... | @@ -246,7 +269,7 @@ const Eval = struct { | ... | @@ -246,7 +269,7 @@ const Eval = struct { |
| 246 | if (eval.allow_stderr) { | 269 | if (eval.allow_stderr) { |
| 247 | std.log.info("error_bundle included stderr:\n{s}", .{stderr_data}); | 270 | std.log.info("error_bundle included stderr:\n{s}", .{stderr_data}); |
| 248 | } else { | 271 | } else { |
| 249 | fatal("error_bundle included unexpected stderr:\n{s}", .{stderr_data}); | 272 | eval.fatal("error_bundle included unexpected stderr:\n{s}", .{stderr_data}); |
| 250 | } | 273 | } |
| 251 | } | 274 | } |
| 252 | if (result_error_bundle.errorMessageCount() != 0) { | 275 | if (result_error_bundle.errorMessageCount() != 0) { |
| ... | @@ -265,7 +288,7 @@ const Eval = struct { | ... | @@ -265,7 +288,7 @@ const Eval = struct { |
| 265 | if (eval.allow_stderr) { | 288 | if (eval.allow_stderr) { |
| 266 | std.log.info("emit_digest included stderr:\n{s}", .{stderr_data}); | 289 | std.log.info("emit_digest included stderr:\n{s}", .{stderr_data}); |
| 267 | } else { | 290 | } else { |
| 268 | fatal("emit_digest included unexpected stderr:\n{s}", .{stderr_data}); | 291 | eval.fatal("emit_digest included unexpected stderr:\n{s}", .{stderr_data}); |
| 269 | } | 292 | } |
| 270 | } | 293 | } |
| 271 | | 294 | |
| ... | @@ -302,16 +325,15 @@ const Eval = struct { | ... | @@ -302,16 +325,15 @@ const Eval = struct { |
| 302 | if (eval.allow_stderr) { | 325 | if (eval.allow_stderr) { |
| 303 | std.log.info("update '{s}' included stderr:\n{s}", .{ update.name, stderr_data }); | 326 | std.log.info("update '{s}' included stderr:\n{s}", .{ update.name, stderr_data }); |
| 304 | } else { | 327 | } else { |
| 305 | fatal("update '{s}' failed:\n{s}", .{ update.name, stderr_data }); | 328 | eval.fatal("update '{s}' failed:\n{s}", .{ update.name, stderr_data }); |
| 306 | } | 329 | } |
| 307 | } | 330 | } |
| 308 | | 331 | |
| 309 | waitChild(eval.child); | 332 | waitChild(eval.child, eval); |
| 310 | fatal("update '{s}': compiler failed to send error_bundle or emit_bin_path", .{update.name}); | 333 | eval.fatal("update '{s}': compiler failed to send error_bundle or emit_bin_path", .{update.name}); |
| 311 | } | 334 | } |
| 312 | | 335 | |
| 313 | fn checkErrorOutcome(eval: *Eval, update: Case.Update, error_bundle: std.zig.ErrorBundle) !void { | 336 | fn checkErrorOutcome(eval: *Eval, update: Case.Update, error_bundle: std.zig.ErrorBundle) !void { |
| 314 | _ = eval; | | |
| 315 | switch (update.outcome) { | 337 | switch (update.outcome) { |
| 316 | .unknown => return, | 338 | .unknown => return, |
| 317 | .compile_errors => |expected_errors| { | 339 | .compile_errors => |expected_errors| { |
| ... | @@ -323,7 +345,7 @@ const Eval = struct { | ... | @@ -323,7 +345,7 @@ const Eval = struct { |
| 323 | .stdout, .exit_code => { | 345 | .stdout, .exit_code => { |
| 324 | const color: std.zig.Color = .auto; | 346 | const color: std.zig.Color = .auto; |
| 325 | error_bundle.renderToStdErr(color.renderOptions()); | 347 | error_bundle.renderToStdErr(color.renderOptions()); |
| 326 | fatal("update '{s}': unexpected compile errors", .{update.name}); | 348 | eval.fatal("update '{s}': unexpected compile errors", .{update.name}); |
| 327 | }, | 349 | }, |
| 328 | } | 350 | } |
| 329 | } | 351 | } |
| ... | @@ -331,7 +353,7 @@ const Eval = struct { | ... | @@ -331,7 +353,7 @@ const Eval = struct { |
| 331 | fn checkSuccessOutcome(eval: *Eval, update: Case.Update, opt_emitted_path: ?[]const u8, prog_node: std.Progress.Node) !void { | 353 | fn checkSuccessOutcome(eval: *Eval, update: Case.Update, opt_emitted_path: ?[]const u8, prog_node: std.Progress.Node) !void { |
| 332 | switch (update.outcome) { | 354 | switch (update.outcome) { |
| 333 | .unknown => return, | 355 | .unknown => return, |
| 334 | .compile_errors => fatal("expected compile errors but compilation incorrectly succeeded", .{}), | 356 | .compile_errors => eval.fatal("expected compile errors but compilation incorrectly succeeded", .{}), |
| 335 | .stdout, .exit_code => {}, | 357 | .stdout, .exit_code => {}, |
| 336 | } | 358 | } |
| 337 | const emitted_path = opt_emitted_path orelse { | 359 | const emitted_path = opt_emitted_path orelse { |
| ... | @@ -388,7 +410,7 @@ const Eval = struct { | ... | @@ -388,7 +410,7 @@ const Eval = struct { |
| 388 | .cwd_dir = eval.tmp_dir, | 410 | .cwd_dir = eval.tmp_dir, |
| 389 | .cwd = eval.tmp_dir_path, | 411 | .cwd = eval.tmp_dir_path, |
| 390 | }) catch |err| { | 412 | }) catch |err| { |
| 391 | fatal("update '{s}': failed to run the generated executable '{s}': {s}", .{ | 413 | eval.fatal("update '{s}': failed to run the generated executable '{s}': {s}", .{ |
| 392 | update.name, binary_path, @errorName(err), | 414 | update.name, binary_path, @errorName(err), |
| 393 | }); | 415 | }); |
| 394 | }; | 416 | }; |
| ... | @@ -402,7 +424,7 @@ const Eval = struct { | ... | @@ -402,7 +424,7 @@ const Eval = struct { |
| 402 | .unknown, .compile_errors => unreachable, | 424 | .unknown, .compile_errors => unreachable, |
| 403 | .stdout => |expected_stdout| { | 425 | .stdout => |expected_stdout| { |
| 404 | if (code != 0) { | 426 | if (code != 0) { |
| 405 | fatal("update '{s}': generated executable '{s}' failed with code {d}", .{ | 427 | eval.fatal("update '{s}': generated executable '{s}' failed with code {d}", .{ |
| 406 | update.name, binary_path, code, | 428 | update.name, binary_path, code, |
| 407 | }); | 429 | }); |
| 408 | } | 430 | } |
| ... | @@ -411,7 +433,7 @@ const Eval = struct { | ... | @@ -411,7 +433,7 @@ const Eval = struct { |
| 411 | .exit_code => |expected_code| try std.testing.expectEqual(expected_code, result.term.Exited), | 433 | .exit_code => |expected_code| try std.testing.expectEqual(expected_code, result.term.Exited), |
| 412 | }, | 434 | }, |
| 413 | .Signal, .Stopped, .Unknown => { | 435 | .Signal, .Stopped, .Unknown => { |
| 414 | fatal("update '{s}': generated executable '{s}' terminated unexpectedly", .{ | 436 | eval.fatal("update '{s}': generated executable '{s}' terminated unexpectedly", .{ |
| 415 | update.name, binary_path, | 437 | update.name, binary_path, |
| 416 | }); | 438 | }); |
| 417 | }, | 439 | }, |
| ... | @@ -428,7 +450,7 @@ const Eval = struct { | ... | @@ -428,7 +450,7 @@ const Eval = struct { |
| 428 | } | 450 | } |
| 429 | | 451 | |
| 430 | fn end(eval: *Eval, poller: *Poller) !void { | 452 | fn end(eval: *Eval, poller: *Poller) !void { |
| 431 | requestExit(eval.child); | 453 | requestExit(eval.child, eval); |
| 432 | | 454 | |
| 433 | const Header = std.zig.Server.Message.Header; | 455 | const Header = std.zig.Server.Message.Header; |
| 434 | const stdout = poller.fifo(.stdout); | 456 | const stdout = poller.fifo(.stdout); |
| ... | @@ -448,7 +470,7 @@ const Eval = struct { | ... | @@ -448,7 +470,7 @@ const Eval = struct { |
| 448 | | 470 | |
| 449 | if (stderr.readableLength() > 0) { | 471 | if (stderr.readableLength() > 0) { |
| 450 | const stderr_data = try stderr.toOwnedSlice(); | 472 | const stderr_data = try stderr.toOwnedSlice(); |
| 451 | fatal("unexpected stderr:\n{s}", .{stderr_data}); | 473 | eval.fatal("unexpected stderr:\n{s}", .{stderr_data}); |
| 452 | } | 474 | } |
| 453 | } | 475 | } |
| 454 | | 476 | |
| ... | @@ -468,7 +490,7 @@ const Eval = struct { | ... | @@ -468,7 +490,7 @@ const Eval = struct { |
| 468 | .cwd = eval.tmp_dir_path, | 490 | .cwd = eval.tmp_dir_path, |
| 469 | .progress_node = child_prog_node, | 491 | .progress_node = child_prog_node, |
| 470 | }) catch |err| { | 492 | }) catch |err| { |
| 471 | fatal("update '{s}': failed to spawn zig cc for '{s}': {s}", .{ | 493 | eval.fatal("update '{s}': failed to spawn zig cc for '{s}': {s}", .{ |
| 472 | update.name, c_path, @errorName(err), | 494 | update.name, c_path, @errorName(err), |
| 473 | }); | 495 | }); |
| 474 | }; | 496 | }; |
| ... | @@ -479,7 +501,7 @@ const Eval = struct { | ... | @@ -479,7 +501,7 @@ const Eval = struct { |
| 479 | update.name, result.stderr, | 501 | update.name, result.stderr, |
| 480 | }); | 502 | }); |
| 481 | } | 503 | } |
| 482 | fatal("update '{s}': zig cc for '{s}' failed with code {d}", .{ | 504 | eval.fatal("update '{s}': zig cc for '{s}' failed with code {d}", .{ |
| 483 | update.name, c_path, code, | 505 | update.name, c_path, code, |
| 484 | }); | 506 | }); |
| 485 | }, | 507 | }, |
| ... | @@ -489,12 +511,22 @@ const Eval = struct { | ... | @@ -489,12 +511,22 @@ const Eval = struct { |
| 489 | update.name, result.stderr, | 511 | update.name, result.stderr, |
| 490 | }); | 512 | }); |
| 491 | } | 513 | } |
| 492 | fatal("update '{s}': zig cc for '{s}' terminated unexpectedly", .{ | 514 | eval.fatal("update '{s}': zig cc for '{s}' terminated unexpectedly", .{ |
| 493 | update.name, c_path, | 515 | update.name, c_path, |
| 494 | }); | 516 | }); |
| 495 | }, | 517 | }, |
| 496 | } | 518 | } |
| 497 | } | 519 | } |
| | 520 | |
| | 521 | fn fatal(eval: *Eval, comptime fmt: []const u8, args: anytype) noreturn { |
| | 522 | eval.tmp_dir.close(); |
| | 523 | if (!eval.preserve_tmp_on_fatal) { |
| | 524 | std.fs.cwd().deleteTree(eval.tmp_dir_path) catch |err| { |
| | 525 | std.log.warn("failed to delete tree '{s}': {s}", .{ eval.tmp_dir_path, @errorName(err) }); |
| | 526 | }; |
| | 527 | } |
| | 528 | std.process.fatal(fmt, args); |
| | 529 | } |
| 498 | }; | 530 | }; |
| 499 | | 531 | |
| 500 | const Case = struct { | 532 | const Case = struct { |
| ... | @@ -550,6 +582,8 @@ const Case = struct { | ... | @@ -550,6 +582,8 @@ const Case = struct { |
| 550 | }; | 582 | }; |
| 551 | | 583 | |
| 552 | fn parse(arena: Allocator, bytes: []const u8) !Case { | 584 | fn parse(arena: Allocator, bytes: []const u8) !Case { |
| | 585 | const fatal = std.process.fatal; |
| | 586 | |
| 553 | var targets: std.ArrayListUnmanaged(Target) = .empty; | 587 | var targets: std.ArrayListUnmanaged(Target) = .empty; |
| 554 | var updates: std.ArrayListUnmanaged(Update) = .empty; | 588 | var updates: std.ArrayListUnmanaged(Update) = .empty; |
| 555 | var changes: std.ArrayListUnmanaged(FullContents) = .empty; | 589 | var changes: std.ArrayListUnmanaged(FullContents) = .empty; |
| ... | @@ -656,7 +690,7 @@ const Case = struct { | ... | @@ -656,7 +690,7 @@ const Case = struct { |
| 656 | } | 690 | } |
| 657 | }; | 691 | }; |
| 658 | | 692 | |
| 659 | fn requestExit(child: *std.process.Child) void { | 693 | fn requestExit(child: *std.process.Child, eval: *Eval) void { |
| 660 | if (child.stdin == null) return; | 694 | if (child.stdin == null) return; |
| 661 | | 695 | |
| 662 | const header: std.zig.Client.Message.Header = .{ | 696 | const header: std.zig.Client.Message.Header = .{ |
| ... | @@ -665,7 +699,7 @@ fn requestExit(child: *std.process.Child) void { | ... | @@ -665,7 +699,7 @@ fn requestExit(child: *std.process.Child) void { |
| 665 | }; | 699 | }; |
| 666 | child.stdin.?.writeAll(std.mem.asBytes(&header)) catch |err| switch (err) { | 700 | child.stdin.?.writeAll(std.mem.asBytes(&header)) catch |err| switch (err) { |
| 667 | error.BrokenPipe => {}, | 701 | error.BrokenPipe => {}, |
| 668 | else => fatal("failed to send exit: {s}", .{@errorName(err)}), | 702 | else => eval.fatal("failed to send exit: {s}", .{@errorName(err)}), |
| 669 | }; | 703 | }; |
| 670 | | 704 | |
| 671 | // Send EOF to stdin. | 705 | // Send EOF to stdin. |
| ... | @@ -673,11 +707,11 @@ fn requestExit(child: *std.process.Child) void { | ... | @@ -673,11 +707,11 @@ fn requestExit(child: *std.process.Child) void { |
| 673 | child.stdin = null; | 707 | child.stdin = null; |
| 674 | } | 708 | } |
| 675 | | 709 | |
| 676 | fn waitChild(child: *std.process.Child) void { | 710 | fn waitChild(child: *std.process.Child, eval: *Eval) void { |
| 677 | requestExit(child); | 711 | requestExit(child, eval); |
| 678 | const term = child.wait() catch |err| fatal("child process failed: {s}", .{@errorName(err)}); | 712 | const term = child.wait() catch |err| eval.fatal("child process failed: {s}", .{@errorName(err)}); |
| 679 | switch (term) { | 713 | switch (term) { |
| 680 | .Exited => |code| if (code != 0) fatal("compiler failed with code {d}", .{code}), | 714 | .Exited => |code| if (code != 0) eval.fatal("compiler failed with code {d}", .{code}), |
| 681 | .Signal, .Stopped, .Unknown => fatal("compiler terminated unexpectedly", .{}), | 715 | .Signal, .Stopped, .Unknown => eval.fatal("compiler terminated unexpectedly", .{}), |
| 682 | } | 716 | } |
| 683 | } | 717 | } |