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 {}...@@ -2780,10 +2780,16 @@ fn noop4() align(4) void {}
27802780
2781test "function alignment" {2781test "function alignment" {
2782 try expect(derp() == 1234);2782 try expect(derp() == 1234);
2783 try expect(@TypeOf(noop1) == fn () align(1) void);2783 try expect(@TypeOf(derp) == fn () i32);
2784 try expect(@TypeOf(noop4) == fn () align(4) void);2784 try expect(@TypeOf(&derp) == *align(@sizeOf(usize) * 2) const fn () i32);
2785
2785 noop1();2786 noop1();
2787 try expect(@TypeOf(noop1) == fn () void);
2788 try expect(@TypeOf(&noop1) == *align(1) const fn () void);
2789
2786 noop4();2790 noop4();
2791 try expect(@TypeOf(noop4) == fn () void);
2792 try expect(@TypeOf(&noop4) == *align(4) const fn () void);
2787}2793}
2788 {#code_end#}2794 {#code_end#}
2789 <p>2795 <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) {...@@ -420,7 +420,6 @@ pub const Type = union(enum) {
420 /// therefore must be kept in sync with the compiler implementation.420 /// therefore must be kept in sync with the compiler implementation.
421 pub const Fn = struct {421 pub const Fn = struct {
422 calling_convention: CallingConvention,422 calling_convention: CallingConvention,
423 alignment: comptime_int,
424 is_generic: bool,423 is_generic: bool,
425 is_var_args: bool,424 is_var_args: bool,
426 /// TODO change the language spec to make this not optional.425 /// 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;...@@ -1053,10 +1053,10 @@ pub const sigset_t = u32;
1053pub const empty_sigset: sigset_t = 0;1053pub const empty_sigset: sigset_t = 0;
10541054
1055pub const SIG = struct {1055pub const SIG = struct {
1056 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));1056 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
1057 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));1057 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
1058 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));1058 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
1059 pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(5));1059 pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(5);
10601060
1061 /// block specified signal set1061 /// block specified signal set
1062 pub const BLOCK = 1;1062 pub const BLOCK = 1;
...@@ -1150,7 +1150,7 @@ pub const siginfo_t = extern struct {...@@ -1150,7 +1150,7 @@ pub const siginfo_t = extern struct {
11501150
1151/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.1151/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
1152pub const Sigaction = extern struct {1152pub 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;
1154 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;1154 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
11551155
1156 handler: extern union {1156 handler: extern union {
lib/std/c/dragonfly.zig+4-4
...@@ -616,9 +616,9 @@ pub const S = struct {...@@ -616,9 +616,9 @@ pub const S = struct {
616pub const BADSIG = SIG.ERR;616pub const BADSIG = SIG.ERR;
617617
618pub const SIG = struct {618pub const SIG = struct {
619 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));619 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
620 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));620 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
621 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));621 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
622622
623 pub const BLOCK = 1;623 pub const BLOCK = 1;
624 pub const UNBLOCK = 2;624 pub const UNBLOCK = 2;
...@@ -690,7 +690,7 @@ pub const empty_sigset = sigset_t{ .__bits = [_]c_uint{0} ** _SIG_WORDS };...@@ -690,7 +690,7 @@ pub const empty_sigset = sigset_t{ .__bits = [_]c_uint{0} ** _SIG_WORDS };
690pub const sig_atomic_t = c_int;690pub const sig_atomic_t = c_int;
691691
692pub const Sigaction = extern struct {692pub 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;
694 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;694 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
695695
696 /// signal handler696 /// signal handler
lib/std/c/freebsd.zig+4-4
...@@ -695,9 +695,9 @@ pub const SIG = struct {...@@ -695,9 +695,9 @@ pub const SIG = struct {
695 pub const UNBLOCK = 2;695 pub const UNBLOCK = 2;
696 pub const SETMASK = 3;696 pub const SETMASK = 3;
697697
698 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));698 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
699 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));699 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
700 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));700 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
701701
702 pub const WORDS = 4;702 pub const WORDS = 4;
703 pub const MAXSIG = 128;703 pub const MAXSIG = 128;
...@@ -1171,7 +1171,7 @@ const NSIG = 32;...@@ -1171,7 +1171,7 @@ const NSIG = 32;
11711171
1172/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.1172/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
1173pub const Sigaction = extern struct {1173pub 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;
1175 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;1175 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
11761176
1177 /// signal handler1177 /// signal handler
lib/std/c/haiku.zig+4-4
...@@ -441,9 +441,9 @@ pub const SA = struct {...@@ -441,9 +441,9 @@ pub const SA = struct {
441};441};
442442
443pub const SIG = struct {443pub const SIG = struct {
444 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));444 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
445 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));445 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
446 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));446 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
447447
448 pub const HUP = 1;448 pub const HUP = 1;
449 pub const INT = 2;449 pub const INT = 2;
...@@ -690,7 +690,7 @@ const NSIG = 32;...@@ -690,7 +690,7 @@ const NSIG = 32;
690690
691/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.691/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
692pub const Sigaction = extern struct {692pub 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
695 /// signal handler695 /// signal handler
696 __sigaction_u: extern union {696 __sigaction_u: extern union {
lib/std/c/netbsd.zig+4-4
...@@ -800,9 +800,9 @@ pub const winsize = extern struct {...@@ -800,9 +800,9 @@ pub const winsize = extern struct {
800const NSIG = 32;800const NSIG = 32;
801801
802pub const SIG = struct {802pub const SIG = struct {
803 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));803 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
804 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));804 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
805 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));805 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
806806
807 pub const WORDS = 4;807 pub const WORDS = 4;
808 pub const MAXSIG = 128;808 pub const MAXSIG = 128;
...@@ -864,7 +864,7 @@ pub const SIG = struct {...@@ -864,7 +864,7 @@ pub const SIG = struct {
864864
865/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.865/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
866pub const Sigaction = extern struct {866pub 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;
868 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;868 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
869869
870 /// signal handler870 /// signal handler
lib/std/c/openbsd.zig+6-6
...@@ -795,11 +795,11 @@ pub const winsize = extern struct {...@@ -795,11 +795,11 @@ pub const winsize = extern struct {
795const NSIG = 33;795const NSIG = 33;
796796
797pub const SIG = struct {797pub const SIG = struct {
798 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));798 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
799 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));799 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
800 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));800 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
801 pub const CATCH = @as(?Sigaction.handler_fn, @ptrFromInt(2));801 pub const CATCH: ?Sigaction.handler_fn = @ptrFromInt(2);
802 pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(3));802 pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(3);
803803
804 pub const HUP = 1;804 pub const HUP = 1;
805 pub const INT = 2;805 pub const INT = 2;
...@@ -842,7 +842,7 @@ pub const SIG = struct {...@@ -842,7 +842,7 @@ pub const SIG = struct {
842842
843/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.843/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
844pub const Sigaction = extern struct {844pub 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;
846 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;846 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
847847
848 /// signal handler848 /// signal handler
lib/std/c/solaris.zig+5-5
...@@ -798,10 +798,10 @@ pub const winsize = extern struct {...@@ -798,10 +798,10 @@ pub const winsize = extern struct {
798const NSIG = 75;798const NSIG = 75;
799799
800pub const SIG = struct {800pub const SIG = struct {
801 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));801 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
802 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));802 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
803 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));803 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
804 pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(2));804 pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(2);
805805
806 pub const WORDS = 4;806 pub const WORDS = 4;
807 pub const MAXSIG = 75;807 pub const MAXSIG = 75;
...@@ -874,7 +874,7 @@ pub const SIG = struct {...@@ -874,7 +874,7 @@ pub const SIG = struct {
874874
875/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.875/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
876pub const Sigaction = extern struct {876pub 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;
878 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;878 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
879879
880 /// signal options880 /// signal options
lib/std/meta.zig+4-5
...@@ -57,10 +57,9 @@ test stringToEnum {...@@ -57,10 +57,9 @@ test stringToEnum {
57}57}
5858
59/// Returns the alignment of type T.59/// Returns the alignment of type T.
60/// Note that if T is a pointer or function type the result is different than60/// Note that if T is a pointer type the result is different than the one
61/// the one returned by @alignOf(T).61/// returned by @alignOf(T).
62/// If T is a pointer type the alignment of the type it points to is returned.62/// 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.
64pub fn alignment(comptime T: type) comptime_int {63pub fn alignment(comptime T: type) comptime_int {
65 return switch (@typeInfo(T)) {64 return switch (@typeInfo(T)) {
66 .Optional => |info| switch (@typeInfo(info.child)) {65 .Optional => |info| switch (@typeInfo(info.child)) {
...@@ -68,7 +67,6 @@ pub fn alignment(comptime T: type) comptime_int {...@@ -68,7 +67,6 @@ pub fn alignment(comptime T: type) comptime_int {
68 else => @alignOf(T),67 else => @alignOf(T),
69 },68 },
70 .Pointer => |info| info.alignment,69 .Pointer => |info| info.alignment,
71 .Fn => |info| info.alignment,
72 else => @alignOf(T),70 else => @alignOf(T),
73 };71 };
74}72}
...@@ -80,7 +78,8 @@ test alignment {...@@ -80,7 +78,8 @@ test alignment {
80 try testing.expect(alignment([]align(1) u8) == 1);78 try testing.expect(alignment([]align(1) u8) == 1);
81 try testing.expect(alignment([]align(2) u8) == 2);79 try testing.expect(alignment([]align(2) u8) == 2);
82 try testing.expect(alignment(fn () void) > 0);80 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);
84}83}
8584
86/// Given a parameterized type (array, vector, pointer, optional), returns the "child type".85/// 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 {...@@ -689,13 +689,13 @@ pub const SIG = struct {
689 pub const SYS = 31;689 pub const SYS = 31;
690 pub const UNUSED = SIG.SYS;690 pub const UNUSED = SIG.SYS;
691691
692 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(std.math.maxInt(usize)));692 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(std.math.maxInt(usize));
693 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));693 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
694 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));694 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
695};695};
696696
697pub const Sigaction = extern struct {697pub 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;
699 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;699 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
700700
701 handler: extern union {701 handler: extern union {
lib/std/os/linux.zig+18-23
...@@ -1327,16 +1327,14 @@ pub fn flock(fd: fd_t, operation: i32) usize {...@@ -1327,16 +1327,14 @@ pub fn flock(fd: fd_t, operation: i32) usize {
1327 return syscall2(.flock, @as(usize, @bitCast(@as(isize, fd))), @as(usize, @bitCast(@as(isize, operation))));1327 return syscall2(.flock, @as(usize, @bitCast(@as(isize, fd))), @as(usize, @bitCast(@as(isize, operation))));
1328}1328}
13291329
1330var vdso_clock_gettime = @as(?*const anyopaque, @ptrCast(&init_vdso_clock_gettime));
1331
1332// We must follow the C calling convention when we call into the VDSO1330// 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
1335pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {1334pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
1336 if (@hasDecl(VDSO, "CGT_SYM")) {1335 if (@hasDecl(VDSO, "CGT_SYM")) {
1337 const ptr = @atomicLoad(?*const anyopaque, &vdso_clock_gettime, .unordered);1336 const ptr = @atomicLoad(?VdsoClockGettime, &vdso_clock_gettime, .unordered);
1338 if (ptr) |fn_ptr| {1337 if (ptr) |f| {
1339 const f = @as(vdso_clock_gettime_ty, @ptrCast(fn_ptr));
1340 const rc = f(clk_id, tp);1338 const rc = f(clk_id, tp);
1341 switch (rc) {1339 switch (rc) {
1342 0, @as(usize, @bitCast(-@as(isize, @intFromEnum(E.INVAL)))) => return rc,1340 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 {...@@ -1348,15 +1346,12 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
1348}1346}
13491347
1350fn init_vdso_clock_gettime(clk: i32, ts: *timespec) callconv(.C) usize {1348fn 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));
1352 // Note that we may not have a VDSO at all, update the stub address anyway1350 // Note that we may not have a VDSO at all, update the stub address anyway
1353 // so that clock_gettime will fall back on the good old (and slow) syscall1351 // 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);
1355 // Call into the VDSO if available1353 // Call into the VDSO if available
1356 if (ptr) |fn_ptr| {1354 if (ptr) |f| return f(clk, ts);
1357 const f = @as(vdso_clock_gettime_ty, @ptrCast(fn_ptr));
1358 return f(clk, ts);
1359 }
1360 return @as(usize, @bitCast(-@as(isize, @intFromEnum(E.NOSYS))));1355 return @as(usize, @bitCast(-@as(isize, @intFromEnum(E.NOSYS))));
1361}1356}
13621357
...@@ -2516,9 +2511,9 @@ pub const SIG = if (is_mips) struct {...@@ -2516,9 +2511,9 @@ pub const SIG = if (is_mips) struct {
2516 pub const SYS = 31;2511 pub const SYS = 31;
2517 pub const UNUSED = SIG.SYS;2512 pub const UNUSED = SIG.SYS;
25182513
2519 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));2514 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
2520 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));2515 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
2521 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));2516 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
2522} else if (is_sparc) struct {2517} else if (is_sparc) struct {
2523 pub const BLOCK = 1;2518 pub const BLOCK = 1;
2524 pub const UNBLOCK = 2;2519 pub const UNBLOCK = 2;
...@@ -2560,9 +2555,9 @@ pub const SIG = if (is_mips) struct {...@@ -2560,9 +2555,9 @@ pub const SIG = if (is_mips) struct {
2560 pub const PWR = LOST;2555 pub const PWR = LOST;
2561 pub const IO = SIG.POLL;2556 pub const IO = SIG.POLL;
25622557
2563 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));2558 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
2564 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));2559 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
2565 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));2560 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
2566} else struct {2561} else struct {
2567 pub const BLOCK = 0;2562 pub const BLOCK = 0;
2568 pub const UNBLOCK = 1;2563 pub const UNBLOCK = 1;
...@@ -2603,9 +2598,9 @@ pub const SIG = if (is_mips) struct {...@@ -2603,9 +2598,9 @@ pub const SIG = if (is_mips) struct {
2603 pub const SYS = 31;2598 pub const SYS = 31;
2604 pub const UNUSED = SIG.SYS;2599 pub const UNUSED = SIG.SYS;
26052600
2606 pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));2601 pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
2607 pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));2602 pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
2608 pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));2603 pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
2609};2604};
26102605
2611pub const kernel_rwf = u32;2606pub const kernel_rwf = u32;
...@@ -3709,7 +3704,7 @@ pub const all_mask: sigset_t = [_]u32{0xffffffff} ** @typeInfo(sigset_t).Array.l...@@ -3709,7 +3704,7 @@ pub const all_mask: sigset_t = [_]u32{0xffffffff} ** @typeInfo(sigset_t).Array.l
3709pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffffffff} ** 30;3704pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffffffff} ** 30;
37103705
3711const k_sigaction_funcs = struct {3706const 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;
3713 const restorer = *const fn () callconv(.C) void;3708 const restorer = *const fn () callconv(.C) void;
3714};3709};
37153710
...@@ -3736,7 +3731,7 @@ pub const k_sigaction = switch (native_arch) {...@@ -3736,7 +3731,7 @@ pub const k_sigaction = switch (native_arch) {
37363731
3737/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.3732/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
3738pub const Sigaction = extern struct {3733pub 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;
3740 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;3735 pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
37413736
3742 handler: extern union {3737 handler: extern union {
lib/std/zig/AstGen.zig+7-7
...@@ -1369,16 +1369,16 @@ fn fnProtoExpr(...@@ -1369,16 +1369,16 @@ fn fnProtoExpr(
1369 break :is_var_args false;1369 break :is_var_args false;
1370 };1370 };
13711371
1372 const align_ref: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {1372 if (fn_proto.ast.align_expr != 0) {
1373 break :inst try expr(&block_scope, scope, coerced_align_ri, fn_proto.ast.align_expr);1373 return astgen.failNode(fn_proto.ast.align_expr, "function type cannot have an alignment", .{});
1374 };1374 }
13751375
1376 if (fn_proto.ast.addrspace_expr != 0) {1376 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", .{});
1378 }1378 }
13791379
1380 if (fn_proto.ast.section_expr != 0) {1380 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", .{});
1382 }1382 }
13831383
1384 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)1384 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
...@@ -1394,7 +1394,7 @@ fn fnProtoExpr(...@@ -1394,7 +1394,7 @@ fn fnProtoExpr(
1394 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;1394 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
1395 const is_inferred_error = token_tags[maybe_bang] == .bang;1395 const is_inferred_error = token_tags[maybe_bang] == .bang;
1396 if (is_inferred_error) {1396 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", .{});
1398 }1398 }
1399 const ret_ty = try expr(&block_scope, scope, coerced_type_ri, fn_proto.ast.return_type);1399 const ret_ty = try expr(&block_scope, scope, coerced_type_ri, fn_proto.ast.return_type);
14001400
...@@ -1403,7 +1403,7 @@ fn fnProtoExpr(...@@ -1403,7 +1403,7 @@ fn fnProtoExpr(
14031403
1404 .cc_ref = cc,1404 .cc_ref = cc,
1405 .cc_gz = null,1405 .cc_gz = null,
1406 .align_ref = align_ref,1406 .align_ref = .none,
1407 .align_gz = null,1407 .align_gz = null,
1408 .ret_ref = ret_ty,1408 .ret_ref = ret_ty,
1409 .ret_gz = null,1409 .ret_gz = null,
src/InternPool.zig+5-23
...@@ -765,16 +765,10 @@ pub const Key = union(enum) {...@@ -765,16 +765,10 @@ pub const Key = union(enum) {
765 /// Tells whether a parameter is noalias. See `paramIsNoalias` helper765 /// Tells whether a parameter is noalias. See `paramIsNoalias` helper
766 /// method for accessing this.766 /// method for accessing this.
767 noalias_bits: u32,767 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,
773 cc: std.builtin.CallingConvention,768 cc: std.builtin.CallingConvention,
774 is_var_args: bool,769 is_var_args: bool,
775 is_generic: bool,770 is_generic: bool,
776 is_noinline: bool,771 is_noinline: bool,
777 align_is_generic: bool,
778 cc_is_generic: bool,772 cc_is_generic: bool,
779 section_is_generic: bool,773 section_is_generic: bool,
780 addrspace_is_generic: bool,774 addrspace_is_generic: bool,
...@@ -794,7 +788,6 @@ pub const Key = union(enum) {...@@ -794,7 +788,6 @@ pub const Key = union(enum) {
794 a.return_type == b.return_type and788 a.return_type == b.return_type and
795 a.comptime_bits == b.comptime_bits and789 a.comptime_bits == b.comptime_bits and
796 a.noalias_bits == b.noalias_bits and790 a.noalias_bits == b.noalias_bits and
797 a.alignment == b.alignment and
798 a.cc == b.cc and791 a.cc == b.cc and
799 a.is_var_args == b.is_var_args and792 a.is_var_args == b.is_var_args and
800 a.is_generic == b.is_generic and793 a.is_generic == b.is_generic and
...@@ -808,7 +801,6 @@ pub const Key = union(enum) {...@@ -808,7 +801,6 @@ pub const Key = union(enum) {
808 std.hash.autoHash(hasher, self.return_type);801 std.hash.autoHash(hasher, self.return_type);
809 std.hash.autoHash(hasher, self.comptime_bits);802 std.hash.autoHash(hasher, self.comptime_bits);
810 std.hash.autoHash(hasher, self.noalias_bits);803 std.hash.autoHash(hasher, self.noalias_bits);
811 std.hash.autoHash(hasher, self.alignment);
812 std.hash.autoHash(hasher, self.cc);804 std.hash.autoHash(hasher, self.cc);
813 std.hash.autoHash(hasher, self.is_var_args);805 std.hash.autoHash(hasher, self.is_var_args);
814 std.hash.autoHash(hasher, self.is_generic);806 std.hash.autoHash(hasher, self.is_generic);
...@@ -3587,18 +3579,16 @@ pub const Tag = enum(u8) {...@@ -3587,18 +3579,16 @@ pub const Tag = enum(u8) {
3587 flags: Flags,3579 flags: Flags,
35883580
3589 pub const Flags = packed struct(u32) {3581 pub const Flags = packed struct(u32) {
3590 alignment: Alignment,
3591 cc: std.builtin.CallingConvention,3582 cc: std.builtin.CallingConvention,
3592 is_var_args: bool,3583 is_var_args: bool,
3593 is_generic: bool,3584 is_generic: bool,
3594 has_comptime_bits: bool,3585 has_comptime_bits: bool,
3595 has_noalias_bits: bool,3586 has_noalias_bits: bool,
3596 is_noinline: bool,3587 is_noinline: bool,
3597 align_is_generic: bool,
3598 cc_is_generic: bool,3588 cc_is_generic: bool,
3599 section_is_generic: bool,3589 section_is_generic: bool,
3600 addrspace_is_generic: bool,3590 addrspace_is_generic: bool,
3601 _: u9 = 0,3591 _: u16 = 0,
3602 };3592 };
3603 };3593 };
36043594
...@@ -4918,11 +4908,9 @@ fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType {...@@ -4918,11 +4908,9 @@ fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType {
4918 .return_type = type_function.data.return_type,4908 .return_type = type_function.data.return_type,
4919 .comptime_bits = comptime_bits,4909 .comptime_bits = comptime_bits,
4920 .noalias_bits = noalias_bits,4910 .noalias_bits = noalias_bits,
4921 .alignment = type_function.data.flags.alignment,
4922 .cc = type_function.data.flags.cc,4911 .cc = type_function.data.flags.cc,
4923 .is_var_args = type_function.data.flags.is_var_args,4912 .is_var_args = type_function.data.flags.is_var_args,
4924 .is_noinline = type_function.data.flags.is_noinline,4913 .is_noinline = type_function.data.flags.is_noinline,
4925 .align_is_generic = type_function.data.flags.align_is_generic,
4926 .cc_is_generic = type_function.data.flags.cc_is_generic,4914 .cc_is_generic = type_function.data.flags.cc_is_generic,
4927 .section_is_generic = type_function.data.flags.section_is_generic,4915 .section_is_generic = type_function.data.flags.section_is_generic,
4928 .addrspace_is_generic = type_function.data.flags.addrspace_is_generic,4916 .addrspace_is_generic = type_function.data.flags.addrspace_is_generic,
...@@ -6211,8 +6199,6 @@ pub const GetFuncTypeKey = struct {...@@ -6211,8 +6199,6 @@ pub const GetFuncTypeKey = struct {
6211 comptime_bits: u32 = 0,6199 comptime_bits: u32 = 0,
6212 noalias_bits: u32 = 0,6200 noalias_bits: u32 = 0,
6213 /// `null` means generic.6201 /// `null` means generic.
6214 alignment: ?Alignment = .none,
6215 /// `null` means generic.
6216 cc: ?std.builtin.CallingConvention = .Unspecified,6202 cc: ?std.builtin.CallingConvention = .Unspecified,
6217 is_var_args: bool = false,6203 is_var_args: bool = false,
6218 is_generic: bool = false,6204 is_generic: bool = false,
...@@ -6242,14 +6228,12 @@ pub fn getFuncType(ip: *InternPool, gpa: Allocator, key: GetFuncTypeKey) Allocat...@@ -6242,14 +6228,12 @@ pub fn getFuncType(ip: *InternPool, gpa: Allocator, key: GetFuncTypeKey) Allocat
6242 .params_len = params_len,6228 .params_len = params_len,
6243 .return_type = key.return_type,6229 .return_type = key.return_type,
6244 .flags = .{6230 .flags = .{
6245 .alignment = key.alignment orelse .none,
6246 .cc = key.cc orelse .Unspecified,6231 .cc = key.cc orelse .Unspecified,
6247 .is_var_args = key.is_var_args,6232 .is_var_args = key.is_var_args,
6248 .has_comptime_bits = key.comptime_bits != 0,6233 .has_comptime_bits = key.comptime_bits != 0,
6249 .has_noalias_bits = key.noalias_bits != 0,6234 .has_noalias_bits = key.noalias_bits != 0,
6250 .is_generic = key.is_generic,6235 .is_generic = key.is_generic,
6251 .is_noinline = key.is_noinline,6236 .is_noinline = key.is_noinline,
6252 .align_is_generic = key.alignment == null,
6253 .cc_is_generic = key.cc == null,6237 .cc_is_generic = key.cc == null,
6254 .section_is_generic = key.section_is_generic,6238 .section_is_generic = key.section_is_generic,
6255 .addrspace_is_generic = key.addrspace_is_generic,6239 .addrspace_is_generic = key.addrspace_is_generic,
...@@ -6433,14 +6417,12 @@ pub fn getFuncDeclIes(ip: *InternPool, gpa: Allocator, key: GetFuncDeclIesKey) A...@@ -6433,14 +6417,12 @@ pub fn getFuncDeclIes(ip: *InternPool, gpa: Allocator, key: GetFuncDeclIesKey) A
6433 .params_len = params_len,6417 .params_len = params_len,
6434 .return_type = @enumFromInt(ip.items.len - 2),6418 .return_type = @enumFromInt(ip.items.len - 2),
6435 .flags = .{6419 .flags = .{
6436 .alignment = key.alignment orelse .none,
6437 .cc = key.cc orelse .Unspecified,6420 .cc = key.cc orelse .Unspecified,
6438 .is_var_args = key.is_var_args,6421 .is_var_args = key.is_var_args,
6439 .has_comptime_bits = key.comptime_bits != 0,6422 .has_comptime_bits = key.comptime_bits != 0,
6440 .has_noalias_bits = key.noalias_bits != 0,6423 .has_noalias_bits = key.noalias_bits != 0,
6441 .is_generic = key.is_generic,6424 .is_generic = key.is_generic,
6442 .is_noinline = key.is_noinline,6425 .is_noinline = key.is_noinline,
6443 .align_is_generic = key.alignment == null,
6444 .cc_is_generic = key.cc == null,6426 .cc_is_generic = key.cc == null,
6445 .section_is_generic = key.section_is_generic,6427 .section_is_generic = key.section_is_generic,
6446 .addrspace_is_generic = key.addrspace_is_generic,6428 .addrspace_is_generic = key.addrspace_is_generic,
...@@ -6553,7 +6535,6 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)...@@ -6553,7 +6535,6 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)
6553 .param_types = arg.param_types,6535 .param_types = arg.param_types,
6554 .return_type = arg.bare_return_type,6536 .return_type = arg.bare_return_type,
6555 .noalias_bits = arg.noalias_bits,6537 .noalias_bits = arg.noalias_bits,
6556 .alignment = arg.alignment,
6557 .cc = arg.cc,6538 .cc = arg.cc,
6558 .is_noinline = arg.is_noinline,6539 .is_noinline = arg.is_noinline,
6559 });6540 });
...@@ -6610,6 +6591,7 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)...@@ -6610,6 +6591,7 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)
6610 func_index,6591 func_index,
6611 func_extra_index,6592 func_extra_index,
6612 func_ty,6593 func_ty,
6594 arg.alignment,
6613 arg.section,6595 arg.section,
6614 );6596 );
6615}6597}
...@@ -6673,14 +6655,12 @@ pub fn getFuncInstanceIes(...@@ -6673,14 +6655,12 @@ pub fn getFuncInstanceIes(
6673 .params_len = params_len,6655 .params_len = params_len,
6674 .return_type = error_union_type,6656 .return_type = error_union_type,
6675 .flags = .{6657 .flags = .{
6676 .alignment = arg.alignment,
6677 .cc = arg.cc,6658 .cc = arg.cc,
6678 .is_var_args = false,6659 .is_var_args = false,
6679 .has_comptime_bits = false,6660 .has_comptime_bits = false,
6680 .has_noalias_bits = arg.noalias_bits != 0,6661 .has_noalias_bits = arg.noalias_bits != 0,
6681 .is_generic = false,6662 .is_generic = false,
6682 .is_noinline = arg.is_noinline,6663 .is_noinline = arg.is_noinline,
6683 .align_is_generic = false,
6684 .cc_is_generic = false,6664 .cc_is_generic = false,
6685 .section_is_generic = false,6665 .section_is_generic = false,
6686 .addrspace_is_generic = false,6666 .addrspace_is_generic = false,
...@@ -6741,6 +6721,7 @@ pub fn getFuncInstanceIes(...@@ -6741,6 +6721,7 @@ pub fn getFuncInstanceIes(
6741 func_index,6721 func_index,
6742 func_extra_index,6722 func_extra_index,
6743 func_ty,6723 func_ty,
6724 arg.alignment,
6744 arg.section,6725 arg.section,
6745 );6726 );
6746}6727}
...@@ -6752,6 +6733,7 @@ fn finishFuncInstance(...@@ -6752,6 +6733,7 @@ fn finishFuncInstance(
6752 func_index: Index,6733 func_index: Index,
6753 func_extra_index: u32,6734 func_extra_index: u32,
6754 func_ty: Index,6735 func_ty: Index,
6736 alignment: Alignment,
6755 section: OptionalNullTerminatedString,6737 section: OptionalNullTerminatedString,
6756) Allocator.Error!Index {6738) Allocator.Error!Index {
6757 const fn_owner_decl = ip.declPtr(ip.funcDeclOwner(generic_owner));6739 const fn_owner_decl = ip.declPtr(ip.funcDeclOwner(generic_owner));
...@@ -6764,7 +6746,7 @@ fn finishFuncInstance(...@@ -6764,7 +6746,7 @@ fn finishFuncInstance(
6764 .owns_tv = true,6746 .owns_tv = true,
6765 .ty = @import("type.zig").Type.fromInterned(func_ty),6747 .ty = @import("type.zig").Type.fromInterned(func_ty),
6766 .val = @import("Value.zig").fromInterned(func_index),6748 .val = @import("Value.zig").fromInterned(func_index),
6767 .alignment = .none,6749 .alignment = alignment,
6768 .@"linksection" = section,6750 .@"linksection" = section,
6769 .@"addrspace" = fn_owner_decl.@"addrspace",6751 .@"addrspace" = fn_owner_decl.@"addrspace",
6770 .analysis = .complete,6752 .analysis = .complete,
src/Module.zig+72-104
...@@ -3596,6 +3596,18 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {...@@ -3596,6 +3596,18 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
35963596
3597 log.debug("semaDecl '{d}'", .{@intFromEnum(decl_index)});3597 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
3599 const decl_inst = decl.zir_decl_index.unwrap().?.resolve(ip);3611 const decl_inst = decl.zir_decl_index.unwrap().?.resolve(ip);
36003612
3601 const gpa = mod.gpa;3613 const gpa = mod.gpa;
...@@ -3733,141 +3745,96 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {...@@ -3733,141 +3745,96 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
3733 };3745 };
3734 }3746 }
37353747
3736 switch (ip.indexToKey(decl_tv.val.toIntern())) {3748 var queue_linker_work = true;
3737 .func => |func| {3749 var is_func = false;
3738 const owns_tv = func.owner_decl == decl_index;3750 var is_inline = false;
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;
3782 switch (decl_tv.val.toIntern()) {3751 switch (decl_tv.val.toIntern()) {
3783 .generic_poison => unreachable,3752 .generic_poison => unreachable,
3784 .unreachable_value => unreachable,3753 .unreachable_value => unreachable,
3785 else => switch (ip.indexToKey(decl_tv.val.toIntern())) {3754 else => switch (ip.indexToKey(decl_tv.val.toIntern())) {
3786 .variable => |variable| if (variable.decl == decl_index) {3755 .variable => |variable| {
3787 decl.owns_tv = true;3756 decl.owns_tv = variable.decl == decl_index;
3788 queue_linker_work = true;3757 queue_linker_work = decl.owns_tv;
3789 },3758 },
37903759
3791 .extern_func => |extern_fn| if (extern_fn.decl == decl_index) {3760 .extern_func => |extern_func| {
3792 decl.owns_tv = true;3761 decl.owns_tv = extern_func.decl == decl_index;
3793 queue_linker_work = true;3762 queue_linker_work = decl.owns_tv;
3794 is_extern = true;3763 is_func = decl.owns_tv;
3795 },3764 },
37963765
3797 .func => {},3766 .func => |func| {
37983767 decl.owns_tv = func.owner_decl == decl_index;
3799 else => {3768 queue_linker_work = false;
3800 queue_linker_work = true;3769 is_inline = decl.owns_tv and decl_tv.ty.fnCallingConvention(mod) == .Inline;
3770 is_func = decl.owns_tv;
3801 },3771 },
3772
3773 else => {},
3802 },3774 },
3803 }3775 }
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
3813 decl.ty = decl_tv.ty;3777 decl.ty = decl_tv.ty;
3814 decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod)));3778 decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod)));
3815 decl.alignment = blk: {3779 // Function linksection, align, and addrspace were already set by Sema
3816 const align_body = decl_bodies.align_body orelse break :blk .none;3780 if (!is_func) {
3817 const align_ref = try sema.resolveInlineBody(&block_scope, align_body, decl_inst);3781 decl.alignment = blk: {
3818 break :blk try sema.analyzeAsAlign(&block_scope, align_src, align_ref);3782 const align_body = decl_bodies.align_body orelse break :blk .none;
3819 };3783 const align_ref = try sema.resolveInlineBody(&block_scope, align_body, decl_inst);
3820 decl.@"linksection" = blk: {3784 break :blk try sema.analyzeAsAlign(&block_scope, align_src, align_ref);
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,
3839 };3785 };
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) {3809 const addrspace_body = decl_bodies.addrspace_body orelse break :blk switch (addrspace_ctx) {
3844 .function => target_util.defaultAddressSpace(target, .function),3810 .function => target_util.defaultAddressSpace(target, .function),
3845 .variable => target_util.defaultAddressSpace(target, .global_mutable),3811 .variable => target_util.defaultAddressSpace(target, .global_mutable),
3846 .constant => target_util.defaultAddressSpace(target, .global_constant),3812 .constant => target_util.defaultAddressSpace(target, .global_constant),
3847 else => unreachable,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);
3848 };3817 };
3849 const addrspace_ref = try sema.resolveInlineBody(&block_scope, addrspace_body, decl_inst);3818 }
3850 break :blk try sema.analyzeAsAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx);
3851 };
3852 decl.has_tv = true;3819 decl.has_tv = true;
3853 decl.analysis = .complete;3820 decl.analysis = .complete;
38543821
3855 const result: SemaDeclResult = if (old_has_tv) .{3822 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,
3857 .invalidate_decl_ref = !decl.ty.eql(old_ty, mod) or3826 .invalidate_decl_ref = !decl.ty.eql(old_ty, mod) or
3858 decl.alignment != old_align or3827 decl.alignment != old_align or
3859 decl.@"linksection" != old_linksection or3828 decl.@"linksection" != old_linksection or
3860 decl.@"addrspace" != old_addrspace,3829 decl.@"addrspace" != old_addrspace or
3830 is_inline != old_is_inline,
3861 } else .{3831 } else .{
3862 .invalidate_decl_val = true,3832 .invalidate_decl_val = true,
3863 .invalidate_decl_ref = true,3833 .invalidate_decl_ref = true,
3864 };3834 };
38653835
3866 const has_runtime_bits = is_extern or3836 const has_runtime_bits = queue_linker_work and (is_func or try sema.typeHasRuntimeBits(decl.ty));
3867 (queue_linker_work and try sema.typeHasRuntimeBits(decl.ty));
3868
3869 if (has_runtime_bits) {3837 if (has_runtime_bits) {
3870
3871 // Needed for codegen_decl which will call updateDecl and then the3838 // Needed for codegen_decl which will call updateDecl and then the
3872 // codegen backend wants full access to the Decl Type.3839 // codegen backend wants full access to the Decl Type.
3873 try sema.resolveTypeFully(decl.ty);3840 try sema.resolveTypeFully(decl.ty);
...@@ -3881,6 +3848,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {...@@ -3881,6 +3848,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
38813848
3882 if (decl.is_exported) {3849 if (decl.is_exported) {
3883 const export_src: LazySrcLoc = .{ .token_offset = @intFromBool(decl.is_pub) };3850 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", .{});
3884 // The scope needs to have the decl in it.3852 // The scope needs to have the decl in it.
3885 try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);3853 try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);
3886 }3854 }
src/Sema.zig+11-32
...@@ -7605,7 +7605,6 @@ fn analyzeCall(...@@ -7605,7 +7605,6 @@ fn analyzeCall(
7605 .param_types = new_param_types,7605 .param_types = new_param_types,
7606 .return_type = owner_info.return_type,7606 .return_type = owner_info.return_type,
7607 .noalias_bits = owner_info.noalias_bits,7607 .noalias_bits = owner_info.noalias_bits,
7608 .alignment = if (owner_info.align_is_generic) null else owner_info.alignment,
7609 .cc = if (owner_info.cc_is_generic) null else owner_info.cc,7608 .cc = if (owner_info.cc_is_generic) null else owner_info.cc,
7610 .is_var_args = owner_info.is_var_args,7609 .is_var_args = owner_info.is_var_args,
7611 .is_noinline = owner_info.is_noinline,7610 .is_noinline = owner_info.is_noinline,
...@@ -9629,7 +9628,6 @@ fn funcCommon(...@@ -9629,7 +9628,6 @@ fn funcCommon(
9629 .comptime_bits = comptime_bits,9628 .comptime_bits = comptime_bits,
9630 .return_type = bare_return_type.toIntern(),9629 .return_type = bare_return_type.toIntern(),
9631 .cc = cc,9630 .cc = cc,
9632 .alignment = alignment,
9633 .section_is_generic = section == .generic,9631 .section_is_generic = section == .generic,
9634 .addrspace_is_generic = address_space == null,9632 .addrspace_is_generic = address_space == null,
9635 .is_var_args = var_args,9633 .is_var_args = var_args,
...@@ -9640,6 +9638,7 @@ fn funcCommon(...@@ -9640,6 +9638,7 @@ fn funcCommon(
9640 if (is_extern) {9638 if (is_extern) {
9641 assert(comptime_bits == 0);9639 assert(comptime_bits == 0);
9642 assert(cc != null);9640 assert(cc != null);
9641 assert(alignment != null);
9643 assert(section != .generic);9642 assert(section != .generic);
9644 assert(address_space != null);9643 assert(address_space != null);
9645 assert(!is_generic);9644 assert(!is_generic);
...@@ -17623,8 +17622,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17623,8 +17622,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17623 const field_values = .{17622 const field_values = .{
17624 // calling_convention: CallingConvention,17623 // calling_convention: CallingConvention,
17625 (try mod.enumValueFieldIndex(callconv_ty, @intFromEnum(func_ty_info.cc))).toIntern(),17624 (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(),
17628 // is_generic: bool,17625 // is_generic: bool,
17629 Value.makeBool(func_ty_info.is_generic).toIntern(),17626 Value.makeBool(func_ty_info.is_generic).toIntern(),
17630 // is_var_args: bool,17627 // is_var_args: bool,
...@@ -19701,12 +19698,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -19701,12 +19698,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
19701 if (inst_data.size != .One) {19698 if (inst_data.size != .One) {
19702 return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{});19699 return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{});
19703 }19700 }
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 }
19710 } else if (inst_data.size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) {19701 } else if (inst_data.size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) {
19711 return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{});19702 return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{});
19712 } else if (inst_data.size == .C) {19703 } else if (inst_data.size == .C) {
...@@ -21030,7 +21021,6 @@ fn zirReify(...@@ -21030,7 +21021,6 @@ fn zirReify(
21030 .needed_comptime_reason = "operand to @Type must be comptime-known",21021 .needed_comptime_reason = "operand to @Type must be comptime-known",
21031 });21022 });
21032 const union_val = ip.indexToKey(val.toIntern()).un;21023 const union_val = ip.indexToKey(val.toIntern()).un;
21033 const target = mod.getTarget();
21034 if (try Value.fromInterned(union_val.val).anyUndef(mod)) return sema.failWithUseOfUndef(block, src);21024 if (try Value.fromInterned(union_val.val).anyUndef(mod)) return sema.failWithUseOfUndef(block, src);
21035 const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?;21025 const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?;
21036 switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) {21026 switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) {
...@@ -21171,12 +21161,6 @@ fn zirReify(...@@ -21171,12 +21161,6 @@ fn zirReify(
21171 if (ptr_size != .One) {21161 if (ptr_size != .One) {
21172 return sema.fail(block, src, "function pointers must be single pointers", .{});21162 return sema.fail(block, src, "function pointers must be single pointers", .{});
21173 }21163 }
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 }
21180 } else if (ptr_size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) {21164 } else if (ptr_size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) {
21181 return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{});21165 return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{});
21182 } else if (ptr_size == .C) {21166 } else if (ptr_size == .C) {
...@@ -21429,10 +21413,6 @@ fn zirReify(...@@ -21429,10 +21413,6 @@ fn zirReify(
21429 ip,21413 ip,
21430 try ip.getOrPutString(gpa, "calling_convention"),21414 try ip.getOrPutString(gpa, "calling_convention"),
21431 ).?);21415 ).?);
21432 const alignment_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
21433 ip,
21434 try ip.getOrPutString(gpa, "alignment"),
21435 ).?);
21436 const is_generic_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(21416 const is_generic_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
21437 ip,21417 ip,
21438 try ip.getOrPutString(gpa, "is_generic"),21418 try ip.getOrPutString(gpa, "is_generic"),
...@@ -21461,11 +21441,6 @@ fn zirReify(...@@ -21461,11 +21441,6 @@ fn zirReify(
21461 try sema.checkCallConvSupportsVarArgs(block, src, cc);21441 try sema.checkCallConvSupportsVarArgs(block, src, cc);
21462 }21442 }
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 };
21469 const return_type = return_type_val.optionalValue(mod) orelse21444 const return_type = return_type_val.optionalValue(mod) orelse
21470 return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});21445 return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});
2147121446
...@@ -21510,7 +21485,6 @@ fn zirReify(...@@ -21510,7 +21485,6 @@ fn zirReify(
21510 .param_types = param_types,21485 .param_types = param_types,
21511 .noalias_bits = noalias_bits,21486 .noalias_bits = noalias_bits,
21512 .return_type = return_type.toIntern(),21487 .return_type = return_type.toIntern(),
21513 .alignment = alignment,
21514 .cc = cc,21488 .cc = cc,
21515 .is_var_args = is_var_args,21489 .is_var_args = is_var_args,
21516 });21490 });
...@@ -32536,16 +32510,21 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn...@@ -32536,16 +32510,21 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn
32536 const mod = sema.mod;32510 const mod = sema.mod;
32537 try sema.ensureDeclAnalyzed(decl_index);32511 try sema.ensureDeclAnalyzed(decl_index);
3253832512
32539 const decl = mod.declPtr(decl_index);32513 const decl_tv = try mod.declPtr(decl_index).typedValue();
32540 const decl_tv = try decl.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 });
32541 // TODO: if this is a `decl_ref` of a non-variable decl, only depend on decl type32520 // TODO: if this is a `decl_ref` of a non-variable decl, only depend on decl type
32542 try sema.declareDependency(.{ .decl_val = decl_index });32521 try sema.declareDependency(.{ .decl_val = decl_index });
32543 const ptr_ty = try sema.ptrType(.{32522 const ptr_ty = try sema.ptrType(.{
32544 .child = decl_tv.ty.toIntern(),32523 .child = decl_tv.ty.toIntern(),
32545 .flags = .{32524 .flags = .{
32546 .alignment = decl.alignment,32525 .alignment = owner_decl.alignment,
32547 .is_const = if (decl.val.getVariable(mod)) |variable| variable.is_const else true,32526 .is_const = if (decl_tv.val.getVariable(mod)) |variable| variable.is_const else true,
32548 .address_space = decl.@"addrspace",32527 .address_space = owner_decl.@"addrspace",
32549 },32528 },
32550 });32529 });
32551 if (analyze_fn_body) {32530 if (analyze_fn_body) {
src/codegen/c.zig+2-2
...@@ -1635,7 +1635,7 @@ pub const DeclGen = struct {...@@ -1635,7 +1635,7 @@ pub const DeclGen = struct {
16351635
1636 switch (kind) {1636 switch (kind) {
1637 .forward => {},1637 .forward => {},
1638 .complete => if (fn_info.alignment.toByteUnitsOptional()) |a| {1638 .complete => if (fn_decl.alignment.toByteUnitsOptional()) |a| {
1639 try w.print("{}zig_align_fn({})", .{ trailing, a });1639 try w.print("{}zig_align_fn({})", .{ trailing, a });
1640 trailing = .maybe_space;1640 trailing = .maybe_space;
1641 },1641 },
...@@ -1666,7 +1666,7 @@ pub const DeclGen = struct {...@@ -1666,7 +1666,7 @@ pub const DeclGen = struct {
16661666
1667 switch (kind) {1667 switch (kind) {
1668 .forward => {1668 .forward => {
1669 if (fn_info.alignment.toByteUnitsOptional()) |a| {1669 if (fn_decl.alignment.toByteUnitsOptional()) |a| {
1670 try w.print(" zig_align_fn({})", .{a});1670 try w.print(" zig_align_fn({})", .{a});
1671 }1671 }
1672 switch (name) {1672 switch (name) {
src/codegen/llvm.zig+2-2
...@@ -2952,8 +2952,8 @@ pub const Object = struct {...@@ -2952,8 +2952,8 @@ pub const Object = struct {
2952 else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder),2952 else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder),
2953 }2953 }
29542954
2955 if (fn_info.alignment != .none)2955 if (decl.alignment != .none)
2956 function_index.setAlignment(fn_info.alignment.toLlvm(), &o.builder);2956 function_index.setAlignment(decl.alignment.toLlvm(), &o.builder);
29572957
2958 // Function attributes that are independent of analysis results of the function body.2958 // Function attributes that are independent of analysis results of the function body.
2959 try o.addCommonFnAttributes(&attributes, owner_mod);2959 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 {...@@ -4995,6 +4995,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
4995 } else .{4995 } else .{
4996 .root = .{4996 .root = .{
4997 .root_dir = zig_lib_directory,4997 .root_dir = zig_lib_directory,
4998 .sub_path = "compiler",
4998 },4999 },
4999 .root_src_path = "build_runner.zig",5000 .root_src_path = "build_runner.zig",
5000 };5001 };
src/type.zig+1-9
...@@ -396,9 +396,6 @@ pub const Type = struct {...@@ -396,9 +396,6 @@ pub const Type = struct {
396 try writer.writeAll("...");396 try writer.writeAll("...");
397 }397 }
398 try writer.writeAll(") ");398 try writer.writeAll(") ");
399 if (fn_info.alignment.toByteUnitsOptional()) |a| {
400 try writer.print("align({d}) ", .{a});
401 }
402 if (fn_info.cc != .Unspecified) {399 if (fn_info.cc != .Unspecified) {
403 try writer.writeAll("callconv(.");400 try writer.writeAll("callconv(.");
404 try writer.writeAll(@tagName(fn_info.cc));401 try writer.writeAll(@tagName(fn_info.cc));
...@@ -949,12 +946,7 @@ pub const Type = struct {...@@ -949,12 +946,7 @@ pub const Type = struct {
949 },946 },
950947
951 // represents machine code; not a pointer948 // represents machine code; not a pointer
952 .func_type => |func_type| return .{949 .func_type => return .{ .scalar = target_util.defaultFunctionAlignment(target) },
953 .scalar = if (func_type.alignment != .none)
954 func_type.alignment
955 else
956 target_util.defaultFunctionAlignment(target),
957 },
958950
959 .simple_type => |t| switch (t) {951 .simple_type => |t| switch (t) {
960 .bool,952 .bool,
stage1/zig.h+157-92
...@@ -25,11 +25,15 @@ typedef char bool;...@@ -25,11 +25,15 @@ typedef char bool;
25#endif25#endif
26#endif26#endif
2727
28#define zig_concat(lhs, rhs) lhs##rhs
29#define zig_expand_concat(lhs, rhs) zig_concat(lhs, rhs)
30
28#if defined(__has_builtin)31#if defined(__has_builtin)
29#define zig_has_builtin(builtin) __has_builtin(__builtin_##builtin)32#define zig_has_builtin(builtin) __has_builtin(__builtin_##builtin)
30#else33#else
31#define zig_has_builtin(builtin) 034#define zig_has_builtin(builtin) 0
32#endif35#endif
36#define zig_expand_has_builtin(b) zig_has_builtin(b)
3337
34#if defined(__has_attribute)38#if defined(__has_attribute)
35#define zig_has_attribute(attribute) __has_attribute(attribute)39#define zig_has_attribute(attribute) __has_attribute(attribute)
...@@ -112,7 +116,7 @@ typedef char bool;...@@ -112,7 +116,7 @@ typedef char bool;
112#define zig_never_tail zig_never_tail_unavailable116#define zig_never_tail zig_never_tail_unavailable
113#endif117#endif
114118
115#if zig_has_attribute(always_inline)119#if zig_has_attribute(musttail)
116#define zig_always_tail __attribute__((musttail))120#define zig_always_tail __attribute__((musttail))
117#else121#else
118#define zig_always_tail zig_always_tail_unavailable122#define zig_always_tail zig_always_tail_unavailable
...@@ -180,20 +184,58 @@ typedef char bool;...@@ -180,20 +184,58 @@ typedef char bool;
180#define zig_extern extern184#define zig_extern extern
181#endif185#endif
182186
183#if zig_has_attribute(alias)187#if _MSC_VER
184#define zig_export(sig, symbol, name) zig_extern sig __attribute__((alias(symbol)))
185#elif _MSC_VER
186#if _M_X64188#if _M_X64
187#define zig_export(sig, symbol, name) sig;\189#define zig_mangle_c(symbol) symbol
188 __pragma(comment(linker, "/alternatename:" name "=" symbol ))
189#else /*_M_X64 */190#else /*_M_X64 */
190#define zig_export(sig, symbol, name) sig;\191#define zig_mangle_c(symbol) "_" symbol
191 __pragma(comment(linker, "/alternatename:_" name "=_" symbol ))
192#endif /*_M_X64 */192#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)))
193#else206#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))
195#endif209#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
197#if zig_has_attribute(weak) || defined(zig_gnuc)239#if zig_has_attribute(weak) || defined(zig_gnuc)
198#define zig_weak_linkage __attribute__((weak))240#define zig_weak_linkage __attribute__((weak))
199#define zig_weak_linkage_fn __attribute__((weak))241#define zig_weak_linkage_fn __attribute__((weak))
...@@ -267,9 +309,6 @@ typedef char bool;...@@ -267,9 +309,6 @@ typedef char bool;
267#define zig_wasm_memory_grow(index, delta) zig_unimplemented()309#define zig_wasm_memory_grow(index, delta) zig_unimplemented()
268#endif310#endif
269311
270#define zig_concat(lhs, rhs) lhs##rhs
271#define zig_expand_concat(lhs, rhs) zig_concat(lhs, rhs)
272
273#if __STDC_VERSION__ >= 201112L312#if __STDC_VERSION__ >= 201112L
274#define zig_noreturn _Noreturn313#define zig_noreturn _Noreturn
275#elif zig_has_attribute(noreturn) || defined(zig_gnuc)314#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...@@ -2163,7 +2202,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo
2163 const uint8_t *rhs_bytes = rhs;2202 const uint8_t *rhs_bytes = rhs;
2164 uint16_t byte_offset = 0;2203 uint16_t byte_offset = 0;
2165 uint16_t remaining_bytes = zig_int_bytes(bits);2204 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);
2167 bool overflow = false;2206 bool overflow = false;
21682207
2169#if zig_big_endian2208#if zig_big_endian
...@@ -2171,7 +2210,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo...@@ -2171,7 +2210,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo
2171#endif2210#endif
21722211
2173 while (remaining_bytes >= 128 / CHAR_BIT) {2212 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
2176#if zig_big_endian2215#if zig_big_endian
2177 byte_offset -= 128 / CHAR_BIT;2216 byte_offset -= 128 / CHAR_BIT;
...@@ -2211,7 +2250,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo...@@ -2211,7 +2250,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo
2211 }2250 }
22122251
2213 while (remaining_bytes >= 64 / CHAR_BIT) {2252 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
2216#if zig_big_endian2255#if zig_big_endian
2217 byte_offset -= 64 / CHAR_BIT;2256 byte_offset -= 64 / CHAR_BIT;
...@@ -2251,7 +2290,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo...@@ -2251,7 +2290,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo
2251 }2290 }
22522291
2253 while (remaining_bytes >= 32 / CHAR_BIT) {2292 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
2256#if zig_big_endian2295#if zig_big_endian
2257 byte_offset -= 32 / CHAR_BIT;2296 byte_offset -= 32 / CHAR_BIT;
...@@ -2291,7 +2330,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo...@@ -2291,7 +2330,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo
2291 }2330 }
22922331
2293 while (remaining_bytes >= 16 / CHAR_BIT) {2332 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
2296#if zig_big_endian2335#if zig_big_endian
2297 byte_offset -= 16 / CHAR_BIT;2336 byte_offset -= 16 / CHAR_BIT;
...@@ -2331,7 +2370,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo...@@ -2331,7 +2370,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo
2331 }2370 }
23322371
2333 while (remaining_bytes >= 8 / CHAR_BIT) {2372 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
2336#if zig_big_endian2375#if zig_big_endian
2337 byte_offset -= 8 / CHAR_BIT;2376 byte_offset -= 8 / CHAR_BIT;
...@@ -2379,7 +2418,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo...@@ -2379,7 +2418,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo
2379 const uint8_t *rhs_bytes = rhs;2418 const uint8_t *rhs_bytes = rhs;
2380 uint16_t byte_offset = 0;2419 uint16_t byte_offset = 0;
2381 uint16_t remaining_bytes = zig_int_bytes(bits);2420 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);
2383 bool overflow = false;2422 bool overflow = false;
23842423
2385#if zig_big_endian2424#if zig_big_endian
...@@ -2387,7 +2426,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo...@@ -2387,7 +2426,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo
2387#endif2426#endif
23882427
2389 while (remaining_bytes >= 128 / CHAR_BIT) {2428 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
2392#if zig_big_endian2431#if zig_big_endian
2393 byte_offset -= 128 / CHAR_BIT;2432 byte_offset -= 128 / CHAR_BIT;
...@@ -2427,7 +2466,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo...@@ -2427,7 +2466,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo
2427 }2466 }
24282467
2429 while (remaining_bytes >= 64 / CHAR_BIT) {2468 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
2432#if zig_big_endian2471#if zig_big_endian
2433 byte_offset -= 64 / CHAR_BIT;2472 byte_offset -= 64 / CHAR_BIT;
...@@ -2467,7 +2506,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo...@@ -2467,7 +2506,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo
2467 }2506 }
24682507
2469 while (remaining_bytes >= 32 / CHAR_BIT) {2508 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
2472#if zig_big_endian2511#if zig_big_endian
2473 byte_offset -= 32 / CHAR_BIT;2512 byte_offset -= 32 / CHAR_BIT;
...@@ -2507,7 +2546,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo...@@ -2507,7 +2546,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo
2507 }2546 }
25082547
2509 while (remaining_bytes >= 16 / CHAR_BIT) {2548 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
2512#if zig_big_endian2551#if zig_big_endian
2513 byte_offset -= 16 / CHAR_BIT;2552 byte_offset -= 16 / CHAR_BIT;
...@@ -2547,7 +2586,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo...@@ -2547,7 +2586,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo
2547 }2586 }
25482587
2549 while (remaining_bytes >= 8 / CHAR_BIT) {2588 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
2552#if zig_big_endian2591#if zig_big_endian
2553 byte_offset -= 8 / CHAR_BIT;2592 byte_offset -= 8 / CHAR_BIT;
...@@ -3093,6 +3132,7 @@ ypedef uint32_t zig_f32;...@@ -3093,6 +3132,7 @@ ypedef uint32_t zig_f32;
30933132
3094#define zig_has_f64 13133#define zig_has_f64 1
3095#define zig_libc_name_f64(name) name3134#define zig_libc_name_f64(name) name
3135
3096#if _MSC_VER3136#if _MSC_VER
3097#define zig_init_special_f64(sign, name, arg, repr) sign zig_make_f64(zig_msvc_flt_##name, )3137#define zig_init_special_f64(sign, name, arg, repr) sign zig_make_f64(zig_msvc_flt_##name, )
3098#else3138#else
...@@ -3336,31 +3376,31 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0)))...@@ -3336,31 +3376,31 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0)))
3336 zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, sub, -) \3376 zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, sub, -) \
3337 zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, mul, *) \3377 zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, mul, *) \
3338 zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, div, /) \3378 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); \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)) \
3340 zig_extern zig_f##w zig_libc_name_f##w(sin)(zig_f##w); \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)) \
3341 zig_extern zig_f##w zig_libc_name_f##w(cos)(zig_f##w); \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)) \
3342 zig_extern zig_f##w zig_libc_name_f##w(tan)(zig_f##w); \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)) \
3343 zig_extern zig_f##w zig_libc_name_f##w(exp)(zig_f##w); \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)) \
3344 zig_extern zig_f##w zig_libc_name_f##w(exp2)(zig_f##w); \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)) \
3345 zig_extern zig_f##w zig_libc_name_f##w(log)(zig_f##w); \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)) \
3346 zig_extern zig_f##w zig_libc_name_f##w(log2)(zig_f##w); \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)) \
3347 zig_extern zig_f##w zig_libc_name_f##w(log10)(zig_f##w); \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)) \
3348 zig_extern zig_f##w zig_libc_name_f##w(fabs)(zig_f##w); \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)) \
3349 zig_extern zig_f##w zig_libc_name_f##w(floor)(zig_f##w); \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)) \
3350 zig_extern zig_f##w zig_libc_name_f##w(ceil)(zig_f##w); \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)) \
3351 zig_extern zig_f##w zig_libc_name_f##w(round)(zig_f##w); \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)) \
3352 zig_extern zig_f##w zig_libc_name_f##w(trunc)(zig_f##w); \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)) \
3353 zig_extern zig_f##w zig_libc_name_f##w(fmod)(zig_f##w, zig_f##w); \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)) \
3354 zig_extern zig_f##w zig_libc_name_f##w(fmin)(zig_f##w, zig_f##w); \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)) \
3355 zig_extern zig_f##w zig_libc_name_f##w(fmax)(zig_f##w, zig_f##w); \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)) \
3356 zig_extern zig_f##w zig_libc_name_f##w(fma)(zig_f##w, zig_f##w, zig_f##w); \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)) \
3357\3397\
3358 static inline zig_f##w zig_div_trunc_f##w(zig_f##w lhs, zig_f##w rhs) { \3398 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)); \
3360 } \3400 } \
3361\3401\
3362 static inline zig_f##w zig_div_floor_f##w(zig_f##w lhs, zig_f##w rhs) { \3402 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)); \
3364 } \3404 } \
3365\3405\
3366 static inline zig_f##w zig_mod_f##w(zig_f##w lhs, zig_f##w rhs) { \3406 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)...@@ -3437,129 +3477,134 @@ zig_float_builtins(64)
3437/* Note that zig_atomicrmw_expected is needed to handle aliasing between res and arg. */3477/* Note that zig_atomicrmw_expected is needed to handle aliasing between res and arg. */
3438#define zig_atomicrmw_xchg_float(res, obj, arg, order, Type, ReprType) do { \3478#define zig_atomicrmw_xchg_float(res, obj, arg, order, Type, ReprType) do { \
3439 zig_##Type zig_atomicrmw_expected; \3479 zig_##Type zig_atomicrmw_expected; \
3440 zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \3480 zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
3441 while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, memory_order_relaxed, Type, ReprType)); \3481 while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, zig_memory_order_relaxed, Type, ReprType)); \
3442 res = zig_atomicrmw_expected; \3482 res = zig_atomicrmw_expected; \
3443} while (0)3483} while (0)
3444#define zig_atomicrmw_add_float(res, obj, arg, order, Type, ReprType) do { \3484#define zig_atomicrmw_add_float(res, obj, arg, order, Type, ReprType) do { \
3445 zig_##Type zig_atomicrmw_expected; \3485 zig_##Type zig_atomicrmw_expected; \
3446 zig_##Type zig_atomicrmw_desired; \3486 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); \
3448 do { \3488 do { \
3449 zig_atomicrmw_desired = zig_add_##Type(zig_atomicrmw_expected, arg); \3489 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)); \
3451 res = zig_atomicrmw_expected; \3491 res = zig_atomicrmw_expected; \
3452} while (0)3492} while (0)
3453#define zig_atomicrmw_sub_float(res, obj, arg, order, Type, ReprType) do { \3493#define zig_atomicrmw_sub_float(res, obj, arg, order, Type, ReprType) do { \
3454 zig_##Type zig_atomicrmw_expected; \3494 zig_##Type zig_atomicrmw_expected; \
3455 zig_##Type zig_atomicrmw_desired; \3495 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); \
3457 do { \3497 do { \
3458 zig_atomicrmw_desired = zig_sub_##Type(zig_atomicrmw_expected, arg); \3498 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)); \
3460 res = zig_atomicrmw_expected; \3500 res = zig_atomicrmw_expected; \
3461} while (0)3501} while (0)
3462#define zig_atomicrmw_min_float(res, obj, arg, order, Type, ReprType) do { \3502#define zig_atomicrmw_min_float(res, obj, arg, order, Type, ReprType) do { \
3463 zig_##Type zig_atomicrmw_expected; \3503 zig_##Type zig_atomicrmw_expected; \
3464 zig_##Type zig_atomicrmw_desired; \3504 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); \
3466 do { \3506 do { \
3467 zig_atomicrmw_desired = zig_libc_name_##Type(fmin)(zig_atomicrmw_expected, arg); \3507 zig_atomicrmw_desired = zig_float_fn_##Type##_fmin(zig_atomicrmw_expected, arg); \
3468 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \3508 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
3469 res = zig_atomicrmw_expected; \3509 res = zig_atomicrmw_expected; \
3470} while (0)3510} while (0)
3471#define zig_atomicrmw_max_float(res, obj, arg, order, Type, ReprType) do { \3511#define zig_atomicrmw_max_float(res, obj, arg, order, Type, ReprType) do { \
3472 zig_##Type zig_atomicrmw_expected; \3512 zig_##Type zig_atomicrmw_expected; \
3473 zig_##Type zig_atomicrmw_desired; \3513 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); \
3475 do { \3515 do { \
3476 zig_atomicrmw_desired = zig_libc_name_##Type(fmax)(zig_atomicrmw_expected, arg); \3516 zig_atomicrmw_desired = zig_float_fn_##Type##_fmax(zig_atomicrmw_expected, arg); \
3477 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \3517 } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
3478 res = zig_atomicrmw_expected; \3518 res = zig_atomicrmw_expected; \
3479} while (0)3519} while (0)
34803520
3481#define zig_atomicrmw_xchg_int128(res, obj, arg, order, Type, ReprType) do { \3521#define zig_atomicrmw_xchg_int128(res, obj, arg, order, Type, ReprType) do { \
3482 zig_##Type zig_atomicrmw_expected; \3522 zig_##Type zig_atomicrmw_expected; \
3483 zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \3523 zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
3484 while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, memory_order_relaxed, Type, ReprType)); \3524 while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, zig_memory_order_relaxed, Type, ReprType)); \
3485 res = zig_atomicrmw_expected; \3525 res = zig_atomicrmw_expected; \
3486} while (0)3526} while (0)
3487#define zig_atomicrmw_add_int128(res, obj, arg, order, Type, ReprType) do { \3527#define zig_atomicrmw_add_int128(res, obj, arg, order, Type, ReprType) do { \
3488 zig_##Type zig_atomicrmw_expected; \3528 zig_##Type zig_atomicrmw_expected; \
3489 zig_##Type zig_atomicrmw_desired; \3529 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); \
3491 do { \3531 do { \
3492 zig_atomicrmw_desired = zig_add_##Type(zig_atomicrmw_expected, arg); \3532 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)); \
3494 res = zig_atomicrmw_expected; \3534 res = zig_atomicrmw_expected; \
3495} while (0)3535} while (0)
3496#define zig_atomicrmw_sub_int128(res, obj, arg, order, Type, ReprType) do { \3536#define zig_atomicrmw_sub_int128(res, obj, arg, order, Type, ReprType) do { \
3497 zig_##Type zig_atomicrmw_expected; \3537 zig_##Type zig_atomicrmw_expected; \
3498 zig_##Type zig_atomicrmw_desired; \3538 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); \
3500 do { \3540 do { \
3501 zig_atomicrmw_desired = zig_sub_##Type(zig_atomicrmw_expected, arg); \3541 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)); \
3503 res = zig_atomicrmw_expected; \3543 res = zig_atomicrmw_expected; \
3504} while (0)3544} while (0)
3505#define zig_atomicrmw_and_int128(res, obj, arg, order, Type, ReprType) do { \3545#define zig_atomicrmw_and_int128(res, obj, arg, order, Type, ReprType) do { \
3506 zig_##Type zig_atomicrmw_expected; \3546 zig_##Type zig_atomicrmw_expected; \
3507 zig_##Type zig_atomicrmw_desired; \3547 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); \
3509 do { \3549 do { \
3510 zig_atomicrmw_desired = zig_and_##Type(zig_atomicrmw_expected, arg); \3550 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)); \
3512 res = zig_atomicrmw_expected; \3552 res = zig_atomicrmw_expected; \
3513} while (0)3553} while (0)
3514#define zig_atomicrmw_nand_int128(res, obj, arg, order, Type, ReprType) do { \3554#define zig_atomicrmw_nand_int128(res, obj, arg, order, Type, ReprType) do { \
3515 zig_##Type zig_atomicrmw_expected; \3555 zig_##Type zig_atomicrmw_expected; \
3516 zig_##Type zig_atomicrmw_desired; \3556 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); \
3518 do { \3558 do { \
3519 zig_atomicrmw_desired = zig_not_##Type(zig_and_##Type(zig_atomicrmw_expected, arg), 128); \3559 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)); \
3521 res = zig_atomicrmw_expected; \3561 res = zig_atomicrmw_expected; \
3522} while (0)3562} while (0)
3523#define zig_atomicrmw_or_int128(res, obj, arg, order, Type, ReprType) do { \3563#define zig_atomicrmw_or_int128(res, obj, arg, order, Type, ReprType) do { \
3524 zig_##Type zig_atomicrmw_expected; \3564 zig_##Type zig_atomicrmw_expected; \
3525 zig_##Type zig_atomicrmw_desired; \3565 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); \
3527 do { \3567 do { \
3528 zig_atomicrmw_desired = zig_or_##Type(zig_atomicrmw_expected, arg); \3568 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)); \
3530 res = zig_atomicrmw_expected; \3570 res = zig_atomicrmw_expected; \
3531} while (0)3571} while (0)
3532#define zig_atomicrmw_xor_int128(res, obj, arg, order, Type, ReprType) do { \3572#define zig_atomicrmw_xor_int128(res, obj, arg, order, Type, ReprType) do { \
3533 zig_##Type zig_atomicrmw_expected; \3573 zig_##Type zig_atomicrmw_expected; \
3534 zig_##Type zig_atomicrmw_desired; \3574 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); \
3536 do { \3576 do { \
3537 zig_atomicrmw_desired = zig_xor_##Type(zig_atomicrmw_expected, arg); \3577 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)); \
3539 res = zig_atomicrmw_expected; \3579 res = zig_atomicrmw_expected; \
3540} while (0)3580} while (0)
3541#define zig_atomicrmw_min_int128(res, obj, arg, order, Type, ReprType) do { \3581#define zig_atomicrmw_min_int128(res, obj, arg, order, Type, ReprType) do { \
3542 zig_##Type zig_atomicrmw_expected; \3582 zig_##Type zig_atomicrmw_expected; \
3543 zig_##Type zig_atomicrmw_desired; \3583 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); \
3545 do { \3585 do { \
3546 zig_atomicrmw_desired = zig_min_##Type(zig_atomicrmw_expected, arg); \3586 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)); \
3548 res = zig_atomicrmw_expected; \3588 res = zig_atomicrmw_expected; \
3549} while (0)3589} while (0)
3550#define zig_atomicrmw_max_int128(res, obj, arg, order, Type, ReprType) do { \3590#define zig_atomicrmw_max_int128(res, obj, arg, order, Type, ReprType) do { \
3551 zig_##Type zig_atomicrmw_expected; \3591 zig_##Type zig_atomicrmw_expected; \
3552 zig_##Type zig_atomicrmw_desired; \3592 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); \
3554 do { \3594 do { \
3555 zig_atomicrmw_desired = zig_max_##Type(zig_atomicrmw_expected, arg); \3595 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)); \
3557 res = zig_atomicrmw_expected; \3597 res = zig_atomicrmw_expected; \
3558} while (0)3598} while (0)
35593599
3560#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)3600#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
3561#include <stdatomic.h>3601#include <stdatomic.h>
3562typedef enum memory_order zig_memory_order;3602typedef 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
3563#define zig_atomic(Type) _Atomic(Type)3608#define zig_atomic(Type) _Atomic(Type)
3564#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail)3609#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail)
3565#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_weak_explicit (obj, &(expected), desired, succ, fail)3610#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;...@@ -3583,12 +3628,11 @@ typedef enum memory_order zig_memory_order;
3583#define zig_fence(order) atomic_thread_fence(order)3628#define zig_fence(order) atomic_thread_fence(order)
3584#elif defined(__GNUC__)3629#elif defined(__GNUC__)
3585typedef int zig_memory_order;3630typedef int zig_memory_order;
3586#define memory_order_relaxed __ATOMIC_RELAXED3631#define zig_memory_order_relaxed __ATOMIC_RELAXED
3587#define memory_order_consume __ATOMIC_CONSUME3632#define zig_memory_order_acquire __ATOMIC_ACQUIRE
3588#define memory_order_acquire __ATOMIC_ACQUIRE3633#define zig_memory_order_release __ATOMIC_RELEASE
3589#define memory_order_release __ATOMIC_RELEASE3634#define zig_memory_order_acq_rel __ATOMIC_ACQ_REL
3590#define memory_order_acq_rel __ATOMIC_ACQ_REL3635#define zig_memory_order_seq_cst __ATOMIC_SEQ_CST
3591#define memory_order_seq_cst __ATOMIC_SEQ_CST
3592#define zig_atomic(Type) Type3636#define zig_atomic(Type) Type
3593#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, &(expected), &(desired), false, succ, fail)3637#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, &(expected), &(desired), false, succ, fail)
3594#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, &(expected), &(desired), true, succ, fail)3638#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;...@@ -3607,12 +3651,11 @@ typedef int zig_memory_order;
3607#define zig_atomicrmw_xchg_float zig_atomicrmw_xchg3651#define zig_atomicrmw_xchg_float zig_atomicrmw_xchg
3608#define zig_fence(order) __atomic_thread_fence(order)3652#define zig_fence(order) __atomic_thread_fence(order)
3609#elif _MSC_VER && (_M_IX86 || _M_X64)3653#elif _MSC_VER && (_M_IX86 || _M_X64)
3610#define memory_order_relaxed 03654#define zig_memory_order_relaxed 0
3611#define memory_order_consume 13655#define zig_memory_order_acquire 2
3612#define memory_order_acquire 23656#define zig_memory_order_release 3
3613#define memory_order_release 33657#define zig_memory_order_acq_rel 4
3614#define memory_order_acq_rel 43658#define zig_memory_order_seq_cst 5
3615#define memory_order_seq_cst 5
3616#define zig_atomic(Type) Type3659#define zig_atomic(Type) Type
3617#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_msvc_cmpxchg_##Type(obj, &(expected), desired)3660#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_msvc_cmpxchg_##Type(obj, &(expected), desired)
3618#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) zig_cmpxchg_strong(obj, expected, desired, succ, fail, Type, ReprType)3661#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;...@@ -3634,12 +3677,11 @@ typedef int zig_memory_order;
3634#endif3677#endif
3635/* TODO: _MSC_VER && (_M_ARM || _M_ARM64) */3678/* TODO: _MSC_VER && (_M_ARM || _M_ARM64) */
3636#else3679#else
3637#define memory_order_relaxed 03680#define zig_memory_order_relaxed 0
3638#define memory_order_consume 13681#define zig_memory_order_acquire 2
3639#define memory_order_acquire 23682#define zig_memory_order_release 3
3640#define memory_order_release 33683#define zig_memory_order_acq_rel 4
3641#define memory_order_acq_rel 43684#define zig_memory_order_seq_cst 5
3642#define memory_order_seq_cst 5
3643#define zig_atomic(Type) Type3685#define zig_atomic(Type) Type
3644#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable3686#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable
3645#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable3687#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...@@ -3830,9 +3872,32 @@ static inline bool zig_msvc_cmpxchg_u128(zig_u128 volatile* obj, zig_u128* expec
3830 return _InterlockedCompareExchange128((__int64 volatile*)obj, (__int64)zig_hi_u128(desired), (__int64)zig_lo_u128(desired), (__int64*)expected);3872 return _InterlockedCompareExchange128((__int64 volatile*)obj, (__int64)zig_hi_u128(desired), (__int64)zig_lo_u128(desired), (__int64*)expected);
3831}3873}
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
3833static inline bool zig_msvc_cmpxchg_i128(zig_i128 volatile* obj, zig_i128* expected, zig_i128 desired) {3886static inline bool zig_msvc_cmpxchg_i128(zig_i128 volatile* obj, zig_i128* expected, zig_i128 desired) {
3834 return _InterlockedCompareExchange128((__int64 volatile*)obj, (__int64)zig_hi_i128(desired), (__int64)zig_lo_i128(desired), (__int64*)expected);3887 return _InterlockedCompareExchange128((__int64 volatile*)obj, (__int64)zig_hi_i128(desired), (__int64)zig_lo_i128(desired), (__int64*)expected);
3835}3888}
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
3836#endif /* _M_IX86 */3901#endif /* _M_IX86 */
38373902
3838#endif /* _MSC_VER && (_M_IX86 || _M_X64) */3903#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" {...@@ -311,12 +311,6 @@ test "page aligned array on stack" {
311 try expect(number2 == 43);311 try expect(number2 == 43);
312}312}
313313
314fn derp() align(@sizeOf(usize) * 2) i32 {
315 return 1234;
316}
317fn noop1() align(1) void {}
318fn noop4() align(4) void {}
319
320test "function alignment" {314test "function alignment" {
321 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;315 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
322 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;316 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
...@@ -325,11 +319,25 @@ test "function alignment" {...@@ -325,11 +319,25 @@ test "function alignment" {
325 // function alignment is a compile error on wasm32/wasm64319 // function alignment is a compile error on wasm32/wasm64
326 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;320 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
327321
328 try expect(derp() == 1234);322 const S = struct {
329 try expect(@TypeOf(noop1) == fn () align(1) void);323 fn alignExpr() align(@sizeOf(usize) * 2) i32 {
330 try expect(@TypeOf(noop4) == fn () align(4) void);324 return 1234;
331 noop1();325 }
332 noop4();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);
333}341}
334342
335test "implicitly decreasing fn alignment" {343test "implicitly decreasing fn alignment" {
...@@ -345,7 +353,7 @@ test "implicitly decreasing fn alignment" {...@@ -345,7 +353,7 @@ test "implicitly decreasing fn alignment" {
345 try testImplicitlyDecreaseFnAlign(alignedBig, 5678);353 try testImplicitlyDecreaseFnAlign(alignedBig, 5678);
346}354}
347355
348fn testImplicitlyDecreaseFnAlign(ptr: *const fn () align(1) i32, answer: i32) !void {356fn testImplicitlyDecreaseFnAlign(ptr: *align(1) const fn () i32, answer: i32) !void {
349 try expect(ptr() == answer);357 try expect(ptr() == answer);
350}358}
351359
...@@ -368,10 +376,10 @@ test "@alignCast functions" {...@@ -368,10 +376,10 @@ test "@alignCast functions" {
368376
369 try expect(fnExpectsOnly1(simple4) == 0x19);377 try expect(fnExpectsOnly1(simple4) == 0x19);
370}378}
371fn fnExpectsOnly1(ptr: *const fn () align(1) i32) i32 {379fn fnExpectsOnly1(ptr: *align(1) const fn () i32) i32 {
372 return fnExpects4(@alignCast(ptr));380 return fnExpects4(@alignCast(ptr));
373}381}
374fn fnExpects4(ptr: *const fn () align(4) i32) i32 {382fn fnExpects4(ptr: *align(4) const fn () i32) i32 {
375 return ptr();383 return ptr();
376}384}
377fn simple4() align(4) i32 {385fn simple4() align(4) i32 {
test/behavior/type.zig-2
...@@ -527,7 +527,6 @@ test "Type.Fn" {...@@ -527,7 +527,6 @@ test "Type.Fn" {
527 {527 {
528 const fn_info = std.builtin.Type{ .Fn = .{528 const fn_info = std.builtin.Type{ .Fn = .{
529 .calling_convention = .C,529 .calling_convention = .C,
530 .alignment = 0,
531 .is_generic = false,530 .is_generic = false,
532 .is_var_args = false,531 .is_var_args = false,
533 .return_type = void,532 .return_type = void,
...@@ -643,7 +642,6 @@ test "reified function type params initialized with field pointer" {...@@ -643,7 +642,6 @@ test "reified function type params initialized with field pointer" {
643 const Bar = @Type(.{642 const Bar = @Type(.{
644 .Fn = .{643 .Fn = .{
645 .calling_convention = .Unspecified,644 .calling_convention = .Unspecified,
646 .alignment = 0,
647 .is_generic = false,645 .is_generic = false,
648 .is_var_args = false,646 .is_var_args = false,
649 .return_type = void,647 .return_type = void,
test/behavior/type_info.zig+32-10
...@@ -356,16 +356,38 @@ test "type info: function type info" {...@@ -356,16 +356,38 @@ test "type info: function type info" {
356}356}
357357
358fn testFunction() !void {358fn testFunction() !void {
359 const fn_info = @typeInfo(@TypeOf(typeInfoFoo));359 const foo_fn_type = @TypeOf(typeInfoFoo);
360 try expect(fn_info == .Fn);360 const foo_fn_info = @typeInfo(foo_fn_type);
361 try expect(fn_info.Fn.alignment > 0);361 try expect(foo_fn_info.Fn.calling_convention == .C);
362 try expect(fn_info.Fn.calling_convention == .C);362 try expect(!foo_fn_info.Fn.is_generic);
363 try expect(!fn_info.Fn.is_generic);363 try expect(foo_fn_info.Fn.params.len == 2);
364 try expect(fn_info.Fn.params.len == 2);364 try expect(foo_fn_info.Fn.is_var_args);
365 try expect(fn_info.Fn.is_var_args);365 try expect(foo_fn_info.Fn.return_type.? == usize);
366 try expect(fn_info.Fn.return_type.? == usize);366 const foo_ptr_fn_info = @typeInfo(@TypeOf(&typeInfoFoo));
367 const fn_aligned_info = @typeInfo(@TypeOf(typeInfoFooAligned));367 try expect(foo_ptr_fn_info.Pointer.size == .One);
368 try expect(fn_aligned_info.Fn.alignment == 4);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);
369}391}
370392
371extern fn typeInfoFoo(a: usize, b: bool, ...) callconv(.C) usize;393extern fn typeInfoFoo(a: usize, b: bool, ...) callconv(.C) usize;
test/behavior/typename.zig+2-4
...@@ -78,11 +78,9 @@ test "basic" {...@@ -78,11 +78,9 @@ test "basic" {
78 try expectEqualStrings("fn (comptime u32) void", @typeName(fn (comptime u32) void));78 try expectEqualStrings("fn (comptime u32) void", @typeName(fn (comptime u32) void));
79 try expectEqualStrings("fn (noalias []u8) void", @typeName(fn (noalias []u8) void));79 try expectEqualStrings("fn (noalias []u8) void", @typeName(fn (noalias []u8) void));
8080
81 try expectEqualStrings("fn () align(32) void", @typeName(fn () align(32) void));
82 try expectEqualStrings("fn () callconv(.C) void", @typeName(fn () callconv(.C) void));81 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));82 try expectEqualStrings("fn (...) callconv(.C) void", @typeName(fn (...) callconv(.C) void));
84 try expectEqualStrings("fn (...) align(32) callconv(.C) void", @typeName(fn (...) align(32) callconv(.C) void));83 try expectEqualStrings("fn (u32, ...) callconv(.C) void", @typeName(fn (u32, ...) callconv(.C) void));
85 try expectEqualStrings("fn (u32, ...) align(32) callconv(.C) void", @typeName(fn (u32, ...) align(32) callconv(.C) void));
86}84}
8785
88test "top level decl" {86test "top level decl" {
test/cases/compile_errors/function_ptr_alignment.zig+8-20
...@@ -1,28 +1,16 @@...@@ -1,28 +1,16 @@
1comptime {1fn align1() align(1) void {}
2 var a: *align(2) @TypeOf(foo) = undefined;2fn align2() align(2) void {}
3 _ = &a;
4}
5fn foo() void {}
63
7comptime {4comptime {
8 var a: *align(1) fn () void = undefined;5 _ = @as(*align(1) const fn () void, &align2);
9 _ = &a;6 _ = @as(*align(1) const fn () void, &align1);
10}7 _ = @as(*align(2) const fn () void, &align2);
11comptime {8 _ = @as(*align(2) const fn () void, &align1);
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;
22}9}
2310
24// error11// error
25// backend=stage212// backend=stage2
26// target=native13// target=native
27//14//
28// :20:19: error: function pointer alignment disagrees with function alignment15// :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 @@...@@ -1,7 +1,7 @@
1export fn entry() void {1export fn entry() void {
2 testImplicitlyDecreaseFnAlign(alignedSmall, 1234);2 testImplicitlyDecreaseFnAlign(alignedSmall, 1234);
3}3}
4fn testImplicitlyDecreaseFnAlign(ptr: *const fn () align(8) i32, answer: i32) void {4fn testImplicitlyDecreaseFnAlign(ptr: *align(8) const fn () i32, answer: i32) void {
5 if (ptr() != answer) unreachable;5 if (ptr() != answer) unreachable;
6}6}
7fn alignedSmall() align(4) i32 {7fn alignedSmall() align(4) i32 {
...@@ -12,5 +12,5 @@ fn alignedSmall() align(4) i32 {...@@ -12,5 +12,5 @@ fn alignedSmall() align(4) i32 {
12// backend=stage212// backend=stage2
13// target=x86_64-linux13// target=x86_64-linux
14//14//
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'
16// :2:35: note: pointer alignment '4' cannot cast into pointer alignment '8'16// :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 @@...@@ -1,7 +1,6 @@
1const Foo = @Type(.{1const Foo = @Type(.{
2 .Fn = .{2 .Fn = .{
3 .calling_convention = .Unspecified,3 .calling_convention = .Unspecified,
4 .alignment = 0,
5 .is_generic = true,4 .is_generic = true,
6 .is_var_args = false,5 .is_var_args = false,
7 .return_type = u0,6 .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 @@...@@ -1,7 +1,6 @@
1const Foo = @Type(.{1const Foo = @Type(.{
2 .Fn = .{2 .Fn = .{
3 .calling_convention = .Unspecified,3 .calling_convention = .Unspecified,
4 .alignment = 0,
5 .is_generic = false,4 .is_generic = false,
6 .is_var_args = true,5 .is_var_args = true,
7 .return_type = u0,6 .return_type = u0,
test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig-1
...@@ -1,7 +1,6 @@...@@ -1,7 +1,6 @@
1const Foo = @Type(.{1const Foo = @Type(.{
2 .Fn = .{2 .Fn = .{
3 .calling_convention = .Unspecified,3 .calling_convention = .Unspecified,
4 .alignment = 0,
5 .is_generic = false,4 .is_generic = false,
6 .is_var_args = false,5 .is_var_args = false,
7 .return_type = null,6 .return_type = null,