authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-03-17 15:19:54-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-03-17 15:19:54-07:00
logd981549d65849591749d8d9db12ddf2bf7361399
treeced0941ad568c7bb7cddc57759e8d320a71ab7fc
parent294f51814f491ae4a09348d9e7221ae3e550c16f
parentedeed592eeed151780ae8a0b13c3d4d17c3f93b2
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #19323 from jacobly0/rm-fn-type-align

AstGen: disallow alignment on function types

35 files changed, 1708 insertions(+), 1695 deletions(-)

doc/langref.html.in+8-2
......@@ -2780,10 +2780,16 @@ fn noop4() align(4) void {}
27802780
27812781test "function alignment" {
27822782 try expect(derp() == 1234);
2783 try expect(@TypeOf(noop1) == fn () align(1) void);
2784 try expect(@TypeOf(noop4) == fn () align(4) void);
2783 try expect(@TypeOf(derp) == fn () i32);
2784 try expect(@TypeOf(&derp) == *align(@sizeOf(usize) * 2) const fn () i32);
2785
27852786 noop1();
2787 try expect(@TypeOf(noop1) == fn () void);
2788 try expect(@TypeOf(&noop1) == *align(1) const fn () void);
2789
27862790 noop4();
2791 try expect(@TypeOf(noop4) == fn () void);
2792 try expect(@TypeOf(&noop4) == *align(4) const fn () void);
27872793}
27882794 {#code_end#}
27892795 <p>
lib/build_runner.zig deleted-1293
......@@ -1,1293 +0,0 @@
1const root = @import("@build");
2const std = @import("std");
3const builtin = @import("builtin");
4const assert = std.debug.assert;
5const io = std.io;
6const fmt = std.fmt;
7const mem = std.mem;
8const process = std.process;
9const ArrayList = std.ArrayList;
10const File = std.fs.File;
11const Step = std.Build.Step;
12
13pub const dependencies = @import("@dependencies");
14
15pub fn main() !void {
16 // Here we use an ArenaAllocator backed by a page allocator because a build is a short-lived,
17 // one shot program. We don't need to waste time freeing memory and finding places to squish
18 // bytes into. So we free everything all at once at the very end.
19 var single_threaded_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
20 defer single_threaded_arena.deinit();
21
22 var thread_safe_arena: std.heap.ThreadSafeAllocator = .{
23 .child_allocator = single_threaded_arena.allocator(),
24 };
25 const arena = thread_safe_arena.allocator();
26
27 const args = try process.argsAlloc(arena);
28
29 // skip my own exe name
30 var arg_idx: usize = 1;
31
32 const zig_exe = nextArg(args, &arg_idx) orelse {
33 std.debug.print("Expected path to zig compiler\n", .{});
34 return error.InvalidArgs;
35 };
36 const build_root = nextArg(args, &arg_idx) orelse {
37 std.debug.print("Expected build root directory path\n", .{});
38 return error.InvalidArgs;
39 };
40 const cache_root = nextArg(args, &arg_idx) orelse {
41 std.debug.print("Expected cache root directory path\n", .{});
42 return error.InvalidArgs;
43 };
44 const global_cache_root = nextArg(args, &arg_idx) orelse {
45 std.debug.print("Expected global cache root directory path\n", .{});
46 return error.InvalidArgs;
47 };
48
49 const build_root_directory: std.Build.Cache.Directory = .{
50 .path = build_root,
51 .handle = try std.fs.cwd().openDir(build_root, .{}),
52 };
53
54 const local_cache_directory: std.Build.Cache.Directory = .{
55 .path = cache_root,
56 .handle = try std.fs.cwd().makeOpenPath(cache_root, .{}),
57 };
58
59 const global_cache_directory: std.Build.Cache.Directory = .{
60 .path = global_cache_root,
61 .handle = try std.fs.cwd().makeOpenPath(global_cache_root, .{}),
62 };
63
64 var graph: std.Build.Graph = .{
65 .arena = arena,
66 .cache = .{
67 .gpa = arena,
68 .manifest_dir = try local_cache_directory.handle.makeOpenPath("h", .{}),
69 },
70 .zig_exe = zig_exe,
71 .env_map = try process.getEnvMap(arena),
72 .global_cache_root = global_cache_directory,
73 };
74
75 graph.cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
76 graph.cache.addPrefix(build_root_directory);
77 graph.cache.addPrefix(local_cache_directory);
78 graph.cache.addPrefix(global_cache_directory);
79 graph.cache.hash.addBytes(builtin.zig_version_string);
80
81 const builder = try std.Build.create(
82 &graph,
83 build_root_directory,
84 local_cache_directory,
85 dependencies.root_deps,
86 );
87
88 var targets = ArrayList([]const u8).init(arena);
89 var debug_log_scopes = ArrayList([]const u8).init(arena);
90 var thread_pool_options: std.Thread.Pool.Options = .{ .allocator = arena };
91
92 var install_prefix: ?[]const u8 = null;
93 var dir_list = std.Build.DirList{};
94 var summary: ?Summary = null;
95 var max_rss: u64 = 0;
96 var skip_oom_steps: bool = false;
97 var color: Color = .auto;
98 var seed: u32 = 0;
99 var prominent_compile_errors: bool = false;
100 var help_menu: bool = false;
101 var steps_menu: bool = false;
102 var output_tmp_nonce: ?[16]u8 = null;
103
104 while (nextArg(args, &arg_idx)) |arg| {
105 if (mem.startsWith(u8, arg, "-Z")) {
106 if (arg.len != 18) fatalWithHint("bad argument: '{s}'", .{arg});
107 output_tmp_nonce = arg[2..18].*;
108 } else if (mem.startsWith(u8, arg, "-D")) {
109 const option_contents = arg[2..];
110 if (option_contents.len == 0)
111 fatalWithHint("expected option name after '-D'", .{});
112 if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| {
113 const option_name = option_contents[0..name_end];
114 const option_value = option_contents[name_end + 1 ..];
115 if (try builder.addUserInputOption(option_name, option_value))
116 fatal(" access the help menu with 'zig build -h'", .{});
117 } else {
118 if (try builder.addUserInputFlag(option_contents))
119 fatal(" access the help menu with 'zig build -h'", .{});
120 }
121 } else if (mem.startsWith(u8, arg, "-")) {
122 if (mem.eql(u8, arg, "--verbose")) {
123 builder.verbose = true;
124 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
125 help_menu = true;
126 } else if (mem.eql(u8, arg, "-p") or mem.eql(u8, arg, "--prefix")) {
127 install_prefix = nextArgOrFatal(args, &arg_idx);
128 } else if (mem.eql(u8, arg, "-l") or mem.eql(u8, arg, "--list-steps")) {
129 steps_menu = true;
130 } else if (mem.startsWith(u8, arg, "-fsys=")) {
131 const name = arg["-fsys=".len..];
132 graph.system_library_options.put(arena, name, .user_enabled) catch @panic("OOM");
133 } else if (mem.startsWith(u8, arg, "-fno-sys=")) {
134 const name = arg["-fno-sys=".len..];
135 graph.system_library_options.put(arena, name, .user_disabled) catch @panic("OOM");
136 } else if (mem.eql(u8, arg, "--release")) {
137 builder.release_mode = .any;
138 } else if (mem.startsWith(u8, arg, "--release=")) {
139 const text = arg["--release=".len..];
140 builder.release_mode = std.meta.stringToEnum(std.Build.ReleaseMode, text) orelse {
141 fatalWithHint("expected [off|any|fast|safe|small] in '{s}', found '{s}'", .{
142 arg, text,
143 });
144 };
145 } else if (mem.eql(u8, arg, "--host-target")) {
146 graph.host_query_options.arch_os_abi = nextArgOrFatal(args, &arg_idx);
147 } else if (mem.eql(u8, arg, "--host-cpu")) {
148 graph.host_query_options.cpu_features = nextArgOrFatal(args, &arg_idx);
149 } else if (mem.eql(u8, arg, "--host-dynamic-linker")) {
150 graph.host_query_options.dynamic_linker = nextArgOrFatal(args, &arg_idx);
151 } else if (mem.eql(u8, arg, "--prefix-lib-dir")) {
152 dir_list.lib_dir = nextArgOrFatal(args, &arg_idx);
153 } else if (mem.eql(u8, arg, "--prefix-exe-dir")) {
154 dir_list.exe_dir = nextArgOrFatal(args, &arg_idx);
155 } else if (mem.eql(u8, arg, "--prefix-include-dir")) {
156 dir_list.include_dir = nextArgOrFatal(args, &arg_idx);
157 } else if (mem.eql(u8, arg, "--sysroot")) {
158 builder.sysroot = nextArgOrFatal(args, &arg_idx);
159 } else if (mem.eql(u8, arg, "--maxrss")) {
160 const max_rss_text = nextArgOrFatal(args, &arg_idx);
161 max_rss = std.fmt.parseIntSizeSuffix(max_rss_text, 10) catch |err| {
162 std.debug.print("invalid byte size: '{s}': {s}\n", .{
163 max_rss_text, @errorName(err),
164 });
165 process.exit(1);
166 };
167 } else if (mem.eql(u8, arg, "--skip-oom-steps")) {
168 skip_oom_steps = true;
169 } else if (mem.eql(u8, arg, "--search-prefix")) {
170 const search_prefix = nextArgOrFatal(args, &arg_idx);
171 builder.addSearchPrefix(search_prefix);
172 } else if (mem.eql(u8, arg, "--libc")) {
173 builder.libc_file = nextArgOrFatal(args, &arg_idx);
174 } else if (mem.eql(u8, arg, "--color")) {
175 const next_arg = nextArg(args, &arg_idx) orelse
176 fatalWithHint("expected [auto|on|off] after '{s}'", .{arg});
177 color = std.meta.stringToEnum(Color, next_arg) orelse {
178 fatalWithHint("expected [auto|on|off] after '{s}', found '{s}'", .{
179 arg, next_arg,
180 });
181 };
182 } else if (mem.eql(u8, arg, "--summary")) {
183 const next_arg = nextArg(args, &arg_idx) orelse
184 fatalWithHint("expected [all|new|failures|none] after '{s}'", .{arg});
185 summary = std.meta.stringToEnum(Summary, next_arg) orelse {
186 fatalWithHint("expected [all|failures|none] after '{s}', found '{s}'", .{
187 arg, next_arg,
188 });
189 };
190 } else if (mem.eql(u8, arg, "--zig-lib-dir")) {
191 builder.zig_lib_dir = .{ .cwd_relative = nextArgOrFatal(args, &arg_idx) };
192 } else if (mem.eql(u8, arg, "--seed")) {
193 const next_arg = nextArg(args, &arg_idx) orelse
194 fatalWithHint("expected u32 after '{s}'", .{arg});
195 seed = std.fmt.parseUnsigned(u32, next_arg, 0) catch |err| {
196 fatal("unable to parse seed '{s}' as 32-bit integer: {s}\n", .{
197 next_arg, @errorName(err),
198 });
199 };
200 } else if (mem.eql(u8, arg, "--debug-log")) {
201 const next_arg = nextArgOrFatal(args, &arg_idx);
202 try debug_log_scopes.append(next_arg);
203 } else if (mem.eql(u8, arg, "--debug-pkg-config")) {
204 builder.debug_pkg_config = true;
205 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
206 builder.debug_compile_errors = true;
207 } else if (mem.eql(u8, arg, "--system")) {
208 // The usage text shows another argument after this parameter
209 // but it is handled by the parent process. The build runner
210 // only sees this flag.
211 graph.system_package_mode = true;
212 } else if (mem.eql(u8, arg, "--glibc-runtimes")) {
213 builder.glibc_runtimes_dir = nextArgOrFatal(args, &arg_idx);
214 } else if (mem.eql(u8, arg, "--verbose-link")) {
215 builder.verbose_link = true;
216 } else if (mem.eql(u8, arg, "--verbose-air")) {
217 builder.verbose_air = true;
218 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
219 builder.verbose_llvm_ir = "-";
220 } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) {
221 builder.verbose_llvm_ir = arg["--verbose-llvm-ir=".len..];
222 } else if (mem.eql(u8, arg, "--verbose-llvm-bc=")) {
223 builder.verbose_llvm_bc = arg["--verbose-llvm-bc=".len..];
224 } else if (mem.eql(u8, arg, "--verbose-cimport")) {
225 builder.verbose_cimport = true;
226 } else if (mem.eql(u8, arg, "--verbose-cc")) {
227 builder.verbose_cc = true;
228 } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {
229 builder.verbose_llvm_cpu_features = true;
230 } else if (mem.eql(u8, arg, "--prominent-compile-errors")) {
231 prominent_compile_errors = true;
232 } else if (mem.eql(u8, arg, "-fwine")) {
233 builder.enable_wine = true;
234 } else if (mem.eql(u8, arg, "-fno-wine")) {
235 builder.enable_wine = false;
236 } else if (mem.eql(u8, arg, "-fqemu")) {
237 builder.enable_qemu = true;
238 } else if (mem.eql(u8, arg, "-fno-qemu")) {
239 builder.enable_qemu = false;
240 } else if (mem.eql(u8, arg, "-fwasmtime")) {
241 builder.enable_wasmtime = true;
242 } else if (mem.eql(u8, arg, "-fno-wasmtime")) {
243 builder.enable_wasmtime = false;
244 } else if (mem.eql(u8, arg, "-frosetta")) {
245 builder.enable_rosetta = true;
246 } else if (mem.eql(u8, arg, "-fno-rosetta")) {
247 builder.enable_rosetta = false;
248 } else if (mem.eql(u8, arg, "-fdarling")) {
249 builder.enable_darling = true;
250 } else if (mem.eql(u8, arg, "-fno-darling")) {
251 builder.enable_darling = false;
252 } else if (mem.eql(u8, arg, "-freference-trace")) {
253 builder.reference_trace = 256;
254 } else if (mem.startsWith(u8, arg, "-freference-trace=")) {
255 const num = arg["-freference-trace=".len..];
256 builder.reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
257 std.debug.print("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) });
258 process.exit(1);
259 };
260 } else if (mem.eql(u8, arg, "-fno-reference-trace")) {
261 builder.reference_trace = null;
262 } else if (mem.startsWith(u8, arg, "-j")) {
263 const num = arg["-j".len..];
264 const n_jobs = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
265 std.debug.print("unable to parse jobs count '{s}': {s}", .{
266 num, @errorName(err),
267 });
268 process.exit(1);
269 };
270 if (n_jobs < 1) {
271 std.debug.print("number of jobs must be at least 1\n", .{});
272 process.exit(1);
273 }
274 thread_pool_options.n_jobs = n_jobs;
275 } else if (mem.eql(u8, arg, "--")) {
276 builder.args = argsRest(args, arg_idx);
277 break;
278 } else {
279 fatalWithHint("unrecognized argument: '{s}'", .{arg});
280 }
281 } else {
282 try targets.append(arg);
283 }
284 }
285
286 const host_query = std.Build.parseTargetQuery(graph.host_query_options) catch |err| switch (err) {
287 error.ParseFailed => process.exit(1),
288 };
289 builder.host = .{
290 .query = .{},
291 .result = try std.zig.system.resolveTargetQuery(host_query),
292 };
293
294 const stderr = std.io.getStdErr();
295 const ttyconf = get_tty_conf(color, stderr);
296 switch (ttyconf) {
297 .no_color => try graph.env_map.put("NO_COLOR", "1"),
298 .escape_codes => try graph.env_map.put("YES_COLOR", "1"),
299 .windows_api => {},
300 }
301
302 var progress: std.Progress = .{ .dont_print_on_dumb = true };
303 const main_progress_node = progress.start("", 0);
304
305 builder.debug_log_scopes = debug_log_scopes.items;
306 builder.resolveInstallPrefix(install_prefix, dir_list);
307 {
308 var prog_node = main_progress_node.start("user build.zig logic", 0);
309 defer prog_node.end();
310 try builder.runBuild(root);
311 }
312
313 if (graph.needed_lazy_dependencies.entries.len != 0) {
314 var buffer: std.ArrayListUnmanaged(u8) = .{};
315 for (graph.needed_lazy_dependencies.keys()) |k| {
316 try buffer.appendSlice(arena, k);
317 try buffer.append(arena, '\n');
318 }
319 const s = std.fs.path.sep_str;
320 const tmp_sub_path = "tmp" ++ s ++ (output_tmp_nonce orelse fatal("missing -Z arg", .{}));
321 local_cache_directory.handle.writeFile2(.{
322 .sub_path = tmp_sub_path,
323 .data = buffer.items,
324 .flags = .{ .exclusive = true },
325 }) catch |err| {
326 fatal("unable to write configuration results to '{}{s}': {s}", .{
327 local_cache_directory, tmp_sub_path, @errorName(err),
328 });
329 };
330 process.exit(3); // Indicate configure phase failed with meaningful stdout.
331 }
332
333 if (builder.validateUserInputDidItFail()) {
334 fatal(" access the help menu with 'zig build -h'", .{});
335 }
336
337 validateSystemLibraryOptions(builder);
338
339 const stdout_writer = io.getStdOut().writer();
340
341 if (help_menu)
342 return usage(builder, stdout_writer);
343
344 if (steps_menu)
345 return steps(builder, stdout_writer);
346
347 var run: Run = .{
348 .max_rss = max_rss,
349 .max_rss_is_default = false,
350 .max_rss_mutex = .{},
351 .skip_oom_steps = skip_oom_steps,
352 .memory_blocked_steps = std.ArrayList(*Step).init(arena),
353 .prominent_compile_errors = prominent_compile_errors,
354
355 .claimed_rss = 0,
356 .summary = summary,
357 .ttyconf = ttyconf,
358 .stderr = stderr,
359 };
360
361 if (run.max_rss == 0) {
362 run.max_rss = process.totalSystemMemory() catch std.math.maxInt(u64);
363 run.max_rss_is_default = true;
364 }
365
366 runStepNames(
367 arena,
368 builder,
369 targets.items,
370 main_progress_node,
371 thread_pool_options,
372 &run,
373 seed,
374 ) catch |err| switch (err) {
375 error.UncleanExit => process.exit(1),
376 else => return err,
377 };
378}
379
380const Run = struct {
381 max_rss: u64,
382 max_rss_is_default: bool,
383 max_rss_mutex: std.Thread.Mutex,
384 skip_oom_steps: bool,
385 memory_blocked_steps: std.ArrayList(*Step),
386 prominent_compile_errors: bool,
387
388 claimed_rss: usize,
389 summary: ?Summary,
390 ttyconf: std.io.tty.Config,
391 stderr: File,
392};
393
394fn runStepNames(
395 arena: std.mem.Allocator,
396 b: *std.Build,
397 step_names: []const []const u8,
398 parent_prog_node: *std.Progress.Node,
399 thread_pool_options: std.Thread.Pool.Options,
400 run: *Run,
401 seed: u32,
402) !void {
403 const gpa = b.allocator;
404 var step_stack: std.AutoArrayHashMapUnmanaged(*Step, void) = .{};
405 defer step_stack.deinit(gpa);
406
407 if (step_names.len == 0) {
408 try step_stack.put(gpa, b.default_step, {});
409 } else {
410 try step_stack.ensureUnusedCapacity(gpa, step_names.len);
411 for (0..step_names.len) |i| {
412 const step_name = step_names[step_names.len - i - 1];
413 const s = b.top_level_steps.get(step_name) orelse {
414 std.debug.print("no step named '{s}'\n access the help menu with 'zig build -h'\n", .{step_name});
415 process.exit(1);
416 };
417 step_stack.putAssumeCapacity(&s.step, {});
418 }
419 }
420
421 const starting_steps = try arena.dupe(*Step, step_stack.keys());
422
423 var rng = std.Random.DefaultPrng.init(seed);
424 const rand = rng.random();
425 rand.shuffle(*Step, starting_steps);
426
427 for (starting_steps) |s| {
428 constructGraphAndCheckForDependencyLoop(b, s, &step_stack, rand) catch |err| switch (err) {
429 error.DependencyLoopDetected => return error.UncleanExit,
430 else => |e| return e,
431 };
432 }
433
434 {
435 // Check that we have enough memory to complete the build.
436 var any_problems = false;
437 for (step_stack.keys()) |s| {
438 if (s.max_rss == 0) continue;
439 if (s.max_rss > run.max_rss) {
440 if (run.skip_oom_steps) {
441 s.state = .skipped_oom;
442 } else {
443 std.debug.print("{s}{s}: this step declares an upper bound of {d} bytes of memory, exceeding the available {d} bytes of memory\n", .{
444 s.owner.dep_prefix, s.name, s.max_rss, run.max_rss,
445 });
446 any_problems = true;
447 }
448 }
449 }
450 if (any_problems) {
451 if (run.max_rss_is_default) {
452 std.debug.print("note: use --maxrss to override the default", .{});
453 }
454 return error.UncleanExit;
455 }
456 }
457
458 var thread_pool: std.Thread.Pool = undefined;
459 try thread_pool.init(thread_pool_options);
460 defer thread_pool.deinit();
461
462 {
463 defer parent_prog_node.end();
464
465 var step_prog = parent_prog_node.start("steps", step_stack.count());
466 defer step_prog.end();
467
468 var wait_group: std.Thread.WaitGroup = .{};
469 defer wait_group.wait();
470
471 // Here we spawn the initial set of tasks with a nice heuristic -
472 // dependency order. Each worker when it finishes a step will then
473 // check whether it should run any dependants.
474 const steps_slice = step_stack.keys();
475 for (0..steps_slice.len) |i| {
476 const step = steps_slice[steps_slice.len - i - 1];
477 if (step.state == .skipped_oom) continue;
478
479 wait_group.start();
480 thread_pool.spawn(workerMakeOneStep, .{
481 &wait_group, &thread_pool, b, step, &step_prog, run,
482 }) catch @panic("OOM");
483 }
484 }
485 assert(run.memory_blocked_steps.items.len == 0);
486
487 var test_skip_count: usize = 0;
488 var test_fail_count: usize = 0;
489 var test_pass_count: usize = 0;
490 var test_leak_count: usize = 0;
491 var test_count: usize = 0;
492
493 var success_count: usize = 0;
494 var skipped_count: usize = 0;
495 var failure_count: usize = 0;
496 var pending_count: usize = 0;
497 var total_compile_errors: usize = 0;
498 var compile_error_steps: std.ArrayListUnmanaged(*Step) = .{};
499 defer compile_error_steps.deinit(gpa);
500
501 for (step_stack.keys()) |s| {
502 test_fail_count += s.test_results.fail_count;
503 test_skip_count += s.test_results.skip_count;
504 test_leak_count += s.test_results.leak_count;
505 test_pass_count += s.test_results.passCount();
506 test_count += s.test_results.test_count;
507
508 switch (s.state) {
509 .precheck_unstarted => unreachable,
510 .precheck_started => unreachable,
511 .running => unreachable,
512 .precheck_done => {
513 // precheck_done is equivalent to dependency_failure in the case of
514 // transitive dependencies. For example:
515 // A -> B -> C (failure)
516 // B will be marked as dependency_failure, while A may never be queued, and thus
517 // remain in the initial state of precheck_done.
518 s.state = .dependency_failure;
519 pending_count += 1;
520 },
521 .dependency_failure => pending_count += 1,
522 .success => success_count += 1,
523 .skipped, .skipped_oom => skipped_count += 1,
524 .failure => {
525 failure_count += 1;
526 const compile_errors_len = s.result_error_bundle.errorMessageCount();
527 if (compile_errors_len > 0) {
528 total_compile_errors += compile_errors_len;
529 try compile_error_steps.append(gpa, s);
530 }
531 },
532 }
533 }
534
535 // A proper command line application defaults to silently succeeding.
536 // The user may request verbose mode if they have a different preference.
537 const failures_only = run.summary != .all and run.summary != .new;
538 if (failure_count == 0 and failures_only) return cleanExit();
539
540 const ttyconf = run.ttyconf;
541 const stderr = run.stderr;
542
543 if (run.summary != Summary.none) {
544 const total_count = success_count + failure_count + pending_count + skipped_count;
545 ttyconf.setColor(stderr, .cyan) catch {};
546 stderr.writeAll("Build Summary:") catch {};
547 ttyconf.setColor(stderr, .reset) catch {};
548 stderr.writer().print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
549 if (skipped_count > 0) stderr.writer().print("; {d} skipped", .{skipped_count}) catch {};
550 if (failure_count > 0) stderr.writer().print("; {d} failed", .{failure_count}) catch {};
551
552 if (test_count > 0) stderr.writer().print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {};
553 if (test_skip_count > 0) stderr.writer().print("; {d} skipped", .{test_skip_count}) catch {};
554 if (test_fail_count > 0) stderr.writer().print("; {d} failed", .{test_fail_count}) catch {};
555 if (test_leak_count > 0) stderr.writer().print("; {d} leaked", .{test_leak_count}) catch {};
556
557 if (run.summary == null) {
558 ttyconf.setColor(stderr, .dim) catch {};
559 stderr.writeAll(" (disable with --summary none)") catch {};
560 ttyconf.setColor(stderr, .reset) catch {};
561 }
562 stderr.writeAll("\n") catch {};
563
564 // Print a fancy tree with build results.
565 var print_node: PrintNode = .{ .parent = null };
566 if (step_names.len == 0) {
567 print_node.last = true;
568 printTreeStep(b, b.default_step, run, stderr, ttyconf, &print_node, &step_stack) catch {};
569 } else {
570 const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: {
571 var i: usize = step_names.len;
572 while (i > 0) {
573 i -= 1;
574 const step = b.top_level_steps.get(step_names[i]).?.step;
575 const found = switch (run.summary orelse .failures) {
576 .all, .none => unreachable,
577 .failures => step.state != .success,
578 .new => !step.result_cached,
579 };
580 if (found) break :blk i;
581 }
582 break :blk b.top_level_steps.count();
583 };
584 for (step_names, 0..) |step_name, i| {
585 const tls = b.top_level_steps.get(step_name).?;
586 print_node.last = i + 1 == last_index;
587 printTreeStep(b, &tls.step, run, stderr, ttyconf, &print_node, &step_stack) catch {};
588 }
589 }
590 }
591
592 if (failure_count == 0) return cleanExit();
593
594 // Finally, render compile errors at the bottom of the terminal.
595 // We use a separate compile_error_steps array list because step_stack is destructively
596 // mutated in printTreeStep above.
597 if (run.prominent_compile_errors and total_compile_errors > 0) {
598 for (compile_error_steps.items) |s| {
599 if (s.result_error_bundle.errorMessageCount() > 0) {
600 s.result_error_bundle.renderToStdErr(renderOptions(ttyconf));
601 }
602 }
603
604 // Signal to parent process that we have printed compile errors. The
605 // parent process may choose to omit the "following command failed"
606 // line in this case.
607 process.exit(2);
608 }
609
610 process.exit(1);
611}
612
613const PrintNode = struct {
614 parent: ?*PrintNode,
615 last: bool = false,
616};
617
618fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void {
619 const parent = node.parent orelse return;
620 if (parent.parent == null) return;
621 try printPrefix(parent, stderr, ttyconf);
622 if (parent.last) {
623 try stderr.writeAll(" ");
624 } else {
625 try stderr.writeAll(switch (ttyconf) {
626 .no_color, .windows_api => "| ",
627 .escape_codes => "\x1B\x28\x30\x78\x1B\x28\x42 ", // │
628 });
629 }
630}
631
632fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void {
633 try stderr.writeAll(switch (ttyconf) {
634 .no_color, .windows_api => "+- ",
635 .escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─
636 });
637}
638
639fn printStepStatus(
640 s: *Step,
641 stderr: File,
642 ttyconf: std.io.tty.Config,
643 run: *const Run,
644) !void {
645 switch (s.state) {
646 .precheck_unstarted => unreachable,
647 .precheck_started => unreachable,
648 .precheck_done => unreachable,
649 .running => unreachable,
650
651 .dependency_failure => {
652 try ttyconf.setColor(stderr, .dim);
653 try stderr.writeAll(" transitive failure\n");
654 try ttyconf.setColor(stderr, .reset);
655 },
656
657 .success => {
658 try ttyconf.setColor(stderr, .green);
659 if (s.result_cached) {
660 try stderr.writeAll(" cached");
661 } else if (s.test_results.test_count > 0) {
662 const pass_count = s.test_results.passCount();
663 try stderr.writer().print(" {d} passed", .{pass_count});
664 if (s.test_results.skip_count > 0) {
665 try ttyconf.setColor(stderr, .yellow);
666 try stderr.writer().print(" {d} skipped", .{s.test_results.skip_count});
667 }
668 } else {
669 try stderr.writeAll(" success");
670 }
671 try ttyconf.setColor(stderr, .reset);
672 if (s.result_duration_ns) |ns| {
673 try ttyconf.setColor(stderr, .dim);
674 if (ns >= std.time.ns_per_min) {
675 try stderr.writer().print(" {d}m", .{ns / std.time.ns_per_min});
676 } else if (ns >= std.time.ns_per_s) {
677 try stderr.writer().print(" {d}s", .{ns / std.time.ns_per_s});
678 } else if (ns >= std.time.ns_per_ms) {
679 try stderr.writer().print(" {d}ms", .{ns / std.time.ns_per_ms});
680 } else if (ns >= std.time.ns_per_us) {
681 try stderr.writer().print(" {d}us", .{ns / std.time.ns_per_us});
682 } else {
683 try stderr.writer().print(" {d}ns", .{ns});
684 }
685 try ttyconf.setColor(stderr, .reset);
686 }
687 if (s.result_peak_rss != 0) {
688 const rss = s.result_peak_rss;
689 try ttyconf.setColor(stderr, .dim);
690 if (rss >= 1000_000_000) {
691 try stderr.writer().print(" MaxRSS:{d}G", .{rss / 1000_000_000});
692 } else if (rss >= 1000_000) {
693 try stderr.writer().print(" MaxRSS:{d}M", .{rss / 1000_000});
694 } else if (rss >= 1000) {
695 try stderr.writer().print(" MaxRSS:{d}K", .{rss / 1000});
696 } else {
697 try stderr.writer().print(" MaxRSS:{d}B", .{rss});
698 }
699 try ttyconf.setColor(stderr, .reset);
700 }
701 try stderr.writeAll("\n");
702 },
703 .skipped, .skipped_oom => |skip| {
704 try ttyconf.setColor(stderr, .yellow);
705 try stderr.writeAll(" skipped");
706 if (skip == .skipped_oom) {
707 try stderr.writeAll(" (not enough memory)");
708 try ttyconf.setColor(stderr, .dim);
709 try stderr.writer().print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });
710 try ttyconf.setColor(stderr, .yellow);
711 }
712 try stderr.writeAll("\n");
713 try ttyconf.setColor(stderr, .reset);
714 },
715 .failure => try printStepFailure(s, stderr, ttyconf),
716 }
717}
718
719fn printStepFailure(
720 s: *Step,
721 stderr: File,
722 ttyconf: std.io.tty.Config,
723) !void {
724 if (s.result_error_bundle.errorMessageCount() > 0) {
725 try ttyconf.setColor(stderr, .red);
726 try stderr.writer().print(" {d} errors\n", .{
727 s.result_error_bundle.errorMessageCount(),
728 });
729 try ttyconf.setColor(stderr, .reset);
730 } else if (!s.test_results.isSuccess()) {
731 try stderr.writer().print(" {d}/{d} passed", .{
732 s.test_results.passCount(), s.test_results.test_count,
733 });
734 if (s.test_results.fail_count > 0) {
735 try stderr.writeAll(", ");
736 try ttyconf.setColor(stderr, .red);
737 try stderr.writer().print("{d} failed", .{
738 s.test_results.fail_count,
739 });
740 try ttyconf.setColor(stderr, .reset);
741 }
742 if (s.test_results.skip_count > 0) {
743 try stderr.writeAll(", ");
744 try ttyconf.setColor(stderr, .yellow);
745 try stderr.writer().print("{d} skipped", .{
746 s.test_results.skip_count,
747 });
748 try ttyconf.setColor(stderr, .reset);
749 }
750 if (s.test_results.leak_count > 0) {
751 try stderr.writeAll(", ");
752 try ttyconf.setColor(stderr, .red);
753 try stderr.writer().print("{d} leaked", .{
754 s.test_results.leak_count,
755 });
756 try ttyconf.setColor(stderr, .reset);
757 }
758 try stderr.writeAll("\n");
759 } else if (s.result_error_msgs.items.len > 0) {
760 try ttyconf.setColor(stderr, .red);
761 try stderr.writeAll(" failure\n");
762 try ttyconf.setColor(stderr, .reset);
763 } else {
764 assert(s.result_stderr.len > 0);
765 try ttyconf.setColor(stderr, .red);
766 try stderr.writeAll(" stderr\n");
767 try ttyconf.setColor(stderr, .reset);
768 }
769}
770
771fn printTreeStep(
772 b: *std.Build,
773 s: *Step,
774 run: *const Run,
775 stderr: File,
776 ttyconf: std.io.tty.Config,
777 parent_node: *PrintNode,
778 step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
779) !void {
780 const first = step_stack.swapRemove(s);
781 const summary = run.summary orelse .failures;
782 const skip = switch (summary) {
783 .none => unreachable,
784 .all => false,
785 .new => s.result_cached,
786 .failures => s.state == .success,
787 };
788 if (skip) return;
789 try printPrefix(parent_node, stderr, ttyconf);
790
791 if (!first) try ttyconf.setColor(stderr, .dim);
792 if (parent_node.parent != null) {
793 if (parent_node.last) {
794 try printChildNodePrefix(stderr, ttyconf);
795 } else {
796 try stderr.writeAll(switch (ttyconf) {
797 .no_color, .windows_api => "+- ",
798 .escape_codes => "\x1B\x28\x30\x74\x71\x1B\x28\x42 ", // ├─
799 });
800 }
801 }
802
803 // dep_prefix omitted here because it is redundant with the tree.
804 try stderr.writeAll(s.name);
805
806 if (first) {
807 try printStepStatus(s, stderr, ttyconf, run);
808
809 const last_index = if (summary == .all) s.dependencies.items.len -| 1 else blk: {
810 var i: usize = s.dependencies.items.len;
811 while (i > 0) {
812 i -= 1;
813
814 const step = s.dependencies.items[i];
815 const found = switch (summary) {
816 .all, .none => unreachable,
817 .failures => step.state != .success,
818 .new => !step.result_cached,
819 };
820 if (found) break :blk i;
821 }
822 break :blk s.dependencies.items.len -| 1;
823 };
824 for (s.dependencies.items, 0..) |dep, i| {
825 var print_node: PrintNode = .{
826 .parent = parent_node,
827 .last = i == last_index,
828 };
829 try printTreeStep(b, dep, run, stderr, ttyconf, &print_node, step_stack);
830 }
831 } else {
832 if (s.dependencies.items.len == 0) {
833 try stderr.writeAll(" (reused)\n");
834 } else {
835 try stderr.writer().print(" (+{d} more reused dependencies)\n", .{
836 s.dependencies.items.len,
837 });
838 }
839 try ttyconf.setColor(stderr, .reset);
840 }
841}
842
843/// Traverse the dependency graph depth-first and make it undirected by having
844/// steps know their dependants (they only know dependencies at start).
845/// Along the way, check that there is no dependency loop, and record the steps
846/// in traversal order in `step_stack`.
847/// Each step has its dependencies traversed in random order, this accomplishes
848/// two things:
849/// - `step_stack` will be in randomized-depth-first order, so the build runner
850/// spawns steps in a random (but optimized) order
851/// - each step's `dependants` list is also filled in a random order, so that
852/// when it finishes executing in `workerMakeOneStep`, it spawns next steps
853/// to run in random order
854fn constructGraphAndCheckForDependencyLoop(
855 b: *std.Build,
856 s: *Step,
857 step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
858 rand: std.Random,
859) !void {
860 switch (s.state) {
861 .precheck_started => {
862 std.debug.print("dependency loop detected:\n {s}\n", .{s.name});
863 return error.DependencyLoopDetected;
864 },
865 .precheck_unstarted => {
866 s.state = .precheck_started;
867
868 try step_stack.ensureUnusedCapacity(b.allocator, s.dependencies.items.len);
869
870 // We dupe to avoid shuffling the steps in the summary, it depends
871 // on s.dependencies' order.
872 const deps = b.allocator.dupe(*Step, s.dependencies.items) catch @panic("OOM");
873 rand.shuffle(*Step, deps);
874
875 for (deps) |dep| {
876 try step_stack.put(b.allocator, dep, {});
877 try dep.dependants.append(b.allocator, s);
878 constructGraphAndCheckForDependencyLoop(b, dep, step_stack, rand) catch |err| {
879 if (err == error.DependencyLoopDetected) {
880 std.debug.print(" {s}\n", .{s.name});
881 }
882 return err;
883 };
884 }
885
886 s.state = .precheck_done;
887 },
888 .precheck_done => {},
889
890 // These don't happen until we actually run the step graph.
891 .dependency_failure => unreachable,
892 .running => unreachable,
893 .success => unreachable,
894 .failure => unreachable,
895 .skipped => unreachable,
896 .skipped_oom => unreachable,
897 }
898}
899
900fn workerMakeOneStep(
901 wg: *std.Thread.WaitGroup,
902 thread_pool: *std.Thread.Pool,
903 b: *std.Build,
904 s: *Step,
905 prog_node: *std.Progress.Node,
906 run: *Run,
907) void {
908 defer wg.finish();
909
910 // First, check the conditions for running this step. If they are not met,
911 // then we return without doing the step, relying on another worker to
912 // queue this step up again when dependencies are met.
913 for (s.dependencies.items) |dep| {
914 switch (@atomicLoad(Step.State, &dep.state, .seq_cst)) {
915 .success, .skipped => continue,
916 .failure, .dependency_failure, .skipped_oom => {
917 @atomicStore(Step.State, &s.state, .dependency_failure, .seq_cst);
918 return;
919 },
920 .precheck_done, .running => {
921 // dependency is not finished yet.
922 return;
923 },
924 .precheck_unstarted => unreachable,
925 .precheck_started => unreachable,
926 }
927 }
928
929 if (s.max_rss != 0) {
930 run.max_rss_mutex.lock();
931 defer run.max_rss_mutex.unlock();
932
933 // Avoid running steps twice.
934 if (s.state != .precheck_done) {
935 // Another worker got the job.
936 return;
937 }
938
939 const new_claimed_rss = run.claimed_rss + s.max_rss;
940 if (new_claimed_rss > run.max_rss) {
941 // Running this step right now could possibly exceed the allotted RSS.
942 // Add this step to the queue of memory-blocked steps.
943 run.memory_blocked_steps.append(s) catch @panic("OOM");
944 return;
945 }
946
947 run.claimed_rss = new_claimed_rss;
948 s.state = .running;
949 } else {
950 // Avoid running steps twice.
951 if (@cmpxchgStrong(Step.State, &s.state, .precheck_done, .running, .seq_cst, .seq_cst) != null) {
952 // Another worker got the job.
953 return;
954 }
955 }
956
957 var sub_prog_node = prog_node.start(s.name, 0);
958 sub_prog_node.activate();
959 defer sub_prog_node.end();
960
961 const make_result = s.make(&sub_prog_node);
962
963 // No matter the result, we want to display error/warning messages.
964 const show_compile_errors = !run.prominent_compile_errors and
965 s.result_error_bundle.errorMessageCount() > 0;
966 const show_error_msgs = s.result_error_msgs.items.len > 0;
967 const show_stderr = s.result_stderr.len > 0;
968
969 if (show_error_msgs or show_compile_errors or show_stderr) {
970 sub_prog_node.context.lock_stderr();
971 defer sub_prog_node.context.unlock_stderr();
972
973 printErrorMessages(b, s, run) catch {};
974 }
975
976 handle_result: {
977 if (make_result) |_| {
978 @atomicStore(Step.State, &s.state, .success, .seq_cst);
979 } else |err| switch (err) {
980 error.MakeFailed => {
981 @atomicStore(Step.State, &s.state, .failure, .seq_cst);
982 break :handle_result;
983 },
984 error.MakeSkipped => @atomicStore(Step.State, &s.state, .skipped, .seq_cst),
985 }
986
987 // Successful completion of a step, so we queue up its dependants as well.
988 for (s.dependants.items) |dep| {
989 wg.start();
990 thread_pool.spawn(workerMakeOneStep, .{
991 wg, thread_pool, b, dep, prog_node, run,
992 }) catch @panic("OOM");
993 }
994 }
995
996 // If this is a step that claims resources, we must now queue up other
997 // steps that are waiting for resources.
998 if (s.max_rss != 0) {
999 run.max_rss_mutex.lock();
1000 defer run.max_rss_mutex.unlock();
1001
1002 // Give the memory back to the scheduler.
1003 run.claimed_rss -= s.max_rss;
1004 // Avoid kicking off too many tasks that we already know will not have
1005 // enough resources.
1006 var remaining = run.max_rss - run.claimed_rss;
1007 var i: usize = 0;
1008 var j: usize = 0;
1009 while (j < run.memory_blocked_steps.items.len) : (j += 1) {
1010 const dep = run.memory_blocked_steps.items[j];
1011 assert(dep.max_rss != 0);
1012 if (dep.max_rss <= remaining) {
1013 remaining -= dep.max_rss;
1014
1015 wg.start();
1016 thread_pool.spawn(workerMakeOneStep, .{
1017 wg, thread_pool, b, dep, prog_node, run,
1018 }) catch @panic("OOM");
1019 } else {
1020 run.memory_blocked_steps.items[i] = dep;
1021 i += 1;
1022 }
1023 }
1024 run.memory_blocked_steps.shrinkRetainingCapacity(i);
1025 }
1026}
1027
1028fn printErrorMessages(b: *std.Build, failing_step: *Step, run: *const Run) !void {
1029 const gpa = b.allocator;
1030 const stderr = run.stderr;
1031 const ttyconf = run.ttyconf;
1032
1033 // Provide context for where these error messages are coming from by
1034 // printing the corresponding Step subtree.
1035
1036 var step_stack: std.ArrayListUnmanaged(*Step) = .{};
1037 defer step_stack.deinit(gpa);
1038 try step_stack.append(gpa, failing_step);
1039 while (step_stack.items[step_stack.items.len - 1].dependants.items.len != 0) {
1040 try step_stack.append(gpa, step_stack.items[step_stack.items.len - 1].dependants.items[0]);
1041 }
1042
1043 // Now, `step_stack` has the subtree that we want to print, in reverse order.
1044 try ttyconf.setColor(stderr, .dim);
1045 var indent: usize = 0;
1046 while (step_stack.popOrNull()) |s| : (indent += 1) {
1047 if (indent > 0) {
1048 try stderr.writer().writeByteNTimes(' ', (indent - 1) * 3);
1049 try printChildNodePrefix(stderr, ttyconf);
1050 }
1051
1052 try stderr.writeAll(s.name);
1053
1054 if (s == failing_step) {
1055 try printStepFailure(s, stderr, ttyconf);
1056 } else {
1057 try stderr.writeAll("\n");
1058 }
1059 }
1060 try ttyconf.setColor(stderr, .reset);
1061
1062 if (failing_step.result_stderr.len > 0) {
1063 try stderr.writeAll(failing_step.result_stderr);
1064 if (!mem.endsWith(u8, failing_step.result_stderr, "\n")) {
1065 try stderr.writeAll("\n");
1066 }
1067 }
1068
1069 if (!run.prominent_compile_errors and failing_step.result_error_bundle.errorMessageCount() > 0)
1070 try failing_step.result_error_bundle.renderToWriter(renderOptions(ttyconf), stderr.writer());
1071
1072 for (failing_step.result_error_msgs.items) |msg| {
1073 try ttyconf.setColor(stderr, .red);
1074 try stderr.writeAll("error: ");
1075 try ttyconf.setColor(stderr, .reset);
1076 try stderr.writeAll(msg);
1077 try stderr.writeAll("\n");
1078 }
1079}
1080
1081fn steps(builder: *std.Build, out_stream: anytype) !void {
1082 const allocator = builder.allocator;
1083 for (builder.top_level_steps.values()) |top_level_step| {
1084 const name = if (&top_level_step.step == builder.default_step)
1085 try fmt.allocPrint(allocator, "{s} (default)", .{top_level_step.step.name})
1086 else
1087 top_level_step.step.name;
1088 try out_stream.print(" {s:<28} {s}\n", .{ name, top_level_step.description });
1089 }
1090}
1091
1092fn usage(b: *std.Build, out_stream: anytype) !void {
1093 try out_stream.print(
1094 \\Usage: {s} build [steps] [options]
1095 \\
1096 \\Steps:
1097 \\
1098 , .{b.graph.zig_exe});
1099 try steps(b, out_stream);
1100
1101 try out_stream.writeAll(
1102 \\
1103 \\General Options:
1104 \\ -p, --prefix [path] Where to install files (default: zig-out)
1105 \\ --prefix-lib-dir [path] Where to install libraries
1106 \\ --prefix-exe-dir [path] Where to install executables
1107 \\ --prefix-include-dir [path] Where to install C header files
1108 \\
1109 \\ --release[=mode] Request release mode, optionally specifying a
1110 \\ preferred optimization mode: fast, safe, small
1111 \\
1112 \\ -fdarling, -fno-darling Integration with system-installed Darling to
1113 \\ execute macOS programs on Linux hosts
1114 \\ (default: no)
1115 \\ -fqemu, -fno-qemu Integration with system-installed QEMU to execute
1116 \\ foreign-architecture programs on Linux hosts
1117 \\ (default: no)
1118 \\ --glibc-runtimes [path] Enhances QEMU integration by providing glibc built
1119 \\ for multiple foreign architectures, allowing
1120 \\ execution of non-native programs that link with glibc.
1121 \\ -frosetta, -fno-rosetta Rely on Rosetta to execute x86_64 programs on
1122 \\ ARM64 macOS hosts. (default: no)
1123 \\ -fwasmtime, -fno-wasmtime Integration with system-installed wasmtime to
1124 \\ execute WASI binaries. (default: no)
1125 \\ -fwine, -fno-wine Integration with system-installed Wine to execute
1126 \\ Windows programs on Linux hosts. (default: no)
1127 \\
1128 \\ -h, --help Print this help and exit
1129 \\ -l, --list-steps Print available steps
1130 \\ --verbose Print commands before executing them
1131 \\ --color [auto|off|on] Enable or disable colored error messages
1132 \\ --prominent-compile-errors Buffer compile errors and display at end
1133 \\ --summary [mode] Control the printing of the build summary
1134 \\ all Print the build summary in its entirety
1135 \\ new Omit cached steps
1136 \\ failures (Default) Only print failed steps
1137 \\ none Do not print the build summary
1138 \\ -j<N> Limit concurrent jobs (default is to use all CPU cores)
1139 \\ --maxrss <bytes> Limit memory usage (default is to use available memory)
1140 \\ --skip-oom-steps Instead of failing, skip steps that would exceed --maxrss
1141 \\ --fetch Exit after fetching dependency tree
1142 \\
1143 \\Project-Specific Options:
1144 \\
1145 );
1146
1147 const arena = b.allocator;
1148 if (b.available_options_list.items.len == 0) {
1149 try out_stream.print(" (none)\n", .{});
1150 } else {
1151 for (b.available_options_list.items) |option| {
1152 const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{
1153 option.name,
1154 @tagName(option.type_id),
1155 });
1156 try out_stream.print("{s:<30} {s}\n", .{ name, option.description });
1157 if (option.enum_options) |enum_options| {
1158 const padding = " " ** 33;
1159 try out_stream.writeAll(padding ++ "Supported Values:\n");
1160 for (enum_options) |enum_option| {
1161 try out_stream.print(padding ++ " {s}\n", .{enum_option});
1162 }
1163 }
1164 }
1165 }
1166
1167 try out_stream.writeAll(
1168 \\
1169 \\System Integration Options:
1170 \\ --search-prefix [path] Add a path to look for binaries, libraries, headers
1171 \\ --sysroot [path] Set the system root directory (usually /)
1172 \\ --libc [file] Provide a file which specifies libc paths
1173 \\
1174 \\ --host-target [triple] Use the provided target as the host
1175 \\ --host-cpu [cpu] Use the provided CPU as the host
1176 \\ --host-dynamic-linker [path] Use the provided dynamic linker as the host
1177 \\
1178 \\ --system [pkgdir] Disable package fetching; enable all integrations
1179 \\ -fsys=[name] Enable a system integration
1180 \\ -fno-sys=[name] Disable a system integration
1181 \\
1182 \\ Available System Integrations: Enabled:
1183 \\
1184 );
1185 if (b.graph.system_library_options.entries.len == 0) {
1186 try out_stream.writeAll(" (none) -\n");
1187 } else {
1188 for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| {
1189 const status = switch (v) {
1190 .declared_enabled => "yes",
1191 .declared_disabled => "no",
1192 .user_enabled, .user_disabled => unreachable, // already emitted error
1193 };
1194 try out_stream.print(" {s:<43} {s}\n", .{ k, status });
1195 }
1196 }
1197
1198 try out_stream.writeAll(
1199 \\
1200 \\Advanced Options:
1201 \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
1202 \\ -fno-reference-trace Disable reference trace
1203 \\ --build-file [file] Override path to build.zig
1204 \\ --cache-dir [path] Override path to local Zig cache directory
1205 \\ --global-cache-dir [path] Override path to global Zig cache directory
1206 \\ --zig-lib-dir [arg] Override path to Zig lib directory
1207 \\ --build-runner [file] Override path to build runner
1208 \\ --seed [integer] For shuffling dependency traversal order (default: random)
1209 \\ --debug-log [scope] Enable debugging the compiler
1210 \\ --debug-pkg-config Fail if unknown pkg-config flags encountered
1211 \\ --verbose-link Enable compiler debug output for linking
1212 \\ --verbose-air Enable compiler debug output for Zig AIR
1213 \\ --verbose-llvm-ir[=file] Enable compiler debug output for LLVM IR
1214 \\ --verbose-llvm-bc=[file] Enable compiler debug output for LLVM BC
1215 \\ --verbose-cimport Enable compiler debug output for C imports
1216 \\ --verbose-cc Enable compiler debug output for C compilation
1217 \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features
1218 \\
1219 );
1220}
1221
1222fn nextArg(args: [][:0]const u8, idx: *usize) ?[:0]const u8 {
1223 if (idx.* >= args.len) return null;
1224 defer idx.* += 1;
1225 return args[idx.*];
1226}
1227
1228fn nextArgOrFatal(args: [][:0]const u8, idx: *usize) [:0]const u8 {
1229 return nextArg(args, idx) orelse {
1230 std.debug.print("expected argument after '{s}'\n access the help menu with 'zig build -h'\n", .{args[idx.*]});
1231 process.exit(1);
1232 };
1233}
1234
1235fn argsRest(args: [][:0]const u8, idx: usize) ?[][:0]const u8 {
1236 if (idx >= args.len) return null;
1237 return args[idx..];
1238}
1239
1240fn cleanExit() void {
1241 // Perhaps in the future there could be an Advanced Options flag such as
1242 // --debug-build-runner-leaks which would make this function return instead
1243 // of calling exit.
1244 process.exit(0);
1245}
1246
1247const Color = enum { auto, off, on };
1248const Summary = enum { all, new, failures, none };
1249
1250fn get_tty_conf(color: Color, stderr: File) std.io.tty.Config {
1251 return switch (color) {
1252 .auto => std.io.tty.detectConfig(stderr),
1253 .on => .escape_codes,
1254 .off => .no_color,
1255 };
1256}
1257
1258fn renderOptions(ttyconf: std.io.tty.Config) std.zig.ErrorBundle.RenderOptions {
1259 return .{
1260 .ttyconf = ttyconf,
1261 .include_source_line = ttyconf != .no_color,
1262 .include_reference_trace = ttyconf != .no_color,
1263 };
1264}
1265
1266fn fatalWithHint(comptime f: []const u8, args: anytype) noreturn {
1267 std.debug.print(f ++ "\n access the help menu with 'zig build -h'\n", args);
1268 process.exit(1);
1269}
1270
1271fn fatal(comptime f: []const u8, args: anytype) noreturn {
1272 std.debug.print(f ++ "\n", args);
1273 process.exit(1);
1274}
1275
1276fn validateSystemLibraryOptions(b: *std.Build) void {
1277 var bad = false;
1278 for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| {
1279 switch (v) {
1280 .user_disabled, .user_enabled => {
1281 // The user tried to enable or disable a system library integration, but
1282 // the build script did not recognize that option.
1283 std.debug.print("system library name not recognized by build script: '{s}'\n", .{k});
1284 bad = true;
1285 },
1286 .declared_disabled, .declared_enabled => {},
1287 }
1288 }
1289 if (bad) {
1290 std.debug.print(" access the help menu with 'zig build -h'\n", .{});
1291 process.exit(1);
1292 }
1293}
lib/compiler/build_runner.zig created+1293
......@@ -0,0 +1,1293 @@
1const root = @import("@build");
2const std = @import("std");
3const builtin = @import("builtin");
4const assert = std.debug.assert;
5const io = std.io;
6const fmt = std.fmt;
7const mem = std.mem;
8const process = std.process;
9const ArrayList = std.ArrayList;
10const File = std.fs.File;
11const Step = std.Build.Step;
12
13pub const dependencies = @import("@dependencies");
14
15pub fn main() !void {
16 // Here we use an ArenaAllocator backed by a page allocator because a build is a short-lived,
17 // one shot program. We don't need to waste time freeing memory and finding places to squish
18 // bytes into. So we free everything all at once at the very end.
19 var single_threaded_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
20 defer single_threaded_arena.deinit();
21
22 var thread_safe_arena: std.heap.ThreadSafeAllocator = .{
23 .child_allocator = single_threaded_arena.allocator(),
24 };
25 const arena = thread_safe_arena.allocator();
26
27 const args = try process.argsAlloc(arena);
28
29 // skip my own exe name
30 var arg_idx: usize = 1;
31
32 const zig_exe = nextArg(args, &arg_idx) orelse {
33 std.debug.print("Expected path to zig compiler\n", .{});
34 return error.InvalidArgs;
35 };
36 const build_root = nextArg(args, &arg_idx) orelse {
37 std.debug.print("Expected build root directory path\n", .{});
38 return error.InvalidArgs;
39 };
40 const cache_root = nextArg(args, &arg_idx) orelse {
41 std.debug.print("Expected cache root directory path\n", .{});
42 return error.InvalidArgs;
43 };
44 const global_cache_root = nextArg(args, &arg_idx) orelse {
45 std.debug.print("Expected global cache root directory path\n", .{});
46 return error.InvalidArgs;
47 };
48
49 const build_root_directory: std.Build.Cache.Directory = .{
50 .path = build_root,
51 .handle = try std.fs.cwd().openDir(build_root, .{}),
52 };
53
54 const local_cache_directory: std.Build.Cache.Directory = .{
55 .path = cache_root,
56 .handle = try std.fs.cwd().makeOpenPath(cache_root, .{}),
57 };
58
59 const global_cache_directory: std.Build.Cache.Directory = .{
60 .path = global_cache_root,
61 .handle = try std.fs.cwd().makeOpenPath(global_cache_root, .{}),
62 };
63
64 var graph: std.Build.Graph = .{
65 .arena = arena,
66 .cache = .{
67 .gpa = arena,
68 .manifest_dir = try local_cache_directory.handle.makeOpenPath("h", .{}),
69 },
70 .zig_exe = zig_exe,
71 .env_map = try process.getEnvMap(arena),
72 .global_cache_root = global_cache_directory,
73 };
74
75 graph.cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
76 graph.cache.addPrefix(build_root_directory);
77 graph.cache.addPrefix(local_cache_directory);
78 graph.cache.addPrefix(global_cache_directory);
79 graph.cache.hash.addBytes(builtin.zig_version_string);
80
81 const builder = try std.Build.create(
82 &graph,
83 build_root_directory,
84 local_cache_directory,
85 dependencies.root_deps,
86 );
87
88 var targets = ArrayList([]const u8).init(arena);
89 var debug_log_scopes = ArrayList([]const u8).init(arena);
90 var thread_pool_options: std.Thread.Pool.Options = .{ .allocator = arena };
91
92 var install_prefix: ?[]const u8 = null;
93 var dir_list = std.Build.DirList{};
94 var summary: ?Summary = null;
95 var max_rss: u64 = 0;
96 var skip_oom_steps: bool = false;
97 var color: Color = .auto;
98 var seed: u32 = 0;
99 var prominent_compile_errors: bool = false;
100 var help_menu: bool = false;
101 var steps_menu: bool = false;
102 var output_tmp_nonce: ?[16]u8 = null;
103
104 while (nextArg(args, &arg_idx)) |arg| {
105 if (mem.startsWith(u8, arg, "-Z")) {
106 if (arg.len != 18) fatalWithHint("bad argument: '{s}'", .{arg});
107 output_tmp_nonce = arg[2..18].*;
108 } else if (mem.startsWith(u8, arg, "-D")) {
109 const option_contents = arg[2..];
110 if (option_contents.len == 0)
111 fatalWithHint("expected option name after '-D'", .{});
112 if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| {
113 const option_name = option_contents[0..name_end];
114 const option_value = option_contents[name_end + 1 ..];
115 if (try builder.addUserInputOption(option_name, option_value))
116 fatal(" access the help menu with 'zig build -h'", .{});
117 } else {
118 if (try builder.addUserInputFlag(option_contents))
119 fatal(" access the help menu with 'zig build -h'", .{});
120 }
121 } else if (mem.startsWith(u8, arg, "-")) {
122 if (mem.eql(u8, arg, "--verbose")) {
123 builder.verbose = true;
124 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
125 help_menu = true;
126 } else if (mem.eql(u8, arg, "-p") or mem.eql(u8, arg, "--prefix")) {
127 install_prefix = nextArgOrFatal(args, &arg_idx);
128 } else if (mem.eql(u8, arg, "-l") or mem.eql(u8, arg, "--list-steps")) {
129 steps_menu = true;
130 } else if (mem.startsWith(u8, arg, "-fsys=")) {
131 const name = arg["-fsys=".len..];
132 graph.system_library_options.put(arena, name, .user_enabled) catch @panic("OOM");
133 } else if (mem.startsWith(u8, arg, "-fno-sys=")) {
134 const name = arg["-fno-sys=".len..];
135 graph.system_library_options.put(arena, name, .user_disabled) catch @panic("OOM");
136 } else if (mem.eql(u8, arg, "--release")) {
137 builder.release_mode = .any;
138 } else if (mem.startsWith(u8, arg, "--release=")) {
139 const text = arg["--release=".len..];
140 builder.release_mode = std.meta.stringToEnum(std.Build.ReleaseMode, text) orelse {
141 fatalWithHint("expected [off|any|fast|safe|small] in '{s}', found '{s}'", .{
142 arg, text,
143 });
144 };
145 } else if (mem.eql(u8, arg, "--host-target")) {
146 graph.host_query_options.arch_os_abi = nextArgOrFatal(args, &arg_idx);
147 } else if (mem.eql(u8, arg, "--host-cpu")) {
148 graph.host_query_options.cpu_features = nextArgOrFatal(args, &arg_idx);
149 } else if (mem.eql(u8, arg, "--host-dynamic-linker")) {
150 graph.host_query_options.dynamic_linker = nextArgOrFatal(args, &arg_idx);
151 } else if (mem.eql(u8, arg, "--prefix-lib-dir")) {
152 dir_list.lib_dir = nextArgOrFatal(args, &arg_idx);
153 } else if (mem.eql(u8, arg, "--prefix-exe-dir")) {
154 dir_list.exe_dir = nextArgOrFatal(args, &arg_idx);
155 } else if (mem.eql(u8, arg, "--prefix-include-dir")) {
156 dir_list.include_dir = nextArgOrFatal(args, &arg_idx);
157 } else if (mem.eql(u8, arg, "--sysroot")) {
158 builder.sysroot = nextArgOrFatal(args, &arg_idx);
159 } else if (mem.eql(u8, arg, "--maxrss")) {
160 const max_rss_text = nextArgOrFatal(args, &arg_idx);
161 max_rss = std.fmt.parseIntSizeSuffix(max_rss_text, 10) catch |err| {
162 std.debug.print("invalid byte size: '{s}': {s}\n", .{
163 max_rss_text, @errorName(err),
164 });
165 process.exit(1);
166 };
167 } else if (mem.eql(u8, arg, "--skip-oom-steps")) {
168 skip_oom_steps = true;
169 } else if (mem.eql(u8, arg, "--search-prefix")) {
170 const search_prefix = nextArgOrFatal(args, &arg_idx);
171 builder.addSearchPrefix(search_prefix);
172 } else if (mem.eql(u8, arg, "--libc")) {
173 builder.libc_file = nextArgOrFatal(args, &arg_idx);
174 } else if (mem.eql(u8, arg, "--color")) {
175 const next_arg = nextArg(args, &arg_idx) orelse
176 fatalWithHint("expected [auto|on|off] after '{s}'", .{arg});
177 color = std.meta.stringToEnum(Color, next_arg) orelse {
178 fatalWithHint("expected [auto|on|off] after '{s}', found '{s}'", .{
179 arg, next_arg,
180 });
181 };
182 } else if (mem.eql(u8, arg, "--summary")) {
183 const next_arg = nextArg(args, &arg_idx) orelse
184 fatalWithHint("expected [all|new|failures|none] after '{s}'", .{arg});
185 summary = std.meta.stringToEnum(Summary, next_arg) orelse {
186 fatalWithHint("expected [all|failures|none] after '{s}', found '{s}'", .{
187 arg, next_arg,
188 });
189 };
190 } else if (mem.eql(u8, arg, "--zig-lib-dir")) {
191 builder.zig_lib_dir = .{ .cwd_relative = nextArgOrFatal(args, &arg_idx) };
192 } else if (mem.eql(u8, arg, "--seed")) {
193 const next_arg = nextArg(args, &arg_idx) orelse
194 fatalWithHint("expected u32 after '{s}'", .{arg});
195 seed = std.fmt.parseUnsigned(u32, next_arg, 0) catch |err| {
196 fatal("unable to parse seed '{s}' as 32-bit integer: {s}\n", .{
197 next_arg, @errorName(err),
198 });
199 };
200 } else if (mem.eql(u8, arg, "--debug-log")) {
201 const next_arg = nextArgOrFatal(args, &arg_idx);
202 try debug_log_scopes.append(next_arg);
203 } else if (mem.eql(u8, arg, "--debug-pkg-config")) {
204 builder.debug_pkg_config = true;
205 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
206 builder.debug_compile_errors = true;
207 } else if (mem.eql(u8, arg, "--system")) {
208 // The usage text shows another argument after this parameter
209 // but it is handled by the parent process. The build runner
210 // only sees this flag.
211 graph.system_package_mode = true;
212 } else if (mem.eql(u8, arg, "--glibc-runtimes")) {
213 builder.glibc_runtimes_dir = nextArgOrFatal(args, &arg_idx);
214 } else if (mem.eql(u8, arg, "--verbose-link")) {
215 builder.verbose_link = true;
216 } else if (mem.eql(u8, arg, "--verbose-air")) {
217 builder.verbose_air = true;
218 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
219 builder.verbose_llvm_ir = "-";
220 } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) {
221 builder.verbose_llvm_ir = arg["--verbose-llvm-ir=".len..];
222 } else if (mem.eql(u8, arg, "--verbose-llvm-bc=")) {
223 builder.verbose_llvm_bc = arg["--verbose-llvm-bc=".len..];
224 } else if (mem.eql(u8, arg, "--verbose-cimport")) {
225 builder.verbose_cimport = true;
226 } else if (mem.eql(u8, arg, "--verbose-cc")) {
227 builder.verbose_cc = true;
228 } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {
229 builder.verbose_llvm_cpu_features = true;
230 } else if (mem.eql(u8, arg, "--prominent-compile-errors")) {
231 prominent_compile_errors = true;
232 } else if (mem.eql(u8, arg, "-fwine")) {
233 builder.enable_wine = true;
234 } else if (mem.eql(u8, arg, "-fno-wine")) {
235 builder.enable_wine = false;
236 } else if (mem.eql(u8, arg, "-fqemu")) {
237 builder.enable_qemu = true;
238 } else if (mem.eql(u8, arg, "-fno-qemu")) {
239 builder.enable_qemu = false;
240 } else if (mem.eql(u8, arg, "-fwasmtime")) {
241 builder.enable_wasmtime = true;
242 } else if (mem.eql(u8, arg, "-fno-wasmtime")) {
243 builder.enable_wasmtime = false;
244 } else if (mem.eql(u8, arg, "-frosetta")) {
245 builder.enable_rosetta = true;
246 } else if (mem.eql(u8, arg, "-fno-rosetta")) {
247 builder.enable_rosetta = false;
248 } else if (mem.eql(u8, arg, "-fdarling")) {
249 builder.enable_darling = true;
250 } else if (mem.eql(u8, arg, "-fno-darling")) {
251 builder.enable_darling = false;
252 } else if (mem.eql(u8, arg, "-freference-trace")) {
253 builder.reference_trace = 256;
254 } else if (mem.startsWith(u8, arg, "-freference-trace=")) {
255 const num = arg["-freference-trace=".len..];
256 builder.reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
257 std.debug.print("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) });
258 process.exit(1);
259 };
260 } else if (mem.eql(u8, arg, "-fno-reference-trace")) {
261 builder.reference_trace = null;
262 } else if (mem.startsWith(u8, arg, "-j")) {
263 const num = arg["-j".len..];
264 const n_jobs = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
265 std.debug.print("unable to parse jobs count '{s}': {s}", .{
266 num, @errorName(err),
267 });
268 process.exit(1);
269 };
270 if (n_jobs < 1) {
271 std.debug.print("number of jobs must be at least 1\n", .{});
272 process.exit(1);
273 }
274 thread_pool_options.n_jobs = n_jobs;
275 } else if (mem.eql(u8, arg, "--")) {
276 builder.args = argsRest(args, arg_idx);
277 break;
278 } else {
279 fatalWithHint("unrecognized argument: '{s}'", .{arg});
280 }
281 } else {
282 try targets.append(arg);
283 }
284 }
285
286 const host_query = std.Build.parseTargetQuery(graph.host_query_options) catch |err| switch (err) {
287 error.ParseFailed => process.exit(1),
288 };
289 builder.host = .{
290 .query = .{},
291 .result = try std.zig.system.resolveTargetQuery(host_query),
292 };
293
294 const stderr = std.io.getStdErr();
295 const ttyconf = get_tty_conf(color, stderr);
296 switch (ttyconf) {
297 .no_color => try graph.env_map.put("NO_COLOR", "1"),
298 .escape_codes => try graph.env_map.put("YES_COLOR", "1"),
299 .windows_api => {},
300 }
301
302 var progress: std.Progress = .{ .dont_print_on_dumb = true };
303 const main_progress_node = progress.start("", 0);
304
305 builder.debug_log_scopes = debug_log_scopes.items;
306 builder.resolveInstallPrefix(install_prefix, dir_list);
307 {
308 var prog_node = main_progress_node.start("user build.zig logic", 0);
309 defer prog_node.end();
310 try builder.runBuild(root);
311 }
312
313 if (graph.needed_lazy_dependencies.entries.len != 0) {
314 var buffer: std.ArrayListUnmanaged(u8) = .{};
315 for (graph.needed_lazy_dependencies.keys()) |k| {
316 try buffer.appendSlice(arena, k);
317 try buffer.append(arena, '\n');
318 }
319 const s = std.fs.path.sep_str;
320 const tmp_sub_path = "tmp" ++ s ++ (output_tmp_nonce orelse fatal("missing -Z arg", .{}));
321 local_cache_directory.handle.writeFile2(.{
322 .sub_path = tmp_sub_path,
323 .data = buffer.items,
324 .flags = .{ .exclusive = true },
325 }) catch |err| {
326 fatal("unable to write configuration results to '{}{s}': {s}", .{
327 local_cache_directory, tmp_sub_path, @errorName(err),
328 });
329 };
330 process.exit(3); // Indicate configure phase failed with meaningful stdout.
331 }
332
333 if (builder.validateUserInputDidItFail()) {
334 fatal(" access the help menu with 'zig build -h'", .{});
335 }
336
337 validateSystemLibraryOptions(builder);
338
339 const stdout_writer = io.getStdOut().writer();
340
341 if (help_menu)
342 return usage(builder, stdout_writer);
343
344 if (steps_menu)
345 return steps(builder, stdout_writer);
346
347 var run: Run = .{
348 .max_rss = max_rss,
349 .max_rss_is_default = false,
350 .max_rss_mutex = .{},
351 .skip_oom_steps = skip_oom_steps,
352 .memory_blocked_steps = std.ArrayList(*Step).init(arena),
353 .prominent_compile_errors = prominent_compile_errors,
354
355 .claimed_rss = 0,
356 .summary = summary,
357 .ttyconf = ttyconf,
358 .stderr = stderr,
359 };
360
361 if (run.max_rss == 0) {
362 run.max_rss = process.totalSystemMemory() catch std.math.maxInt(u64);
363 run.max_rss_is_default = true;
364 }
365
366 runStepNames(
367 arena,
368 builder,
369 targets.items,
370 main_progress_node,
371 thread_pool_options,
372 &run,
373 seed,
374 ) catch |err| switch (err) {
375 error.UncleanExit => process.exit(1),
376 else => return err,
377 };
378}
379
380const Run = struct {
381 max_rss: u64,
382 max_rss_is_default: bool,
383 max_rss_mutex: std.Thread.Mutex,
384 skip_oom_steps: bool,
385 memory_blocked_steps: std.ArrayList(*Step),
386 prominent_compile_errors: bool,
387
388 claimed_rss: usize,
389 summary: ?Summary,
390 ttyconf: std.io.tty.Config,
391 stderr: File,
392};
393
394fn runStepNames(
395 arena: std.mem.Allocator,
396 b: *std.Build,
397 step_names: []const []const u8,
398 parent_prog_node: *std.Progress.Node,
399 thread_pool_options: std.Thread.Pool.Options,
400 run: *Run,
401 seed: u32,
402) !void {
403 const gpa = b.allocator;
404 var step_stack: std.AutoArrayHashMapUnmanaged(*Step, void) = .{};
405 defer step_stack.deinit(gpa);
406
407 if (step_names.len == 0) {
408 try step_stack.put(gpa, b.default_step, {});
409 } else {
410 try step_stack.ensureUnusedCapacity(gpa, step_names.len);
411 for (0..step_names.len) |i| {
412 const step_name = step_names[step_names.len - i - 1];
413 const s = b.top_level_steps.get(step_name) orelse {
414 std.debug.print("no step named '{s}'\n access the help menu with 'zig build -h'\n", .{step_name});
415 process.exit(1);
416 };
417 step_stack.putAssumeCapacity(&s.step, {});
418 }
419 }
420
421 const starting_steps = try arena.dupe(*Step, step_stack.keys());
422
423 var rng = std.Random.DefaultPrng.init(seed);
424 const rand = rng.random();
425 rand.shuffle(*Step, starting_steps);
426
427 for (starting_steps) |s| {
428 constructGraphAndCheckForDependencyLoop(b, s, &step_stack, rand) catch |err| switch (err) {
429 error.DependencyLoopDetected => return error.UncleanExit,
430 else => |e| return e,
431 };
432 }
433
434 {
435 // Check that we have enough memory to complete the build.
436 var any_problems = false;
437 for (step_stack.keys()) |s| {
438 if (s.max_rss == 0) continue;
439 if (s.max_rss > run.max_rss) {
440 if (run.skip_oom_steps) {
441 s.state = .skipped_oom;
442 } else {
443 std.debug.print("{s}{s}: this step declares an upper bound of {d} bytes of memory, exceeding the available {d} bytes of memory\n", .{
444 s.owner.dep_prefix, s.name, s.max_rss, run.max_rss,
445 });
446 any_problems = true;
447 }
448 }
449 }
450 if (any_problems) {
451 if (run.max_rss_is_default) {
452 std.debug.print("note: use --maxrss to override the default", .{});
453 }
454 return error.UncleanExit;
455 }
456 }
457
458 var thread_pool: std.Thread.Pool = undefined;
459 try thread_pool.init(thread_pool_options);
460 defer thread_pool.deinit();
461
462 {
463 defer parent_prog_node.end();
464
465 var step_prog = parent_prog_node.start("steps", step_stack.count());
466 defer step_prog.end();
467
468 var wait_group: std.Thread.WaitGroup = .{};
469 defer wait_group.wait();
470
471 // Here we spawn the initial set of tasks with a nice heuristic -
472 // dependency order. Each worker when it finishes a step will then
473 // check whether it should run any dependants.
474 const steps_slice = step_stack.keys();
475 for (0..steps_slice.len) |i| {
476 const step = steps_slice[steps_slice.len - i - 1];
477 if (step.state == .skipped_oom) continue;
478
479 wait_group.start();
480 thread_pool.spawn(workerMakeOneStep, .{
481 &wait_group, &thread_pool, b, step, &step_prog, run,
482 }) catch @panic("OOM");
483 }
484 }
485 assert(run.memory_blocked_steps.items.len == 0);
486
487 var test_skip_count: usize = 0;
488 var test_fail_count: usize = 0;
489 var test_pass_count: usize = 0;
490 var test_leak_count: usize = 0;
491 var test_count: usize = 0;
492
493 var success_count: usize = 0;
494 var skipped_count: usize = 0;
495 var failure_count: usize = 0;
496 var pending_count: usize = 0;
497 var total_compile_errors: usize = 0;
498 var compile_error_steps: std.ArrayListUnmanaged(*Step) = .{};
499 defer compile_error_steps.deinit(gpa);
500
501 for (step_stack.keys()) |s| {
502 test_fail_count += s.test_results.fail_count;
503 test_skip_count += s.test_results.skip_count;
504 test_leak_count += s.test_results.leak_count;
505 test_pass_count += s.test_results.passCount();
506 test_count += s.test_results.test_count;
507
508 switch (s.state) {
509 .precheck_unstarted => unreachable,
510 .precheck_started => unreachable,
511 .running => unreachable,
512 .precheck_done => {
513 // precheck_done is equivalent to dependency_failure in the case of
514 // transitive dependencies. For example:
515 // A -> B -> C (failure)
516 // B will be marked as dependency_failure, while A may never be queued, and thus
517 // remain in the initial state of precheck_done.
518 s.state = .dependency_failure;
519 pending_count += 1;
520 },
521 .dependency_failure => pending_count += 1,
522 .success => success_count += 1,
523 .skipped, .skipped_oom => skipped_count += 1,
524 .failure => {
525 failure_count += 1;
526 const compile_errors_len = s.result_error_bundle.errorMessageCount();
527 if (compile_errors_len > 0) {
528 total_compile_errors += compile_errors_len;
529 try compile_error_steps.append(gpa, s);
530 }
531 },
532 }
533 }
534
535 // A proper command line application defaults to silently succeeding.
536 // The user may request verbose mode if they have a different preference.
537 const failures_only = run.summary != .all and run.summary != .new;
538 if (failure_count == 0 and failures_only) return cleanExit();
539
540 const ttyconf = run.ttyconf;
541 const stderr = run.stderr;
542
543 if (run.summary != Summary.none) {
544 const total_count = success_count + failure_count + pending_count + skipped_count;
545 ttyconf.setColor(stderr, .cyan) catch {};
546 stderr.writeAll("Build Summary:") catch {};
547 ttyconf.setColor(stderr, .reset) catch {};
548 stderr.writer().print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
549 if (skipped_count > 0) stderr.writer().print("; {d} skipped", .{skipped_count}) catch {};
550 if (failure_count > 0) stderr.writer().print("; {d} failed", .{failure_count}) catch {};
551
552 if (test_count > 0) stderr.writer().print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {};
553 if (test_skip_count > 0) stderr.writer().print("; {d} skipped", .{test_skip_count}) catch {};
554 if (test_fail_count > 0) stderr.writer().print("; {d} failed", .{test_fail_count}) catch {};
555 if (test_leak_count > 0) stderr.writer().print("; {d} leaked", .{test_leak_count}) catch {};
556
557 if (run.summary == null) {
558 ttyconf.setColor(stderr, .dim) catch {};
559 stderr.writeAll(" (disable with --summary none)") catch {};
560 ttyconf.setColor(stderr, .reset) catch {};
561 }
562 stderr.writeAll("\n") catch {};
563
564 // Print a fancy tree with build results.
565 var print_node: PrintNode = .{ .parent = null };
566 if (step_names.len == 0) {
567 print_node.last = true;
568 printTreeStep(b, b.default_step, run, stderr, ttyconf, &print_node, &step_stack) catch {};
569 } else {
570 const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: {
571 var i: usize = step_names.len;
572 while (i > 0) {
573 i -= 1;
574 const step = b.top_level_steps.get(step_names[i]).?.step;
575 const found = switch (run.summary orelse .failures) {
576 .all, .none => unreachable,
577 .failures => step.state != .success,
578 .new => !step.result_cached,
579 };
580 if (found) break :blk i;
581 }
582 break :blk b.top_level_steps.count();
583 };
584 for (step_names, 0..) |step_name, i| {
585 const tls = b.top_level_steps.get(step_name).?;
586 print_node.last = i + 1 == last_index;
587 printTreeStep(b, &tls.step, run, stderr, ttyconf, &print_node, &step_stack) catch {};
588 }
589 }
590 }
591
592 if (failure_count == 0) return cleanExit();
593
594 // Finally, render compile errors at the bottom of the terminal.
595 // We use a separate compile_error_steps array list because step_stack is destructively
596 // mutated in printTreeStep above.
597 if (run.prominent_compile_errors and total_compile_errors > 0) {
598 for (compile_error_steps.items) |s| {
599 if (s.result_error_bundle.errorMessageCount() > 0) {
600 s.result_error_bundle.renderToStdErr(renderOptions(ttyconf));
601 }
602 }
603
604 // Signal to parent process that we have printed compile errors. The
605 // parent process may choose to omit the "following command failed"
606 // line in this case.
607 process.exit(2);
608 }
609
610 process.exit(1);
611}
612
613const PrintNode = struct {
614 parent: ?*PrintNode,
615 last: bool = false,
616};
617
618fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void {
619 const parent = node.parent orelse return;
620 if (parent.parent == null) return;
621 try printPrefix(parent, stderr, ttyconf);
622 if (parent.last) {
623 try stderr.writeAll(" ");
624 } else {
625 try stderr.writeAll(switch (ttyconf) {
626 .no_color, .windows_api => "| ",
627 .escape_codes => "\x1B\x28\x30\x78\x1B\x28\x42 ", // │
628 });
629 }
630}
631
632fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void {
633 try stderr.writeAll(switch (ttyconf) {
634 .no_color, .windows_api => "+- ",
635 .escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─
636 });
637}
638
639fn printStepStatus(
640 s: *Step,
641 stderr: File,
642 ttyconf: std.io.tty.Config,
643 run: *const Run,
644) !void {
645 switch (s.state) {
646 .precheck_unstarted => unreachable,
647 .precheck_started => unreachable,
648 .precheck_done => unreachable,
649 .running => unreachable,
650
651 .dependency_failure => {
652 try ttyconf.setColor(stderr, .dim);
653 try stderr.writeAll(" transitive failure\n");
654 try ttyconf.setColor(stderr, .reset);
655 },
656
657 .success => {
658 try ttyconf.setColor(stderr, .green);
659 if (s.result_cached) {
660 try stderr.writeAll(" cached");
661 } else if (s.test_results.test_count > 0) {
662 const pass_count = s.test_results.passCount();
663 try stderr.writer().print(" {d} passed", .{pass_count});
664 if (s.test_results.skip_count > 0) {
665 try ttyconf.setColor(stderr, .yellow);
666 try stderr.writer().print(" {d} skipped", .{s.test_results.skip_count});
667 }
668 } else {
669 try stderr.writeAll(" success");
670 }
671 try ttyconf.setColor(stderr, .reset);
672 if (s.result_duration_ns) |ns| {
673 try ttyconf.setColor(stderr, .dim);
674 if (ns >= std.time.ns_per_min) {
675 try stderr.writer().print(" {d}m", .{ns / std.time.ns_per_min});
676 } else if (ns >= std.time.ns_per_s) {
677 try stderr.writer().print(" {d}s", .{ns / std.time.ns_per_s});
678 } else if (ns >= std.time.ns_per_ms) {
679 try stderr.writer().print(" {d}ms", .{ns / std.time.ns_per_ms});
680 } else if (ns >= std.time.ns_per_us) {
681 try stderr.writer().print(" {d}us", .{ns / std.time.ns_per_us});
682 } else {
683 try stderr.writer().print(" {d}ns", .{ns});
684 }
685 try ttyconf.setColor(stderr, .reset);
686 }
687 if (s.result_peak_rss != 0) {
688 const rss = s.result_peak_rss;
689 try ttyconf.setColor(stderr, .dim);
690 if (rss >= 1000_000_000) {
691 try stderr.writer().print(" MaxRSS:{d}G", .{rss / 1000_000_000});
692 } else if (rss >= 1000_000) {
693 try stderr.writer().print(" MaxRSS:{d}M", .{rss / 1000_000});
694 } else if (rss >= 1000) {
695 try stderr.writer().print(" MaxRSS:{d}K", .{rss / 1000});
696 } else {
697 try stderr.writer().print(" MaxRSS:{d}B", .{rss});
698 }
699 try ttyconf.setColor(stderr, .reset);
700 }
701 try stderr.writeAll("\n");
702 },
703 .skipped, .skipped_oom => |skip| {
704 try ttyconf.setColor(stderr, .yellow);
705 try stderr.writeAll(" skipped");
706 if (skip == .skipped_oom) {
707 try stderr.writeAll(" (not enough memory)");
708 try ttyconf.setColor(stderr, .dim);
709 try stderr.writer().print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });
710 try ttyconf.setColor(stderr, .yellow);
711 }
712 try stderr.writeAll("\n");
713 try ttyconf.setColor(stderr, .reset);
714 },
715 .failure => try printStepFailure(s, stderr, ttyconf),
716 }
717}
718
719fn printStepFailure(
720 s: *Step,
721 stderr: File,
722 ttyconf: std.io.tty.Config,
723) !void {
724 if (s.result_error_bundle.errorMessageCount() > 0) {
725 try ttyconf.setColor(stderr, .red);
726 try stderr.writer().print(" {d} errors\n", .{
727 s.result_error_bundle.errorMessageCount(),
728 });
729 try ttyconf.setColor(stderr, .reset);
730 } else if (!s.test_results.isSuccess()) {
731 try stderr.writer().print(" {d}/{d} passed", .{
732 s.test_results.passCount(), s.test_results.test_count,
733 });
734 if (s.test_results.fail_count > 0) {
735 try stderr.writeAll(", ");
736 try ttyconf.setColor(stderr, .red);
737 try stderr.writer().print("{d} failed", .{
738 s.test_results.fail_count,
739 });
740 try ttyconf.setColor(stderr, .reset);
741 }
742 if (s.test_results.skip_count > 0) {
743 try stderr.writeAll(", ");
744 try ttyconf.setColor(stderr, .yellow);
745 try stderr.writer().print("{d} skipped", .{
746 s.test_results.skip_count,
747 });
748 try ttyconf.setColor(stderr, .reset);
749 }
750 if (s.test_results.leak_count > 0) {
751 try stderr.writeAll(", ");
752 try ttyconf.setColor(stderr, .red);
753 try stderr.writer().print("{d} leaked", .{
754 s.test_results.leak_count,
755 });
756 try ttyconf.setColor(stderr, .reset);
757 }
758 try stderr.writeAll("\n");
759 } else if (s.result_error_msgs.items.len > 0) {
760 try ttyconf.setColor(stderr, .red);
761 try stderr.writeAll(" failure\n");
762 try ttyconf.setColor(stderr, .reset);
763 } else {
764 assert(s.result_stderr.len > 0);
765 try ttyconf.setColor(stderr, .red);
766 try stderr.writeAll(" stderr\n");
767 try ttyconf.setColor(stderr, .reset);
768 }
769}
770
771fn printTreeStep(
772 b: *std.Build,
773 s: *Step,
774 run: *const Run,
775 stderr: File,
776 ttyconf: std.io.tty.Config,
777 parent_node: *PrintNode,
778 step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
779) !void {
780 const first = step_stack.swapRemove(s);
781 const summary = run.summary orelse .failures;
782 const skip = switch (summary) {
783 .none => unreachable,
784 .all => false,
785 .new => s.result_cached,
786 .failures => s.state == .success,
787 };
788 if (skip) return;
789 try printPrefix(parent_node, stderr, ttyconf);
790
791 if (!first) try ttyconf.setColor(stderr, .dim);
792 if (parent_node.parent != null) {
793 if (parent_node.last) {
794 try printChildNodePrefix(stderr, ttyconf);
795 } else {
796 try stderr.writeAll(switch (ttyconf) {
797 .no_color, .windows_api => "+- ",
798 .escape_codes => "\x1B\x28\x30\x74\x71\x1B\x28\x42 ", // ├─
799 });
800 }
801 }
802
803 // dep_prefix omitted here because it is redundant with the tree.
804 try stderr.writeAll(s.name);
805
806 if (first) {
807 try printStepStatus(s, stderr, ttyconf, run);
808
809 const last_index = if (summary == .all) s.dependencies.items.len -| 1 else blk: {
810 var i: usize = s.dependencies.items.len;
811 while (i > 0) {
812 i -= 1;
813
814 const step = s.dependencies.items[i];
815 const found = switch (summary) {
816 .all, .none => unreachable,
817 .failures => step.state != .success,
818 .new => !step.result_cached,
819 };
820 if (found) break :blk i;
821 }
822 break :blk s.dependencies.items.len -| 1;
823 };
824 for (s.dependencies.items, 0..) |dep, i| {
825 var print_node: PrintNode = .{
826 .parent = parent_node,
827 .last = i == last_index,
828 };
829 try printTreeStep(b, dep, run, stderr, ttyconf, &print_node, step_stack);
830 }
831 } else {
832 if (s.dependencies.items.len == 0) {
833 try stderr.writeAll(" (reused)\n");
834 } else {
835 try stderr.writer().print(" (+{d} more reused dependencies)\n", .{
836 s.dependencies.items.len,
837 });
838 }
839 try ttyconf.setColor(stderr, .reset);
840 }
841}
842
843/// Traverse the dependency graph depth-first and make it undirected by having
844/// steps know their dependants (they only know dependencies at start).
845/// Along the way, check that there is no dependency loop, and record the steps
846/// in traversal order in `step_stack`.
847/// Each step has its dependencies traversed in random order, this accomplishes
848/// two things:
849/// - `step_stack` will be in randomized-depth-first order, so the build runner
850/// spawns steps in a random (but optimized) order
851/// - each step's `dependants` list is also filled in a random order, so that
852/// when it finishes executing in `workerMakeOneStep`, it spawns next steps
853/// to run in random order
854fn constructGraphAndCheckForDependencyLoop(
855 b: *std.Build,
856 s: *Step,
857 step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
858 rand: std.Random,
859) !void {
860 switch (s.state) {
861 .precheck_started => {
862 std.debug.print("dependency loop detected:\n {s}\n", .{s.name});
863 return error.DependencyLoopDetected;
864 },
865 .precheck_unstarted => {
866 s.state = .precheck_started;
867
868 try step_stack.ensureUnusedCapacity(b.allocator, s.dependencies.items.len);
869
870 // We dupe to avoid shuffling the steps in the summary, it depends
871 // on s.dependencies' order.
872 const deps = b.allocator.dupe(*Step, s.dependencies.items) catch @panic("OOM");
873 rand.shuffle(*Step, deps);
874
875 for (deps) |dep| {
876 try step_stack.put(b.allocator, dep, {});
877 try dep.dependants.append(b.allocator, s);
878 constructGraphAndCheckForDependencyLoop(b, dep, step_stack, rand) catch |err| {
879 if (err == error.DependencyLoopDetected) {
880 std.debug.print(" {s}\n", .{s.name});
881 }
882 return err;
883 };
884 }
885
886 s.state = .precheck_done;
887 },
888 .precheck_done => {},
889
890 // These don't happen until we actually run the step graph.
891 .dependency_failure => unreachable,
892 .running => unreachable,
893 .success => unreachable,
894 .failure => unreachable,
895 .skipped => unreachable,
896 .skipped_oom => unreachable,
897 }
898}
899
900fn workerMakeOneStep(
901 wg: *std.Thread.WaitGroup,
902 thread_pool: *std.Thread.Pool,
903 b: *std.Build,
904 s: *Step,
905 prog_node: *std.Progress.Node,
906 run: *Run,
907) void {
908 defer wg.finish();
909
910 // First, check the conditions for running this step. If they are not met,
911 // then we return without doing the step, relying on another worker to
912 // queue this step up again when dependencies are met.
913 for (s.dependencies.items) |dep| {
914 switch (@atomicLoad(Step.State, &dep.state, .seq_cst)) {
915 .success, .skipped => continue,
916 .failure, .dependency_failure, .skipped_oom => {
917 @atomicStore(Step.State, &s.state, .dependency_failure, .seq_cst);
918 return;
919 },
920 .precheck_done, .running => {
921 // dependency is not finished yet.
922 return;
923 },
924 .precheck_unstarted => unreachable,
925 .precheck_started => unreachable,
926 }
927 }
928
929 if (s.max_rss != 0) {
930 run.max_rss_mutex.lock();
931 defer run.max_rss_mutex.unlock();
932
933 // Avoid running steps twice.
934 if (s.state != .precheck_done) {
935 // Another worker got the job.
936 return;
937 }
938
939 const new_claimed_rss = run.claimed_rss + s.max_rss;
940 if (new_claimed_rss > run.max_rss) {
941 // Running this step right now could possibly exceed the allotted RSS.
942 // Add this step to the queue of memory-blocked steps.
943 run.memory_blocked_steps.append(s) catch @panic("OOM");
944 return;
945 }
946
947 run.claimed_rss = new_claimed_rss;
948 s.state = .running;
949 } else {
950 // Avoid running steps twice.
951 if (@cmpxchgStrong(Step.State, &s.state, .precheck_done, .running, .seq_cst, .seq_cst) != null) {
952 // Another worker got the job.
953 return;
954 }
955 }
956
957 var sub_prog_node = prog_node.start(s.name, 0);
958 sub_prog_node.activate();
959 defer sub_prog_node.end();
960
961 const make_result = s.make(&sub_prog_node);
962
963 // No matter the result, we want to display error/warning messages.
964 const show_compile_errors = !run.prominent_compile_errors and
965 s.result_error_bundle.errorMessageCount() > 0;
966 const show_error_msgs = s.result_error_msgs.items.len > 0;
967 const show_stderr = s.result_stderr.len > 0;
968
969 if (show_error_msgs or show_compile_errors or show_stderr) {
970 sub_prog_node.context.lock_stderr();
971 defer sub_prog_node.context.unlock_stderr();
972
973 printErrorMessages(b, s, run) catch {};
974 }
975
976 handle_result: {
977 if (make_result) |_| {
978 @atomicStore(Step.State, &s.state, .success, .seq_cst);
979 } else |err| switch (err) {
980 error.MakeFailed => {
981 @atomicStore(Step.State, &s.state, .failure, .seq_cst);
982 break :handle_result;
983 },
984 error.MakeSkipped => @atomicStore(Step.State, &s.state, .skipped, .seq_cst),
985 }
986
987 // Successful completion of a step, so we queue up its dependants as well.
988 for (s.dependants.items) |dep| {
989 wg.start();
990 thread_pool.spawn(workerMakeOneStep, .{
991 wg, thread_pool, b, dep, prog_node, run,
992 }) catch @panic("OOM");
993 }
994 }
995
996 // If this is a step that claims resources, we must now queue up other
997 // steps that are waiting for resources.
998 if (s.max_rss != 0) {
999 run.max_rss_mutex.lock();
1000 defer run.max_rss_mutex.unlock();
1001
1002 // Give the memory back to the scheduler.
1003 run.claimed_rss -= s.max_rss;
1004 // Avoid kicking off too many tasks that we already know will not have
1005 // enough resources.
1006 var remaining = run.max_rss - run.claimed_rss;
1007 var i: usize = 0;
1008 var j: usize = 0;
1009 while (j < run.memory_blocked_steps.items.len) : (j += 1) {
1010 const dep = run.memory_blocked_steps.items[j];
1011 assert(dep.max_rss != 0);
1012 if (dep.max_rss <= remaining) {
1013 remaining -= dep.max_rss;
1014
1015 wg.start();
1016 thread_pool.spawn(workerMakeOneStep, .{
1017 wg, thread_pool, b, dep, prog_node, run,
1018 }) catch @panic("OOM");
1019 } else {
1020 run.memory_blocked_steps.items[i] = dep;
1021 i += 1;
1022 }
1023 }
1024 run.memory_blocked_steps.shrinkRetainingCapacity(i);
1025 }
1026}
1027
1028fn printErrorMessages(b: *std.Build, failing_step: *Step, run: *const Run) !void {
1029 const gpa = b.allocator;
1030 const stderr = run.stderr;
1031 const ttyconf = run.ttyconf;
1032
1033 // Provide context for where these error messages are coming from by
1034 // printing the corresponding Step subtree.
1035
1036 var step_stack: std.ArrayListUnmanaged(*Step) = .{};
1037 defer step_stack.deinit(gpa);
1038 try step_stack.append(gpa, failing_step);
1039 while (step_stack.items[step_stack.items.len - 1].dependants.items.len != 0) {
1040 try step_stack.append(gpa, step_stack.items[step_stack.items.len - 1].dependants.items[0]);
1041 }
1042
1043 // Now, `step_stack` has the subtree that we want to print, in reverse order.
1044 try ttyconf.setColor(stderr, .dim);
1045 var indent: usize = 0;
1046 while (step_stack.popOrNull()) |s| : (indent += 1) {
1047 if (indent > 0) {
1048 try stderr.writer().writeByteNTimes(' ', (indent - 1) * 3);
1049 try printChildNodePrefix(stderr, ttyconf);
1050 }
1051
1052 try stderr.writeAll(s.name);
1053
1054 if (s == failing_step) {
1055 try printStepFailure(s, stderr, ttyconf);
1056 } else {
1057 try stderr.writeAll("\n");
1058 }
1059 }
1060 try ttyconf.setColor(stderr, .reset);
1061
1062 if (failing_step.result_stderr.len > 0) {
1063 try stderr.writeAll(failing_step.result_stderr);
1064 if (!mem.endsWith(u8, failing_step.result_stderr, "\n")) {
1065 try stderr.writeAll("\n");
1066 }
1067 }
1068
1069 if (!run.prominent_compile_errors and failing_step.result_error_bundle.errorMessageCount() > 0)
1070 try failing_step.result_error_bundle.renderToWriter(renderOptions(ttyconf), stderr.writer());
1071
1072 for (failing_step.result_error_msgs.items) |msg| {
1073 try ttyconf.setColor(stderr, .red);
1074 try stderr.writeAll("error: ");
1075 try ttyconf.setColor(stderr, .reset);
1076 try stderr.writeAll(msg);
1077 try stderr.writeAll("\n");
1078 }
1079}
1080
1081fn steps(builder: *std.Build, out_stream: anytype) !void {
1082 const allocator = builder.allocator;
1083 for (builder.top_level_steps.values()) |top_level_step| {
1084 const name = if (&top_level_step.step == builder.default_step)
1085 try fmt.allocPrint(allocator, "{s} (default)", .{top_level_step.step.name})
1086 else
1087 top_level_step.step.name;
1088 try out_stream.print(" {s:<28} {s}\n", .{ name, top_level_step.description });
1089 }
1090}
1091
1092fn usage(b: *std.Build, out_stream: anytype) !void {
1093 try out_stream.print(
1094 \\Usage: {s} build [steps] [options]
1095 \\
1096 \\Steps:
1097 \\
1098 , .{b.graph.zig_exe});
1099 try steps(b, out_stream);
1100
1101 try out_stream.writeAll(
1102 \\
1103 \\General Options:
1104 \\ -p, --prefix [path] Where to install files (default: zig-out)
1105 \\ --prefix-lib-dir [path] Where to install libraries
1106 \\ --prefix-exe-dir [path] Where to install executables
1107 \\ --prefix-include-dir [path] Where to install C header files
1108 \\
1109 \\ --release[=mode] Request release mode, optionally specifying a
1110 \\ preferred optimization mode: fast, safe, small
1111 \\
1112 \\ -fdarling, -fno-darling Integration with system-installed Darling to
1113 \\ execute macOS programs on Linux hosts
1114 \\ (default: no)
1115 \\ -fqemu, -fno-qemu Integration with system-installed QEMU to execute
1116 \\ foreign-architecture programs on Linux hosts
1117 \\ (default: no)
1118 \\ --glibc-runtimes [path] Enhances QEMU integration by providing glibc built
1119 \\ for multiple foreign architectures, allowing
1120 \\ execution of non-native programs that link with glibc.
1121 \\ -frosetta, -fno-rosetta Rely on Rosetta to execute x86_64 programs on
1122 \\ ARM64 macOS hosts. (default: no)
1123 \\ -fwasmtime, -fno-wasmtime Integration with system-installed wasmtime to
1124 \\ execute WASI binaries. (default: no)
1125 \\ -fwine, -fno-wine Integration with system-installed Wine to execute
1126 \\ Windows programs on Linux hosts. (default: no)
1127 \\
1128 \\ -h, --help Print this help and exit
1129 \\ -l, --list-steps Print available steps
1130 \\ --verbose Print commands before executing them
1131 \\ --color [auto|off|on] Enable or disable colored error messages
1132 \\ --prominent-compile-errors Buffer compile errors and display at end
1133 \\ --summary [mode] Control the printing of the build summary
1134 \\ all Print the build summary in its entirety
1135 \\ new Omit cached steps
1136 \\ failures (Default) Only print failed steps
1137 \\ none Do not print the build summary
1138 \\ -j<N> Limit concurrent jobs (default is to use all CPU cores)
1139 \\ --maxrss <bytes> Limit memory usage (default is to use available memory)
1140 \\ --skip-oom-steps Instead of failing, skip steps that would exceed --maxrss
1141 \\ --fetch Exit after fetching dependency tree
1142 \\
1143 \\Project-Specific Options:
1144 \\
1145 );
1146
1147 const arena = b.allocator;
1148 if (b.available_options_list.items.len == 0) {
1149 try out_stream.print(" (none)\n", .{});
1150 } else {
1151 for (b.available_options_list.items) |option| {
1152 const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{
1153 option.name,
1154 @tagName(option.type_id),
1155 });
1156 try out_stream.print("{s:<30} {s}\n", .{ name, option.description });
1157 if (option.enum_options) |enum_options| {
1158 const padding = " " ** 33;
1159 try out_stream.writeAll(padding ++ "Supported Values:\n");
1160 for (enum_options) |enum_option| {
1161 try out_stream.print(padding ++ " {s}\n", .{enum_option});
1162 }
1163 }
1164 }
1165 }
1166
1167 try out_stream.writeAll(
1168 \\
1169 \\System Integration Options:
1170 \\ --search-prefix [path] Add a path to look for binaries, libraries, headers
1171 \\ --sysroot [path] Set the system root directory (usually /)
1172 \\ --libc [file] Provide a file which specifies libc paths
1173 \\
1174 \\ --host-target [triple] Use the provided target as the host
1175 \\ --host-cpu [cpu] Use the provided CPU as the host
1176 \\ --host-dynamic-linker [path] Use the provided dynamic linker as the host
1177 \\
1178 \\ --system [pkgdir] Disable package fetching; enable all integrations
1179 \\ -fsys=[name] Enable a system integration
1180 \\ -fno-sys=[name] Disable a system integration
1181 \\
1182 \\ Available System Integrations: Enabled:
1183 \\
1184 );
1185 if (b.graph.system_library_options.entries.len == 0) {
1186 try out_stream.writeAll(" (none) -\n");
1187 } else {
1188 for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| {
1189 const status = switch (v) {
1190 .declared_enabled => "yes",
1191 .declared_disabled => "no",
1192 .user_enabled, .user_disabled => unreachable, // already emitted error
1193 };
1194 try out_stream.print(" {s:<43} {s}\n", .{ k, status });
1195 }
1196 }
1197
1198 try out_stream.writeAll(
1199 \\
1200 \\Advanced Options:
1201 \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
1202 \\ -fno-reference-trace Disable reference trace
1203 \\ --build-file [file] Override path to build.zig
1204 \\ --cache-dir [path] Override path to local Zig cache directory
1205 \\ --global-cache-dir [path] Override path to global Zig cache directory
1206 \\ --zig-lib-dir [arg] Override path to Zig lib directory
1207 \\ --build-runner [file] Override path to build runner
1208 \\ --seed [integer] For shuffling dependency traversal order (default: random)
1209 \\ --debug-log [scope] Enable debugging the compiler
1210 \\ --debug-pkg-config Fail if unknown pkg-config flags encountered
1211 \\ --verbose-link Enable compiler debug output for linking
1212 \\ --verbose-air Enable compiler debug output for Zig AIR
1213 \\ --verbose-llvm-ir[=file] Enable compiler debug output for LLVM IR
1214 \\ --verbose-llvm-bc=[file] Enable compiler debug output for LLVM BC
1215 \\ --verbose-cimport Enable compiler debug output for C imports
1216 \\ --verbose-cc Enable compiler debug output for C compilation
1217 \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features
1218 \\
1219 );
1220}
1221
1222fn nextArg(args: [][:0]const u8, idx: *usize) ?[:0]const u8 {
1223 if (idx.* >= args.len) return null;
1224 defer idx.* += 1;
1225 return args[idx.*];
1226}
1227
1228fn nextArgOrFatal(args: [][:0]const u8, idx: *usize) [:0]const u8 {
1229 return nextArg(args, idx) orelse {
1230 std.debug.print("expected argument after '{s}'\n access the help menu with 'zig build -h'\n", .{args[idx.*]});
1231 process.exit(1);
1232 };
1233}
1234
1235fn argsRest(args: [][:0]const u8, idx: usize) ?[][:0]const u8 {
1236 if (idx >= args.len) return null;
1237 return args[idx..];
1238}
1239
1240fn cleanExit() void {
1241 // Perhaps in the future there could be an Advanced Options flag such as
1242 // --debug-build-runner-leaks which would make this function return instead
1243 // of calling exit.
1244 process.exit(0);
1245}
1246
1247const Color = enum { auto, off, on };
1248const Summary = enum { all, new, failures, none };
1249
1250fn get_tty_conf(color: Color, stderr: File) std.io.tty.Config {
1251 return switch (color) {
1252 .auto => std.io.tty.detectConfig(stderr),
1253 .on => .escape_codes,
1254 .off => .no_color,
1255 };
1256}
1257
1258fn renderOptions(ttyconf: std.io.tty.Config) std.zig.ErrorBundle.RenderOptions {
1259 return .{
1260 .ttyconf = ttyconf,
1261 .include_source_line = ttyconf != .no_color,
1262 .include_reference_trace = ttyconf != .no_color,
1263 };
1264}
1265
1266fn fatalWithHint(comptime f: []const u8, args: anytype) noreturn {
1267 std.debug.print(f ++ "\n access the help menu with 'zig build -h'\n", args);
1268 process.exit(1);
1269}
1270
1271fn fatal(comptime f: []const u8, args: anytype) noreturn {
1272 std.debug.print(f ++ "\n", args);
1273 process.exit(1);
1274}
1275
1276fn validateSystemLibraryOptions(b: *std.Build) void {
1277 var bad = false;
1278 for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| {
1279 switch (v) {
1280 .user_disabled, .user_enabled => {
1281 // The user tried to enable or disable a system library integration, but
1282 // the build script did not recognize that option.
1283 std.debug.print("system library name not recognized by build script: '{s}'\n", .{k});
1284 bad = true;
1285 },
1286 .declared_disabled, .declared_enabled => {},
1287 }
1288 }
1289 if (bad) {
1290 std.debug.print(" access the help menu with 'zig build -h'\n", .{});
1291 process.exit(1);
1292 }
1293}
lib/std/builtin.zig-1
......@@ -420,7 +420,6 @@ pub const Type = union(enum) {
420420 /// therefore must be kept in sync with the compiler implementation.
421421 pub const Fn = struct {
422422 calling_convention: CallingConvention,
423 alignment: comptime_int,
424423 is_generic: bool,
425424 is_var_args: bool,
426425 /// TODO change the language spec to make this not optional.
lib/std/c/darwin.zig+5-5
......@@ -1053,10 +1053,10 @@ pub const sigset_t = u32;
10531053pub const empty_sigset: sigset_t = 0;
10541054
10551055pub const SIG = struct {
1056 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
1057 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
1058 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
1059 pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(5));
1056 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
1057 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
1058 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
1059 pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(5);
10601060
10611061 /// block specified signal set
10621062 pub const BLOCK = 1;
......@@ -1150,7 +1150,7 @@ pub const siginfo_t = extern struct {
11501150
11511151/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
11521152pub const Sigaction = extern struct {
1153 pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void;
1153 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
11541154 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
11551155
11561156 handler: extern union {
lib/std/c/dragonfly.zig+4-4
......@@ -616,9 +616,9 @@ pub const S = struct {
616616pub const BADSIG = SIG.ERR;
617617
618618pub const SIG = struct {
619 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
620 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
621 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
619 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
620 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
621 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
622622
623623 pub const BLOCK = 1;
624624 pub const UNBLOCK = 2;
......@@ -690,7 +690,7 @@ pub const empty_sigset = sigset_t{ .__bits = [_]c_uint{0} ** _SIG_WORDS };
690690pub const sig_atomic_t = c_int;
691691
692692pub const Sigaction = extern struct {
693 pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void;
693 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
694694 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
695695
696696 /// signal handler
lib/std/c/freebsd.zig+4-4
......@@ -695,9 +695,9 @@ pub const SIG = struct {
695695 pub const UNBLOCK = 2;
696696 pub const SETMASK = 3;
697697
698 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
699 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
700 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
698 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
699 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
700 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
701701
702702 pub const WORDS = 4;
703703 pub const MAXSIG = 128;
......@@ -1171,7 +1171,7 @@ const NSIG = 32;
11711171
11721172/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
11731173pub const Sigaction = extern struct {
1174 pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void;
1174 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
11751175 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
11761176
11771177 /// signal handler
lib/std/c/haiku.zig+4-4
......@@ -441,9 +441,9 @@ pub const SA = struct {
441441};
442442
443443pub const SIG = struct {
444 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
445 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
446 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
444 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
445 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
446 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
447447
448448 pub const HUP = 1;
449449 pub const INT = 2;
......@@ -690,7 +690,7 @@ const NSIG = 32;
690690
691691/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
692692pub const Sigaction = extern struct {
693 pub const handler_fn = *const fn (i32) align(1) callconv(.C) void;
693 pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
694694
695695 /// signal handler
696696 __sigaction_u: extern union {
lib/std/c/netbsd.zig+4-4
......@@ -800,9 +800,9 @@ pub const winsize = extern struct {
800800const NSIG = 32;
801801
802802pub const SIG = struct {
803 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
804 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
805 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
803 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
804 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
805 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
806806
807807 pub const WORDS = 4;
808808 pub const MAXSIG = 128;
......@@ -864,7 +864,7 @@ pub const SIG = struct {
864864
865865/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
866866pub const Sigaction = extern struct {
867 pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void;
867 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
868868 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
869869
870870 /// signal handler
lib/std/c/openbsd.zig+6-6
......@@ -795,11 +795,11 @@ pub const winsize = extern struct {
795795const NSIG = 33;
796796
797797pub const SIG = struct {
798 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
799 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
800 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
801 pub const CATCH = @as(?Sigaction.handler_fn, @ptrFromInt(2));
802 pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(3));
798 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
799 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
800 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
801 pub const CATCH: ?Sigaction.handler_fn = @ptrFromInt(2);
802 pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(3);
803803
804804 pub const HUP = 1;
805805 pub const INT = 2;
......@@ -842,7 +842,7 @@ pub const SIG = struct {
842842
843843/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
844844pub const Sigaction = extern struct {
845 pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void;
845 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
846846 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
847847
848848 /// signal handler
lib/std/c/solaris.zig+5-5
......@@ -798,10 +798,10 @@ pub const winsize = extern struct {
798798const NSIG = 75;
799799
800800pub const SIG = struct {
801 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
802 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
803 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
804 pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(2));
801 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
802 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
803 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
804 pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(2);
805805
806806 pub const WORDS = 4;
807807 pub const MAXSIG = 75;
......@@ -874,7 +874,7 @@ pub const SIG = struct {
874874
875875/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
876876pub const Sigaction = extern struct {
877 pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void;
877 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
878878 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
879879
880880 /// signal options
lib/std/meta.zig+4-5
......@@ -57,10 +57,9 @@ test stringToEnum {
5757}
5858
5959/// Returns the alignment of type T.
60/// Note that if T is a pointer or function type the result is different than
61/// the one returned by @alignOf(T).
60/// Note that if T is a pointer type the result is different than the one
61/// returned by @alignOf(T).
6262/// If T is a pointer type the alignment of the type it points to is returned.
63/// If T is a function type the alignment a target-dependent value is returned.
6463pub fn alignment(comptime T: type) comptime_int {
6564 return switch (@typeInfo(T)) {
6665 .Optional => |info| switch (@typeInfo(info.child)) {
......@@ -68,7 +67,6 @@ pub fn alignment(comptime T: type) comptime_int {
6867 else => @alignOf(T),
6968 },
7069 .Pointer => |info| info.alignment,
71 .Fn => |info| info.alignment,
7270 else => @alignOf(T),
7371 };
7472}
......@@ -80,7 +78,8 @@ test alignment {
8078 try testing.expect(alignment([]align(1) u8) == 1);
8179 try testing.expect(alignment([]align(2) u8) == 2);
8280 try testing.expect(alignment(fn () void) > 0);
83 try testing.expect(alignment(fn () align(128) void) == 128);
81 try testing.expect(alignment(*const fn () void) > 0);
82 try testing.expect(alignment(*align(128) const fn () void) == 128);
8483}
8584
8685/// Given a parameterized type (array, vector, pointer, optional), returns the "child type".
lib/std/os/emscripten.zig+4-4
......@@ -689,13 +689,13 @@ pub const SIG = struct {
689689 pub const SYS = 31;
690690 pub const UNUSED = SIG.SYS;
691691
692 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(std.math.maxInt(usize)));
693 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
694 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
692 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(std.math.maxInt(usize));
693 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
694 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
695695};
696696
697697pub const Sigaction = extern struct {
698 pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void;
698 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
699699 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
700700
701701 handler: extern union {
lib/std/os/linux.zig+18-23
......@@ -1327,16 +1327,14 @@ pub fn flock(fd: fd_t, operation: i32) usize {
13271327 return syscall2(.flock, @as(usize, @bitCast(@as(isize, fd))), @as(usize, @bitCast(@as(isize, operation))));
13281328}
13291329
1330var vdso_clock_gettime = @as(?*const anyopaque, @ptrCast(&init_vdso_clock_gettime));
1331
13321330// We must follow the C calling convention when we call into the VDSO
1333const vdso_clock_gettime_ty = *align(1) const fn (i32, *timespec) callconv(.C) usize;
1331const VdsoClockGettime = *align(1) const fn (i32, *timespec) callconv(.C) usize;
1332var vdso_clock_gettime: ?VdsoClockGettime = &init_vdso_clock_gettime;
13341333
13351334pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
13361335 if (@hasDecl(VDSO, "CGT_SYM")) {
1337 const ptr = @atomicLoad(?*const anyopaque, &vdso_clock_gettime, .unordered);
1338 if (ptr) |fn_ptr| {
1339 const f = @as(vdso_clock_gettime_ty, @ptrCast(fn_ptr));
1336 const ptr = @atomicLoad(?VdsoClockGettime, &vdso_clock_gettime, .unordered);
1337 if (ptr) |f| {
13401338 const rc = f(clk_id, tp);
13411339 switch (rc) {
13421340 0, @as(usize, @bitCast(-@as(isize, @intFromEnum(E.INVAL)))) => return rc,
......@@ -1348,15 +1346,12 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
13481346}
13491347
13501348fn init_vdso_clock_gettime(clk: i32, ts: *timespec) callconv(.C) usize {
1351 const ptr = @as(?*const anyopaque, @ptrFromInt(vdso.lookup(VDSO.CGT_VER, VDSO.CGT_SYM)));
1349 const ptr: ?VdsoClockGettime = @ptrFromInt(vdso.lookup(VDSO.CGT_VER, VDSO.CGT_SYM));
13521350 // Note that we may not have a VDSO at all, update the stub address anyway
13531351 // so that clock_gettime will fall back on the good old (and slow) syscall
1354 @atomicStore(?*const anyopaque, &vdso_clock_gettime, ptr, .monotonic);
1352 @atomicStore(?VdsoClockGettime, &vdso_clock_gettime, ptr, .monotonic);
13551353 // Call into the VDSO if available
1356 if (ptr) |fn_ptr| {
1357 const f = @as(vdso_clock_gettime_ty, @ptrCast(fn_ptr));
1358 return f(clk, ts);
1359 }
1354 if (ptr) |f| return f(clk, ts);
13601355 return @as(usize, @bitCast(-@as(isize, @intFromEnum(E.NOSYS))));
13611356}
13621357
......@@ -2516,9 +2511,9 @@ pub const SIG = if (is_mips) struct {
25162511 pub const SYS = 31;
25172512 pub const UNUSED = SIG.SYS;
25182513
2519 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
2520 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
2521 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
2514 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
2515 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
2516 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
25222517} else if (is_sparc) struct {
25232518 pub const BLOCK = 1;
25242519 pub const UNBLOCK = 2;
......@@ -2560,9 +2555,9 @@ pub const SIG = if (is_mips) struct {
25602555 pub const PWR = LOST;
25612556 pub const IO = SIG.POLL;
25622557
2563 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
2564 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
2565 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
2558 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
2559 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
2560 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
25662561} else struct {
25672562 pub const BLOCK = 0;
25682563 pub const UNBLOCK = 1;
......@@ -2603,9 +2598,9 @@ pub const SIG = if (is_mips) struct {
26032598 pub const SYS = 31;
26042599 pub const UNUSED = SIG.SYS;
26052600
2606 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
2607 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
2608 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
2601 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
2602 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
2603 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
26092604};
26102605
26112606pub const kernel_rwf = u32;
......@@ -3709,7 +3704,7 @@ pub const all_mask: sigset_t = [_]u32{0xffffffff} ** @typeInfo(sigset_t).Array.l
37093704pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffffffff} ** 30;
37103705
37113706const k_sigaction_funcs = struct {
3712 const handler = ?*const fn (c_int) align(1) callconv(.C) void;
3707 const handler = ?*align(1) const fn (c_int) callconv(.C) void;
37133708 const restorer = *const fn () callconv(.C) void;
37143709};
37153710
......@@ -3736,7 +3731,7 @@ pub const k_sigaction = switch (native_arch) {
37363731
37373732/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
37383733pub const Sigaction = extern struct {
3739 pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void;
3734 pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
37403735 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
37413736
37423737 handler: extern union {
lib/std/zig/AstGen.zig+7-7
......@@ -1369,16 +1369,16 @@ fn fnProtoExpr(
13691369 break :is_var_args false;
13701370 };
13711371
1372 const align_ref: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
1373 break :inst try expr(&block_scope, scope, coerced_align_ri, fn_proto.ast.align_expr);
1374 };
1372 if (fn_proto.ast.align_expr != 0) {
1373 return astgen.failNode(fn_proto.ast.align_expr, "function type cannot have an alignment", .{});
1374 }
13751375
13761376 if (fn_proto.ast.addrspace_expr != 0) {
1377 return astgen.failNode(fn_proto.ast.addrspace_expr, "addrspace not allowed on function prototypes", .{});
1377 return astgen.failNode(fn_proto.ast.addrspace_expr, "function type cannot have an addrspace", .{});
13781378 }
13791379
13801380 if (fn_proto.ast.section_expr != 0) {
1381 return astgen.failNode(fn_proto.ast.section_expr, "linksection not allowed on function prototypes", .{});
1381 return astgen.failNode(fn_proto.ast.section_expr, "function type cannot have a linksection", .{});
13821382 }
13831383
13841384 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
......@@ -1394,7 +1394,7 @@ fn fnProtoExpr(
13941394 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
13951395 const is_inferred_error = token_tags[maybe_bang] == .bang;
13961396 if (is_inferred_error) {
1397 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
1397 return astgen.failTok(maybe_bang, "function type cannot have an inferred error set", .{});
13981398 }
13991399 const ret_ty = try expr(&block_scope, scope, coerced_type_ri, fn_proto.ast.return_type);
14001400
......@@ -1403,7 +1403,7 @@ fn fnProtoExpr(
14031403
14041404 .cc_ref = cc,
14051405 .cc_gz = null,
1406 .align_ref = align_ref,
1406 .align_ref = .none,
14071407 .align_gz = null,
14081408 .ret_ref = ret_ty,
14091409 .ret_gz = null,
src/InternPool.zig+5-23
......@@ -765,16 +765,10 @@ pub const Key = union(enum) {
765765 /// Tells whether a parameter is noalias. See `paramIsNoalias` helper
766766 /// method for accessing this.
767767 noalias_bits: u32,
768 /// `none` indicates the function has the default alignment for
769 /// function code on the target. In this case, this field *must* be set
770 /// to `none`, otherwise the `InternPool` equality and hashing
771 /// functions will return incorrect results.
772 alignment: Alignment,
773768 cc: std.builtin.CallingConvention,
774769 is_var_args: bool,
775770 is_generic: bool,
776771 is_noinline: bool,
777 align_is_generic: bool,
778772 cc_is_generic: bool,
779773 section_is_generic: bool,
780774 addrspace_is_generic: bool,
......@@ -794,7 +788,6 @@ pub const Key = union(enum) {
794788 a.return_type == b.return_type and
795789 a.comptime_bits == b.comptime_bits and
796790 a.noalias_bits == b.noalias_bits and
797 a.alignment == b.alignment and
798791 a.cc == b.cc and
799792 a.is_var_args == b.is_var_args and
800793 a.is_generic == b.is_generic and
......@@ -808,7 +801,6 @@ pub const Key = union(enum) {
808801 std.hash.autoHash(hasher, self.return_type);
809802 std.hash.autoHash(hasher, self.comptime_bits);
810803 std.hash.autoHash(hasher, self.noalias_bits);
811 std.hash.autoHash(hasher, self.alignment);
812804 std.hash.autoHash(hasher, self.cc);
813805 std.hash.autoHash(hasher, self.is_var_args);
814806 std.hash.autoHash(hasher, self.is_generic);
......@@ -3587,18 +3579,16 @@ pub const Tag = enum(u8) {
35873579 flags: Flags,
35883580
35893581 pub const Flags = packed struct(u32) {
3590 alignment: Alignment,
35913582 cc: std.builtin.CallingConvention,
35923583 is_var_args: bool,
35933584 is_generic: bool,
35943585 has_comptime_bits: bool,
35953586 has_noalias_bits: bool,
35963587 is_noinline: bool,
3597 align_is_generic: bool,
35983588 cc_is_generic: bool,
35993589 section_is_generic: bool,
36003590 addrspace_is_generic: bool,
3601 _: u9 = 0,
3591 _: u16 = 0,
36023592 };
36033593 };
36043594
......@@ -4918,11 +4908,9 @@ fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType {
49184908 .return_type = type_function.data.return_type,
49194909 .comptime_bits = comptime_bits,
49204910 .noalias_bits = noalias_bits,
4921 .alignment = type_function.data.flags.alignment,
49224911 .cc = type_function.data.flags.cc,
49234912 .is_var_args = type_function.data.flags.is_var_args,
49244913 .is_noinline = type_function.data.flags.is_noinline,
4925 .align_is_generic = type_function.data.flags.align_is_generic,
49264914 .cc_is_generic = type_function.data.flags.cc_is_generic,
49274915 .section_is_generic = type_function.data.flags.section_is_generic,
49284916 .addrspace_is_generic = type_function.data.flags.addrspace_is_generic,
......@@ -6211,8 +6199,6 @@ pub const GetFuncTypeKey = struct {
62116199 comptime_bits: u32 = 0,
62126200 noalias_bits: u32 = 0,
62136201 /// `null` means generic.
6214 alignment: ?Alignment = .none,
6215 /// `null` means generic.
62166202 cc: ?std.builtin.CallingConvention = .Unspecified,
62176203 is_var_args: bool = false,
62186204 is_generic: bool = false,
......@@ -6242,14 +6228,12 @@ pub fn getFuncType(ip: *InternPool, gpa: Allocator, key: GetFuncTypeKey) Allocat
62426228 .params_len = params_len,
62436229 .return_type = key.return_type,
62446230 .flags = .{
6245 .alignment = key.alignment orelse .none,
62466231 .cc = key.cc orelse .Unspecified,
62476232 .is_var_args = key.is_var_args,
62486233 .has_comptime_bits = key.comptime_bits != 0,
62496234 .has_noalias_bits = key.noalias_bits != 0,
62506235 .is_generic = key.is_generic,
62516236 .is_noinline = key.is_noinline,
6252 .align_is_generic = key.alignment == null,
62536237 .cc_is_generic = key.cc == null,
62546238 .section_is_generic = key.section_is_generic,
62556239 .addrspace_is_generic = key.addrspace_is_generic,
......@@ -6433,14 +6417,12 @@ pub fn getFuncDeclIes(ip: *InternPool, gpa: Allocator, key: GetFuncDeclIesKey) A
64336417 .params_len = params_len,
64346418 .return_type = @enumFromInt(ip.items.len - 2),
64356419 .flags = .{
6436 .alignment = key.alignment orelse .none,
64376420 .cc = key.cc orelse .Unspecified,
64386421 .is_var_args = key.is_var_args,
64396422 .has_comptime_bits = key.comptime_bits != 0,
64406423 .has_noalias_bits = key.noalias_bits != 0,
64416424 .is_generic = key.is_generic,
64426425 .is_noinline = key.is_noinline,
6443 .align_is_generic = key.alignment == null,
64446426 .cc_is_generic = key.cc == null,
64456427 .section_is_generic = key.section_is_generic,
64466428 .addrspace_is_generic = key.addrspace_is_generic,
......@@ -6553,7 +6535,6 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)
65536535 .param_types = arg.param_types,
65546536 .return_type = arg.bare_return_type,
65556537 .noalias_bits = arg.noalias_bits,
6556 .alignment = arg.alignment,
65576538 .cc = arg.cc,
65586539 .is_noinline = arg.is_noinline,
65596540 });
......@@ -6610,6 +6591,7 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)
66106591 func_index,
66116592 func_extra_index,
66126593 func_ty,
6594 arg.alignment,
66136595 arg.section,
66146596 );
66156597}
......@@ -6673,14 +6655,12 @@ pub fn getFuncInstanceIes(
66736655 .params_len = params_len,
66746656 .return_type = error_union_type,
66756657 .flags = .{
6676 .alignment = arg.alignment,
66776658 .cc = arg.cc,
66786659 .is_var_args = false,
66796660 .has_comptime_bits = false,
66806661 .has_noalias_bits = arg.noalias_bits != 0,
66816662 .is_generic = false,
66826663 .is_noinline = arg.is_noinline,
6683 .align_is_generic = false,
66846664 .cc_is_generic = false,
66856665 .section_is_generic = false,
66866666 .addrspace_is_generic = false,
......@@ -6741,6 +6721,7 @@ pub fn getFuncInstanceIes(
67416721 func_index,
67426722 func_extra_index,
67436723 func_ty,
6724 arg.alignment,
67446725 arg.section,
67456726 );
67466727}
......@@ -6752,6 +6733,7 @@ fn finishFuncInstance(
67526733 func_index: Index,
67536734 func_extra_index: u32,
67546735 func_ty: Index,
6736 alignment: Alignment,
67556737 section: OptionalNullTerminatedString,
67566738) Allocator.Error!Index {
67576739 const fn_owner_decl = ip.declPtr(ip.funcDeclOwner(generic_owner));
......@@ -6764,7 +6746,7 @@ fn finishFuncInstance(
67646746 .owns_tv = true,
67656747 .ty = @import("type.zig").Type.fromInterned(func_ty),
67666748 .val = @import("Value.zig").fromInterned(func_index),
6767 .alignment = .none,
6749 .alignment = alignment,
67686750 .@"linksection" = section,
67696751 .@"addrspace" = fn_owner_decl.@"addrspace",
67706752 .analysis = .complete,
src/Module.zig+72-104
......@@ -3596,6 +3596,18 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
35963596
35973597 log.debug("semaDecl '{d}'", .{@intFromEnum(decl_index)});
35983598
3599 const old_has_tv = decl.has_tv;
3600 // The following values are ignored if `!old_has_tv`
3601 const old_ty = decl.ty;
3602 const old_val = decl.val;
3603 const old_align = decl.alignment;
3604 const old_linksection = decl.@"linksection";
3605 const old_addrspace = decl.@"addrspace";
3606 const old_is_inline = if (decl.getOwnedFunction(mod)) |prev_func|
3607 prev_func.analysis(ip).state == .inline_only
3608 else
3609 false;
3610
35993611 const decl_inst = decl.zir_decl_index.unwrap().?.resolve(ip);
36003612
36013613 const gpa = mod.gpa;
......@@ -3733,141 +3745,96 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
37333745 };
37343746 }
37353747
3736 switch (ip.indexToKey(decl_tv.val.toIntern())) {
3737 .func => |func| {
3738 const owns_tv = func.owner_decl == decl_index;
3739 if (owns_tv) {
3740 var prev_type_has_bits = false;
3741 var prev_is_inline = false;
3742 var type_changed = true;
3743
3744 if (decl.has_tv) {
3745 prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits(mod);
3746 type_changed = !decl.ty.eql(decl_tv.ty, mod);
3747 if (decl.getOwnedFunction(mod)) |prev_func| {
3748 prev_is_inline = prev_func.analysis(ip).state == .inline_only;
3749 }
3750 }
3751
3752 decl.ty = decl_tv.ty;
3753 decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod)));
3754 // linksection, align, and addrspace were already set by Sema
3755 decl.has_tv = true;
3756 decl.owns_tv = owns_tv;
3757 decl.analysis = .complete;
3758
3759 const is_inline = decl.ty.fnCallingConvention(mod) == .Inline;
3760 if (decl.is_exported) {
3761 const export_src: LazySrcLoc = .{ .token_offset = @intFromBool(decl.is_pub) };
3762 if (is_inline) {
3763 return sema.fail(&block_scope, export_src, "export of inline function", .{});
3764 }
3765 // The scope needs to have the decl in it.
3766 try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);
3767 }
3768 // TODO: align, linksection, addrspace?
3769 const changed = type_changed or is_inline != prev_is_inline;
3770 return .{
3771 .invalidate_decl_val = changed,
3772 .invalidate_decl_ref = changed,
3773 };
3774 }
3775 },
3776 else => {},
3777 }
3778
3779 decl.owns_tv = false;
3780 var queue_linker_work = false;
3781 var is_extern = false;
3748 var queue_linker_work = true;
3749 var is_func = false;
3750 var is_inline = false;
37823751 switch (decl_tv.val.toIntern()) {
37833752 .generic_poison => unreachable,
37843753 .unreachable_value => unreachable,
37853754 else => switch (ip.indexToKey(decl_tv.val.toIntern())) {
3786 .variable => |variable| if (variable.decl == decl_index) {
3787 decl.owns_tv = true;
3788 queue_linker_work = true;
3755 .variable => |variable| {
3756 decl.owns_tv = variable.decl == decl_index;
3757 queue_linker_work = decl.owns_tv;
37893758 },
37903759
3791 .extern_func => |extern_fn| if (extern_fn.decl == decl_index) {
3792 decl.owns_tv = true;
3793 queue_linker_work = true;
3794 is_extern = true;
3760 .extern_func => |extern_func| {
3761 decl.owns_tv = extern_func.decl == decl_index;
3762 queue_linker_work = decl.owns_tv;
3763 is_func = decl.owns_tv;
37953764 },
37963765
3797 .func => {},
3798
3799 else => {
3800 queue_linker_work = true;
3766 .func => |func| {
3767 decl.owns_tv = func.owner_decl == decl_index;
3768 queue_linker_work = false;
3769 is_inline = decl.owns_tv and decl_tv.ty.fnCallingConvention(mod) == .Inline;
3770 is_func = decl.owns_tv;
38013771 },
3772
3773 else => {},
38023774 },
38033775 }
38043776
3805 const old_has_tv = decl.has_tv;
3806 // The following values are ignored if `!old_has_tv`
3807 const old_ty = decl.ty;
3808 const old_val = decl.val;
3809 const old_align = decl.alignment;
3810 const old_linksection = decl.@"linksection";
3811 const old_addrspace = decl.@"addrspace";
3812
38133777 decl.ty = decl_tv.ty;
38143778 decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod)));
3815 decl.alignment = blk: {
3816 const align_body = decl_bodies.align_body orelse break :blk .none;
3817 const align_ref = try sema.resolveInlineBody(&block_scope, align_body, decl_inst);
3818 break :blk try sema.analyzeAsAlign(&block_scope, align_src, align_ref);
3819 };
3820 decl.@"linksection" = blk: {
3821 const linksection_body = decl_bodies.linksection_body orelse break :blk .none;
3822 const linksection_ref = try sema.resolveInlineBody(&block_scope, linksection_body, decl_inst);
3823 const bytes = try sema.toConstString(&block_scope, section_src, linksection_ref, .{
3824 .needed_comptime_reason = "linksection must be comptime-known",
3825 });
3826 if (mem.indexOfScalar(u8, bytes, 0) != null) {
3827 return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{});
3828 } else if (bytes.len == 0) {
3829 return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{});
3830 }
3831 const section = try ip.getOrPutString(gpa, bytes);
3832 break :blk section.toOptional();
3833 };
3834 decl.@"addrspace" = blk: {
3835 const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(decl_tv.val.toIntern())) {
3836 .variable => .variable,
3837 .extern_func, .func => .function,
3838 else => .constant,
3779 // Function linksection, align, and addrspace were already set by Sema
3780 if (!is_func) {
3781 decl.alignment = blk: {
3782 const align_body = decl_bodies.align_body orelse break :blk .none;
3783 const align_ref = try sema.resolveInlineBody(&block_scope, align_body, decl_inst);
3784 break :blk try sema.analyzeAsAlign(&block_scope, align_src, align_ref);
38393785 };
3786 decl.@"linksection" = blk: {
3787 const linksection_body = decl_bodies.linksection_body orelse break :blk .none;
3788 const linksection_ref = try sema.resolveInlineBody(&block_scope, linksection_body, decl_inst);
3789 const bytes = try sema.toConstString(&block_scope, section_src, linksection_ref, .{
3790 .needed_comptime_reason = "linksection must be comptime-known",
3791 });
3792 if (mem.indexOfScalar(u8, bytes, 0) != null) {
3793 return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{});
3794 } else if (bytes.len == 0) {
3795 return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{});
3796 }
3797 const section = try ip.getOrPutString(gpa, bytes);
3798 break :blk section.toOptional();
3799 };
3800 decl.@"addrspace" = blk: {
3801 const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(decl_tv.val.toIntern())) {
3802 .variable => .variable,
3803 .extern_func, .func => .function,
3804 else => .constant,
3805 };
38403806
3841 const target = sema.mod.getTarget();
3807 const target = sema.mod.getTarget();
38423808
3843 const addrspace_body = decl_bodies.addrspace_body orelse break :blk switch (addrspace_ctx) {
3844 .function => target_util.defaultAddressSpace(target, .function),
3845 .variable => target_util.defaultAddressSpace(target, .global_mutable),
3846 .constant => target_util.defaultAddressSpace(target, .global_constant),
3847 else => unreachable,
3809 const addrspace_body = decl_bodies.addrspace_body orelse break :blk switch (addrspace_ctx) {
3810 .function => target_util.defaultAddressSpace(target, .function),
3811 .variable => target_util.defaultAddressSpace(target, .global_mutable),
3812 .constant => target_util.defaultAddressSpace(target, .global_constant),
3813 else => unreachable,
3814 };
3815 const addrspace_ref = try sema.resolveInlineBody(&block_scope, addrspace_body, decl_inst);
3816 break :blk try sema.analyzeAsAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx);
38483817 };
3849 const addrspace_ref = try sema.resolveInlineBody(&block_scope, addrspace_body, decl_inst);
3850 break :blk try sema.analyzeAsAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx);
3851 };
3818 }
38523819 decl.has_tv = true;
38533820 decl.analysis = .complete;
38543821
38553822 const result: SemaDeclResult = if (old_has_tv) .{
3856 .invalidate_decl_val = !decl.ty.eql(old_ty, mod) or !decl.val.eql(old_val, decl.ty, mod),
3823 .invalidate_decl_val = !decl.ty.eql(old_ty, mod) or
3824 !decl.val.eql(old_val, decl.ty, mod) or
3825 is_inline != old_is_inline,
38573826 .invalidate_decl_ref = !decl.ty.eql(old_ty, mod) or
38583827 decl.alignment != old_align or
38593828 decl.@"linksection" != old_linksection or
3860 decl.@"addrspace" != old_addrspace,
3829 decl.@"addrspace" != old_addrspace or
3830 is_inline != old_is_inline,
38613831 } else .{
38623832 .invalidate_decl_val = true,
38633833 .invalidate_decl_ref = true,
38643834 };
38653835
3866 const has_runtime_bits = is_extern or
3867 (queue_linker_work and try sema.typeHasRuntimeBits(decl.ty));
3868
3836 const has_runtime_bits = queue_linker_work and (is_func or try sema.typeHasRuntimeBits(decl.ty));
38693837 if (has_runtime_bits) {
3870
38713838 // Needed for codegen_decl which will call updateDecl and then the
38723839 // codegen backend wants full access to the Decl Type.
38733840 try sema.resolveTypeFully(decl.ty);
......@@ -3881,6 +3848,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
38813848
38823849 if (decl.is_exported) {
38833850 const export_src: LazySrcLoc = .{ .token_offset = @intFromBool(decl.is_pub) };
3851 if (is_inline) return sema.fail(&block_scope, export_src, "export of inline function", .{});
38843852 // The scope needs to have the decl in it.
38853853 try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);
38863854 }
src/Sema.zig+11-32
......@@ -7605,7 +7605,6 @@ fn analyzeCall(
76057605 .param_types = new_param_types,
76067606 .return_type = owner_info.return_type,
76077607 .noalias_bits = owner_info.noalias_bits,
7608 .alignment = if (owner_info.align_is_generic) null else owner_info.alignment,
76097608 .cc = if (owner_info.cc_is_generic) null else owner_info.cc,
76107609 .is_var_args = owner_info.is_var_args,
76117610 .is_noinline = owner_info.is_noinline,
......@@ -9629,7 +9628,6 @@ fn funcCommon(
96299628 .comptime_bits = comptime_bits,
96309629 .return_type = bare_return_type.toIntern(),
96319630 .cc = cc,
9632 .alignment = alignment,
96339631 .section_is_generic = section == .generic,
96349632 .addrspace_is_generic = address_space == null,
96359633 .is_var_args = var_args,
......@@ -9640,6 +9638,7 @@ fn funcCommon(
96409638 if (is_extern) {
96419639 assert(comptime_bits == 0);
96429640 assert(cc != null);
9641 assert(alignment != null);
96439642 assert(section != .generic);
96449643 assert(address_space != null);
96459644 assert(!is_generic);
......@@ -17623,8 +17622,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1762317622 const field_values = .{
1762417623 // calling_convention: CallingConvention,
1762517624 (try mod.enumValueFieldIndex(callconv_ty, @intFromEnum(func_ty_info.cc))).toIntern(),
17626 // alignment: comptime_int,
17627 (try mod.intValue(Type.comptime_int, ty.abiAlignment(mod).toByteUnits(0))).toIntern(),
1762817625 // is_generic: bool,
1762917626 Value.makeBool(func_ty_info.is_generic).toIntern(),
1763017627 // is_var_args: bool,
......@@ -19701,12 +19698,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1970119698 if (inst_data.size != .One) {
1970219699 return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{});
1970319700 }
19704 const fn_align = mod.typeToFunc(elem_ty).?.alignment;
19705 if (inst_data.flags.has_align and abi_align != .none and fn_align != .none and
19706 abi_align != fn_align)
19707 {
19708 return sema.fail(block, align_src, "function pointer alignment disagrees with function alignment", .{});
19709 }
1971019701 } else if (inst_data.size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) {
1971119702 return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{});
1971219703 } else if (inst_data.size == .C) {
......@@ -21030,7 +21021,6 @@ fn zirReify(
2103021021 .needed_comptime_reason = "operand to @Type must be comptime-known",
2103121022 });
2103221023 const union_val = ip.indexToKey(val.toIntern()).un;
21033 const target = mod.getTarget();
2103421024 if (try Value.fromInterned(union_val.val).anyUndef(mod)) return sema.failWithUseOfUndef(block, src);
2103521025 const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?;
2103621026 switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) {
......@@ -21171,12 +21161,6 @@ fn zirReify(
2117121161 if (ptr_size != .One) {
2117221162 return sema.fail(block, src, "function pointers must be single pointers", .{});
2117321163 }
21174 const fn_align = mod.typeToFunc(elem_ty).?.alignment;
21175 if (abi_align != .none and fn_align != .none and
21176 abi_align != fn_align)
21177 {
21178 return sema.fail(block, src, "function pointer alignment disagrees with function alignment", .{});
21179 }
2118021164 } else if (ptr_size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) {
2118121165 return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{});
2118221166 } else if (ptr_size == .C) {
......@@ -21429,10 +21413,6 @@ fn zirReify(
2142921413 ip,
2143021414 try ip.getOrPutString(gpa, "calling_convention"),
2143121415 ).?);
21432 const alignment_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
21433 ip,
21434 try ip.getOrPutString(gpa, "alignment"),
21435 ).?);
2143621416 const is_generic_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
2143721417 ip,
2143821418 try ip.getOrPutString(gpa, "is_generic"),
......@@ -21461,11 +21441,6 @@ fn zirReify(
2146121441 try sema.checkCallConvSupportsVarArgs(block, src, cc);
2146221442 }
2146321443
21464 const alignment = alignment: {
21465 const alignment = try sema.validateAlignAllowZero(block, src, try alignment_val.toUnsignedIntAdvanced(sema));
21466 const default = target_util.defaultFunctionAlignment(target);
21467 break :alignment if (alignment == default) .none else alignment;
21468 };
2146921444 const return_type = return_type_val.optionalValue(mod) orelse
2147021445 return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});
2147121446
......@@ -21510,7 +21485,6 @@ fn zirReify(
2151021485 .param_types = param_types,
2151121486 .noalias_bits = noalias_bits,
2151221487 .return_type = return_type.toIntern(),
21513 .alignment = alignment,
2151421488 .cc = cc,
2151521489 .is_var_args = is_var_args,
2151621490 });
......@@ -32536,16 +32510,21 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn
3253632510 const mod = sema.mod;
3253732511 try sema.ensureDeclAnalyzed(decl_index);
3253832512
32539 const decl = mod.declPtr(decl_index);
32540 const decl_tv = try decl.typedValue();
32513 const decl_tv = try mod.declPtr(decl_index).typedValue();
32514 const owner_decl = mod.declPtr(switch (mod.intern_pool.indexToKey(decl_tv.val.toIntern())) {
32515 .variable => |variable| variable.decl,
32516 .extern_func => |extern_func| extern_func.decl,
32517 .func => |func| func.owner_decl,
32518 else => decl_index,
32519 });
3254132520 // TODO: if this is a `decl_ref` of a non-variable decl, only depend on decl type
3254232521 try sema.declareDependency(.{ .decl_val = decl_index });
3254332522 const ptr_ty = try sema.ptrType(.{
3254432523 .child = decl_tv.ty.toIntern(),
3254532524 .flags = .{
32546 .alignment = decl.alignment,
32547 .is_const = if (decl.val.getVariable(mod)) |variable| variable.is_const else true,
32548 .address_space = decl.@"addrspace",
32525 .alignment = owner_decl.alignment,
32526 .is_const = if (decl_tv.val.getVariable(mod)) |variable| variable.is_const else true,
32527 .address_space = owner_decl.@"addrspace",
3254932528 },
3255032529 });
3255132530 if (analyze_fn_body) {
src/codegen/c.zig+2-2
......@@ -1635,7 +1635,7 @@ pub const DeclGen = struct {
16351635
16361636 switch (kind) {
16371637 .forward => {},
1638 .complete => if (fn_info.alignment.toByteUnitsOptional()) |a| {
1638 .complete => if (fn_decl.alignment.toByteUnitsOptional()) |a| {
16391639 try w.print("{}zig_align_fn({})", .{ trailing, a });
16401640 trailing = .maybe_space;
16411641 },
......@@ -1666,7 +1666,7 @@ pub const DeclGen = struct {
16661666
16671667 switch (kind) {
16681668 .forward => {
1669 if (fn_info.alignment.toByteUnitsOptional()) |a| {
1669 if (fn_decl.alignment.toByteUnitsOptional()) |a| {
16701670 try w.print(" zig_align_fn({})", .{a});
16711671 }
16721672 switch (name) {
src/codegen/llvm.zig+2-2
......@@ -2952,8 +2952,8 @@ pub const Object = struct {
29522952 else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder),
29532953 }
29542954
2955 if (fn_info.alignment != .none)
2956 function_index.setAlignment(fn_info.alignment.toLlvm(), &o.builder);
2955 if (decl.alignment != .none)
2956 function_index.setAlignment(decl.alignment.toLlvm(), &o.builder);
29572957
29582958 // Function attributes that are independent of analysis results of the function body.
29592959 try o.addCommonFnAttributes(&attributes, owner_mod);
src/main.zig+1
......@@ -4995,6 +4995,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
49954995 } else .{
49964996 .root = .{
49974997 .root_dir = zig_lib_directory,
4998 .sub_path = "compiler",
49984999 },
49995000 .root_src_path = "build_runner.zig",
50005001 };
src/type.zig+1-9
......@@ -396,9 +396,6 @@ pub const Type = struct {
396396 try writer.writeAll("...");
397397 }
398398 try writer.writeAll(") ");
399 if (fn_info.alignment.toByteUnitsOptional()) |a| {
400 try writer.print("align({d}) ", .{a});
401 }
402399 if (fn_info.cc != .Unspecified) {
403400 try writer.writeAll("callconv(.");
404401 try writer.writeAll(@tagName(fn_info.cc));
......@@ -949,12 +946,7 @@ pub const Type = struct {
949946 },
950947
951948 // represents machine code; not a pointer
952 .func_type => |func_type| return .{
953 .scalar = if (func_type.alignment != .none)
954 func_type.alignment
955 else
956 target_util.defaultFunctionAlignment(target),
957 },
949 .func_type => return .{ .scalar = target_util.defaultFunctionAlignment(target) },
958950
959951 .simple_type => |t| switch (t) {
960952 .bool,
stage1/zig.h+157-92
......@@ -25,11 +25,15 @@ typedef char bool;
2525#endif
2626#endif
2727
28#define zig_concat(lhs, rhs) lhs##rhs
29#define zig_expand_concat(lhs, rhs) zig_concat(lhs, rhs)
30
2831#if defined(__has_builtin)
2932#define zig_has_builtin(builtin) __has_builtin(__builtin_##builtin)
3033#else
3134#define zig_has_builtin(builtin) 0
3235#endif
36#define zig_expand_has_builtin(b) zig_has_builtin(b)
3337
3438#if defined(__has_attribute)
3539#define zig_has_attribute(attribute) __has_attribute(attribute)
......@@ -112,7 +116,7 @@ typedef char bool;
112116#define zig_never_tail zig_never_tail_unavailable
113117#endif
114118
115#if zig_has_attribute(always_inline)
119#if zig_has_attribute(musttail)
116120#define zig_always_tail __attribute__((musttail))
117121#else
118122#define zig_always_tail zig_always_tail_unavailable
......@@ -180,20 +184,58 @@ typedef char bool;
180184#define zig_extern extern
181185#endif
182186
183#if zig_has_attribute(alias)
184#define zig_export(sig, symbol, name) zig_extern sig __attribute__((alias(symbol)))
185#elif _MSC_VER
187#if _MSC_VER
186188#if _M_X64
187#define zig_export(sig, symbol, name) sig;\
188 __pragma(comment(linker, "/alternatename:" name "=" symbol ))
189#define zig_mangle_c(symbol) symbol
189190#else /*_M_X64 */
190#define zig_export(sig, symbol, name) sig;\
191 __pragma(comment(linker, "/alternatename:_" name "=_" symbol ))
191#define zig_mangle_c(symbol) "_" symbol
192192#endif /*_M_X64 */
193#else /* _MSC_VER */
194#if __APPLE__
195#define zig_mangle_c(symbol) "_" symbol
196#else /* __APPLE__ */
197#define zig_mangle_c(symbol) symbol
198#endif /* __APPLE__ */
199#endif /* _MSC_VER */
200
201#if zig_has_attribute(alias) && !__APPLE__
202#define zig_export(symbol, name) __attribute__((alias(symbol)))
203#elif _MSC_VER
204#define zig_export(symbol, name) ; \
205 __pragma(comment(linker, "/alternatename:" zig_mangle_c(name) "=" zig_mangle_c(symbol)))
193206#else
194#define zig_export(sig, symbol, name) __asm(name " = " symbol)
207#define zig_export(symbol, name) ; \
208 __asm(zig_mangle_c(name) " = " zig_mangle_c(symbol))
195209#endif
196210
211#if _MSC_VER
212#define zig_mangled_tentative(mangled, unmangled)
213#define zig_mangled_final(mangled, unmangled) ; \
214 zig_export(#mangled, unmangled)
215#define zig_mangled_export(mangled, unmangled, symbol) \
216 zig_export(unmangled, #mangled) \
217 zig_export(symbol, unmangled)
218#else /* _MSC_VER */
219#define zig_mangled_tentative(mangled, unmangled) __asm(zig_mangle_c(unmangled))
220#define zig_mangled_final(mangled, unmangled) zig_mangled_tentative(mangled, unmangled)
221#define zig_mangled_export(mangled, unmangled, symbol) \
222 zig_mangled_final(mangled, unmangled) \
223 zig_export(symbol, unmangled)
224#endif /* _MSC_VER */
225
226#if _MSC_VER
227#define zig_import(Type, fn_name, libc_name, sig_args, call_args) zig_extern Type fn_name sig_args;\
228 __pragma(comment(linker, "/alternatename:" zig_mangle_c(#fn_name) "=" zig_mangle_c(#libc_name)));
229#define zig_import_builtin(Type, fn_name, libc_name, sig_args, call_args) zig_import(Type, fn_name, sig_args, call_args)
230#else /* _MSC_VER */
231#define zig_import(Type, fn_name, libc_name, sig_args, call_args) zig_extern Type fn_name sig_args __asm(zig_mangle_c(#libc_name));
232#define zig_import_builtin(Type, fn_name, libc_name, sig_args, call_args) zig_extern Type libc_name sig_args; \
233 static inline Type fn_name sig_args { return libc_name call_args; }
234#endif
235
236#define zig_expand_import_0(Type, fn_name, libc_name, sig_args, call_args) zig_import(Type, fn_name, libc_name, sig_args, call_args)
237#define zig_expand_import_1(Type, fn_name, libc_name, sig_args, call_args) zig_import_builtin(Type, fn_name, libc_name, sig_args, call_args)
238
197239#if zig_has_attribute(weak) || defined(zig_gnuc)
198240#define zig_weak_linkage __attribute__((weak))
199241#define zig_weak_linkage_fn __attribute__((weak))
......@@ -267,9 +309,6 @@ typedef char bool;
267309#define zig_wasm_memory_grow(index, delta) zig_unimplemented()
268310#endif
269311
270#define zig_concat(lhs, rhs) lhs##rhs
271#define zig_expand_concat(lhs, rhs) zig_concat(lhs, rhs)
272
273312#if __STDC_VERSION__ >= 201112L
274313#define zig_noreturn _Noreturn
275314#elif zig_has_attribute(noreturn) || defined(zig_gnuc)
......@@ -2163,7 +2202,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo
21632202 const uint8_t *rhs_bytes = rhs;
21642203 uint16_t byte_offset = 0;
21652204 uint16_t remaining_bytes = zig_int_bytes(bits);
2166 uint16_t top_bits = remaining_bytes * 8 - bits;
2205 uint8_t top_bits = (uint8_t)(remaining_bytes * 8 - bits);
21672206 bool overflow = false;
21682207
21692208#if zig_big_endian
......@@ -2171,7 +2210,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo
21712210#endif
21722211
21732212 while (remaining_bytes >= 128 / CHAR_BIT) {
2174 uint16_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0);
2213 uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0);
21752214
21762215#if zig_big_endian
21772216 byte_offset -= 128 / CHAR_BIT;
......@@ -2211,7 +2250,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo
22112250 }
22122251
22132252 while (remaining_bytes >= 64 / CHAR_BIT) {
2214 uint16_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0);
2253 uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0);
22152254
22162255#if zig_big_endian
22172256 byte_offset -= 64 / CHAR_BIT;
......@@ -2251,7 +2290,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo
22512290 }
22522291
22532292 while (remaining_bytes >= 32 / CHAR_BIT) {
2254 uint16_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0);
2293 uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0);
22552294
22562295#if zig_big_endian
22572296 byte_offset -= 32 / CHAR_BIT;
......@@ -2291,7 +2330,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo
22912330 }
22922331
22932332 while (remaining_bytes >= 16 / CHAR_BIT) {
2294 uint16_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0);
2333 uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0);
22952334
22962335#if zig_big_endian
22972336 byte_offset -= 16 / CHAR_BIT;
......@@ -2331,7 +2370,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo
23312370 }
23322371
23332372 while (remaining_bytes >= 8 / CHAR_BIT) {
2334 uint16_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0);
2373 uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0);
23352374
23362375#if zig_big_endian
23372376 byte_offset -= 8 / CHAR_BIT;
......@@ -2379,7 +2418,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo
23792418 const uint8_t *rhs_bytes = rhs;
23802419 uint16_t byte_offset = 0;
23812420 uint16_t remaining_bytes = zig_int_bytes(bits);
2382 uint16_t top_bits = remaining_bytes * 8 - bits;
2421 uint8_t top_bits = (uint8_t)(remaining_bytes * 8 - bits);
23832422 bool overflow = false;
23842423
23852424#if zig_big_endian
......@@ -2387,7 +2426,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo
23872426#endif
23882427
23892428 while (remaining_bytes >= 128 / CHAR_BIT) {
2390 uint16_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0);
2429 uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0);
23912430
23922431#if zig_big_endian
23932432 byte_offset -= 128 / CHAR_BIT;
......@@ -2427,7 +2466,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo
24272466 }
24282467
24292468 while (remaining_bytes >= 64 / CHAR_BIT) {
2430 uint16_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0);
2469 uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0);
24312470
24322471#if zig_big_endian
24332472 byte_offset -= 64 / CHAR_BIT;
......@@ -2467,7 +2506,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo
24672506 }
24682507
24692508 while (remaining_bytes >= 32 / CHAR_BIT) {
2470 uint16_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0);
2509 uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0);
24712510
24722511#if zig_big_endian
24732512 byte_offset -= 32 / CHAR_BIT;
......@@ -2507,7 +2546,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo
25072546 }
25082547
25092548 while (remaining_bytes >= 16 / CHAR_BIT) {
2510 uint16_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0);
2549 uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0);
25112550
25122551#if zig_big_endian
25132552 byte_offset -= 16 / CHAR_BIT;
......@@ -2547,7 +2586,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo
25472586 }
25482587
25492588 while (remaining_bytes >= 8 / CHAR_BIT) {
2550 uint16_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0);
2589 uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0);
25512590
25522591#if zig_big_endian
25532592 byte_offset -= 8 / CHAR_BIT;
......@@ -3093,6 +3132,7 @@ ypedef uint32_t zig_f32;
30933132
30943133#define zig_has_f64 1
30953134#define zig_libc_name_f64(name) name
3135
30963136#if _MSC_VER
30973137#define zig_init_special_f64(sign, name, arg, repr) sign zig_make_f64(zig_msvc_flt_##name, )
30983138#else
......@@ -3336,31 +3376,31 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0)))
33363376 zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, sub, -) \
33373377 zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, mul, *) \
33383378 zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, div, /) \
3339 zig_extern zig_f##w zig_libc_name_f##w(sqrt)(zig_f##w); \
3340 zig_extern zig_f##w zig_libc_name_f##w(sin)(zig_f##w); \
3341 zig_extern zig_f##w zig_libc_name_f##w(cos)(zig_f##w); \
3342 zig_extern zig_f##w zig_libc_name_f##w(tan)(zig_f##w); \
3343 zig_extern zig_f##w zig_libc_name_f##w(exp)(zig_f##w); \
3344 zig_extern zig_f##w zig_libc_name_f##w(exp2)(zig_f##w); \
3345 zig_extern zig_f##w zig_libc_name_f##w(log)(zig_f##w); \
3346 zig_extern zig_f##w zig_libc_name_f##w(log2)(zig_f##w); \
3347 zig_extern zig_f##w zig_libc_name_f##w(log10)(zig_f##w); \
3348 zig_extern zig_f##w zig_libc_name_f##w(fabs)(zig_f##w); \
3349 zig_extern zig_f##w zig_libc_name_f##w(floor)(zig_f##w); \
3350 zig_extern zig_f##w zig_libc_name_f##w(ceil)(zig_f##w); \
3351 zig_extern zig_f##w zig_libc_name_f##w(round)(zig_f##w); \
3352 zig_extern zig_f##w zig_libc_name_f##w(trunc)(zig_f##w); \
3353 zig_extern zig_f##w zig_libc_name_f##w(fmod)(zig_f##w, zig_f##w); \
3354 zig_extern zig_f##w zig_libc_name_f##w(fmin)(zig_f##w, zig_f##w); \
3355 zig_extern zig_f##w zig_libc_name_f##w(fmax)(zig_f##w, zig_f##w); \
3356 zig_extern zig_f##w zig_libc_name_f##w(fma)(zig_f##w, zig_f##w, zig_f##w); \
3379 zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(sqrt)))(zig_f##w, zig_float_fn_f##w##_sqrt, zig_libc_name_f##w(sqrt), (zig_f##w x), (x)) \
3380 zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(sin)))(zig_f##w, zig_float_fn_f##w##_sin, zig_libc_name_f##w(sin), (zig_f##w x), (x)) \
3381 zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(cos)))(zig_f##w, zig_float_fn_f##w##_cos, zig_libc_name_f##w(cos), (zig_f##w x), (x)) \
3382 zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(tan)))(zig_f##w, zig_float_fn_f##w##_tan, zig_libc_name_f##w(tan), (zig_f##w x), (x)) \
3383 zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(exp)))(zig_f##w, zig_float_fn_f##w##_exp, zig_libc_name_f##w(exp), (zig_f##w x), (x)) \
3384 zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(exp2)))(zig_f##w, zig_float_fn_f##w##_exp2, zig_libc_name_f##w(exp2), (zig_f##w x), (x)) \
3385 zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(log)))(zig_f##w, zig_float_fn_f##w##_log, zig_libc_name_f##w(log), (zig_f##w x), (x)) \
3386 zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(log2)))(zig_f##w, zig_float_fn_f##w##_log2, zig_libc_name_f##w(log2), (zig_f##w x), (x)) \
3387 zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(log10)))(zig_f##w, zig_float_fn_f##w##_log10, zig_libc_name_f##w(log10), (zig_f##w x), (x)) \
3388 zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fabs)))(zig_f##w, zig_float_fn_f##w##_fabs, zig_libc_name_f##w(fabs), (zig_f##w x), (x)) \
3389 zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(floor)))(zig_f##w, zig_float_fn_f##w##_floor, zig_libc_name_f##w(floor), (zig_f##w x), (x)) \
3390 zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(ceil)))(zig_f##w, zig_float_fn_f##w##_ceil, zig_libc_name_f##w(ceil), (zig_f##w x), (x)) \
3391 zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(round)))(zig_f##w, zig_float_fn_f##w##_round, zig_libc_name_f##w(round), (zig_f##w x), (x)) \
3392 zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(trunc)))(zig_f##w, zig_float_fn_f##w##_trunc, zig_libc_name_f##w(trunc), (zig_f##w x), (x)) \
3393 zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fmod)))(zig_f##w, zig_float_fn_f##w##_fmod, zig_libc_name_f##w(fmod), (zig_f##w x, zig_f##w y), (x, y)) \
3394 zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fmin)))(zig_f##w, zig_float_fn_f##w##_fmin, zig_libc_name_f##w(fmin), (zig_f##w x, zig_f##w y), (x, y)) \
3395 zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fmax)))(zig_f##w, zig_float_fn_f##w##_fmax, zig_libc_name_f##w(fmax), (zig_f##w x, zig_f##w y), (x, y)) \
3396 zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fma)))(zig_f##w, zig_float_fn_f##w##_fma, zig_libc_name_f##w(fma), (zig_f##w x, zig_f##w y, zig_f##w z), (x, y, z)) \
33573397\
33583398 static inline zig_f##w zig_div_trunc_f##w(zig_f##w lhs, zig_f##w rhs) { \
3359 return zig_libc_name_f##w(trunc)(zig_div_f##w(lhs, rhs)); \
3399 return zig_float_fn_f##w##_trunc(zig_div_f##w(lhs, rhs)); \
33603400 } \
33613401\
33623402 static inline zig_f##w zig_div_floor_f##w(zig_f##w lhs, zig_f##w rhs) { \
3363 return zig_libc_name_f##w(floor)(zig_div_f##w(lhs, rhs)); \
3403 return zig_float_fn_f##w##_floor(zig_div_f##w(lhs, rhs)); \
33643404 } \
33653405\
33663406 static inline zig_f##w zig_mod_f##w(zig_f##w lhs, zig_f##w rhs) { \
......@@ -3437,129 +3477,134 @@ zig_float_builtins(64)
34373477/* Note that zig_atomicrmw_expected is needed to handle aliasing between res and arg. */
34383478#define zig_atomicrmw_xchg_float(res, obj, arg, order, Type, ReprType) do { \
34393479 zig_##Type zig_atomicrmw_expected; \
3440 zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
3441 while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, memory_order_relaxed, Type, ReprType)); \
3480 zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
3481 while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, zig_memory_order_relaxed, Type, ReprType)); \
34423482 res = zig_atomicrmw_expected; \
34433483} while (0)
34443484#define zig_atomicrmw_add_float(res, obj, arg, order, Type, ReprType) do { \
34453485 zig_##Type zig_atomicrmw_expected; \
34463486 zig_##Type zig_atomicrmw_desired; \
3447 zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
3487 zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
34483488 do { \
34493489 zig_atomicrmw_desired = zig_add_##Type(zig_atomicrmw_expected, arg); \
3450 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
3490 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
34513491 res = zig_atomicrmw_expected; \
34523492} while (0)
34533493#define zig_atomicrmw_sub_float(res, obj, arg, order, Type, ReprType) do { \
34543494 zig_##Type zig_atomicrmw_expected; \
34553495 zig_##Type zig_atomicrmw_desired; \
3456 zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
3496 zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
34573497 do { \
34583498 zig_atomicrmw_desired = zig_sub_##Type(zig_atomicrmw_expected, arg); \
3459 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
3499 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
34603500 res = zig_atomicrmw_expected; \
34613501} while (0)
34623502#define zig_atomicrmw_min_float(res, obj, arg, order, Type, ReprType) do { \
34633503 zig_##Type zig_atomicrmw_expected; \
34643504 zig_##Type zig_atomicrmw_desired; \
3465 zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
3505 zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
34663506 do { \
3467 zig_atomicrmw_desired = zig_libc_name_##Type(fmin)(zig_atomicrmw_expected, arg); \
3468 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
3507 zig_atomicrmw_desired = zig_float_fn_##Type##_fmin(zig_atomicrmw_expected, arg); \
3508 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
34693509 res = zig_atomicrmw_expected; \
34703510} while (0)
34713511#define zig_atomicrmw_max_float(res, obj, arg, order, Type, ReprType) do { \
34723512 zig_##Type zig_atomicrmw_expected; \
34733513 zig_##Type zig_atomicrmw_desired; \
3474 zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
3514 zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
34753515 do { \
3476 zig_atomicrmw_desired = zig_libc_name_##Type(fmax)(zig_atomicrmw_expected, arg); \
3477 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
3516 zig_atomicrmw_desired = zig_float_fn_##Type##_fmax(zig_atomicrmw_expected, arg); \
3517 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
34783518 res = zig_atomicrmw_expected; \
34793519} while (0)
34803520
34813521#define zig_atomicrmw_xchg_int128(res, obj, arg, order, Type, ReprType) do { \
34823522 zig_##Type zig_atomicrmw_expected; \
3483 zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
3484 while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, memory_order_relaxed, Type, ReprType)); \
3523 zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
3524 while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, zig_memory_order_relaxed, Type, ReprType)); \
34853525 res = zig_atomicrmw_expected; \
34863526} while (0)
34873527#define zig_atomicrmw_add_int128(res, obj, arg, order, Type, ReprType) do { \
34883528 zig_##Type zig_atomicrmw_expected; \
34893529 zig_##Type zig_atomicrmw_desired; \
3490 zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
3530 zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
34913531 do { \
34923532 zig_atomicrmw_desired = zig_add_##Type(zig_atomicrmw_expected, arg); \
3493 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
3533 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
34943534 res = zig_atomicrmw_expected; \
34953535} while (0)
34963536#define zig_atomicrmw_sub_int128(res, obj, arg, order, Type, ReprType) do { \
34973537 zig_##Type zig_atomicrmw_expected; \
34983538 zig_##Type zig_atomicrmw_desired; \
3499 zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
3539 zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
35003540 do { \
35013541 zig_atomicrmw_desired = zig_sub_##Type(zig_atomicrmw_expected, arg); \
3502 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
3542 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
35033543 res = zig_atomicrmw_expected; \
35043544} while (0)
35053545#define zig_atomicrmw_and_int128(res, obj, arg, order, Type, ReprType) do { \
35063546 zig_##Type zig_atomicrmw_expected; \
35073547 zig_##Type zig_atomicrmw_desired; \
3508 zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
3548 zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
35093549 do { \
35103550 zig_atomicrmw_desired = zig_and_##Type(zig_atomicrmw_expected, arg); \
3511 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
3551 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
35123552 res = zig_atomicrmw_expected; \
35133553} while (0)
35143554#define zig_atomicrmw_nand_int128(res, obj, arg, order, Type, ReprType) do { \
35153555 zig_##Type zig_atomicrmw_expected; \
35163556 zig_##Type zig_atomicrmw_desired; \
3517 zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
3557 zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
35183558 do { \
35193559 zig_atomicrmw_desired = zig_not_##Type(zig_and_##Type(zig_atomicrmw_expected, arg), 128); \
3520 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
3560 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
35213561 res = zig_atomicrmw_expected; \
35223562} while (0)
35233563#define zig_atomicrmw_or_int128(res, obj, arg, order, Type, ReprType) do { \
35243564 zig_##Type zig_atomicrmw_expected; \
35253565 zig_##Type zig_atomicrmw_desired; \
3526 zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
3566 zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
35273567 do { \
35283568 zig_atomicrmw_desired = zig_or_##Type(zig_atomicrmw_expected, arg); \
3529 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
3569 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
35303570 res = zig_atomicrmw_expected; \
35313571} while (0)
35323572#define zig_atomicrmw_xor_int128(res, obj, arg, order, Type, ReprType) do { \
35333573 zig_##Type zig_atomicrmw_expected; \
35343574 zig_##Type zig_atomicrmw_desired; \
3535 zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
3575 zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
35363576 do { \
35373577 zig_atomicrmw_desired = zig_xor_##Type(zig_atomicrmw_expected, arg); \
3538 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
3578 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
35393579 res = zig_atomicrmw_expected; \
35403580} while (0)
35413581#define zig_atomicrmw_min_int128(res, obj, arg, order, Type, ReprType) do { \
35423582 zig_##Type zig_atomicrmw_expected; \
35433583 zig_##Type zig_atomicrmw_desired; \
3544 zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
3584 zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
35453585 do { \
35463586 zig_atomicrmw_desired = zig_min_##Type(zig_atomicrmw_expected, arg); \
3547 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
3587 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
35483588 res = zig_atomicrmw_expected; \
35493589} while (0)
35503590#define zig_atomicrmw_max_int128(res, obj, arg, order, Type, ReprType) do { \
35513591 zig_##Type zig_atomicrmw_expected; \
35523592 zig_##Type zig_atomicrmw_desired; \
3553 zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
3593 zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
35543594 do { \
35553595 zig_atomicrmw_desired = zig_max_##Type(zig_atomicrmw_expected, arg); \
3556 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
3596 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
35573597 res = zig_atomicrmw_expected; \
35583598} while (0)
35593599
35603600#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
35613601#include <stdatomic.h>
35623602typedef enum memory_order zig_memory_order;
3603#define zig_memory_order_relaxed memory_order_relaxed
3604#define zig_memory_order_acquire memory_order_acquire
3605#define zig_memory_order_release memory_order_release
3606#define zig_memory_order_acq_rel memory_order_acq_rel
3607#define zig_memory_order_seq_cst memory_order_seq_cst
35633608#define zig_atomic(Type) _Atomic(Type)
35643609#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail)
35653610#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_weak_explicit (obj, &(expected), desired, succ, fail)
......@@ -3583,12 +3628,11 @@ typedef enum memory_order zig_memory_order;
35833628#define zig_fence(order) atomic_thread_fence(order)
35843629#elif defined(__GNUC__)
35853630typedef int zig_memory_order;
3586#define memory_order_relaxed __ATOMIC_RELAXED
3587#define memory_order_consume __ATOMIC_CONSUME
3588#define memory_order_acquire __ATOMIC_ACQUIRE
3589#define memory_order_release __ATOMIC_RELEASE
3590#define memory_order_acq_rel __ATOMIC_ACQ_REL
3591#define memory_order_seq_cst __ATOMIC_SEQ_CST
3631#define zig_memory_order_relaxed __ATOMIC_RELAXED
3632#define zig_memory_order_acquire __ATOMIC_ACQUIRE
3633#define zig_memory_order_release __ATOMIC_RELEASE
3634#define zig_memory_order_acq_rel __ATOMIC_ACQ_REL
3635#define zig_memory_order_seq_cst __ATOMIC_SEQ_CST
35923636#define zig_atomic(Type) Type
35933637#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, &(expected), &(desired), false, succ, fail)
35943638#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, &(expected), &(desired), true, succ, fail)
......@@ -3607,12 +3651,11 @@ typedef int zig_memory_order;
36073651#define zig_atomicrmw_xchg_float zig_atomicrmw_xchg
36083652#define zig_fence(order) __atomic_thread_fence(order)
36093653#elif _MSC_VER && (_M_IX86 || _M_X64)
3610#define memory_order_relaxed 0
3611#define memory_order_consume 1
3612#define memory_order_acquire 2
3613#define memory_order_release 3
3614#define memory_order_acq_rel 4
3615#define memory_order_seq_cst 5
3654#define zig_memory_order_relaxed 0
3655#define zig_memory_order_acquire 2
3656#define zig_memory_order_release 3
3657#define zig_memory_order_acq_rel 4
3658#define zig_memory_order_seq_cst 5
36163659#define zig_atomic(Type) Type
36173660#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_msvc_cmpxchg_##Type(obj, &(expected), desired)
36183661#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) zig_cmpxchg_strong(obj, expected, desired, succ, fail, Type, ReprType)
......@@ -3634,12 +3677,11 @@ typedef int zig_memory_order;
36343677#endif
36353678/* TODO: _MSC_VER && (_M_ARM || _M_ARM64) */
36363679#else
3637#define memory_order_relaxed 0
3638#define memory_order_consume 1
3639#define memory_order_acquire 2
3640#define memory_order_release 3
3641#define memory_order_acq_rel 4
3642#define memory_order_seq_cst 5
3680#define zig_memory_order_relaxed 0
3681#define zig_memory_order_acquire 2
3682#define zig_memory_order_release 3
3683#define zig_memory_order_acq_rel 4
3684#define zig_memory_order_seq_cst 5
36433685#define zig_atomic(Type) Type
36443686#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable
36453687#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable
......@@ -3830,9 +3872,32 @@ static inline bool zig_msvc_cmpxchg_u128(zig_u128 volatile* obj, zig_u128* expec
38303872 return _InterlockedCompareExchange128((__int64 volatile*)obj, (__int64)zig_hi_u128(desired), (__int64)zig_lo_u128(desired), (__int64*)expected);
38313873}
38323874
3875static inline zig_u128 zig_msvc_atomic_load_u128(zig_u128 volatile* obj) {
3876 zig_u128 expected = zig_make_u128(UINT64_C(0), UINT64_C(0));
3877 (void)zig_cmpxchg_strong(obj, expected, expected, zig_memory_order_seq_cst, zig_memory_order_seq_cst, u128, zig_u128);
3878 return expected;
3879}
3880
3881static inline void zig_msvc_atomic_store_u128(zig_u128 volatile* obj, zig_u128 arg) {
3882 zig_u128 expected = zig_make_u128(UINT64_C(0), UINT64_C(0));
3883 while (!zig_cmpxchg_weak(obj, expected, arg, zig_memory_order_seq_cst, zig_memory_order_seq_cst, u128, zig_u128));
3884}
3885
38333886static inline bool zig_msvc_cmpxchg_i128(zig_i128 volatile* obj, zig_i128* expected, zig_i128 desired) {
38343887 return _InterlockedCompareExchange128((__int64 volatile*)obj, (__int64)zig_hi_i128(desired), (__int64)zig_lo_i128(desired), (__int64*)expected);
38353888}
3889
3890static inline zig_i128 zig_msvc_atomic_load_i128(zig_i128 volatile* obj) {
3891 zig_i128 expected = zig_make_i128(INT64_C(0), UINT64_C(0));
3892 (void)zig_cmpxchg_strong(obj, expected, expected, zig_memory_order_seq_cst, zig_memory_order_seq_cst, i128, zig_i128);
3893 return expected;
3894}
3895
3896static inline void zig_msvc_atomic_store_i128(zig_i128 volatile* obj, zig_i128 arg) {
3897 zig_i128 expected = zig_make_i128(INT64_C(0), UINT64_C(0));
3898 while (!zig_cmpxchg_weak(obj, expected, arg, zig_memory_order_seq_cst, zig_memory_order_seq_cst, i128, zig_i128));
3899}
3900
38363901#endif /* _M_IX86 */
38373902
38383903#endif /* _MSC_VER && (_M_IX86 || _M_X64) */
stage1/zig1.wasm
Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ
test/behavior/align.zig+22-14
......@@ -311,12 +311,6 @@ test "page aligned array on stack" {
311311 try expect(number2 == 43);
312312}
313313
314fn derp() align(@sizeOf(usize) * 2) i32 {
315 return 1234;
316}
317fn noop1() align(1) void {}
318fn noop4() align(4) void {}
319
320314test "function alignment" {
321315 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
322316 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
......@@ -325,11 +319,25 @@ test "function alignment" {
325319 // function alignment is a compile error on wasm32/wasm64
326320 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
327321
328 try expect(derp() == 1234);
329 try expect(@TypeOf(noop1) == fn () align(1) void);
330 try expect(@TypeOf(noop4) == fn () align(4) void);
331 noop1();
332 noop4();
322 const S = struct {
323 fn alignExpr() align(@sizeOf(usize) * 2) i32 {
324 return 1234;
325 }
326 fn align1() align(1) void {}
327 fn align4() align(4) void {}
328 };
329
330 try expect(S.alignExpr() == 1234);
331 try expect(@TypeOf(S.alignExpr) == fn () i32);
332 try expect(@TypeOf(&S.alignExpr) == *align(@sizeOf(usize) * 2) const fn () i32);
333
334 S.align1();
335 try expect(@TypeOf(S.align1) == fn () void);
336 try expect(@TypeOf(&S.align1) == *align(1) const fn () void);
337
338 S.align4();
339 try expect(@TypeOf(S.align4) == fn () void);
340 try expect(@TypeOf(&S.align4) == *align(4) const fn () void);
333341}
334342
335343test "implicitly decreasing fn alignment" {
......@@ -345,7 +353,7 @@ test "implicitly decreasing fn alignment" {
345353 try testImplicitlyDecreaseFnAlign(alignedBig, 5678);
346354}
347355
348fn testImplicitlyDecreaseFnAlign(ptr: *const fn () align(1) i32, answer: i32) !void {
356fn testImplicitlyDecreaseFnAlign(ptr: *align(1) const fn () i32, answer: i32) !void {
349357 try expect(ptr() == answer);
350358}
351359
......@@ -368,10 +376,10 @@ test "@alignCast functions" {
368376
369377 try expect(fnExpectsOnly1(simple4) == 0x19);
370378}
371fn fnExpectsOnly1(ptr: *const fn () align(1) i32) i32 {
379fn fnExpectsOnly1(ptr: *align(1) const fn () i32) i32 {
372380 return fnExpects4(@alignCast(ptr));
373381}
374fn fnExpects4(ptr: *const fn () align(4) i32) i32 {
382fn fnExpects4(ptr: *align(4) const fn () i32) i32 {
375383 return ptr();
376384}
377385fn simple4() align(4) i32 {
test/behavior/type.zig-2
......@@ -527,7 +527,6 @@ test "Type.Fn" {
527527 {
528528 const fn_info = std.builtin.Type{ .Fn = .{
529529 .calling_convention = .C,
530 .alignment = 0,
531530 .is_generic = false,
532531 .is_var_args = false,
533532 .return_type = void,
......@@ -643,7 +642,6 @@ test "reified function type params initialized with field pointer" {
643642 const Bar = @Type(.{
644643 .Fn = .{
645644 .calling_convention = .Unspecified,
646 .alignment = 0,
647645 .is_generic = false,
648646 .is_var_args = false,
649647 .return_type = void,
test/behavior/type_info.zig+32-10
......@@ -356,16 +356,38 @@ test "type info: function type info" {
356356}
357357
358358fn testFunction() !void {
359 const fn_info = @typeInfo(@TypeOf(typeInfoFoo));
360 try expect(fn_info == .Fn);
361 try expect(fn_info.Fn.alignment > 0);
362 try expect(fn_info.Fn.calling_convention == .C);
363 try expect(!fn_info.Fn.is_generic);
364 try expect(fn_info.Fn.params.len == 2);
365 try expect(fn_info.Fn.is_var_args);
366 try expect(fn_info.Fn.return_type.? == usize);
367 const fn_aligned_info = @typeInfo(@TypeOf(typeInfoFooAligned));
368 try expect(fn_aligned_info.Fn.alignment == 4);
359 const foo_fn_type = @TypeOf(typeInfoFoo);
360 const foo_fn_info = @typeInfo(foo_fn_type);
361 try expect(foo_fn_info.Fn.calling_convention == .C);
362 try expect(!foo_fn_info.Fn.is_generic);
363 try expect(foo_fn_info.Fn.params.len == 2);
364 try expect(foo_fn_info.Fn.is_var_args);
365 try expect(foo_fn_info.Fn.return_type.? == usize);
366 const foo_ptr_fn_info = @typeInfo(@TypeOf(&typeInfoFoo));
367 try expect(foo_ptr_fn_info.Pointer.size == .One);
368 try expect(foo_ptr_fn_info.Pointer.is_const);
369 try expect(!foo_ptr_fn_info.Pointer.is_volatile);
370 try expect(foo_ptr_fn_info.Pointer.address_space == .generic);
371 try expect(foo_ptr_fn_info.Pointer.child == foo_fn_type);
372 try expect(!foo_ptr_fn_info.Pointer.is_allowzero);
373 try expect(foo_ptr_fn_info.Pointer.sentinel == null);
374
375 const aligned_foo_fn_type = @TypeOf(typeInfoFooAligned);
376 const aligned_foo_fn_info = @typeInfo(aligned_foo_fn_type);
377 try expect(aligned_foo_fn_info.Fn.calling_convention == .C);
378 try expect(!aligned_foo_fn_info.Fn.is_generic);
379 try expect(aligned_foo_fn_info.Fn.params.len == 2);
380 try expect(aligned_foo_fn_info.Fn.is_var_args);
381 try expect(aligned_foo_fn_info.Fn.return_type.? == usize);
382 const aligned_foo_ptr_fn_info = @typeInfo(@TypeOf(&typeInfoFooAligned));
383 try expect(aligned_foo_ptr_fn_info.Pointer.size == .One);
384 try expect(aligned_foo_ptr_fn_info.Pointer.is_const);
385 try expect(!aligned_foo_ptr_fn_info.Pointer.is_volatile);
386 try expect(aligned_foo_ptr_fn_info.Pointer.alignment == 4);
387 try expect(aligned_foo_ptr_fn_info.Pointer.address_space == .generic);
388 try expect(aligned_foo_ptr_fn_info.Pointer.child == aligned_foo_fn_type);
389 try expect(!aligned_foo_ptr_fn_info.Pointer.is_allowzero);
390 try expect(aligned_foo_ptr_fn_info.Pointer.sentinel == null);
369391}
370392
371393extern fn typeInfoFoo(a: usize, b: bool, ...) callconv(.C) usize;
test/behavior/typename.zig+2-4
......@@ -78,11 +78,9 @@ test "basic" {
7878 try expectEqualStrings("fn (comptime u32) void", @typeName(fn (comptime u32) void));
7979 try expectEqualStrings("fn (noalias []u8) void", @typeName(fn (noalias []u8) void));
8080
81 try expectEqualStrings("fn () align(32) void", @typeName(fn () align(32) void));
8281 try expectEqualStrings("fn () callconv(.C) void", @typeName(fn () callconv(.C) void));
83 try expectEqualStrings("fn () align(32) callconv(.C) void", @typeName(fn () align(32) callconv(.C) void));
84 try expectEqualStrings("fn (...) align(32) callconv(.C) void", @typeName(fn (...) align(32) callconv(.C) void));
85 try expectEqualStrings("fn (u32, ...) align(32) callconv(.C) void", @typeName(fn (u32, ...) align(32) callconv(.C) void));
82 try expectEqualStrings("fn (...) callconv(.C) void", @typeName(fn (...) callconv(.C) void));
83 try expectEqualStrings("fn (u32, ...) callconv(.C) void", @typeName(fn (u32, ...) callconv(.C) void));
8684}
8785
8886test "top level decl" {
test/cases/compile_errors/function_ptr_alignment.zig+8-20
......@@ -1,28 +1,16 @@
1comptime {
2 var a: *align(2) @TypeOf(foo) = undefined;
3 _ = &a;
4}
5fn foo() void {}
1fn align1() align(1) void {}
2fn align2() align(2) void {}
63
74comptime {
8 var a: *align(1) fn () void = undefined;
9 _ = &a;
10}
11comptime {
12 var a: *align(2) fn () align(2) void = undefined;
13 _ = &a;
14}
15comptime {
16 var a: *align(2) fn () void = undefined;
17 _ = &a;
18}
19comptime {
20 var a: *align(1) fn () align(2) void = undefined;
21 _ = &a;
5 _ = @as(*align(1) const fn () void, &align2);
6 _ = @as(*align(1) const fn () void, &align1);
7 _ = @as(*align(2) const fn () void, &align2);
8 _ = @as(*align(2) const fn () void, &align1);
229}
2310
2411// error
2512// backend=stage2
2613// target=native
2714//
28// :20:19: error: function pointer alignment disagrees with function alignment
15// :8:41: error: expected type '*align(2) const fn () void', found '*const fn () void'
16// :8:41: note: pointer alignment '1' cannot cast into pointer alignment '2'
test/cases/compile_errors/inferring_error_set_of_function_pointer.zig deleted-9
......@@ -1,9 +0,0 @@
1comptime {
2 const z: ?fn () !void = null;
3}
4
5// error
6// backend=stage2
7// target=native
8//
9// :2:21: error: function prototype may not have inferred error set
test/cases/compile_errors/invalid_function_types.zig created+25
......@@ -0,0 +1,25 @@
1comptime {
2 _ = fn name() void;
3}
4comptime {
5 _ = fn () align(128) void;
6}
7comptime {
8 _ = fn () addrspace(.generic) void;
9}
10comptime {
11 _ = fn () linksection("section") void;
12}
13comptime {
14 _ = fn () !void;
15}
16
17// error
18// backend=stage2
19// target=native
20//
21// :2:12: error: function type cannot have a name
22// :5:21: error: function type cannot have an alignment
23// :8:26: error: function type cannot have an addrspace
24// :11:27: error: function type cannot have a linksection
25// :14:15: error: function type cannot have an inferred error set
test/cases/compile_errors/passing_an_under-aligned_function_pointer.zig+2-2
......@@ -1,7 +1,7 @@
11export fn entry() void {
22 testImplicitlyDecreaseFnAlign(alignedSmall, 1234);
33}
4fn testImplicitlyDecreaseFnAlign(ptr: *const fn () align(8) i32, answer: i32) void {
4fn testImplicitlyDecreaseFnAlign(ptr: *align(8) const fn () i32, answer: i32) void {
55 if (ptr() != answer) unreachable;
66}
77fn alignedSmall() align(4) i32 {
......@@ -12,5 +12,5 @@ fn alignedSmall() align(4) i32 {
1212// backend=stage2
1313// target=x86_64-linux
1414//
15// :2:35: error: expected type '*const fn () align(8) i32', found '*const fn () align(4) i32'
15// :2:35: error: expected type '*align(8) const fn () i32', found '*align(4) const fn () i32'
1616// :2:35: note: pointer alignment '4' cannot cast into pointer alignment '8'
test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig-1
......@@ -1,7 +1,6 @@
11const Foo = @Type(.{
22 .Fn = .{
33 .calling_convention = .Unspecified,
4 .alignment = 0,
54 .is_generic = true,
65 .is_var_args = false,
76 .return_type = u0,
test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig-1
......@@ -1,7 +1,6 @@
11const Foo = @Type(.{
22 .Fn = .{
33 .calling_convention = .Unspecified,
4 .alignment = 0,
54 .is_generic = false,
65 .is_var_args = true,
76 .return_type = u0,
test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig-1
......@@ -1,7 +1,6 @@
11const Foo = @Type(.{
22 .Fn = .{
33 .calling_convention = .Unspecified,
4 .alignment = 0,
54 .is_generic = false,
65 .is_var_args = false,
76 .return_type = null,