diff --git a/doc/langref.html.in b/doc/langref.html.in
index 9d48238843032a0cd0dc286b2494ae9141de19ac..7ffbcc01108669087224d943b3fc9a36ceaa98ea 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -2780,10 +2780,16 @@ fn noop4() align(4) void {}
test "function alignment" {
try expect(derp() == 1234);
- try expect(@TypeOf(noop1) == fn () align(1) void);
- try expect(@TypeOf(noop4) == fn () align(4) void);
+ try expect(@TypeOf(derp) == fn () i32);
+ try expect(@TypeOf(&derp) == *align(@sizeOf(usize) * 2) const fn () i32);
+
noop1();
+ try expect(@TypeOf(noop1) == fn () void);
+ try expect(@TypeOf(&noop1) == *align(1) const fn () void);
+
noop4();
+ try expect(@TypeOf(noop4) == fn () void);
+ try expect(@TypeOf(&noop4) == *align(4) const fn () void);
}
{#code_end#}
diff --git a/lib/build_runner.zig b/lib/build_runner.zig
deleted file mode 100644
index f19713776916b94baada339ef967edd0a9aa303a..0000000000000000000000000000000000000000
--- a/lib/build_runner.zig
+++ /dev/null
@@ -1,1293 +0,0 @@
-const root = @import("@build");
-const std = @import("std");
-const builtin = @import("builtin");
-const assert = std.debug.assert;
-const io = std.io;
-const fmt = std.fmt;
-const mem = std.mem;
-const process = std.process;
-const ArrayList = std.ArrayList;
-const File = std.fs.File;
-const Step = std.Build.Step;
-
-pub const dependencies = @import("@dependencies");
-
-pub fn main() !void {
- // Here we use an ArenaAllocator backed by a page allocator because a build is a short-lived,
- // one shot program. We don't need to waste time freeing memory and finding places to squish
- // bytes into. So we free everything all at once at the very end.
- var single_threaded_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
- defer single_threaded_arena.deinit();
-
- var thread_safe_arena: std.heap.ThreadSafeAllocator = .{
- .child_allocator = single_threaded_arena.allocator(),
- };
- const arena = thread_safe_arena.allocator();
-
- const args = try process.argsAlloc(arena);
-
- // skip my own exe name
- var arg_idx: usize = 1;
-
- const zig_exe = nextArg(args, &arg_idx) orelse {
- std.debug.print("Expected path to zig compiler\n", .{});
- return error.InvalidArgs;
- };
- const build_root = nextArg(args, &arg_idx) orelse {
- std.debug.print("Expected build root directory path\n", .{});
- return error.InvalidArgs;
- };
- const cache_root = nextArg(args, &arg_idx) orelse {
- std.debug.print("Expected cache root directory path\n", .{});
- return error.InvalidArgs;
- };
- const global_cache_root = nextArg(args, &arg_idx) orelse {
- std.debug.print("Expected global cache root directory path\n", .{});
- return error.InvalidArgs;
- };
-
- const build_root_directory: std.Build.Cache.Directory = .{
- .path = build_root,
- .handle = try std.fs.cwd().openDir(build_root, .{}),
- };
-
- const local_cache_directory: std.Build.Cache.Directory = .{
- .path = cache_root,
- .handle = try std.fs.cwd().makeOpenPath(cache_root, .{}),
- };
-
- const global_cache_directory: std.Build.Cache.Directory = .{
- .path = global_cache_root,
- .handle = try std.fs.cwd().makeOpenPath(global_cache_root, .{}),
- };
-
- var graph: std.Build.Graph = .{
- .arena = arena,
- .cache = .{
- .gpa = arena,
- .manifest_dir = try local_cache_directory.handle.makeOpenPath("h", .{}),
- },
- .zig_exe = zig_exe,
- .env_map = try process.getEnvMap(arena),
- .global_cache_root = global_cache_directory,
- };
-
- graph.cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
- graph.cache.addPrefix(build_root_directory);
- graph.cache.addPrefix(local_cache_directory);
- graph.cache.addPrefix(global_cache_directory);
- graph.cache.hash.addBytes(builtin.zig_version_string);
-
- const builder = try std.Build.create(
- &graph,
- build_root_directory,
- local_cache_directory,
- dependencies.root_deps,
- );
-
- var targets = ArrayList([]const u8).init(arena);
- var debug_log_scopes = ArrayList([]const u8).init(arena);
- var thread_pool_options: std.Thread.Pool.Options = .{ .allocator = arena };
-
- var install_prefix: ?[]const u8 = null;
- var dir_list = std.Build.DirList{};
- var summary: ?Summary = null;
- var max_rss: u64 = 0;
- var skip_oom_steps: bool = false;
- var color: Color = .auto;
- var seed: u32 = 0;
- var prominent_compile_errors: bool = false;
- var help_menu: bool = false;
- var steps_menu: bool = false;
- var output_tmp_nonce: ?[16]u8 = null;
-
- while (nextArg(args, &arg_idx)) |arg| {
- if (mem.startsWith(u8, arg, "-Z")) {
- if (arg.len != 18) fatalWithHint("bad argument: '{s}'", .{arg});
- output_tmp_nonce = arg[2..18].*;
- } else if (mem.startsWith(u8, arg, "-D")) {
- const option_contents = arg[2..];
- if (option_contents.len == 0)
- fatalWithHint("expected option name after '-D'", .{});
- if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| {
- const option_name = option_contents[0..name_end];
- const option_value = option_contents[name_end + 1 ..];
- if (try builder.addUserInputOption(option_name, option_value))
- fatal(" access the help menu with 'zig build -h'", .{});
- } else {
- if (try builder.addUserInputFlag(option_contents))
- fatal(" access the help menu with 'zig build -h'", .{});
- }
- } else if (mem.startsWith(u8, arg, "-")) {
- if (mem.eql(u8, arg, "--verbose")) {
- builder.verbose = true;
- } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
- help_menu = true;
- } else if (mem.eql(u8, arg, "-p") or mem.eql(u8, arg, "--prefix")) {
- install_prefix = nextArgOrFatal(args, &arg_idx);
- } else if (mem.eql(u8, arg, "-l") or mem.eql(u8, arg, "--list-steps")) {
- steps_menu = true;
- } else if (mem.startsWith(u8, arg, "-fsys=")) {
- const name = arg["-fsys=".len..];
- graph.system_library_options.put(arena, name, .user_enabled) catch @panic("OOM");
- } else if (mem.startsWith(u8, arg, "-fno-sys=")) {
- const name = arg["-fno-sys=".len..];
- graph.system_library_options.put(arena, name, .user_disabled) catch @panic("OOM");
- } else if (mem.eql(u8, arg, "--release")) {
- builder.release_mode = .any;
- } else if (mem.startsWith(u8, arg, "--release=")) {
- const text = arg["--release=".len..];
- builder.release_mode = std.meta.stringToEnum(std.Build.ReleaseMode, text) orelse {
- fatalWithHint("expected [off|any|fast|safe|small] in '{s}', found '{s}'", .{
- arg, text,
- });
- };
- } else if (mem.eql(u8, arg, "--host-target")) {
- graph.host_query_options.arch_os_abi = nextArgOrFatal(args, &arg_idx);
- } else if (mem.eql(u8, arg, "--host-cpu")) {
- graph.host_query_options.cpu_features = nextArgOrFatal(args, &arg_idx);
- } else if (mem.eql(u8, arg, "--host-dynamic-linker")) {
- graph.host_query_options.dynamic_linker = nextArgOrFatal(args, &arg_idx);
- } else if (mem.eql(u8, arg, "--prefix-lib-dir")) {
- dir_list.lib_dir = nextArgOrFatal(args, &arg_idx);
- } else if (mem.eql(u8, arg, "--prefix-exe-dir")) {
- dir_list.exe_dir = nextArgOrFatal(args, &arg_idx);
- } else if (mem.eql(u8, arg, "--prefix-include-dir")) {
- dir_list.include_dir = nextArgOrFatal(args, &arg_idx);
- } else if (mem.eql(u8, arg, "--sysroot")) {
- builder.sysroot = nextArgOrFatal(args, &arg_idx);
- } else if (mem.eql(u8, arg, "--maxrss")) {
- const max_rss_text = nextArgOrFatal(args, &arg_idx);
- max_rss = std.fmt.parseIntSizeSuffix(max_rss_text, 10) catch |err| {
- std.debug.print("invalid byte size: '{s}': {s}\n", .{
- max_rss_text, @errorName(err),
- });
- process.exit(1);
- };
- } else if (mem.eql(u8, arg, "--skip-oom-steps")) {
- skip_oom_steps = true;
- } else if (mem.eql(u8, arg, "--search-prefix")) {
- const search_prefix = nextArgOrFatal(args, &arg_idx);
- builder.addSearchPrefix(search_prefix);
- } else if (mem.eql(u8, arg, "--libc")) {
- builder.libc_file = nextArgOrFatal(args, &arg_idx);
- } else if (mem.eql(u8, arg, "--color")) {
- const next_arg = nextArg(args, &arg_idx) orelse
- fatalWithHint("expected [auto|on|off] after '{s}'", .{arg});
- color = std.meta.stringToEnum(Color, next_arg) orelse {
- fatalWithHint("expected [auto|on|off] after '{s}', found '{s}'", .{
- arg, next_arg,
- });
- };
- } else if (mem.eql(u8, arg, "--summary")) {
- const next_arg = nextArg(args, &arg_idx) orelse
- fatalWithHint("expected [all|new|failures|none] after '{s}'", .{arg});
- summary = std.meta.stringToEnum(Summary, next_arg) orelse {
- fatalWithHint("expected [all|failures|none] after '{s}', found '{s}'", .{
- arg, next_arg,
- });
- };
- } else if (mem.eql(u8, arg, "--zig-lib-dir")) {
- builder.zig_lib_dir = .{ .cwd_relative = nextArgOrFatal(args, &arg_idx) };
- } else if (mem.eql(u8, arg, "--seed")) {
- const next_arg = nextArg(args, &arg_idx) orelse
- fatalWithHint("expected u32 after '{s}'", .{arg});
- seed = std.fmt.parseUnsigned(u32, next_arg, 0) catch |err| {
- fatal("unable to parse seed '{s}' as 32-bit integer: {s}\n", .{
- next_arg, @errorName(err),
- });
- };
- } else if (mem.eql(u8, arg, "--debug-log")) {
- const next_arg = nextArgOrFatal(args, &arg_idx);
- try debug_log_scopes.append(next_arg);
- } else if (mem.eql(u8, arg, "--debug-pkg-config")) {
- builder.debug_pkg_config = true;
- } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
- builder.debug_compile_errors = true;
- } else if (mem.eql(u8, arg, "--system")) {
- // The usage text shows another argument after this parameter
- // but it is handled by the parent process. The build runner
- // only sees this flag.
- graph.system_package_mode = true;
- } else if (mem.eql(u8, arg, "--glibc-runtimes")) {
- builder.glibc_runtimes_dir = nextArgOrFatal(args, &arg_idx);
- } else if (mem.eql(u8, arg, "--verbose-link")) {
- builder.verbose_link = true;
- } else if (mem.eql(u8, arg, "--verbose-air")) {
- builder.verbose_air = true;
- } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
- builder.verbose_llvm_ir = "-";
- } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) {
- builder.verbose_llvm_ir = arg["--verbose-llvm-ir=".len..];
- } else if (mem.eql(u8, arg, "--verbose-llvm-bc=")) {
- builder.verbose_llvm_bc = arg["--verbose-llvm-bc=".len..];
- } else if (mem.eql(u8, arg, "--verbose-cimport")) {
- builder.verbose_cimport = true;
- } else if (mem.eql(u8, arg, "--verbose-cc")) {
- builder.verbose_cc = true;
- } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {
- builder.verbose_llvm_cpu_features = true;
- } else if (mem.eql(u8, arg, "--prominent-compile-errors")) {
- prominent_compile_errors = true;
- } else if (mem.eql(u8, arg, "-fwine")) {
- builder.enable_wine = true;
- } else if (mem.eql(u8, arg, "-fno-wine")) {
- builder.enable_wine = false;
- } else if (mem.eql(u8, arg, "-fqemu")) {
- builder.enable_qemu = true;
- } else if (mem.eql(u8, arg, "-fno-qemu")) {
- builder.enable_qemu = false;
- } else if (mem.eql(u8, arg, "-fwasmtime")) {
- builder.enable_wasmtime = true;
- } else if (mem.eql(u8, arg, "-fno-wasmtime")) {
- builder.enable_wasmtime = false;
- } else if (mem.eql(u8, arg, "-frosetta")) {
- builder.enable_rosetta = true;
- } else if (mem.eql(u8, arg, "-fno-rosetta")) {
- builder.enable_rosetta = false;
- } else if (mem.eql(u8, arg, "-fdarling")) {
- builder.enable_darling = true;
- } else if (mem.eql(u8, arg, "-fno-darling")) {
- builder.enable_darling = false;
- } else if (mem.eql(u8, arg, "-freference-trace")) {
- builder.reference_trace = 256;
- } else if (mem.startsWith(u8, arg, "-freference-trace=")) {
- const num = arg["-freference-trace=".len..];
- builder.reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
- std.debug.print("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) });
- process.exit(1);
- };
- } else if (mem.eql(u8, arg, "-fno-reference-trace")) {
- builder.reference_trace = null;
- } else if (mem.startsWith(u8, arg, "-j")) {
- const num = arg["-j".len..];
- const n_jobs = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
- std.debug.print("unable to parse jobs count '{s}': {s}", .{
- num, @errorName(err),
- });
- process.exit(1);
- };
- if (n_jobs < 1) {
- std.debug.print("number of jobs must be at least 1\n", .{});
- process.exit(1);
- }
- thread_pool_options.n_jobs = n_jobs;
- } else if (mem.eql(u8, arg, "--")) {
- builder.args = argsRest(args, arg_idx);
- break;
- } else {
- fatalWithHint("unrecognized argument: '{s}'", .{arg});
- }
- } else {
- try targets.append(arg);
- }
- }
-
- const host_query = std.Build.parseTargetQuery(graph.host_query_options) catch |err| switch (err) {
- error.ParseFailed => process.exit(1),
- };
- builder.host = .{
- .query = .{},
- .result = try std.zig.system.resolveTargetQuery(host_query),
- };
-
- const stderr = std.io.getStdErr();
- const ttyconf = get_tty_conf(color, stderr);
- switch (ttyconf) {
- .no_color => try graph.env_map.put("NO_COLOR", "1"),
- .escape_codes => try graph.env_map.put("YES_COLOR", "1"),
- .windows_api => {},
- }
-
- var progress: std.Progress = .{ .dont_print_on_dumb = true };
- const main_progress_node = progress.start("", 0);
-
- builder.debug_log_scopes = debug_log_scopes.items;
- builder.resolveInstallPrefix(install_prefix, dir_list);
- {
- var prog_node = main_progress_node.start("user build.zig logic", 0);
- defer prog_node.end();
- try builder.runBuild(root);
- }
-
- if (graph.needed_lazy_dependencies.entries.len != 0) {
- var buffer: std.ArrayListUnmanaged(u8) = .{};
- for (graph.needed_lazy_dependencies.keys()) |k| {
- try buffer.appendSlice(arena, k);
- try buffer.append(arena, '\n');
- }
- const s = std.fs.path.sep_str;
- const tmp_sub_path = "tmp" ++ s ++ (output_tmp_nonce orelse fatal("missing -Z arg", .{}));
- local_cache_directory.handle.writeFile2(.{
- .sub_path = tmp_sub_path,
- .data = buffer.items,
- .flags = .{ .exclusive = true },
- }) catch |err| {
- fatal("unable to write configuration results to '{}{s}': {s}", .{
- local_cache_directory, tmp_sub_path, @errorName(err),
- });
- };
- process.exit(3); // Indicate configure phase failed with meaningful stdout.
- }
-
- if (builder.validateUserInputDidItFail()) {
- fatal(" access the help menu with 'zig build -h'", .{});
- }
-
- validateSystemLibraryOptions(builder);
-
- const stdout_writer = io.getStdOut().writer();
-
- if (help_menu)
- return usage(builder, stdout_writer);
-
- if (steps_menu)
- return steps(builder, stdout_writer);
-
- var run: Run = .{
- .max_rss = max_rss,
- .max_rss_is_default = false,
- .max_rss_mutex = .{},
- .skip_oom_steps = skip_oom_steps,
- .memory_blocked_steps = std.ArrayList(*Step).init(arena),
- .prominent_compile_errors = prominent_compile_errors,
-
- .claimed_rss = 0,
- .summary = summary,
- .ttyconf = ttyconf,
- .stderr = stderr,
- };
-
- if (run.max_rss == 0) {
- run.max_rss = process.totalSystemMemory() catch std.math.maxInt(u64);
- run.max_rss_is_default = true;
- }
-
- runStepNames(
- arena,
- builder,
- targets.items,
- main_progress_node,
- thread_pool_options,
- &run,
- seed,
- ) catch |err| switch (err) {
- error.UncleanExit => process.exit(1),
- else => return err,
- };
-}
-
-const Run = struct {
- max_rss: u64,
- max_rss_is_default: bool,
- max_rss_mutex: std.Thread.Mutex,
- skip_oom_steps: bool,
- memory_blocked_steps: std.ArrayList(*Step),
- prominent_compile_errors: bool,
-
- claimed_rss: usize,
- summary: ?Summary,
- ttyconf: std.io.tty.Config,
- stderr: File,
-};
-
-fn runStepNames(
- arena: std.mem.Allocator,
- b: *std.Build,
- step_names: []const []const u8,
- parent_prog_node: *std.Progress.Node,
- thread_pool_options: std.Thread.Pool.Options,
- run: *Run,
- seed: u32,
-) !void {
- const gpa = b.allocator;
- var step_stack: std.AutoArrayHashMapUnmanaged(*Step, void) = .{};
- defer step_stack.deinit(gpa);
-
- if (step_names.len == 0) {
- try step_stack.put(gpa, b.default_step, {});
- } else {
- try step_stack.ensureUnusedCapacity(gpa, step_names.len);
- for (0..step_names.len) |i| {
- const step_name = step_names[step_names.len - i - 1];
- const s = b.top_level_steps.get(step_name) orelse {
- std.debug.print("no step named '{s}'\n access the help menu with 'zig build -h'\n", .{step_name});
- process.exit(1);
- };
- step_stack.putAssumeCapacity(&s.step, {});
- }
- }
-
- const starting_steps = try arena.dupe(*Step, step_stack.keys());
-
- var rng = std.Random.DefaultPrng.init(seed);
- const rand = rng.random();
- rand.shuffle(*Step, starting_steps);
-
- for (starting_steps) |s| {
- constructGraphAndCheckForDependencyLoop(b, s, &step_stack, rand) catch |err| switch (err) {
- error.DependencyLoopDetected => return error.UncleanExit,
- else => |e| return e,
- };
- }
-
- {
- // Check that we have enough memory to complete the build.
- var any_problems = false;
- for (step_stack.keys()) |s| {
- if (s.max_rss == 0) continue;
- if (s.max_rss > run.max_rss) {
- if (run.skip_oom_steps) {
- s.state = .skipped_oom;
- } else {
- std.debug.print("{s}{s}: this step declares an upper bound of {d} bytes of memory, exceeding the available {d} bytes of memory\n", .{
- s.owner.dep_prefix, s.name, s.max_rss, run.max_rss,
- });
- any_problems = true;
- }
- }
- }
- if (any_problems) {
- if (run.max_rss_is_default) {
- std.debug.print("note: use --maxrss to override the default", .{});
- }
- return error.UncleanExit;
- }
- }
-
- var thread_pool: std.Thread.Pool = undefined;
- try thread_pool.init(thread_pool_options);
- defer thread_pool.deinit();
-
- {
- defer parent_prog_node.end();
-
- var step_prog = parent_prog_node.start("steps", step_stack.count());
- defer step_prog.end();
-
- var wait_group: std.Thread.WaitGroup = .{};
- defer wait_group.wait();
-
- // Here we spawn the initial set of tasks with a nice heuristic -
- // dependency order. Each worker when it finishes a step will then
- // check whether it should run any dependants.
- const steps_slice = step_stack.keys();
- for (0..steps_slice.len) |i| {
- const step = steps_slice[steps_slice.len - i - 1];
- if (step.state == .skipped_oom) continue;
-
- wait_group.start();
- thread_pool.spawn(workerMakeOneStep, .{
- &wait_group, &thread_pool, b, step, &step_prog, run,
- }) catch @panic("OOM");
- }
- }
- assert(run.memory_blocked_steps.items.len == 0);
-
- var test_skip_count: usize = 0;
- var test_fail_count: usize = 0;
- var test_pass_count: usize = 0;
- var test_leak_count: usize = 0;
- var test_count: usize = 0;
-
- var success_count: usize = 0;
- var skipped_count: usize = 0;
- var failure_count: usize = 0;
- var pending_count: usize = 0;
- var total_compile_errors: usize = 0;
- var compile_error_steps: std.ArrayListUnmanaged(*Step) = .{};
- defer compile_error_steps.deinit(gpa);
-
- for (step_stack.keys()) |s| {
- test_fail_count += s.test_results.fail_count;
- test_skip_count += s.test_results.skip_count;
- test_leak_count += s.test_results.leak_count;
- test_pass_count += s.test_results.passCount();
- test_count += s.test_results.test_count;
-
- switch (s.state) {
- .precheck_unstarted => unreachable,
- .precheck_started => unreachable,
- .running => unreachable,
- .precheck_done => {
- // precheck_done is equivalent to dependency_failure in the case of
- // transitive dependencies. For example:
- // A -> B -> C (failure)
- // B will be marked as dependency_failure, while A may never be queued, and thus
- // remain in the initial state of precheck_done.
- s.state = .dependency_failure;
- pending_count += 1;
- },
- .dependency_failure => pending_count += 1,
- .success => success_count += 1,
- .skipped, .skipped_oom => skipped_count += 1,
- .failure => {
- failure_count += 1;
- const compile_errors_len = s.result_error_bundle.errorMessageCount();
- if (compile_errors_len > 0) {
- total_compile_errors += compile_errors_len;
- try compile_error_steps.append(gpa, s);
- }
- },
- }
- }
-
- // A proper command line application defaults to silently succeeding.
- // The user may request verbose mode if they have a different preference.
- const failures_only = run.summary != .all and run.summary != .new;
- if (failure_count == 0 and failures_only) return cleanExit();
-
- const ttyconf = run.ttyconf;
- const stderr = run.stderr;
-
- if (run.summary != Summary.none) {
- const total_count = success_count + failure_count + pending_count + skipped_count;
- ttyconf.setColor(stderr, .cyan) catch {};
- stderr.writeAll("Build Summary:") catch {};
- ttyconf.setColor(stderr, .reset) catch {};
- stderr.writer().print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
- if (skipped_count > 0) stderr.writer().print("; {d} skipped", .{skipped_count}) catch {};
- if (failure_count > 0) stderr.writer().print("; {d} failed", .{failure_count}) catch {};
-
- if (test_count > 0) stderr.writer().print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {};
- if (test_skip_count > 0) stderr.writer().print("; {d} skipped", .{test_skip_count}) catch {};
- if (test_fail_count > 0) stderr.writer().print("; {d} failed", .{test_fail_count}) catch {};
- if (test_leak_count > 0) stderr.writer().print("; {d} leaked", .{test_leak_count}) catch {};
-
- if (run.summary == null) {
- ttyconf.setColor(stderr, .dim) catch {};
- stderr.writeAll(" (disable with --summary none)") catch {};
- ttyconf.setColor(stderr, .reset) catch {};
- }
- stderr.writeAll("\n") catch {};
-
- // Print a fancy tree with build results.
- var print_node: PrintNode = .{ .parent = null };
- if (step_names.len == 0) {
- print_node.last = true;
- printTreeStep(b, b.default_step, run, stderr, ttyconf, &print_node, &step_stack) catch {};
- } else {
- const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: {
- var i: usize = step_names.len;
- while (i > 0) {
- i -= 1;
- const step = b.top_level_steps.get(step_names[i]).?.step;
- const found = switch (run.summary orelse .failures) {
- .all, .none => unreachable,
- .failures => step.state != .success,
- .new => !step.result_cached,
- };
- if (found) break :blk i;
- }
- break :blk b.top_level_steps.count();
- };
- for (step_names, 0..) |step_name, i| {
- const tls = b.top_level_steps.get(step_name).?;
- print_node.last = i + 1 == last_index;
- printTreeStep(b, &tls.step, run, stderr, ttyconf, &print_node, &step_stack) catch {};
- }
- }
- }
-
- if (failure_count == 0) return cleanExit();
-
- // Finally, render compile errors at the bottom of the terminal.
- // We use a separate compile_error_steps array list because step_stack is destructively
- // mutated in printTreeStep above.
- if (run.prominent_compile_errors and total_compile_errors > 0) {
- for (compile_error_steps.items) |s| {
- if (s.result_error_bundle.errorMessageCount() > 0) {
- s.result_error_bundle.renderToStdErr(renderOptions(ttyconf));
- }
- }
-
- // Signal to parent process that we have printed compile errors. The
- // parent process may choose to omit the "following command failed"
- // line in this case.
- process.exit(2);
- }
-
- process.exit(1);
-}
-
-const PrintNode = struct {
- parent: ?*PrintNode,
- last: bool = false,
-};
-
-fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void {
- const parent = node.parent orelse return;
- if (parent.parent == null) return;
- try printPrefix(parent, stderr, ttyconf);
- if (parent.last) {
- try stderr.writeAll(" ");
- } else {
- try stderr.writeAll(switch (ttyconf) {
- .no_color, .windows_api => "| ",
- .escape_codes => "\x1B\x28\x30\x78\x1B\x28\x42 ", // │
- });
- }
-}
-
-fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void {
- try stderr.writeAll(switch (ttyconf) {
- .no_color, .windows_api => "+- ",
- .escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─
- });
-}
-
-fn printStepStatus(
- s: *Step,
- stderr: File,
- ttyconf: std.io.tty.Config,
- run: *const Run,
-) !void {
- switch (s.state) {
- .precheck_unstarted => unreachable,
- .precheck_started => unreachable,
- .precheck_done => unreachable,
- .running => unreachable,
-
- .dependency_failure => {
- try ttyconf.setColor(stderr, .dim);
- try stderr.writeAll(" transitive failure\n");
- try ttyconf.setColor(stderr, .reset);
- },
-
- .success => {
- try ttyconf.setColor(stderr, .green);
- if (s.result_cached) {
- try stderr.writeAll(" cached");
- } else if (s.test_results.test_count > 0) {
- const pass_count = s.test_results.passCount();
- try stderr.writer().print(" {d} passed", .{pass_count});
- if (s.test_results.skip_count > 0) {
- try ttyconf.setColor(stderr, .yellow);
- try stderr.writer().print(" {d} skipped", .{s.test_results.skip_count});
- }
- } else {
- try stderr.writeAll(" success");
- }
- try ttyconf.setColor(stderr, .reset);
- if (s.result_duration_ns) |ns| {
- try ttyconf.setColor(stderr, .dim);
- if (ns >= std.time.ns_per_min) {
- try stderr.writer().print(" {d}m", .{ns / std.time.ns_per_min});
- } else if (ns >= std.time.ns_per_s) {
- try stderr.writer().print(" {d}s", .{ns / std.time.ns_per_s});
- } else if (ns >= std.time.ns_per_ms) {
- try stderr.writer().print(" {d}ms", .{ns / std.time.ns_per_ms});
- } else if (ns >= std.time.ns_per_us) {
- try stderr.writer().print(" {d}us", .{ns / std.time.ns_per_us});
- } else {
- try stderr.writer().print(" {d}ns", .{ns});
- }
- try ttyconf.setColor(stderr, .reset);
- }
- if (s.result_peak_rss != 0) {
- const rss = s.result_peak_rss;
- try ttyconf.setColor(stderr, .dim);
- if (rss >= 1000_000_000) {
- try stderr.writer().print(" MaxRSS:{d}G", .{rss / 1000_000_000});
- } else if (rss >= 1000_000) {
- try stderr.writer().print(" MaxRSS:{d}M", .{rss / 1000_000});
- } else if (rss >= 1000) {
- try stderr.writer().print(" MaxRSS:{d}K", .{rss / 1000});
- } else {
- try stderr.writer().print(" MaxRSS:{d}B", .{rss});
- }
- try ttyconf.setColor(stderr, .reset);
- }
- try stderr.writeAll("\n");
- },
- .skipped, .skipped_oom => |skip| {
- try ttyconf.setColor(stderr, .yellow);
- try stderr.writeAll(" skipped");
- if (skip == .skipped_oom) {
- try stderr.writeAll(" (not enough memory)");
- try ttyconf.setColor(stderr, .dim);
- try stderr.writer().print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });
- try ttyconf.setColor(stderr, .yellow);
- }
- try stderr.writeAll("\n");
- try ttyconf.setColor(stderr, .reset);
- },
- .failure => try printStepFailure(s, stderr, ttyconf),
- }
-}
-
-fn printStepFailure(
- s: *Step,
- stderr: File,
- ttyconf: std.io.tty.Config,
-) !void {
- if (s.result_error_bundle.errorMessageCount() > 0) {
- try ttyconf.setColor(stderr, .red);
- try stderr.writer().print(" {d} errors\n", .{
- s.result_error_bundle.errorMessageCount(),
- });
- try ttyconf.setColor(stderr, .reset);
- } else if (!s.test_results.isSuccess()) {
- try stderr.writer().print(" {d}/{d} passed", .{
- s.test_results.passCount(), s.test_results.test_count,
- });
- if (s.test_results.fail_count > 0) {
- try stderr.writeAll(", ");
- try ttyconf.setColor(stderr, .red);
- try stderr.writer().print("{d} failed", .{
- s.test_results.fail_count,
- });
- try ttyconf.setColor(stderr, .reset);
- }
- if (s.test_results.skip_count > 0) {
- try stderr.writeAll(", ");
- try ttyconf.setColor(stderr, .yellow);
- try stderr.writer().print("{d} skipped", .{
- s.test_results.skip_count,
- });
- try ttyconf.setColor(stderr, .reset);
- }
- if (s.test_results.leak_count > 0) {
- try stderr.writeAll(", ");
- try ttyconf.setColor(stderr, .red);
- try stderr.writer().print("{d} leaked", .{
- s.test_results.leak_count,
- });
- try ttyconf.setColor(stderr, .reset);
- }
- try stderr.writeAll("\n");
- } else if (s.result_error_msgs.items.len > 0) {
- try ttyconf.setColor(stderr, .red);
- try stderr.writeAll(" failure\n");
- try ttyconf.setColor(stderr, .reset);
- } else {
- assert(s.result_stderr.len > 0);
- try ttyconf.setColor(stderr, .red);
- try stderr.writeAll(" stderr\n");
- try ttyconf.setColor(stderr, .reset);
- }
-}
-
-fn printTreeStep(
- b: *std.Build,
- s: *Step,
- run: *const Run,
- stderr: File,
- ttyconf: std.io.tty.Config,
- parent_node: *PrintNode,
- step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
-) !void {
- const first = step_stack.swapRemove(s);
- const summary = run.summary orelse .failures;
- const skip = switch (summary) {
- .none => unreachable,
- .all => false,
- .new => s.result_cached,
- .failures => s.state == .success,
- };
- if (skip) return;
- try printPrefix(parent_node, stderr, ttyconf);
-
- if (!first) try ttyconf.setColor(stderr, .dim);
- if (parent_node.parent != null) {
- if (parent_node.last) {
- try printChildNodePrefix(stderr, ttyconf);
- } else {
- try stderr.writeAll(switch (ttyconf) {
- .no_color, .windows_api => "+- ",
- .escape_codes => "\x1B\x28\x30\x74\x71\x1B\x28\x42 ", // ├─
- });
- }
- }
-
- // dep_prefix omitted here because it is redundant with the tree.
- try stderr.writeAll(s.name);
-
- if (first) {
- try printStepStatus(s, stderr, ttyconf, run);
-
- const last_index = if (summary == .all) s.dependencies.items.len -| 1 else blk: {
- var i: usize = s.dependencies.items.len;
- while (i > 0) {
- i -= 1;
-
- const step = s.dependencies.items[i];
- const found = switch (summary) {
- .all, .none => unreachable,
- .failures => step.state != .success,
- .new => !step.result_cached,
- };
- if (found) break :blk i;
- }
- break :blk s.dependencies.items.len -| 1;
- };
- for (s.dependencies.items, 0..) |dep, i| {
- var print_node: PrintNode = .{
- .parent = parent_node,
- .last = i == last_index,
- };
- try printTreeStep(b, dep, run, stderr, ttyconf, &print_node, step_stack);
- }
- } else {
- if (s.dependencies.items.len == 0) {
- try stderr.writeAll(" (reused)\n");
- } else {
- try stderr.writer().print(" (+{d} more reused dependencies)\n", .{
- s.dependencies.items.len,
- });
- }
- try ttyconf.setColor(stderr, .reset);
- }
-}
-
-/// Traverse the dependency graph depth-first and make it undirected by having
-/// steps know their dependants (they only know dependencies at start).
-/// Along the way, check that there is no dependency loop, and record the steps
-/// in traversal order in `step_stack`.
-/// Each step has its dependencies traversed in random order, this accomplishes
-/// two things:
-/// - `step_stack` will be in randomized-depth-first order, so the build runner
-/// spawns steps in a random (but optimized) order
-/// - each step's `dependants` list is also filled in a random order, so that
-/// when it finishes executing in `workerMakeOneStep`, it spawns next steps
-/// to run in random order
-fn constructGraphAndCheckForDependencyLoop(
- b: *std.Build,
- s: *Step,
- step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
- rand: std.Random,
-) !void {
- switch (s.state) {
- .precheck_started => {
- std.debug.print("dependency loop detected:\n {s}\n", .{s.name});
- return error.DependencyLoopDetected;
- },
- .precheck_unstarted => {
- s.state = .precheck_started;
-
- try step_stack.ensureUnusedCapacity(b.allocator, s.dependencies.items.len);
-
- // We dupe to avoid shuffling the steps in the summary, it depends
- // on s.dependencies' order.
- const deps = b.allocator.dupe(*Step, s.dependencies.items) catch @panic("OOM");
- rand.shuffle(*Step, deps);
-
- for (deps) |dep| {
- try step_stack.put(b.allocator, dep, {});
- try dep.dependants.append(b.allocator, s);
- constructGraphAndCheckForDependencyLoop(b, dep, step_stack, rand) catch |err| {
- if (err == error.DependencyLoopDetected) {
- std.debug.print(" {s}\n", .{s.name});
- }
- return err;
- };
- }
-
- s.state = .precheck_done;
- },
- .precheck_done => {},
-
- // These don't happen until we actually run the step graph.
- .dependency_failure => unreachable,
- .running => unreachable,
- .success => unreachable,
- .failure => unreachable,
- .skipped => unreachable,
- .skipped_oom => unreachable,
- }
-}
-
-fn workerMakeOneStep(
- wg: *std.Thread.WaitGroup,
- thread_pool: *std.Thread.Pool,
- b: *std.Build,
- s: *Step,
- prog_node: *std.Progress.Node,
- run: *Run,
-) void {
- defer wg.finish();
-
- // First, check the conditions for running this step. If they are not met,
- // then we return without doing the step, relying on another worker to
- // queue this step up again when dependencies are met.
- for (s.dependencies.items) |dep| {
- switch (@atomicLoad(Step.State, &dep.state, .seq_cst)) {
- .success, .skipped => continue,
- .failure, .dependency_failure, .skipped_oom => {
- @atomicStore(Step.State, &s.state, .dependency_failure, .seq_cst);
- return;
- },
- .precheck_done, .running => {
- // dependency is not finished yet.
- return;
- },
- .precheck_unstarted => unreachable,
- .precheck_started => unreachable,
- }
- }
-
- if (s.max_rss != 0) {
- run.max_rss_mutex.lock();
- defer run.max_rss_mutex.unlock();
-
- // Avoid running steps twice.
- if (s.state != .precheck_done) {
- // Another worker got the job.
- return;
- }
-
- const new_claimed_rss = run.claimed_rss + s.max_rss;
- if (new_claimed_rss > run.max_rss) {
- // Running this step right now could possibly exceed the allotted RSS.
- // Add this step to the queue of memory-blocked steps.
- run.memory_blocked_steps.append(s) catch @panic("OOM");
- return;
- }
-
- run.claimed_rss = new_claimed_rss;
- s.state = .running;
- } else {
- // Avoid running steps twice.
- if (@cmpxchgStrong(Step.State, &s.state, .precheck_done, .running, .seq_cst, .seq_cst) != null) {
- // Another worker got the job.
- return;
- }
- }
-
- var sub_prog_node = prog_node.start(s.name, 0);
- sub_prog_node.activate();
- defer sub_prog_node.end();
-
- const make_result = s.make(&sub_prog_node);
-
- // No matter the result, we want to display error/warning messages.
- const show_compile_errors = !run.prominent_compile_errors and
- s.result_error_bundle.errorMessageCount() > 0;
- const show_error_msgs = s.result_error_msgs.items.len > 0;
- const show_stderr = s.result_stderr.len > 0;
-
- if (show_error_msgs or show_compile_errors or show_stderr) {
- sub_prog_node.context.lock_stderr();
- defer sub_prog_node.context.unlock_stderr();
-
- printErrorMessages(b, s, run) catch {};
- }
-
- handle_result: {
- if (make_result) |_| {
- @atomicStore(Step.State, &s.state, .success, .seq_cst);
- } else |err| switch (err) {
- error.MakeFailed => {
- @atomicStore(Step.State, &s.state, .failure, .seq_cst);
- break :handle_result;
- },
- error.MakeSkipped => @atomicStore(Step.State, &s.state, .skipped, .seq_cst),
- }
-
- // Successful completion of a step, so we queue up its dependants as well.
- for (s.dependants.items) |dep| {
- wg.start();
- thread_pool.spawn(workerMakeOneStep, .{
- wg, thread_pool, b, dep, prog_node, run,
- }) catch @panic("OOM");
- }
- }
-
- // If this is a step that claims resources, we must now queue up other
- // steps that are waiting for resources.
- if (s.max_rss != 0) {
- run.max_rss_mutex.lock();
- defer run.max_rss_mutex.unlock();
-
- // Give the memory back to the scheduler.
- run.claimed_rss -= s.max_rss;
- // Avoid kicking off too many tasks that we already know will not have
- // enough resources.
- var remaining = run.max_rss - run.claimed_rss;
- var i: usize = 0;
- var j: usize = 0;
- while (j < run.memory_blocked_steps.items.len) : (j += 1) {
- const dep = run.memory_blocked_steps.items[j];
- assert(dep.max_rss != 0);
- if (dep.max_rss <= remaining) {
- remaining -= dep.max_rss;
-
- wg.start();
- thread_pool.spawn(workerMakeOneStep, .{
- wg, thread_pool, b, dep, prog_node, run,
- }) catch @panic("OOM");
- } else {
- run.memory_blocked_steps.items[i] = dep;
- i += 1;
- }
- }
- run.memory_blocked_steps.shrinkRetainingCapacity(i);
- }
-}
-
-fn printErrorMessages(b: *std.Build, failing_step: *Step, run: *const Run) !void {
- const gpa = b.allocator;
- const stderr = run.stderr;
- const ttyconf = run.ttyconf;
-
- // Provide context for where these error messages are coming from by
- // printing the corresponding Step subtree.
-
- var step_stack: std.ArrayListUnmanaged(*Step) = .{};
- defer step_stack.deinit(gpa);
- try step_stack.append(gpa, failing_step);
- while (step_stack.items[step_stack.items.len - 1].dependants.items.len != 0) {
- try step_stack.append(gpa, step_stack.items[step_stack.items.len - 1].dependants.items[0]);
- }
-
- // Now, `step_stack` has the subtree that we want to print, in reverse order.
- try ttyconf.setColor(stderr, .dim);
- var indent: usize = 0;
- while (step_stack.popOrNull()) |s| : (indent += 1) {
- if (indent > 0) {
- try stderr.writer().writeByteNTimes(' ', (indent - 1) * 3);
- try printChildNodePrefix(stderr, ttyconf);
- }
-
- try stderr.writeAll(s.name);
-
- if (s == failing_step) {
- try printStepFailure(s, stderr, ttyconf);
- } else {
- try stderr.writeAll("\n");
- }
- }
- try ttyconf.setColor(stderr, .reset);
-
- if (failing_step.result_stderr.len > 0) {
- try stderr.writeAll(failing_step.result_stderr);
- if (!mem.endsWith(u8, failing_step.result_stderr, "\n")) {
- try stderr.writeAll("\n");
- }
- }
-
- if (!run.prominent_compile_errors and failing_step.result_error_bundle.errorMessageCount() > 0)
- try failing_step.result_error_bundle.renderToWriter(renderOptions(ttyconf), stderr.writer());
-
- for (failing_step.result_error_msgs.items) |msg| {
- try ttyconf.setColor(stderr, .red);
- try stderr.writeAll("error: ");
- try ttyconf.setColor(stderr, .reset);
- try stderr.writeAll(msg);
- try stderr.writeAll("\n");
- }
-}
-
-fn steps(builder: *std.Build, out_stream: anytype) !void {
- const allocator = builder.allocator;
- for (builder.top_level_steps.values()) |top_level_step| {
- const name = if (&top_level_step.step == builder.default_step)
- try fmt.allocPrint(allocator, "{s} (default)", .{top_level_step.step.name})
- else
- top_level_step.step.name;
- try out_stream.print(" {s:<28} {s}\n", .{ name, top_level_step.description });
- }
-}
-
-fn usage(b: *std.Build, out_stream: anytype) !void {
- try out_stream.print(
- \\Usage: {s} build [steps] [options]
- \\
- \\Steps:
- \\
- , .{b.graph.zig_exe});
- try steps(b, out_stream);
-
- try out_stream.writeAll(
- \\
- \\General Options:
- \\ -p, --prefix [path] Where to install files (default: zig-out)
- \\ --prefix-lib-dir [path] Where to install libraries
- \\ --prefix-exe-dir [path] Where to install executables
- \\ --prefix-include-dir [path] Where to install C header files
- \\
- \\ --release[=mode] Request release mode, optionally specifying a
- \\ preferred optimization mode: fast, safe, small
- \\
- \\ -fdarling, -fno-darling Integration with system-installed Darling to
- \\ execute macOS programs on Linux hosts
- \\ (default: no)
- \\ -fqemu, -fno-qemu Integration with system-installed QEMU to execute
- \\ foreign-architecture programs on Linux hosts
- \\ (default: no)
- \\ --glibc-runtimes [path] Enhances QEMU integration by providing glibc built
- \\ for multiple foreign architectures, allowing
- \\ execution of non-native programs that link with glibc.
- \\ -frosetta, -fno-rosetta Rely on Rosetta to execute x86_64 programs on
- \\ ARM64 macOS hosts. (default: no)
- \\ -fwasmtime, -fno-wasmtime Integration with system-installed wasmtime to
- \\ execute WASI binaries. (default: no)
- \\ -fwine, -fno-wine Integration with system-installed Wine to execute
- \\ Windows programs on Linux hosts. (default: no)
- \\
- \\ -h, --help Print this help and exit
- \\ -l, --list-steps Print available steps
- \\ --verbose Print commands before executing them
- \\ --color [auto|off|on] Enable or disable colored error messages
- \\ --prominent-compile-errors Buffer compile errors and display at end
- \\ --summary [mode] Control the printing of the build summary
- \\ all Print the build summary in its entirety
- \\ new Omit cached steps
- \\ failures (Default) Only print failed steps
- \\ none Do not print the build summary
- \\ -j Limit concurrent jobs (default is to use all CPU cores)
- \\ --maxrss Limit memory usage (default is to use available memory)
- \\ --skip-oom-steps Instead of failing, skip steps that would exceed --maxrss
- \\ --fetch Exit after fetching dependency tree
- \\
- \\Project-Specific Options:
- \\
- );
-
- const arena = b.allocator;
- if (b.available_options_list.items.len == 0) {
- try out_stream.print(" (none)\n", .{});
- } else {
- for (b.available_options_list.items) |option| {
- const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{
- option.name,
- @tagName(option.type_id),
- });
- try out_stream.print("{s:<30} {s}\n", .{ name, option.description });
- if (option.enum_options) |enum_options| {
- const padding = " " ** 33;
- try out_stream.writeAll(padding ++ "Supported Values:\n");
- for (enum_options) |enum_option| {
- try out_stream.print(padding ++ " {s}\n", .{enum_option});
- }
- }
- }
- }
-
- try out_stream.writeAll(
- \\
- \\System Integration Options:
- \\ --search-prefix [path] Add a path to look for binaries, libraries, headers
- \\ --sysroot [path] Set the system root directory (usually /)
- \\ --libc [file] Provide a file which specifies libc paths
- \\
- \\ --host-target [triple] Use the provided target as the host
- \\ --host-cpu [cpu] Use the provided CPU as the host
- \\ --host-dynamic-linker [path] Use the provided dynamic linker as the host
- \\
- \\ --system [pkgdir] Disable package fetching; enable all integrations
- \\ -fsys=[name] Enable a system integration
- \\ -fno-sys=[name] Disable a system integration
- \\
- \\ Available System Integrations: Enabled:
- \\
- );
- if (b.graph.system_library_options.entries.len == 0) {
- try out_stream.writeAll(" (none) -\n");
- } else {
- for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| {
- const status = switch (v) {
- .declared_enabled => "yes",
- .declared_disabled => "no",
- .user_enabled, .user_disabled => unreachable, // already emitted error
- };
- try out_stream.print(" {s:<43} {s}\n", .{ k, status });
- }
- }
-
- try out_stream.writeAll(
- \\
- \\Advanced Options:
- \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
- \\ -fno-reference-trace Disable reference trace
- \\ --build-file [file] Override path to build.zig
- \\ --cache-dir [path] Override path to local Zig cache directory
- \\ --global-cache-dir [path] Override path to global Zig cache directory
- \\ --zig-lib-dir [arg] Override path to Zig lib directory
- \\ --build-runner [file] Override path to build runner
- \\ --seed [integer] For shuffling dependency traversal order (default: random)
- \\ --debug-log [scope] Enable debugging the compiler
- \\ --debug-pkg-config Fail if unknown pkg-config flags encountered
- \\ --verbose-link Enable compiler debug output for linking
- \\ --verbose-air Enable compiler debug output for Zig AIR
- \\ --verbose-llvm-ir[=file] Enable compiler debug output for LLVM IR
- \\ --verbose-llvm-bc=[file] Enable compiler debug output for LLVM BC
- \\ --verbose-cimport Enable compiler debug output for C imports
- \\ --verbose-cc Enable compiler debug output for C compilation
- \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features
- \\
- );
-}
-
-fn nextArg(args: [][:0]const u8, idx: *usize) ?[:0]const u8 {
- if (idx.* >= args.len) return null;
- defer idx.* += 1;
- return args[idx.*];
-}
-
-fn nextArgOrFatal(args: [][:0]const u8, idx: *usize) [:0]const u8 {
- return nextArg(args, idx) orelse {
- std.debug.print("expected argument after '{s}'\n access the help menu with 'zig build -h'\n", .{args[idx.*]});
- process.exit(1);
- };
-}
-
-fn argsRest(args: [][:0]const u8, idx: usize) ?[][:0]const u8 {
- if (idx >= args.len) return null;
- return args[idx..];
-}
-
-fn cleanExit() void {
- // Perhaps in the future there could be an Advanced Options flag such as
- // --debug-build-runner-leaks which would make this function return instead
- // of calling exit.
- process.exit(0);
-}
-
-const Color = enum { auto, off, on };
-const Summary = enum { all, new, failures, none };
-
-fn get_tty_conf(color: Color, stderr: File) std.io.tty.Config {
- return switch (color) {
- .auto => std.io.tty.detectConfig(stderr),
- .on => .escape_codes,
- .off => .no_color,
- };
-}
-
-fn renderOptions(ttyconf: std.io.tty.Config) std.zig.ErrorBundle.RenderOptions {
- return .{
- .ttyconf = ttyconf,
- .include_source_line = ttyconf != .no_color,
- .include_reference_trace = ttyconf != .no_color,
- };
-}
-
-fn fatalWithHint(comptime f: []const u8, args: anytype) noreturn {
- std.debug.print(f ++ "\n access the help menu with 'zig build -h'\n", args);
- process.exit(1);
-}
-
-fn fatal(comptime f: []const u8, args: anytype) noreturn {
- std.debug.print(f ++ "\n", args);
- process.exit(1);
-}
-
-fn validateSystemLibraryOptions(b: *std.Build) void {
- var bad = false;
- for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| {
- switch (v) {
- .user_disabled, .user_enabled => {
- // The user tried to enable or disable a system library integration, but
- // the build script did not recognize that option.
- std.debug.print("system library name not recognized by build script: '{s}'\n", .{k});
- bad = true;
- },
- .declared_disabled, .declared_enabled => {},
- }
- }
- if (bad) {
- std.debug.print(" access the help menu with 'zig build -h'\n", .{});
- process.exit(1);
- }
-}
diff --git a/lib/compiler/build_runner.zig b/lib/compiler/build_runner.zig
new file mode 100644
index 0000000000000000000000000000000000000000..f19713776916b94baada339ef967edd0a9aa303a
--- /dev/null
+++ b/lib/compiler/build_runner.zig
@@ -0,0 +1,1293 @@
+const root = @import("@build");
+const std = @import("std");
+const builtin = @import("builtin");
+const assert = std.debug.assert;
+const io = std.io;
+const fmt = std.fmt;
+const mem = std.mem;
+const process = std.process;
+const ArrayList = std.ArrayList;
+const File = std.fs.File;
+const Step = std.Build.Step;
+
+pub const dependencies = @import("@dependencies");
+
+pub fn main() !void {
+ // Here we use an ArenaAllocator backed by a page allocator because a build is a short-lived,
+ // one shot program. We don't need to waste time freeing memory and finding places to squish
+ // bytes into. So we free everything all at once at the very end.
+ var single_threaded_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+ defer single_threaded_arena.deinit();
+
+ var thread_safe_arena: std.heap.ThreadSafeAllocator = .{
+ .child_allocator = single_threaded_arena.allocator(),
+ };
+ const arena = thread_safe_arena.allocator();
+
+ const args = try process.argsAlloc(arena);
+
+ // skip my own exe name
+ var arg_idx: usize = 1;
+
+ const zig_exe = nextArg(args, &arg_idx) orelse {
+ std.debug.print("Expected path to zig compiler\n", .{});
+ return error.InvalidArgs;
+ };
+ const build_root = nextArg(args, &arg_idx) orelse {
+ std.debug.print("Expected build root directory path\n", .{});
+ return error.InvalidArgs;
+ };
+ const cache_root = nextArg(args, &arg_idx) orelse {
+ std.debug.print("Expected cache root directory path\n", .{});
+ return error.InvalidArgs;
+ };
+ const global_cache_root = nextArg(args, &arg_idx) orelse {
+ std.debug.print("Expected global cache root directory path\n", .{});
+ return error.InvalidArgs;
+ };
+
+ const build_root_directory: std.Build.Cache.Directory = .{
+ .path = build_root,
+ .handle = try std.fs.cwd().openDir(build_root, .{}),
+ };
+
+ const local_cache_directory: std.Build.Cache.Directory = .{
+ .path = cache_root,
+ .handle = try std.fs.cwd().makeOpenPath(cache_root, .{}),
+ };
+
+ const global_cache_directory: std.Build.Cache.Directory = .{
+ .path = global_cache_root,
+ .handle = try std.fs.cwd().makeOpenPath(global_cache_root, .{}),
+ };
+
+ var graph: std.Build.Graph = .{
+ .arena = arena,
+ .cache = .{
+ .gpa = arena,
+ .manifest_dir = try local_cache_directory.handle.makeOpenPath("h", .{}),
+ },
+ .zig_exe = zig_exe,
+ .env_map = try process.getEnvMap(arena),
+ .global_cache_root = global_cache_directory,
+ };
+
+ graph.cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
+ graph.cache.addPrefix(build_root_directory);
+ graph.cache.addPrefix(local_cache_directory);
+ graph.cache.addPrefix(global_cache_directory);
+ graph.cache.hash.addBytes(builtin.zig_version_string);
+
+ const builder = try std.Build.create(
+ &graph,
+ build_root_directory,
+ local_cache_directory,
+ dependencies.root_deps,
+ );
+
+ var targets = ArrayList([]const u8).init(arena);
+ var debug_log_scopes = ArrayList([]const u8).init(arena);
+ var thread_pool_options: std.Thread.Pool.Options = .{ .allocator = arena };
+
+ var install_prefix: ?[]const u8 = null;
+ var dir_list = std.Build.DirList{};
+ var summary: ?Summary = null;
+ var max_rss: u64 = 0;
+ var skip_oom_steps: bool = false;
+ var color: Color = .auto;
+ var seed: u32 = 0;
+ var prominent_compile_errors: bool = false;
+ var help_menu: bool = false;
+ var steps_menu: bool = false;
+ var output_tmp_nonce: ?[16]u8 = null;
+
+ while (nextArg(args, &arg_idx)) |arg| {
+ if (mem.startsWith(u8, arg, "-Z")) {
+ if (arg.len != 18) fatalWithHint("bad argument: '{s}'", .{arg});
+ output_tmp_nonce = arg[2..18].*;
+ } else if (mem.startsWith(u8, arg, "-D")) {
+ const option_contents = arg[2..];
+ if (option_contents.len == 0)
+ fatalWithHint("expected option name after '-D'", .{});
+ if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| {
+ const option_name = option_contents[0..name_end];
+ const option_value = option_contents[name_end + 1 ..];
+ if (try builder.addUserInputOption(option_name, option_value))
+ fatal(" access the help menu with 'zig build -h'", .{});
+ } else {
+ if (try builder.addUserInputFlag(option_contents))
+ fatal(" access the help menu with 'zig build -h'", .{});
+ }
+ } else if (mem.startsWith(u8, arg, "-")) {
+ if (mem.eql(u8, arg, "--verbose")) {
+ builder.verbose = true;
+ } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
+ help_menu = true;
+ } else if (mem.eql(u8, arg, "-p") or mem.eql(u8, arg, "--prefix")) {
+ install_prefix = nextArgOrFatal(args, &arg_idx);
+ } else if (mem.eql(u8, arg, "-l") or mem.eql(u8, arg, "--list-steps")) {
+ steps_menu = true;
+ } else if (mem.startsWith(u8, arg, "-fsys=")) {
+ const name = arg["-fsys=".len..];
+ graph.system_library_options.put(arena, name, .user_enabled) catch @panic("OOM");
+ } else if (mem.startsWith(u8, arg, "-fno-sys=")) {
+ const name = arg["-fno-sys=".len..];
+ graph.system_library_options.put(arena, name, .user_disabled) catch @panic("OOM");
+ } else if (mem.eql(u8, arg, "--release")) {
+ builder.release_mode = .any;
+ } else if (mem.startsWith(u8, arg, "--release=")) {
+ const text = arg["--release=".len..];
+ builder.release_mode = std.meta.stringToEnum(std.Build.ReleaseMode, text) orelse {
+ fatalWithHint("expected [off|any|fast|safe|small] in '{s}', found '{s}'", .{
+ arg, text,
+ });
+ };
+ } else if (mem.eql(u8, arg, "--host-target")) {
+ graph.host_query_options.arch_os_abi = nextArgOrFatal(args, &arg_idx);
+ } else if (mem.eql(u8, arg, "--host-cpu")) {
+ graph.host_query_options.cpu_features = nextArgOrFatal(args, &arg_idx);
+ } else if (mem.eql(u8, arg, "--host-dynamic-linker")) {
+ graph.host_query_options.dynamic_linker = nextArgOrFatal(args, &arg_idx);
+ } else if (mem.eql(u8, arg, "--prefix-lib-dir")) {
+ dir_list.lib_dir = nextArgOrFatal(args, &arg_idx);
+ } else if (mem.eql(u8, arg, "--prefix-exe-dir")) {
+ dir_list.exe_dir = nextArgOrFatal(args, &arg_idx);
+ } else if (mem.eql(u8, arg, "--prefix-include-dir")) {
+ dir_list.include_dir = nextArgOrFatal(args, &arg_idx);
+ } else if (mem.eql(u8, arg, "--sysroot")) {
+ builder.sysroot = nextArgOrFatal(args, &arg_idx);
+ } else if (mem.eql(u8, arg, "--maxrss")) {
+ const max_rss_text = nextArgOrFatal(args, &arg_idx);
+ max_rss = std.fmt.parseIntSizeSuffix(max_rss_text, 10) catch |err| {
+ std.debug.print("invalid byte size: '{s}': {s}\n", .{
+ max_rss_text, @errorName(err),
+ });
+ process.exit(1);
+ };
+ } else if (mem.eql(u8, arg, "--skip-oom-steps")) {
+ skip_oom_steps = true;
+ } else if (mem.eql(u8, arg, "--search-prefix")) {
+ const search_prefix = nextArgOrFatal(args, &arg_idx);
+ builder.addSearchPrefix(search_prefix);
+ } else if (mem.eql(u8, arg, "--libc")) {
+ builder.libc_file = nextArgOrFatal(args, &arg_idx);
+ } else if (mem.eql(u8, arg, "--color")) {
+ const next_arg = nextArg(args, &arg_idx) orelse
+ fatalWithHint("expected [auto|on|off] after '{s}'", .{arg});
+ color = std.meta.stringToEnum(Color, next_arg) orelse {
+ fatalWithHint("expected [auto|on|off] after '{s}', found '{s}'", .{
+ arg, next_arg,
+ });
+ };
+ } else if (mem.eql(u8, arg, "--summary")) {
+ const next_arg = nextArg(args, &arg_idx) orelse
+ fatalWithHint("expected [all|new|failures|none] after '{s}'", .{arg});
+ summary = std.meta.stringToEnum(Summary, next_arg) orelse {
+ fatalWithHint("expected [all|failures|none] after '{s}', found '{s}'", .{
+ arg, next_arg,
+ });
+ };
+ } else if (mem.eql(u8, arg, "--zig-lib-dir")) {
+ builder.zig_lib_dir = .{ .cwd_relative = nextArgOrFatal(args, &arg_idx) };
+ } else if (mem.eql(u8, arg, "--seed")) {
+ const next_arg = nextArg(args, &arg_idx) orelse
+ fatalWithHint("expected u32 after '{s}'", .{arg});
+ seed = std.fmt.parseUnsigned(u32, next_arg, 0) catch |err| {
+ fatal("unable to parse seed '{s}' as 32-bit integer: {s}\n", .{
+ next_arg, @errorName(err),
+ });
+ };
+ } else if (mem.eql(u8, arg, "--debug-log")) {
+ const next_arg = nextArgOrFatal(args, &arg_idx);
+ try debug_log_scopes.append(next_arg);
+ } else if (mem.eql(u8, arg, "--debug-pkg-config")) {
+ builder.debug_pkg_config = true;
+ } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
+ builder.debug_compile_errors = true;
+ } else if (mem.eql(u8, arg, "--system")) {
+ // The usage text shows another argument after this parameter
+ // but it is handled by the parent process. The build runner
+ // only sees this flag.
+ graph.system_package_mode = true;
+ } else if (mem.eql(u8, arg, "--glibc-runtimes")) {
+ builder.glibc_runtimes_dir = nextArgOrFatal(args, &arg_idx);
+ } else if (mem.eql(u8, arg, "--verbose-link")) {
+ builder.verbose_link = true;
+ } else if (mem.eql(u8, arg, "--verbose-air")) {
+ builder.verbose_air = true;
+ } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
+ builder.verbose_llvm_ir = "-";
+ } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) {
+ builder.verbose_llvm_ir = arg["--verbose-llvm-ir=".len..];
+ } else if (mem.eql(u8, arg, "--verbose-llvm-bc=")) {
+ builder.verbose_llvm_bc = arg["--verbose-llvm-bc=".len..];
+ } else if (mem.eql(u8, arg, "--verbose-cimport")) {
+ builder.verbose_cimport = true;
+ } else if (mem.eql(u8, arg, "--verbose-cc")) {
+ builder.verbose_cc = true;
+ } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {
+ builder.verbose_llvm_cpu_features = true;
+ } else if (mem.eql(u8, arg, "--prominent-compile-errors")) {
+ prominent_compile_errors = true;
+ } else if (mem.eql(u8, arg, "-fwine")) {
+ builder.enable_wine = true;
+ } else if (mem.eql(u8, arg, "-fno-wine")) {
+ builder.enable_wine = false;
+ } else if (mem.eql(u8, arg, "-fqemu")) {
+ builder.enable_qemu = true;
+ } else if (mem.eql(u8, arg, "-fno-qemu")) {
+ builder.enable_qemu = false;
+ } else if (mem.eql(u8, arg, "-fwasmtime")) {
+ builder.enable_wasmtime = true;
+ } else if (mem.eql(u8, arg, "-fno-wasmtime")) {
+ builder.enable_wasmtime = false;
+ } else if (mem.eql(u8, arg, "-frosetta")) {
+ builder.enable_rosetta = true;
+ } else if (mem.eql(u8, arg, "-fno-rosetta")) {
+ builder.enable_rosetta = false;
+ } else if (mem.eql(u8, arg, "-fdarling")) {
+ builder.enable_darling = true;
+ } else if (mem.eql(u8, arg, "-fno-darling")) {
+ builder.enable_darling = false;
+ } else if (mem.eql(u8, arg, "-freference-trace")) {
+ builder.reference_trace = 256;
+ } else if (mem.startsWith(u8, arg, "-freference-trace=")) {
+ const num = arg["-freference-trace=".len..];
+ builder.reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
+ std.debug.print("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) });
+ process.exit(1);
+ };
+ } else if (mem.eql(u8, arg, "-fno-reference-trace")) {
+ builder.reference_trace = null;
+ } else if (mem.startsWith(u8, arg, "-j")) {
+ const num = arg["-j".len..];
+ const n_jobs = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
+ std.debug.print("unable to parse jobs count '{s}': {s}", .{
+ num, @errorName(err),
+ });
+ process.exit(1);
+ };
+ if (n_jobs < 1) {
+ std.debug.print("number of jobs must be at least 1\n", .{});
+ process.exit(1);
+ }
+ thread_pool_options.n_jobs = n_jobs;
+ } else if (mem.eql(u8, arg, "--")) {
+ builder.args = argsRest(args, arg_idx);
+ break;
+ } else {
+ fatalWithHint("unrecognized argument: '{s}'", .{arg});
+ }
+ } else {
+ try targets.append(arg);
+ }
+ }
+
+ const host_query = std.Build.parseTargetQuery(graph.host_query_options) catch |err| switch (err) {
+ error.ParseFailed => process.exit(1),
+ };
+ builder.host = .{
+ .query = .{},
+ .result = try std.zig.system.resolveTargetQuery(host_query),
+ };
+
+ const stderr = std.io.getStdErr();
+ const ttyconf = get_tty_conf(color, stderr);
+ switch (ttyconf) {
+ .no_color => try graph.env_map.put("NO_COLOR", "1"),
+ .escape_codes => try graph.env_map.put("YES_COLOR", "1"),
+ .windows_api => {},
+ }
+
+ var progress: std.Progress = .{ .dont_print_on_dumb = true };
+ const main_progress_node = progress.start("", 0);
+
+ builder.debug_log_scopes = debug_log_scopes.items;
+ builder.resolveInstallPrefix(install_prefix, dir_list);
+ {
+ var prog_node = main_progress_node.start("user build.zig logic", 0);
+ defer prog_node.end();
+ try builder.runBuild(root);
+ }
+
+ if (graph.needed_lazy_dependencies.entries.len != 0) {
+ var buffer: std.ArrayListUnmanaged(u8) = .{};
+ for (graph.needed_lazy_dependencies.keys()) |k| {
+ try buffer.appendSlice(arena, k);
+ try buffer.append(arena, '\n');
+ }
+ const s = std.fs.path.sep_str;
+ const tmp_sub_path = "tmp" ++ s ++ (output_tmp_nonce orelse fatal("missing -Z arg", .{}));
+ local_cache_directory.handle.writeFile2(.{
+ .sub_path = tmp_sub_path,
+ .data = buffer.items,
+ .flags = .{ .exclusive = true },
+ }) catch |err| {
+ fatal("unable to write configuration results to '{}{s}': {s}", .{
+ local_cache_directory, tmp_sub_path, @errorName(err),
+ });
+ };
+ process.exit(3); // Indicate configure phase failed with meaningful stdout.
+ }
+
+ if (builder.validateUserInputDidItFail()) {
+ fatal(" access the help menu with 'zig build -h'", .{});
+ }
+
+ validateSystemLibraryOptions(builder);
+
+ const stdout_writer = io.getStdOut().writer();
+
+ if (help_menu)
+ return usage(builder, stdout_writer);
+
+ if (steps_menu)
+ return steps(builder, stdout_writer);
+
+ var run: Run = .{
+ .max_rss = max_rss,
+ .max_rss_is_default = false,
+ .max_rss_mutex = .{},
+ .skip_oom_steps = skip_oom_steps,
+ .memory_blocked_steps = std.ArrayList(*Step).init(arena),
+ .prominent_compile_errors = prominent_compile_errors,
+
+ .claimed_rss = 0,
+ .summary = summary,
+ .ttyconf = ttyconf,
+ .stderr = stderr,
+ };
+
+ if (run.max_rss == 0) {
+ run.max_rss = process.totalSystemMemory() catch std.math.maxInt(u64);
+ run.max_rss_is_default = true;
+ }
+
+ runStepNames(
+ arena,
+ builder,
+ targets.items,
+ main_progress_node,
+ thread_pool_options,
+ &run,
+ seed,
+ ) catch |err| switch (err) {
+ error.UncleanExit => process.exit(1),
+ else => return err,
+ };
+}
+
+const Run = struct {
+ max_rss: u64,
+ max_rss_is_default: bool,
+ max_rss_mutex: std.Thread.Mutex,
+ skip_oom_steps: bool,
+ memory_blocked_steps: std.ArrayList(*Step),
+ prominent_compile_errors: bool,
+
+ claimed_rss: usize,
+ summary: ?Summary,
+ ttyconf: std.io.tty.Config,
+ stderr: File,
+};
+
+fn runStepNames(
+ arena: std.mem.Allocator,
+ b: *std.Build,
+ step_names: []const []const u8,
+ parent_prog_node: *std.Progress.Node,
+ thread_pool_options: std.Thread.Pool.Options,
+ run: *Run,
+ seed: u32,
+) !void {
+ const gpa = b.allocator;
+ var step_stack: std.AutoArrayHashMapUnmanaged(*Step, void) = .{};
+ defer step_stack.deinit(gpa);
+
+ if (step_names.len == 0) {
+ try step_stack.put(gpa, b.default_step, {});
+ } else {
+ try step_stack.ensureUnusedCapacity(gpa, step_names.len);
+ for (0..step_names.len) |i| {
+ const step_name = step_names[step_names.len - i - 1];
+ const s = b.top_level_steps.get(step_name) orelse {
+ std.debug.print("no step named '{s}'\n access the help menu with 'zig build -h'\n", .{step_name});
+ process.exit(1);
+ };
+ step_stack.putAssumeCapacity(&s.step, {});
+ }
+ }
+
+ const starting_steps = try arena.dupe(*Step, step_stack.keys());
+
+ var rng = std.Random.DefaultPrng.init(seed);
+ const rand = rng.random();
+ rand.shuffle(*Step, starting_steps);
+
+ for (starting_steps) |s| {
+ constructGraphAndCheckForDependencyLoop(b, s, &step_stack, rand) catch |err| switch (err) {
+ error.DependencyLoopDetected => return error.UncleanExit,
+ else => |e| return e,
+ };
+ }
+
+ {
+ // Check that we have enough memory to complete the build.
+ var any_problems = false;
+ for (step_stack.keys()) |s| {
+ if (s.max_rss == 0) continue;
+ if (s.max_rss > run.max_rss) {
+ if (run.skip_oom_steps) {
+ s.state = .skipped_oom;
+ } else {
+ std.debug.print("{s}{s}: this step declares an upper bound of {d} bytes of memory, exceeding the available {d} bytes of memory\n", .{
+ s.owner.dep_prefix, s.name, s.max_rss, run.max_rss,
+ });
+ any_problems = true;
+ }
+ }
+ }
+ if (any_problems) {
+ if (run.max_rss_is_default) {
+ std.debug.print("note: use --maxrss to override the default", .{});
+ }
+ return error.UncleanExit;
+ }
+ }
+
+ var thread_pool: std.Thread.Pool = undefined;
+ try thread_pool.init(thread_pool_options);
+ defer thread_pool.deinit();
+
+ {
+ defer parent_prog_node.end();
+
+ var step_prog = parent_prog_node.start("steps", step_stack.count());
+ defer step_prog.end();
+
+ var wait_group: std.Thread.WaitGroup = .{};
+ defer wait_group.wait();
+
+ // Here we spawn the initial set of tasks with a nice heuristic -
+ // dependency order. Each worker when it finishes a step will then
+ // check whether it should run any dependants.
+ const steps_slice = step_stack.keys();
+ for (0..steps_slice.len) |i| {
+ const step = steps_slice[steps_slice.len - i - 1];
+ if (step.state == .skipped_oom) continue;
+
+ wait_group.start();
+ thread_pool.spawn(workerMakeOneStep, .{
+ &wait_group, &thread_pool, b, step, &step_prog, run,
+ }) catch @panic("OOM");
+ }
+ }
+ assert(run.memory_blocked_steps.items.len == 0);
+
+ var test_skip_count: usize = 0;
+ var test_fail_count: usize = 0;
+ var test_pass_count: usize = 0;
+ var test_leak_count: usize = 0;
+ var test_count: usize = 0;
+
+ var success_count: usize = 0;
+ var skipped_count: usize = 0;
+ var failure_count: usize = 0;
+ var pending_count: usize = 0;
+ var total_compile_errors: usize = 0;
+ var compile_error_steps: std.ArrayListUnmanaged(*Step) = .{};
+ defer compile_error_steps.deinit(gpa);
+
+ for (step_stack.keys()) |s| {
+ test_fail_count += s.test_results.fail_count;
+ test_skip_count += s.test_results.skip_count;
+ test_leak_count += s.test_results.leak_count;
+ test_pass_count += s.test_results.passCount();
+ test_count += s.test_results.test_count;
+
+ switch (s.state) {
+ .precheck_unstarted => unreachable,
+ .precheck_started => unreachable,
+ .running => unreachable,
+ .precheck_done => {
+ // precheck_done is equivalent to dependency_failure in the case of
+ // transitive dependencies. For example:
+ // A -> B -> C (failure)
+ // B will be marked as dependency_failure, while A may never be queued, and thus
+ // remain in the initial state of precheck_done.
+ s.state = .dependency_failure;
+ pending_count += 1;
+ },
+ .dependency_failure => pending_count += 1,
+ .success => success_count += 1,
+ .skipped, .skipped_oom => skipped_count += 1,
+ .failure => {
+ failure_count += 1;
+ const compile_errors_len = s.result_error_bundle.errorMessageCount();
+ if (compile_errors_len > 0) {
+ total_compile_errors += compile_errors_len;
+ try compile_error_steps.append(gpa, s);
+ }
+ },
+ }
+ }
+
+ // A proper command line application defaults to silently succeeding.
+ // The user may request verbose mode if they have a different preference.
+ const failures_only = run.summary != .all and run.summary != .new;
+ if (failure_count == 0 and failures_only) return cleanExit();
+
+ const ttyconf = run.ttyconf;
+ const stderr = run.stderr;
+
+ if (run.summary != Summary.none) {
+ const total_count = success_count + failure_count + pending_count + skipped_count;
+ ttyconf.setColor(stderr, .cyan) catch {};
+ stderr.writeAll("Build Summary:") catch {};
+ ttyconf.setColor(stderr, .reset) catch {};
+ stderr.writer().print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
+ if (skipped_count > 0) stderr.writer().print("; {d} skipped", .{skipped_count}) catch {};
+ if (failure_count > 0) stderr.writer().print("; {d} failed", .{failure_count}) catch {};
+
+ if (test_count > 0) stderr.writer().print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {};
+ if (test_skip_count > 0) stderr.writer().print("; {d} skipped", .{test_skip_count}) catch {};
+ if (test_fail_count > 0) stderr.writer().print("; {d} failed", .{test_fail_count}) catch {};
+ if (test_leak_count > 0) stderr.writer().print("; {d} leaked", .{test_leak_count}) catch {};
+
+ if (run.summary == null) {
+ ttyconf.setColor(stderr, .dim) catch {};
+ stderr.writeAll(" (disable with --summary none)") catch {};
+ ttyconf.setColor(stderr, .reset) catch {};
+ }
+ stderr.writeAll("\n") catch {};
+
+ // Print a fancy tree with build results.
+ var print_node: PrintNode = .{ .parent = null };
+ if (step_names.len == 0) {
+ print_node.last = true;
+ printTreeStep(b, b.default_step, run, stderr, ttyconf, &print_node, &step_stack) catch {};
+ } else {
+ const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: {
+ var i: usize = step_names.len;
+ while (i > 0) {
+ i -= 1;
+ const step = b.top_level_steps.get(step_names[i]).?.step;
+ const found = switch (run.summary orelse .failures) {
+ .all, .none => unreachable,
+ .failures => step.state != .success,
+ .new => !step.result_cached,
+ };
+ if (found) break :blk i;
+ }
+ break :blk b.top_level_steps.count();
+ };
+ for (step_names, 0..) |step_name, i| {
+ const tls = b.top_level_steps.get(step_name).?;
+ print_node.last = i + 1 == last_index;
+ printTreeStep(b, &tls.step, run, stderr, ttyconf, &print_node, &step_stack) catch {};
+ }
+ }
+ }
+
+ if (failure_count == 0) return cleanExit();
+
+ // Finally, render compile errors at the bottom of the terminal.
+ // We use a separate compile_error_steps array list because step_stack is destructively
+ // mutated in printTreeStep above.
+ if (run.prominent_compile_errors and total_compile_errors > 0) {
+ for (compile_error_steps.items) |s| {
+ if (s.result_error_bundle.errorMessageCount() > 0) {
+ s.result_error_bundle.renderToStdErr(renderOptions(ttyconf));
+ }
+ }
+
+ // Signal to parent process that we have printed compile errors. The
+ // parent process may choose to omit the "following command failed"
+ // line in this case.
+ process.exit(2);
+ }
+
+ process.exit(1);
+}
+
+const PrintNode = struct {
+ parent: ?*PrintNode,
+ last: bool = false,
+};
+
+fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void {
+ const parent = node.parent orelse return;
+ if (parent.parent == null) return;
+ try printPrefix(parent, stderr, ttyconf);
+ if (parent.last) {
+ try stderr.writeAll(" ");
+ } else {
+ try stderr.writeAll(switch (ttyconf) {
+ .no_color, .windows_api => "| ",
+ .escape_codes => "\x1B\x28\x30\x78\x1B\x28\x42 ", // │
+ });
+ }
+}
+
+fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void {
+ try stderr.writeAll(switch (ttyconf) {
+ .no_color, .windows_api => "+- ",
+ .escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─
+ });
+}
+
+fn printStepStatus(
+ s: *Step,
+ stderr: File,
+ ttyconf: std.io.tty.Config,
+ run: *const Run,
+) !void {
+ switch (s.state) {
+ .precheck_unstarted => unreachable,
+ .precheck_started => unreachable,
+ .precheck_done => unreachable,
+ .running => unreachable,
+
+ .dependency_failure => {
+ try ttyconf.setColor(stderr, .dim);
+ try stderr.writeAll(" transitive failure\n");
+ try ttyconf.setColor(stderr, .reset);
+ },
+
+ .success => {
+ try ttyconf.setColor(stderr, .green);
+ if (s.result_cached) {
+ try stderr.writeAll(" cached");
+ } else if (s.test_results.test_count > 0) {
+ const pass_count = s.test_results.passCount();
+ try stderr.writer().print(" {d} passed", .{pass_count});
+ if (s.test_results.skip_count > 0) {
+ try ttyconf.setColor(stderr, .yellow);
+ try stderr.writer().print(" {d} skipped", .{s.test_results.skip_count});
+ }
+ } else {
+ try stderr.writeAll(" success");
+ }
+ try ttyconf.setColor(stderr, .reset);
+ if (s.result_duration_ns) |ns| {
+ try ttyconf.setColor(stderr, .dim);
+ if (ns >= std.time.ns_per_min) {
+ try stderr.writer().print(" {d}m", .{ns / std.time.ns_per_min});
+ } else if (ns >= std.time.ns_per_s) {
+ try stderr.writer().print(" {d}s", .{ns / std.time.ns_per_s});
+ } else if (ns >= std.time.ns_per_ms) {
+ try stderr.writer().print(" {d}ms", .{ns / std.time.ns_per_ms});
+ } else if (ns >= std.time.ns_per_us) {
+ try stderr.writer().print(" {d}us", .{ns / std.time.ns_per_us});
+ } else {
+ try stderr.writer().print(" {d}ns", .{ns});
+ }
+ try ttyconf.setColor(stderr, .reset);
+ }
+ if (s.result_peak_rss != 0) {
+ const rss = s.result_peak_rss;
+ try ttyconf.setColor(stderr, .dim);
+ if (rss >= 1000_000_000) {
+ try stderr.writer().print(" MaxRSS:{d}G", .{rss / 1000_000_000});
+ } else if (rss >= 1000_000) {
+ try stderr.writer().print(" MaxRSS:{d}M", .{rss / 1000_000});
+ } else if (rss >= 1000) {
+ try stderr.writer().print(" MaxRSS:{d}K", .{rss / 1000});
+ } else {
+ try stderr.writer().print(" MaxRSS:{d}B", .{rss});
+ }
+ try ttyconf.setColor(stderr, .reset);
+ }
+ try stderr.writeAll("\n");
+ },
+ .skipped, .skipped_oom => |skip| {
+ try ttyconf.setColor(stderr, .yellow);
+ try stderr.writeAll(" skipped");
+ if (skip == .skipped_oom) {
+ try stderr.writeAll(" (not enough memory)");
+ try ttyconf.setColor(stderr, .dim);
+ try stderr.writer().print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });
+ try ttyconf.setColor(stderr, .yellow);
+ }
+ try stderr.writeAll("\n");
+ try ttyconf.setColor(stderr, .reset);
+ },
+ .failure => try printStepFailure(s, stderr, ttyconf),
+ }
+}
+
+fn printStepFailure(
+ s: *Step,
+ stderr: File,
+ ttyconf: std.io.tty.Config,
+) !void {
+ if (s.result_error_bundle.errorMessageCount() > 0) {
+ try ttyconf.setColor(stderr, .red);
+ try stderr.writer().print(" {d} errors\n", .{
+ s.result_error_bundle.errorMessageCount(),
+ });
+ try ttyconf.setColor(stderr, .reset);
+ } else if (!s.test_results.isSuccess()) {
+ try stderr.writer().print(" {d}/{d} passed", .{
+ s.test_results.passCount(), s.test_results.test_count,
+ });
+ if (s.test_results.fail_count > 0) {
+ try stderr.writeAll(", ");
+ try ttyconf.setColor(stderr, .red);
+ try stderr.writer().print("{d} failed", .{
+ s.test_results.fail_count,
+ });
+ try ttyconf.setColor(stderr, .reset);
+ }
+ if (s.test_results.skip_count > 0) {
+ try stderr.writeAll(", ");
+ try ttyconf.setColor(stderr, .yellow);
+ try stderr.writer().print("{d} skipped", .{
+ s.test_results.skip_count,
+ });
+ try ttyconf.setColor(stderr, .reset);
+ }
+ if (s.test_results.leak_count > 0) {
+ try stderr.writeAll(", ");
+ try ttyconf.setColor(stderr, .red);
+ try stderr.writer().print("{d} leaked", .{
+ s.test_results.leak_count,
+ });
+ try ttyconf.setColor(stderr, .reset);
+ }
+ try stderr.writeAll("\n");
+ } else if (s.result_error_msgs.items.len > 0) {
+ try ttyconf.setColor(stderr, .red);
+ try stderr.writeAll(" failure\n");
+ try ttyconf.setColor(stderr, .reset);
+ } else {
+ assert(s.result_stderr.len > 0);
+ try ttyconf.setColor(stderr, .red);
+ try stderr.writeAll(" stderr\n");
+ try ttyconf.setColor(stderr, .reset);
+ }
+}
+
+fn printTreeStep(
+ b: *std.Build,
+ s: *Step,
+ run: *const Run,
+ stderr: File,
+ ttyconf: std.io.tty.Config,
+ parent_node: *PrintNode,
+ step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
+) !void {
+ const first = step_stack.swapRemove(s);
+ const summary = run.summary orelse .failures;
+ const skip = switch (summary) {
+ .none => unreachable,
+ .all => false,
+ .new => s.result_cached,
+ .failures => s.state == .success,
+ };
+ if (skip) return;
+ try printPrefix(parent_node, stderr, ttyconf);
+
+ if (!first) try ttyconf.setColor(stderr, .dim);
+ if (parent_node.parent != null) {
+ if (parent_node.last) {
+ try printChildNodePrefix(stderr, ttyconf);
+ } else {
+ try stderr.writeAll(switch (ttyconf) {
+ .no_color, .windows_api => "+- ",
+ .escape_codes => "\x1B\x28\x30\x74\x71\x1B\x28\x42 ", // ├─
+ });
+ }
+ }
+
+ // dep_prefix omitted here because it is redundant with the tree.
+ try stderr.writeAll(s.name);
+
+ if (first) {
+ try printStepStatus(s, stderr, ttyconf, run);
+
+ const last_index = if (summary == .all) s.dependencies.items.len -| 1 else blk: {
+ var i: usize = s.dependencies.items.len;
+ while (i > 0) {
+ i -= 1;
+
+ const step = s.dependencies.items[i];
+ const found = switch (summary) {
+ .all, .none => unreachable,
+ .failures => step.state != .success,
+ .new => !step.result_cached,
+ };
+ if (found) break :blk i;
+ }
+ break :blk s.dependencies.items.len -| 1;
+ };
+ for (s.dependencies.items, 0..) |dep, i| {
+ var print_node: PrintNode = .{
+ .parent = parent_node,
+ .last = i == last_index,
+ };
+ try printTreeStep(b, dep, run, stderr, ttyconf, &print_node, step_stack);
+ }
+ } else {
+ if (s.dependencies.items.len == 0) {
+ try stderr.writeAll(" (reused)\n");
+ } else {
+ try stderr.writer().print(" (+{d} more reused dependencies)\n", .{
+ s.dependencies.items.len,
+ });
+ }
+ try ttyconf.setColor(stderr, .reset);
+ }
+}
+
+/// Traverse the dependency graph depth-first and make it undirected by having
+/// steps know their dependants (they only know dependencies at start).
+/// Along the way, check that there is no dependency loop, and record the steps
+/// in traversal order in `step_stack`.
+/// Each step has its dependencies traversed in random order, this accomplishes
+/// two things:
+/// - `step_stack` will be in randomized-depth-first order, so the build runner
+/// spawns steps in a random (but optimized) order
+/// - each step's `dependants` list is also filled in a random order, so that
+/// when it finishes executing in `workerMakeOneStep`, it spawns next steps
+/// to run in random order
+fn constructGraphAndCheckForDependencyLoop(
+ b: *std.Build,
+ s: *Step,
+ step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
+ rand: std.Random,
+) !void {
+ switch (s.state) {
+ .precheck_started => {
+ std.debug.print("dependency loop detected:\n {s}\n", .{s.name});
+ return error.DependencyLoopDetected;
+ },
+ .precheck_unstarted => {
+ s.state = .precheck_started;
+
+ try step_stack.ensureUnusedCapacity(b.allocator, s.dependencies.items.len);
+
+ // We dupe to avoid shuffling the steps in the summary, it depends
+ // on s.dependencies' order.
+ const deps = b.allocator.dupe(*Step, s.dependencies.items) catch @panic("OOM");
+ rand.shuffle(*Step, deps);
+
+ for (deps) |dep| {
+ try step_stack.put(b.allocator, dep, {});
+ try dep.dependants.append(b.allocator, s);
+ constructGraphAndCheckForDependencyLoop(b, dep, step_stack, rand) catch |err| {
+ if (err == error.DependencyLoopDetected) {
+ std.debug.print(" {s}\n", .{s.name});
+ }
+ return err;
+ };
+ }
+
+ s.state = .precheck_done;
+ },
+ .precheck_done => {},
+
+ // These don't happen until we actually run the step graph.
+ .dependency_failure => unreachable,
+ .running => unreachable,
+ .success => unreachable,
+ .failure => unreachable,
+ .skipped => unreachable,
+ .skipped_oom => unreachable,
+ }
+}
+
+fn workerMakeOneStep(
+ wg: *std.Thread.WaitGroup,
+ thread_pool: *std.Thread.Pool,
+ b: *std.Build,
+ s: *Step,
+ prog_node: *std.Progress.Node,
+ run: *Run,
+) void {
+ defer wg.finish();
+
+ // First, check the conditions for running this step. If they are not met,
+ // then we return without doing the step, relying on another worker to
+ // queue this step up again when dependencies are met.
+ for (s.dependencies.items) |dep| {
+ switch (@atomicLoad(Step.State, &dep.state, .seq_cst)) {
+ .success, .skipped => continue,
+ .failure, .dependency_failure, .skipped_oom => {
+ @atomicStore(Step.State, &s.state, .dependency_failure, .seq_cst);
+ return;
+ },
+ .precheck_done, .running => {
+ // dependency is not finished yet.
+ return;
+ },
+ .precheck_unstarted => unreachable,
+ .precheck_started => unreachable,
+ }
+ }
+
+ if (s.max_rss != 0) {
+ run.max_rss_mutex.lock();
+ defer run.max_rss_mutex.unlock();
+
+ // Avoid running steps twice.
+ if (s.state != .precheck_done) {
+ // Another worker got the job.
+ return;
+ }
+
+ const new_claimed_rss = run.claimed_rss + s.max_rss;
+ if (new_claimed_rss > run.max_rss) {
+ // Running this step right now could possibly exceed the allotted RSS.
+ // Add this step to the queue of memory-blocked steps.
+ run.memory_blocked_steps.append(s) catch @panic("OOM");
+ return;
+ }
+
+ run.claimed_rss = new_claimed_rss;
+ s.state = .running;
+ } else {
+ // Avoid running steps twice.
+ if (@cmpxchgStrong(Step.State, &s.state, .precheck_done, .running, .seq_cst, .seq_cst) != null) {
+ // Another worker got the job.
+ return;
+ }
+ }
+
+ var sub_prog_node = prog_node.start(s.name, 0);
+ sub_prog_node.activate();
+ defer sub_prog_node.end();
+
+ const make_result = s.make(&sub_prog_node);
+
+ // No matter the result, we want to display error/warning messages.
+ const show_compile_errors = !run.prominent_compile_errors and
+ s.result_error_bundle.errorMessageCount() > 0;
+ const show_error_msgs = s.result_error_msgs.items.len > 0;
+ const show_stderr = s.result_stderr.len > 0;
+
+ if (show_error_msgs or show_compile_errors or show_stderr) {
+ sub_prog_node.context.lock_stderr();
+ defer sub_prog_node.context.unlock_stderr();
+
+ printErrorMessages(b, s, run) catch {};
+ }
+
+ handle_result: {
+ if (make_result) |_| {
+ @atomicStore(Step.State, &s.state, .success, .seq_cst);
+ } else |err| switch (err) {
+ error.MakeFailed => {
+ @atomicStore(Step.State, &s.state, .failure, .seq_cst);
+ break :handle_result;
+ },
+ error.MakeSkipped => @atomicStore(Step.State, &s.state, .skipped, .seq_cst),
+ }
+
+ // Successful completion of a step, so we queue up its dependants as well.
+ for (s.dependants.items) |dep| {
+ wg.start();
+ thread_pool.spawn(workerMakeOneStep, .{
+ wg, thread_pool, b, dep, prog_node, run,
+ }) catch @panic("OOM");
+ }
+ }
+
+ // If this is a step that claims resources, we must now queue up other
+ // steps that are waiting for resources.
+ if (s.max_rss != 0) {
+ run.max_rss_mutex.lock();
+ defer run.max_rss_mutex.unlock();
+
+ // Give the memory back to the scheduler.
+ run.claimed_rss -= s.max_rss;
+ // Avoid kicking off too many tasks that we already know will not have
+ // enough resources.
+ var remaining = run.max_rss - run.claimed_rss;
+ var i: usize = 0;
+ var j: usize = 0;
+ while (j < run.memory_blocked_steps.items.len) : (j += 1) {
+ const dep = run.memory_blocked_steps.items[j];
+ assert(dep.max_rss != 0);
+ if (dep.max_rss <= remaining) {
+ remaining -= dep.max_rss;
+
+ wg.start();
+ thread_pool.spawn(workerMakeOneStep, .{
+ wg, thread_pool, b, dep, prog_node, run,
+ }) catch @panic("OOM");
+ } else {
+ run.memory_blocked_steps.items[i] = dep;
+ i += 1;
+ }
+ }
+ run.memory_blocked_steps.shrinkRetainingCapacity(i);
+ }
+}
+
+fn printErrorMessages(b: *std.Build, failing_step: *Step, run: *const Run) !void {
+ const gpa = b.allocator;
+ const stderr = run.stderr;
+ const ttyconf = run.ttyconf;
+
+ // Provide context for where these error messages are coming from by
+ // printing the corresponding Step subtree.
+
+ var step_stack: std.ArrayListUnmanaged(*Step) = .{};
+ defer step_stack.deinit(gpa);
+ try step_stack.append(gpa, failing_step);
+ while (step_stack.items[step_stack.items.len - 1].dependants.items.len != 0) {
+ try step_stack.append(gpa, step_stack.items[step_stack.items.len - 1].dependants.items[0]);
+ }
+
+ // Now, `step_stack` has the subtree that we want to print, in reverse order.
+ try ttyconf.setColor(stderr, .dim);
+ var indent: usize = 0;
+ while (step_stack.popOrNull()) |s| : (indent += 1) {
+ if (indent > 0) {
+ try stderr.writer().writeByteNTimes(' ', (indent - 1) * 3);
+ try printChildNodePrefix(stderr, ttyconf);
+ }
+
+ try stderr.writeAll(s.name);
+
+ if (s == failing_step) {
+ try printStepFailure(s, stderr, ttyconf);
+ } else {
+ try stderr.writeAll("\n");
+ }
+ }
+ try ttyconf.setColor(stderr, .reset);
+
+ if (failing_step.result_stderr.len > 0) {
+ try stderr.writeAll(failing_step.result_stderr);
+ if (!mem.endsWith(u8, failing_step.result_stderr, "\n")) {
+ try stderr.writeAll("\n");
+ }
+ }
+
+ if (!run.prominent_compile_errors and failing_step.result_error_bundle.errorMessageCount() > 0)
+ try failing_step.result_error_bundle.renderToWriter(renderOptions(ttyconf), stderr.writer());
+
+ for (failing_step.result_error_msgs.items) |msg| {
+ try ttyconf.setColor(stderr, .red);
+ try stderr.writeAll("error: ");
+ try ttyconf.setColor(stderr, .reset);
+ try stderr.writeAll(msg);
+ try stderr.writeAll("\n");
+ }
+}
+
+fn steps(builder: *std.Build, out_stream: anytype) !void {
+ const allocator = builder.allocator;
+ for (builder.top_level_steps.values()) |top_level_step| {
+ const name = if (&top_level_step.step == builder.default_step)
+ try fmt.allocPrint(allocator, "{s} (default)", .{top_level_step.step.name})
+ else
+ top_level_step.step.name;
+ try out_stream.print(" {s:<28} {s}\n", .{ name, top_level_step.description });
+ }
+}
+
+fn usage(b: *std.Build, out_stream: anytype) !void {
+ try out_stream.print(
+ \\Usage: {s} build [steps] [options]
+ \\
+ \\Steps:
+ \\
+ , .{b.graph.zig_exe});
+ try steps(b, out_stream);
+
+ try out_stream.writeAll(
+ \\
+ \\General Options:
+ \\ -p, --prefix [path] Where to install files (default: zig-out)
+ \\ --prefix-lib-dir [path] Where to install libraries
+ \\ --prefix-exe-dir [path] Where to install executables
+ \\ --prefix-include-dir [path] Where to install C header files
+ \\
+ \\ --release[=mode] Request release mode, optionally specifying a
+ \\ preferred optimization mode: fast, safe, small
+ \\
+ \\ -fdarling, -fno-darling Integration with system-installed Darling to
+ \\ execute macOS programs on Linux hosts
+ \\ (default: no)
+ \\ -fqemu, -fno-qemu Integration with system-installed QEMU to execute
+ \\ foreign-architecture programs on Linux hosts
+ \\ (default: no)
+ \\ --glibc-runtimes [path] Enhances QEMU integration by providing glibc built
+ \\ for multiple foreign architectures, allowing
+ \\ execution of non-native programs that link with glibc.
+ \\ -frosetta, -fno-rosetta Rely on Rosetta to execute x86_64 programs on
+ \\ ARM64 macOS hosts. (default: no)
+ \\ -fwasmtime, -fno-wasmtime Integration with system-installed wasmtime to
+ \\ execute WASI binaries. (default: no)
+ \\ -fwine, -fno-wine Integration with system-installed Wine to execute
+ \\ Windows programs on Linux hosts. (default: no)
+ \\
+ \\ -h, --help Print this help and exit
+ \\ -l, --list-steps Print available steps
+ \\ --verbose Print commands before executing them
+ \\ --color [auto|off|on] Enable or disable colored error messages
+ \\ --prominent-compile-errors Buffer compile errors and display at end
+ \\ --summary [mode] Control the printing of the build summary
+ \\ all Print the build summary in its entirety
+ \\ new Omit cached steps
+ \\ failures (Default) Only print failed steps
+ \\ none Do not print the build summary
+ \\ -j Limit concurrent jobs (default is to use all CPU cores)
+ \\ --maxrss Limit memory usage (default is to use available memory)
+ \\ --skip-oom-steps Instead of failing, skip steps that would exceed --maxrss
+ \\ --fetch Exit after fetching dependency tree
+ \\
+ \\Project-Specific Options:
+ \\
+ );
+
+ const arena = b.allocator;
+ if (b.available_options_list.items.len == 0) {
+ try out_stream.print(" (none)\n", .{});
+ } else {
+ for (b.available_options_list.items) |option| {
+ const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{
+ option.name,
+ @tagName(option.type_id),
+ });
+ try out_stream.print("{s:<30} {s}\n", .{ name, option.description });
+ if (option.enum_options) |enum_options| {
+ const padding = " " ** 33;
+ try out_stream.writeAll(padding ++ "Supported Values:\n");
+ for (enum_options) |enum_option| {
+ try out_stream.print(padding ++ " {s}\n", .{enum_option});
+ }
+ }
+ }
+ }
+
+ try out_stream.writeAll(
+ \\
+ \\System Integration Options:
+ \\ --search-prefix [path] Add a path to look for binaries, libraries, headers
+ \\ --sysroot [path] Set the system root directory (usually /)
+ \\ --libc [file] Provide a file which specifies libc paths
+ \\
+ \\ --host-target [triple] Use the provided target as the host
+ \\ --host-cpu [cpu] Use the provided CPU as the host
+ \\ --host-dynamic-linker [path] Use the provided dynamic linker as the host
+ \\
+ \\ --system [pkgdir] Disable package fetching; enable all integrations
+ \\ -fsys=[name] Enable a system integration
+ \\ -fno-sys=[name] Disable a system integration
+ \\
+ \\ Available System Integrations: Enabled:
+ \\
+ );
+ if (b.graph.system_library_options.entries.len == 0) {
+ try out_stream.writeAll(" (none) -\n");
+ } else {
+ for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| {
+ const status = switch (v) {
+ .declared_enabled => "yes",
+ .declared_disabled => "no",
+ .user_enabled, .user_disabled => unreachable, // already emitted error
+ };
+ try out_stream.print(" {s:<43} {s}\n", .{ k, status });
+ }
+ }
+
+ try out_stream.writeAll(
+ \\
+ \\Advanced Options:
+ \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
+ \\ -fno-reference-trace Disable reference trace
+ \\ --build-file [file] Override path to build.zig
+ \\ --cache-dir [path] Override path to local Zig cache directory
+ \\ --global-cache-dir [path] Override path to global Zig cache directory
+ \\ --zig-lib-dir [arg] Override path to Zig lib directory
+ \\ --build-runner [file] Override path to build runner
+ \\ --seed [integer] For shuffling dependency traversal order (default: random)
+ \\ --debug-log [scope] Enable debugging the compiler
+ \\ --debug-pkg-config Fail if unknown pkg-config flags encountered
+ \\ --verbose-link Enable compiler debug output for linking
+ \\ --verbose-air Enable compiler debug output for Zig AIR
+ \\ --verbose-llvm-ir[=file] Enable compiler debug output for LLVM IR
+ \\ --verbose-llvm-bc=[file] Enable compiler debug output for LLVM BC
+ \\ --verbose-cimport Enable compiler debug output for C imports
+ \\ --verbose-cc Enable compiler debug output for C compilation
+ \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features
+ \\
+ );
+}
+
+fn nextArg(args: [][:0]const u8, idx: *usize) ?[:0]const u8 {
+ if (idx.* >= args.len) return null;
+ defer idx.* += 1;
+ return args[idx.*];
+}
+
+fn nextArgOrFatal(args: [][:0]const u8, idx: *usize) [:0]const u8 {
+ return nextArg(args, idx) orelse {
+ std.debug.print("expected argument after '{s}'\n access the help menu with 'zig build -h'\n", .{args[idx.*]});
+ process.exit(1);
+ };
+}
+
+fn argsRest(args: [][:0]const u8, idx: usize) ?[][:0]const u8 {
+ if (idx >= args.len) return null;
+ return args[idx..];
+}
+
+fn cleanExit() void {
+ // Perhaps in the future there could be an Advanced Options flag such as
+ // --debug-build-runner-leaks which would make this function return instead
+ // of calling exit.
+ process.exit(0);
+}
+
+const Color = enum { auto, off, on };
+const Summary = enum { all, new, failures, none };
+
+fn get_tty_conf(color: Color, stderr: File) std.io.tty.Config {
+ return switch (color) {
+ .auto => std.io.tty.detectConfig(stderr),
+ .on => .escape_codes,
+ .off => .no_color,
+ };
+}
+
+fn renderOptions(ttyconf: std.io.tty.Config) std.zig.ErrorBundle.RenderOptions {
+ return .{
+ .ttyconf = ttyconf,
+ .include_source_line = ttyconf != .no_color,
+ .include_reference_trace = ttyconf != .no_color,
+ };
+}
+
+fn fatalWithHint(comptime f: []const u8, args: anytype) noreturn {
+ std.debug.print(f ++ "\n access the help menu with 'zig build -h'\n", args);
+ process.exit(1);
+}
+
+fn fatal(comptime f: []const u8, args: anytype) noreturn {
+ std.debug.print(f ++ "\n", args);
+ process.exit(1);
+}
+
+fn validateSystemLibraryOptions(b: *std.Build) void {
+ var bad = false;
+ for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| {
+ switch (v) {
+ .user_disabled, .user_enabled => {
+ // The user tried to enable or disable a system library integration, but
+ // the build script did not recognize that option.
+ std.debug.print("system library name not recognized by build script: '{s}'\n", .{k});
+ bad = true;
+ },
+ .declared_disabled, .declared_enabled => {},
+ }
+ }
+ if (bad) {
+ std.debug.print(" access the help menu with 'zig build -h'\n", .{});
+ process.exit(1);
+ }
+}
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index d9e72f2019a6fc5e20b85a287a08d43785f9270a..0238d35c7d9dc2fec6b54cab2411a1bfd5ae1bd9 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -420,7 +420,6 @@ pub const Type = union(enum) {
/// therefore must be kept in sync with the compiler implementation.
pub const Fn = struct {
calling_convention: CallingConvention,
- alignment: comptime_int,
is_generic: bool,
is_var_args: bool,
/// TODO change the language spec to make this not optional.
diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig
index 8dd122c3ba676e4654ce746120e5ed43d1a6c533..8442ac9fe00ce1374a0a0f4a06f5b9bd8a26dd6a 100644
--- a/lib/std/c/darwin.zig
+++ b/lib/std/c/darwin.zig
@@ -1053,10 +1053,10 @@ pub const sigset_t = u32;
pub const empty_sigset: sigset_t = 0;
pub const SIG = struct {
- pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
- pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
- pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
- pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(5));
+ pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
+ pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
+ pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
+ pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(5);
/// block specified signal set
pub const BLOCK = 1;
@@ -1150,7 +1150,7 @@ pub const siginfo_t = extern struct {
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name.
pub const Sigaction = extern struct {
- pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void;
+ pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
handler: extern union {
diff --git a/lib/std/c/dragonfly.zig b/lib/std/c/dragonfly.zig
index 8cbdd22c401f122b19294fa3844af3b83519c03c..183a81bba2a273a30f277b990d5d6ad93263a125 100644
--- a/lib/std/c/dragonfly.zig
+++ b/lib/std/c/dragonfly.zig
@@ -616,9 +616,9 @@ pub const S = struct {
pub const BADSIG = SIG.ERR;
pub const SIG = struct {
- pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
- pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
- pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
+ pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
+ pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
+ pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
pub const BLOCK = 1;
pub const UNBLOCK = 2;
@@ -690,7 +690,7 @@ pub const empty_sigset = sigset_t{ .__bits = [_]c_uint{0} ** _SIG_WORDS };
pub const sig_atomic_t = c_int;
pub const Sigaction = extern struct {
- pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void;
+ pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
/// signal handler
diff --git a/lib/std/c/freebsd.zig b/lib/std/c/freebsd.zig
index 94854cf09005431900d44b10be3d6231c253ec03..a89ca30968fc8423760f8b5be273bdddf3a0d7fb 100644
--- a/lib/std/c/freebsd.zig
+++ b/lib/std/c/freebsd.zig
@@ -695,9 +695,9 @@ pub const SIG = struct {
pub const UNBLOCK = 2;
pub const SETMASK = 3;
- pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
- pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
- pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
+ pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
+ pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
+ pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
pub const WORDS = 4;
pub const MAXSIG = 128;
@@ -1171,7 +1171,7 @@ const NSIG = 32;
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct {
- pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void;
+ pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
/// signal handler
diff --git a/lib/std/c/haiku.zig b/lib/std/c/haiku.zig
index 723d953d2d76c8c43e999361a1b4c3f649e4469c..12b5201acd864e2785daaa593ccdc8390ee0edad 100644
--- a/lib/std/c/haiku.zig
+++ b/lib/std/c/haiku.zig
@@ -441,9 +441,9 @@ pub const SA = struct {
};
pub const SIG = struct {
- pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
- pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
- pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
+ pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
+ pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
+ pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
pub const HUP = 1;
pub const INT = 2;
@@ -690,7 +690,7 @@ const NSIG = 32;
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct {
- pub const handler_fn = *const fn (i32) align(1) callconv(.C) void;
+ pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
/// signal handler
__sigaction_u: extern union {
diff --git a/lib/std/c/netbsd.zig b/lib/std/c/netbsd.zig
index 475fd55e22bfa5a44e0bf653f8b3aec5d9c6bcf7..c06857787ae46885e804cc51629f525ccde9bfc7 100644
--- a/lib/std/c/netbsd.zig
+++ b/lib/std/c/netbsd.zig
@@ -800,9 +800,9 @@ pub const winsize = extern struct {
const NSIG = 32;
pub const SIG = struct {
- pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
- pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
- pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
+ pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
+ pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
+ pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
pub const WORDS = 4;
pub const MAXSIG = 128;
@@ -864,7 +864,7 @@ pub const SIG = struct {
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct {
- pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void;
+ pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
/// signal handler
diff --git a/lib/std/c/openbsd.zig b/lib/std/c/openbsd.zig
index 75a4d6e0e8ee2c444431be2d803b4067350e03c4..4fd450cd5ce465fa6f76135060cf58786b8a4b58 100644
--- a/lib/std/c/openbsd.zig
+++ b/lib/std/c/openbsd.zig
@@ -795,11 +795,11 @@ pub const winsize = extern struct {
const NSIG = 33;
pub const SIG = struct {
- pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
- pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
- pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
- pub const CATCH = @as(?Sigaction.handler_fn, @ptrFromInt(2));
- pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(3));
+ pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
+ pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
+ pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
+ pub const CATCH: ?Sigaction.handler_fn = @ptrFromInt(2);
+ pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(3);
pub const HUP = 1;
pub const INT = 2;
@@ -842,7 +842,7 @@ pub const SIG = struct {
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct {
- pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void;
+ pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
/// signal handler
diff --git a/lib/std/c/solaris.zig b/lib/std/c/solaris.zig
index ef64acd43b931a65a01fc57b2649906e10569172..838b6985cc0873a86ea8451a6b70733cf9e7ce5d 100644
--- a/lib/std/c/solaris.zig
+++ b/lib/std/c/solaris.zig
@@ -798,10 +798,10 @@ pub const winsize = extern struct {
const NSIG = 75;
pub const SIG = struct {
- pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
- pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
- pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
- pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(2));
+ pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
+ pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
+ pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
+ pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(2);
pub const WORDS = 4;
pub const MAXSIG = 75;
@@ -874,7 +874,7 @@ pub const SIG = struct {
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct {
- pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void;
+ pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
/// signal options
diff --git a/lib/std/meta.zig b/lib/std/meta.zig
index f7b418d71d3104abfa82ff0e54ac70e650fc56d8..da0f629748ed53794585a27bba17f743802f6062 100644
--- a/lib/std/meta.zig
+++ b/lib/std/meta.zig
@@ -57,10 +57,9 @@ test stringToEnum {
}
/// Returns the alignment of type T.
-/// Note that if T is a pointer or function type the result is different than
-/// the one returned by @alignOf(T).
+/// Note that if T is a pointer type the result is different than the one
+/// returned by @alignOf(T).
/// If T is a pointer type the alignment of the type it points to is returned.
-/// If T is a function type the alignment a target-dependent value is returned.
pub fn alignment(comptime T: type) comptime_int {
return switch (@typeInfo(T)) {
.Optional => |info| switch (@typeInfo(info.child)) {
@@ -68,7 +67,6 @@ pub fn alignment(comptime T: type) comptime_int {
else => @alignOf(T),
},
.Pointer => |info| info.alignment,
- .Fn => |info| info.alignment,
else => @alignOf(T),
};
}
@@ -80,7 +78,8 @@ test alignment {
try testing.expect(alignment([]align(1) u8) == 1);
try testing.expect(alignment([]align(2) u8) == 2);
try testing.expect(alignment(fn () void) > 0);
- try testing.expect(alignment(fn () align(128) void) == 128);
+ try testing.expect(alignment(*const fn () void) > 0);
+ try testing.expect(alignment(*align(128) const fn () void) == 128);
}
/// Given a parameterized type (array, vector, pointer, optional), returns the "child type".
diff --git a/lib/std/os/emscripten.zig b/lib/std/os/emscripten.zig
index 04c3996f152f2087b8da8c90b5b01fcdba26539d..924b2dd0b21daee49444fee993176758d5e47fc6 100644
--- a/lib/std/os/emscripten.zig
+++ b/lib/std/os/emscripten.zig
@@ -689,13 +689,13 @@ pub const SIG = struct {
pub const SYS = 31;
pub const UNUSED = SIG.SYS;
- pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(std.math.maxInt(usize)));
- pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
- pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
+ pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(std.math.maxInt(usize));
+ pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
+ pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
};
pub const Sigaction = extern struct {
- pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void;
+ pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
handler: extern union {
diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig
index 3892e4326a558deae3c14e9ff4df6ea8ebbf4de9..a5cdab18ce8103a60c56b99994a22fe632fb15a2 100644
--- a/lib/std/os/linux.zig
+++ b/lib/std/os/linux.zig
@@ -1327,16 +1327,14 @@ pub fn flock(fd: fd_t, operation: i32) usize {
return syscall2(.flock, @as(usize, @bitCast(@as(isize, fd))), @as(usize, @bitCast(@as(isize, operation))));
}
-var vdso_clock_gettime = @as(?*const anyopaque, @ptrCast(&init_vdso_clock_gettime));
-
// We must follow the C calling convention when we call into the VDSO
-const vdso_clock_gettime_ty = *align(1) const fn (i32, *timespec) callconv(.C) usize;
+const VdsoClockGettime = *align(1) const fn (i32, *timespec) callconv(.C) usize;
+var vdso_clock_gettime: ?VdsoClockGettime = &init_vdso_clock_gettime;
pub fn clock_gettime(clk_id: i32, tp: *timespec) usize {
if (@hasDecl(VDSO, "CGT_SYM")) {
- const ptr = @atomicLoad(?*const anyopaque, &vdso_clock_gettime, .unordered);
- if (ptr) |fn_ptr| {
- const f = @as(vdso_clock_gettime_ty, @ptrCast(fn_ptr));
+ const ptr = @atomicLoad(?VdsoClockGettime, &vdso_clock_gettime, .unordered);
+ if (ptr) |f| {
const rc = f(clk_id, tp);
switch (rc) {
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 {
}
fn init_vdso_clock_gettime(clk: i32, ts: *timespec) callconv(.C) usize {
- const ptr = @as(?*const anyopaque, @ptrFromInt(vdso.lookup(VDSO.CGT_VER, VDSO.CGT_SYM)));
+ const ptr: ?VdsoClockGettime = @ptrFromInt(vdso.lookup(VDSO.CGT_VER, VDSO.CGT_SYM));
// Note that we may not have a VDSO at all, update the stub address anyway
// so that clock_gettime will fall back on the good old (and slow) syscall
- @atomicStore(?*const anyopaque, &vdso_clock_gettime, ptr, .monotonic);
+ @atomicStore(?VdsoClockGettime, &vdso_clock_gettime, ptr, .monotonic);
// Call into the VDSO if available
- if (ptr) |fn_ptr| {
- const f = @as(vdso_clock_gettime_ty, @ptrCast(fn_ptr));
- return f(clk, ts);
- }
+ if (ptr) |f| return f(clk, ts);
return @as(usize, @bitCast(-@as(isize, @intFromEnum(E.NOSYS))));
}
@@ -2516,9 +2511,9 @@ pub const SIG = if (is_mips) struct {
pub const SYS = 31;
pub const UNUSED = SIG.SYS;
- pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
- pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
- pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
+ pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
+ pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
+ pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
} else if (is_sparc) struct {
pub const BLOCK = 1;
pub const UNBLOCK = 2;
@@ -2560,9 +2555,9 @@ pub const SIG = if (is_mips) struct {
pub const PWR = LOST;
pub const IO = SIG.POLL;
- pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
- pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
- pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
+ pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
+ pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
+ pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
} else struct {
pub const BLOCK = 0;
pub const UNBLOCK = 1;
@@ -2603,9 +2598,9 @@ pub const SIG = if (is_mips) struct {
pub const SYS = 31;
pub const UNUSED = SIG.SYS;
- pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize)));
- pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0));
- pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1));
+ pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize));
+ pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0);
+ pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1);
};
pub const kernel_rwf = u32;
@@ -3709,7 +3704,7 @@ pub const all_mask: sigset_t = [_]u32{0xffffffff} ** @typeInfo(sigset_t).Array.l
pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffffffff} ** 30;
const k_sigaction_funcs = struct {
- const handler = ?*const fn (c_int) align(1) callconv(.C) void;
+ const handler = ?*align(1) const fn (c_int) callconv(.C) void;
const restorer = *const fn () callconv(.C) void;
};
@@ -3736,7 +3731,7 @@ pub const k_sigaction = switch (native_arch) {
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct {
- pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void;
+ pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void;
pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
handler: extern union {
diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig
index 364e49ae8fba5fdea98e35009e9422efccded89f..54efe22b8d623c06bdd5b682354436bc766ba371 100644
--- a/lib/std/zig/AstGen.zig
+++ b/lib/std/zig/AstGen.zig
@@ -1369,16 +1369,16 @@ fn fnProtoExpr(
break :is_var_args false;
};
- const align_ref: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
- break :inst try expr(&block_scope, scope, coerced_align_ri, fn_proto.ast.align_expr);
- };
+ if (fn_proto.ast.align_expr != 0) {
+ return astgen.failNode(fn_proto.ast.align_expr, "function type cannot have an alignment", .{});
+ }
if (fn_proto.ast.addrspace_expr != 0) {
- return astgen.failNode(fn_proto.ast.addrspace_expr, "addrspace not allowed on function prototypes", .{});
+ return astgen.failNode(fn_proto.ast.addrspace_expr, "function type cannot have an addrspace", .{});
}
if (fn_proto.ast.section_expr != 0) {
- return astgen.failNode(fn_proto.ast.section_expr, "linksection not allowed on function prototypes", .{});
+ return astgen.failNode(fn_proto.ast.section_expr, "function type cannot have a linksection", .{});
}
const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
@@ -1394,7 +1394,7 @@ fn fnProtoExpr(
const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
const is_inferred_error = token_tags[maybe_bang] == .bang;
if (is_inferred_error) {
- return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
+ return astgen.failTok(maybe_bang, "function type cannot have an inferred error set", .{});
}
const ret_ty = try expr(&block_scope, scope, coerced_type_ri, fn_proto.ast.return_type);
@@ -1403,7 +1403,7 @@ fn fnProtoExpr(
.cc_ref = cc,
.cc_gz = null,
- .align_ref = align_ref,
+ .align_ref = .none,
.align_gz = null,
.ret_ref = ret_ty,
.ret_gz = null,
diff --git a/src/InternPool.zig b/src/InternPool.zig
index 832927071e24bd66bdb609752ff7e82efff20adf..8611a6756476cd92a728254c3319b2c07706e3c7 100644
--- a/src/InternPool.zig
+++ b/src/InternPool.zig
@@ -765,16 +765,10 @@ pub const Key = union(enum) {
/// Tells whether a parameter is noalias. See `paramIsNoalias` helper
/// method for accessing this.
noalias_bits: u32,
- /// `none` indicates the function has the default alignment for
- /// function code on the target. In this case, this field *must* be set
- /// to `none`, otherwise the `InternPool` equality and hashing
- /// functions will return incorrect results.
- alignment: Alignment,
cc: std.builtin.CallingConvention,
is_var_args: bool,
is_generic: bool,
is_noinline: bool,
- align_is_generic: bool,
cc_is_generic: bool,
section_is_generic: bool,
addrspace_is_generic: bool,
@@ -794,7 +788,6 @@ pub const Key = union(enum) {
a.return_type == b.return_type and
a.comptime_bits == b.comptime_bits and
a.noalias_bits == b.noalias_bits and
- a.alignment == b.alignment and
a.cc == b.cc and
a.is_var_args == b.is_var_args and
a.is_generic == b.is_generic and
@@ -808,7 +801,6 @@ pub const Key = union(enum) {
std.hash.autoHash(hasher, self.return_type);
std.hash.autoHash(hasher, self.comptime_bits);
std.hash.autoHash(hasher, self.noalias_bits);
- std.hash.autoHash(hasher, self.alignment);
std.hash.autoHash(hasher, self.cc);
std.hash.autoHash(hasher, self.is_var_args);
std.hash.autoHash(hasher, self.is_generic);
@@ -3587,18 +3579,16 @@ pub const Tag = enum(u8) {
flags: Flags,
pub const Flags = packed struct(u32) {
- alignment: Alignment,
cc: std.builtin.CallingConvention,
is_var_args: bool,
is_generic: bool,
has_comptime_bits: bool,
has_noalias_bits: bool,
is_noinline: bool,
- align_is_generic: bool,
cc_is_generic: bool,
section_is_generic: bool,
addrspace_is_generic: bool,
- _: u9 = 0,
+ _: u16 = 0,
};
};
@@ -4918,11 +4908,9 @@ fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType {
.return_type = type_function.data.return_type,
.comptime_bits = comptime_bits,
.noalias_bits = noalias_bits,
- .alignment = type_function.data.flags.alignment,
.cc = type_function.data.flags.cc,
.is_var_args = type_function.data.flags.is_var_args,
.is_noinline = type_function.data.flags.is_noinline,
- .align_is_generic = type_function.data.flags.align_is_generic,
.cc_is_generic = type_function.data.flags.cc_is_generic,
.section_is_generic = type_function.data.flags.section_is_generic,
.addrspace_is_generic = type_function.data.flags.addrspace_is_generic,
@@ -6211,8 +6199,6 @@ pub const GetFuncTypeKey = struct {
comptime_bits: u32 = 0,
noalias_bits: u32 = 0,
/// `null` means generic.
- alignment: ?Alignment = .none,
- /// `null` means generic.
cc: ?std.builtin.CallingConvention = .Unspecified,
is_var_args: bool = false,
is_generic: bool = false,
@@ -6242,14 +6228,12 @@ pub fn getFuncType(ip: *InternPool, gpa: Allocator, key: GetFuncTypeKey) Allocat
.params_len = params_len,
.return_type = key.return_type,
.flags = .{
- .alignment = key.alignment orelse .none,
.cc = key.cc orelse .Unspecified,
.is_var_args = key.is_var_args,
.has_comptime_bits = key.comptime_bits != 0,
.has_noalias_bits = key.noalias_bits != 0,
.is_generic = key.is_generic,
.is_noinline = key.is_noinline,
- .align_is_generic = key.alignment == null,
.cc_is_generic = key.cc == null,
.section_is_generic = key.section_is_generic,
.addrspace_is_generic = key.addrspace_is_generic,
@@ -6433,14 +6417,12 @@ pub fn getFuncDeclIes(ip: *InternPool, gpa: Allocator, key: GetFuncDeclIesKey) A
.params_len = params_len,
.return_type = @enumFromInt(ip.items.len - 2),
.flags = .{
- .alignment = key.alignment orelse .none,
.cc = key.cc orelse .Unspecified,
.is_var_args = key.is_var_args,
.has_comptime_bits = key.comptime_bits != 0,
.has_noalias_bits = key.noalias_bits != 0,
.is_generic = key.is_generic,
.is_noinline = key.is_noinline,
- .align_is_generic = key.alignment == null,
.cc_is_generic = key.cc == null,
.section_is_generic = key.section_is_generic,
.addrspace_is_generic = key.addrspace_is_generic,
@@ -6553,7 +6535,6 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)
.param_types = arg.param_types,
.return_type = arg.bare_return_type,
.noalias_bits = arg.noalias_bits,
- .alignment = arg.alignment,
.cc = arg.cc,
.is_noinline = arg.is_noinline,
});
@@ -6610,6 +6591,7 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)
func_index,
func_extra_index,
func_ty,
+ arg.alignment,
arg.section,
);
}
@@ -6673,14 +6655,12 @@ pub fn getFuncInstanceIes(
.params_len = params_len,
.return_type = error_union_type,
.flags = .{
- .alignment = arg.alignment,
.cc = arg.cc,
.is_var_args = false,
.has_comptime_bits = false,
.has_noalias_bits = arg.noalias_bits != 0,
.is_generic = false,
.is_noinline = arg.is_noinline,
- .align_is_generic = false,
.cc_is_generic = false,
.section_is_generic = false,
.addrspace_is_generic = false,
@@ -6741,6 +6721,7 @@ pub fn getFuncInstanceIes(
func_index,
func_extra_index,
func_ty,
+ arg.alignment,
arg.section,
);
}
@@ -6752,6 +6733,7 @@ fn finishFuncInstance(
func_index: Index,
func_extra_index: u32,
func_ty: Index,
+ alignment: Alignment,
section: OptionalNullTerminatedString,
) Allocator.Error!Index {
const fn_owner_decl = ip.declPtr(ip.funcDeclOwner(generic_owner));
@@ -6764,7 +6746,7 @@ fn finishFuncInstance(
.owns_tv = true,
.ty = @import("type.zig").Type.fromInterned(func_ty),
.val = @import("Value.zig").fromInterned(func_index),
- .alignment = .none,
+ .alignment = alignment,
.@"linksection" = section,
.@"addrspace" = fn_owner_decl.@"addrspace",
.analysis = .complete,
diff --git a/src/Module.zig b/src/Module.zig
index 8f6def21ae6d04d05c6152c6450cfbc1ad0b0c6f..bfc5a35e101ae6f3a0c099369e32f235fc42b81d 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -3596,6 +3596,18 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
log.debug("semaDecl '{d}'", .{@intFromEnum(decl_index)});
+ const old_has_tv = decl.has_tv;
+ // The following values are ignored if `!old_has_tv`
+ const old_ty = decl.ty;
+ const old_val = decl.val;
+ const old_align = decl.alignment;
+ const old_linksection = decl.@"linksection";
+ const old_addrspace = decl.@"addrspace";
+ const old_is_inline = if (decl.getOwnedFunction(mod)) |prev_func|
+ prev_func.analysis(ip).state == .inline_only
+ else
+ false;
+
const decl_inst = decl.zir_decl_index.unwrap().?.resolve(ip);
const gpa = mod.gpa;
@@ -3733,141 +3745,96 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
};
}
- switch (ip.indexToKey(decl_tv.val.toIntern())) {
- .func => |func| {
- const owns_tv = func.owner_decl == decl_index;
- if (owns_tv) {
- var prev_type_has_bits = false;
- var prev_is_inline = false;
- var type_changed = true;
-
- if (decl.has_tv) {
- prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits(mod);
- type_changed = !decl.ty.eql(decl_tv.ty, mod);
- if (decl.getOwnedFunction(mod)) |prev_func| {
- prev_is_inline = prev_func.analysis(ip).state == .inline_only;
- }
- }
-
- decl.ty = decl_tv.ty;
- decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod)));
- // linksection, align, and addrspace were already set by Sema
- decl.has_tv = true;
- decl.owns_tv = owns_tv;
- decl.analysis = .complete;
-
- const is_inline = decl.ty.fnCallingConvention(mod) == .Inline;
- if (decl.is_exported) {
- const export_src: LazySrcLoc = .{ .token_offset = @intFromBool(decl.is_pub) };
- if (is_inline) {
- return sema.fail(&block_scope, export_src, "export of inline function", .{});
- }
- // The scope needs to have the decl in it.
- try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);
- }
- // TODO: align, linksection, addrspace?
- const changed = type_changed or is_inline != prev_is_inline;
- return .{
- .invalidate_decl_val = changed,
- .invalidate_decl_ref = changed,
- };
- }
- },
- else => {},
- }
-
- decl.owns_tv = false;
- var queue_linker_work = false;
- var is_extern = false;
+ var queue_linker_work = true;
+ var is_func = false;
+ var is_inline = false;
switch (decl_tv.val.toIntern()) {
.generic_poison => unreachable,
.unreachable_value => unreachable,
else => switch (ip.indexToKey(decl_tv.val.toIntern())) {
- .variable => |variable| if (variable.decl == decl_index) {
- decl.owns_tv = true;
- queue_linker_work = true;
+ .variable => |variable| {
+ decl.owns_tv = variable.decl == decl_index;
+ queue_linker_work = decl.owns_tv;
},
- .extern_func => |extern_fn| if (extern_fn.decl == decl_index) {
- decl.owns_tv = true;
- queue_linker_work = true;
- is_extern = true;
+ .extern_func => |extern_func| {
+ decl.owns_tv = extern_func.decl == decl_index;
+ queue_linker_work = decl.owns_tv;
+ is_func = decl.owns_tv;
},
- .func => {},
-
- else => {
- queue_linker_work = true;
+ .func => |func| {
+ decl.owns_tv = func.owner_decl == decl_index;
+ queue_linker_work = false;
+ is_inline = decl.owns_tv and decl_tv.ty.fnCallingConvention(mod) == .Inline;
+ is_func = decl.owns_tv;
},
+
+ else => {},
},
}
- const old_has_tv = decl.has_tv;
- // The following values are ignored if `!old_has_tv`
- const old_ty = decl.ty;
- const old_val = decl.val;
- const old_align = decl.alignment;
- const old_linksection = decl.@"linksection";
- const old_addrspace = decl.@"addrspace";
-
decl.ty = decl_tv.ty;
decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod)));
- decl.alignment = blk: {
- const align_body = decl_bodies.align_body orelse break :blk .none;
- const align_ref = try sema.resolveInlineBody(&block_scope, align_body, decl_inst);
- break :blk try sema.analyzeAsAlign(&block_scope, align_src, align_ref);
- };
- decl.@"linksection" = blk: {
- const linksection_body = decl_bodies.linksection_body orelse break :blk .none;
- const linksection_ref = try sema.resolveInlineBody(&block_scope, linksection_body, decl_inst);
- const bytes = try sema.toConstString(&block_scope, section_src, linksection_ref, .{
- .needed_comptime_reason = "linksection must be comptime-known",
- });
- if (mem.indexOfScalar(u8, bytes, 0) != null) {
- return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{});
- } else if (bytes.len == 0) {
- return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{});
- }
- const section = try ip.getOrPutString(gpa, bytes);
- break :blk section.toOptional();
- };
- decl.@"addrspace" = blk: {
- const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(decl_tv.val.toIntern())) {
- .variable => .variable,
- .extern_func, .func => .function,
- else => .constant,
+ // Function linksection, align, and addrspace were already set by Sema
+ if (!is_func) {
+ decl.alignment = blk: {
+ const align_body = decl_bodies.align_body orelse break :blk .none;
+ const align_ref = try sema.resolveInlineBody(&block_scope, align_body, decl_inst);
+ break :blk try sema.analyzeAsAlign(&block_scope, align_src, align_ref);
};
+ decl.@"linksection" = blk: {
+ const linksection_body = decl_bodies.linksection_body orelse break :blk .none;
+ const linksection_ref = try sema.resolveInlineBody(&block_scope, linksection_body, decl_inst);
+ const bytes = try sema.toConstString(&block_scope, section_src, linksection_ref, .{
+ .needed_comptime_reason = "linksection must be comptime-known",
+ });
+ if (mem.indexOfScalar(u8, bytes, 0) != null) {
+ return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{});
+ } else if (bytes.len == 0) {
+ return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{});
+ }
+ const section = try ip.getOrPutString(gpa, bytes);
+ break :blk section.toOptional();
+ };
+ decl.@"addrspace" = blk: {
+ const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(decl_tv.val.toIntern())) {
+ .variable => .variable,
+ .extern_func, .func => .function,
+ else => .constant,
+ };
- const target = sema.mod.getTarget();
+ const target = sema.mod.getTarget();
- const addrspace_body = decl_bodies.addrspace_body orelse break :blk switch (addrspace_ctx) {
- .function => target_util.defaultAddressSpace(target, .function),
- .variable => target_util.defaultAddressSpace(target, .global_mutable),
- .constant => target_util.defaultAddressSpace(target, .global_constant),
- else => unreachable,
+ const addrspace_body = decl_bodies.addrspace_body orelse break :blk switch (addrspace_ctx) {
+ .function => target_util.defaultAddressSpace(target, .function),
+ .variable => target_util.defaultAddressSpace(target, .global_mutable),
+ .constant => target_util.defaultAddressSpace(target, .global_constant),
+ else => unreachable,
+ };
+ const addrspace_ref = try sema.resolveInlineBody(&block_scope, addrspace_body, decl_inst);
+ break :blk try sema.analyzeAsAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx);
};
- const addrspace_ref = try sema.resolveInlineBody(&block_scope, addrspace_body, decl_inst);
- break :blk try sema.analyzeAsAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx);
- };
+ }
decl.has_tv = true;
decl.analysis = .complete;
const result: SemaDeclResult = if (old_has_tv) .{
- .invalidate_decl_val = !decl.ty.eql(old_ty, mod) or !decl.val.eql(old_val, decl.ty, mod),
+ .invalidate_decl_val = !decl.ty.eql(old_ty, mod) or
+ !decl.val.eql(old_val, decl.ty, mod) or
+ is_inline != old_is_inline,
.invalidate_decl_ref = !decl.ty.eql(old_ty, mod) or
decl.alignment != old_align or
decl.@"linksection" != old_linksection or
- decl.@"addrspace" != old_addrspace,
+ decl.@"addrspace" != old_addrspace or
+ is_inline != old_is_inline,
} else .{
.invalidate_decl_val = true,
.invalidate_decl_ref = true,
};
- const has_runtime_bits = is_extern or
- (queue_linker_work and try sema.typeHasRuntimeBits(decl.ty));
-
+ const has_runtime_bits = queue_linker_work and (is_func or try sema.typeHasRuntimeBits(decl.ty));
if (has_runtime_bits) {
-
// Needed for codegen_decl which will call updateDecl and then the
// codegen backend wants full access to the Decl Type.
try sema.resolveTypeFully(decl.ty);
@@ -3881,6 +3848,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
if (decl.is_exported) {
const export_src: LazySrcLoc = .{ .token_offset = @intFromBool(decl.is_pub) };
+ if (is_inline) return sema.fail(&block_scope, export_src, "export of inline function", .{});
// The scope needs to have the decl in it.
try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);
}
diff --git a/src/Sema.zig b/src/Sema.zig
index 54d5e6df7dae06ab5b8a75b3059caa4ad7350aab..cf103e7230915b248b42e519c230f275b31c62a8 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -7605,7 +7605,6 @@ fn analyzeCall(
.param_types = new_param_types,
.return_type = owner_info.return_type,
.noalias_bits = owner_info.noalias_bits,
- .alignment = if (owner_info.align_is_generic) null else owner_info.alignment,
.cc = if (owner_info.cc_is_generic) null else owner_info.cc,
.is_var_args = owner_info.is_var_args,
.is_noinline = owner_info.is_noinline,
@@ -9629,7 +9628,6 @@ fn funcCommon(
.comptime_bits = comptime_bits,
.return_type = bare_return_type.toIntern(),
.cc = cc,
- .alignment = alignment,
.section_is_generic = section == .generic,
.addrspace_is_generic = address_space == null,
.is_var_args = var_args,
@@ -9640,6 +9638,7 @@ fn funcCommon(
if (is_extern) {
assert(comptime_bits == 0);
assert(cc != null);
+ assert(alignment != null);
assert(section != .generic);
assert(address_space != null);
assert(!is_generic);
@@ -17623,8 +17622,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const field_values = .{
// calling_convention: CallingConvention,
(try mod.enumValueFieldIndex(callconv_ty, @intFromEnum(func_ty_info.cc))).toIntern(),
- // alignment: comptime_int,
- (try mod.intValue(Type.comptime_int, ty.abiAlignment(mod).toByteUnits(0))).toIntern(),
// is_generic: bool,
Value.makeBool(func_ty_info.is_generic).toIntern(),
// is_var_args: bool,
@@ -19701,12 +19698,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
if (inst_data.size != .One) {
return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{});
}
- const fn_align = mod.typeToFunc(elem_ty).?.alignment;
- if (inst_data.flags.has_align and abi_align != .none and fn_align != .none and
- abi_align != fn_align)
- {
- return sema.fail(block, align_src, "function pointer alignment disagrees with function alignment", .{});
- }
} else if (inst_data.size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) {
return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{});
} else if (inst_data.size == .C) {
@@ -21030,7 +21021,6 @@ fn zirReify(
.needed_comptime_reason = "operand to @Type must be comptime-known",
});
const union_val = ip.indexToKey(val.toIntern()).un;
- const target = mod.getTarget();
if (try Value.fromInterned(union_val.val).anyUndef(mod)) return sema.failWithUseOfUndef(block, src);
const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?;
switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) {
@@ -21171,12 +21161,6 @@ fn zirReify(
if (ptr_size != .One) {
return sema.fail(block, src, "function pointers must be single pointers", .{});
}
- const fn_align = mod.typeToFunc(elem_ty).?.alignment;
- if (abi_align != .none and fn_align != .none and
- abi_align != fn_align)
- {
- return sema.fail(block, src, "function pointer alignment disagrees with function alignment", .{});
- }
} else if (ptr_size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) {
return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{});
} else if (ptr_size == .C) {
@@ -21429,10 +21413,6 @@ fn zirReify(
ip,
try ip.getOrPutString(gpa, "calling_convention"),
).?);
- const alignment_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, "alignment"),
- ).?);
const is_generic_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
try ip.getOrPutString(gpa, "is_generic"),
@@ -21461,11 +21441,6 @@ fn zirReify(
try sema.checkCallConvSupportsVarArgs(block, src, cc);
}
- const alignment = alignment: {
- const alignment = try sema.validateAlignAllowZero(block, src, try alignment_val.toUnsignedIntAdvanced(sema));
- const default = target_util.defaultFunctionAlignment(target);
- break :alignment if (alignment == default) .none else alignment;
- };
const return_type = return_type_val.optionalValue(mod) orelse
return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});
@@ -21510,7 +21485,6 @@ fn zirReify(
.param_types = param_types,
.noalias_bits = noalias_bits,
.return_type = return_type.toIntern(),
- .alignment = alignment,
.cc = cc,
.is_var_args = is_var_args,
});
@@ -32536,16 +32510,21 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn
const mod = sema.mod;
try sema.ensureDeclAnalyzed(decl_index);
- const decl = mod.declPtr(decl_index);
- const decl_tv = try decl.typedValue();
+ const decl_tv = try mod.declPtr(decl_index).typedValue();
+ const owner_decl = mod.declPtr(switch (mod.intern_pool.indexToKey(decl_tv.val.toIntern())) {
+ .variable => |variable| variable.decl,
+ .extern_func => |extern_func| extern_func.decl,
+ .func => |func| func.owner_decl,
+ else => decl_index,
+ });
// TODO: if this is a `decl_ref` of a non-variable decl, only depend on decl type
try sema.declareDependency(.{ .decl_val = decl_index });
const ptr_ty = try sema.ptrType(.{
.child = decl_tv.ty.toIntern(),
.flags = .{
- .alignment = decl.alignment,
- .is_const = if (decl.val.getVariable(mod)) |variable| variable.is_const else true,
- .address_space = decl.@"addrspace",
+ .alignment = owner_decl.alignment,
+ .is_const = if (decl_tv.val.getVariable(mod)) |variable| variable.is_const else true,
+ .address_space = owner_decl.@"addrspace",
},
});
if (analyze_fn_body) {
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 8d630480e2e65080abacb9029610fd632d91d6cc..928cc995dc67595e951bd34d9c5bf04f4ae48cb1 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -1635,7 +1635,7 @@ pub const DeclGen = struct {
switch (kind) {
.forward => {},
- .complete => if (fn_info.alignment.toByteUnitsOptional()) |a| {
+ .complete => if (fn_decl.alignment.toByteUnitsOptional()) |a| {
try w.print("{}zig_align_fn({})", .{ trailing, a });
trailing = .maybe_space;
},
@@ -1666,7 +1666,7 @@ pub const DeclGen = struct {
switch (kind) {
.forward => {
- if (fn_info.alignment.toByteUnitsOptional()) |a| {
+ if (fn_decl.alignment.toByteUnitsOptional()) |a| {
try w.print(" zig_align_fn({})", .{a});
}
switch (name) {
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 6273ce0942e9a30549343f736cec150308776770..d159a531751859a28e64d0d420ff46d77d87814a 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -2952,8 +2952,8 @@ pub const Object = struct {
else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder),
}
- if (fn_info.alignment != .none)
- function_index.setAlignment(fn_info.alignment.toLlvm(), &o.builder);
+ if (decl.alignment != .none)
+ function_index.setAlignment(decl.alignment.toLlvm(), &o.builder);
// Function attributes that are independent of analysis results of the function body.
try o.addCommonFnAttributes(&attributes, owner_mod);
diff --git a/src/main.zig b/src/main.zig
index 8c445fdd1e2dd9c36212a6c16ee07d2c6e8a0f0e..db76f7605ca6ecdf4336444241579b8d3f346dca 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -4995,6 +4995,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
} else .{
.root = .{
.root_dir = zig_lib_directory,
+ .sub_path = "compiler",
},
.root_src_path = "build_runner.zig",
};
diff --git a/src/type.zig b/src/type.zig
index 664498e353d6e6902bc0d65437b5f15a65bc872d..9ea16d6224f6196a48315544fd3b80fe023b22c8 100644
--- a/src/type.zig
+++ b/src/type.zig
@@ -396,9 +396,6 @@ pub const Type = struct {
try writer.writeAll("...");
}
try writer.writeAll(") ");
- if (fn_info.alignment.toByteUnitsOptional()) |a| {
- try writer.print("align({d}) ", .{a});
- }
if (fn_info.cc != .Unspecified) {
try writer.writeAll("callconv(.");
try writer.writeAll(@tagName(fn_info.cc));
@@ -949,12 +946,7 @@ pub const Type = struct {
},
// represents machine code; not a pointer
- .func_type => |func_type| return .{
- .scalar = if (func_type.alignment != .none)
- func_type.alignment
- else
- target_util.defaultFunctionAlignment(target),
- },
+ .func_type => return .{ .scalar = target_util.defaultFunctionAlignment(target) },
.simple_type => |t| switch (t) {
.bool,
diff --git a/stage1/zig.h b/stage1/zig.h
index acd7b1d700ff0811b35f7dfe2755c454576f5613..7a1c69575a24928b97cb232abb04ee9cf5f26957 100644
--- a/stage1/zig.h
+++ b/stage1/zig.h
@@ -25,11 +25,15 @@ typedef char bool;
#endif
#endif
+#define zig_concat(lhs, rhs) lhs##rhs
+#define zig_expand_concat(lhs, rhs) zig_concat(lhs, rhs)
+
#if defined(__has_builtin)
#define zig_has_builtin(builtin) __has_builtin(__builtin_##builtin)
#else
#define zig_has_builtin(builtin) 0
#endif
+#define zig_expand_has_builtin(b) zig_has_builtin(b)
#if defined(__has_attribute)
#define zig_has_attribute(attribute) __has_attribute(attribute)
@@ -112,7 +116,7 @@ typedef char bool;
#define zig_never_tail zig_never_tail_unavailable
#endif
-#if zig_has_attribute(always_inline)
+#if zig_has_attribute(musttail)
#define zig_always_tail __attribute__((musttail))
#else
#define zig_always_tail zig_always_tail_unavailable
@@ -180,20 +184,58 @@ typedef char bool;
#define zig_extern extern
#endif
-#if zig_has_attribute(alias)
-#define zig_export(sig, symbol, name) zig_extern sig __attribute__((alias(symbol)))
-#elif _MSC_VER
+#if _MSC_VER
#if _M_X64
-#define zig_export(sig, symbol, name) sig;\
- __pragma(comment(linker, "/alternatename:" name "=" symbol ))
+#define zig_mangle_c(symbol) symbol
#else /*_M_X64 */
-#define zig_export(sig, symbol, name) sig;\
- __pragma(comment(linker, "/alternatename:_" name "=_" symbol ))
+#define zig_mangle_c(symbol) "_" symbol
#endif /*_M_X64 */
+#else /* _MSC_VER */
+#if __APPLE__
+#define zig_mangle_c(symbol) "_" symbol
+#else /* __APPLE__ */
+#define zig_mangle_c(symbol) symbol
+#endif /* __APPLE__ */
+#endif /* _MSC_VER */
+
+#if zig_has_attribute(alias) && !__APPLE__
+#define zig_export(symbol, name) __attribute__((alias(symbol)))
+#elif _MSC_VER
+#define zig_export(symbol, name) ; \
+ __pragma(comment(linker, "/alternatename:" zig_mangle_c(name) "=" zig_mangle_c(symbol)))
#else
-#define zig_export(sig, symbol, name) __asm(name " = " symbol)
+#define zig_export(symbol, name) ; \
+ __asm(zig_mangle_c(name) " = " zig_mangle_c(symbol))
#endif
+#if _MSC_VER
+#define zig_mangled_tentative(mangled, unmangled)
+#define zig_mangled_final(mangled, unmangled) ; \
+ zig_export(#mangled, unmangled)
+#define zig_mangled_export(mangled, unmangled, symbol) \
+ zig_export(unmangled, #mangled) \
+ zig_export(symbol, unmangled)
+#else /* _MSC_VER */
+#define zig_mangled_tentative(mangled, unmangled) __asm(zig_mangle_c(unmangled))
+#define zig_mangled_final(mangled, unmangled) zig_mangled_tentative(mangled, unmangled)
+#define zig_mangled_export(mangled, unmangled, symbol) \
+ zig_mangled_final(mangled, unmangled) \
+ zig_export(symbol, unmangled)
+#endif /* _MSC_VER */
+
+#if _MSC_VER
+#define zig_import(Type, fn_name, libc_name, sig_args, call_args) zig_extern Type fn_name sig_args;\
+ __pragma(comment(linker, "/alternatename:" zig_mangle_c(#fn_name) "=" zig_mangle_c(#libc_name)));
+#define zig_import_builtin(Type, fn_name, libc_name, sig_args, call_args) zig_import(Type, fn_name, sig_args, call_args)
+#else /* _MSC_VER */
+#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));
+#define zig_import_builtin(Type, fn_name, libc_name, sig_args, call_args) zig_extern Type libc_name sig_args; \
+ static inline Type fn_name sig_args { return libc_name call_args; }
+#endif
+
+#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)
+#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)
+
#if zig_has_attribute(weak) || defined(zig_gnuc)
#define zig_weak_linkage __attribute__((weak))
#define zig_weak_linkage_fn __attribute__((weak))
@@ -267,9 +309,6 @@ typedef char bool;
#define zig_wasm_memory_grow(index, delta) zig_unimplemented()
#endif
-#define zig_concat(lhs, rhs) lhs##rhs
-#define zig_expand_concat(lhs, rhs) zig_concat(lhs, rhs)
-
#if __STDC_VERSION__ >= 201112L
#define zig_noreturn _Noreturn
#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
const uint8_t *rhs_bytes = rhs;
uint16_t byte_offset = 0;
uint16_t remaining_bytes = zig_int_bytes(bits);
- uint16_t top_bits = remaining_bytes * 8 - bits;
+ uint8_t top_bits = (uint8_t)(remaining_bytes * 8 - bits);
bool overflow = false;
#if zig_big_endian
@@ -2171,7 +2210,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo
#endif
while (remaining_bytes >= 128 / CHAR_BIT) {
- uint16_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0);
+ uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0);
#if zig_big_endian
byte_offset -= 128 / CHAR_BIT;
@@ -2211,7 +2250,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo
}
while (remaining_bytes >= 64 / CHAR_BIT) {
- uint16_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0);
+ uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0);
#if zig_big_endian
byte_offset -= 64 / CHAR_BIT;
@@ -2251,7 +2290,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo
}
while (remaining_bytes >= 32 / CHAR_BIT) {
- uint16_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0);
+ uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0);
#if zig_big_endian
byte_offset -= 32 / CHAR_BIT;
@@ -2291,7 +2330,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo
}
while (remaining_bytes >= 16 / CHAR_BIT) {
- uint16_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0);
+ uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0);
#if zig_big_endian
byte_offset -= 16 / CHAR_BIT;
@@ -2331,7 +2370,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo
}
while (remaining_bytes >= 8 / CHAR_BIT) {
- uint16_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0);
+ uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0);
#if zig_big_endian
byte_offset -= 8 / CHAR_BIT;
@@ -2379,7 +2418,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo
const uint8_t *rhs_bytes = rhs;
uint16_t byte_offset = 0;
uint16_t remaining_bytes = zig_int_bytes(bits);
- uint16_t top_bits = remaining_bytes * 8 - bits;
+ uint8_t top_bits = (uint8_t)(remaining_bytes * 8 - bits);
bool overflow = false;
#if zig_big_endian
@@ -2387,7 +2426,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo
#endif
while (remaining_bytes >= 128 / CHAR_BIT) {
- uint16_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0);
+ uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0);
#if zig_big_endian
byte_offset -= 128 / CHAR_BIT;
@@ -2427,7 +2466,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo
}
while (remaining_bytes >= 64 / CHAR_BIT) {
- uint16_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0);
+ uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0);
#if zig_big_endian
byte_offset -= 64 / CHAR_BIT;
@@ -2467,7 +2506,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo
}
while (remaining_bytes >= 32 / CHAR_BIT) {
- uint16_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0);
+ uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0);
#if zig_big_endian
byte_offset -= 32 / CHAR_BIT;
@@ -2507,7 +2546,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo
}
while (remaining_bytes >= 16 / CHAR_BIT) {
- uint16_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0);
+ uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0);
#if zig_big_endian
byte_offset -= 16 / CHAR_BIT;
@@ -2547,7 +2586,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo
}
while (remaining_bytes >= 8 / CHAR_BIT) {
- uint16_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0);
+ uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0);
#if zig_big_endian
byte_offset -= 8 / CHAR_BIT;
@@ -3093,6 +3132,7 @@ ypedef uint32_t zig_f32;
#define zig_has_f64 1
#define zig_libc_name_f64(name) name
+
#if _MSC_VER
#define zig_init_special_f64(sign, name, arg, repr) sign zig_make_f64(zig_msvc_flt_##name, )
#else
@@ -3336,31 +3376,31 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0)))
zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, sub, -) \
zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, mul, *) \
zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, div, /) \
- zig_extern zig_f##w zig_libc_name_f##w(sqrt)(zig_f##w); \
- zig_extern zig_f##w zig_libc_name_f##w(sin)(zig_f##w); \
- zig_extern zig_f##w zig_libc_name_f##w(cos)(zig_f##w); \
- zig_extern zig_f##w zig_libc_name_f##w(tan)(zig_f##w); \
- zig_extern zig_f##w zig_libc_name_f##w(exp)(zig_f##w); \
- zig_extern zig_f##w zig_libc_name_f##w(exp2)(zig_f##w); \
- zig_extern zig_f##w zig_libc_name_f##w(log)(zig_f##w); \
- zig_extern zig_f##w zig_libc_name_f##w(log2)(zig_f##w); \
- zig_extern zig_f##w zig_libc_name_f##w(log10)(zig_f##w); \
- zig_extern zig_f##w zig_libc_name_f##w(fabs)(zig_f##w); \
- zig_extern zig_f##w zig_libc_name_f##w(floor)(zig_f##w); \
- zig_extern zig_f##w zig_libc_name_f##w(ceil)(zig_f##w); \
- zig_extern zig_f##w zig_libc_name_f##w(round)(zig_f##w); \
- zig_extern zig_f##w zig_libc_name_f##w(trunc)(zig_f##w); \
- zig_extern zig_f##w zig_libc_name_f##w(fmod)(zig_f##w, zig_f##w); \
- zig_extern zig_f##w zig_libc_name_f##w(fmin)(zig_f##w, zig_f##w); \
- zig_extern zig_f##w zig_libc_name_f##w(fmax)(zig_f##w, zig_f##w); \
- zig_extern zig_f##w zig_libc_name_f##w(fma)(zig_f##w, zig_f##w, zig_f##w); \
+ 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)) \
+ 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)) \
+ 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)) \
+ 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)) \
+ 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)) \
+ 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)) \
+ 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)) \
+ 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)) \
+ 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)) \
+ 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)) \
+ 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)) \
+ 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)) \
+ 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)) \
+ 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)) \
+ 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)) \
+ 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)) \
+ 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)) \
+ 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)) \
\
static inline zig_f##w zig_div_trunc_f##w(zig_f##w lhs, zig_f##w rhs) { \
- return zig_libc_name_f##w(trunc)(zig_div_f##w(lhs, rhs)); \
+ return zig_float_fn_f##w##_trunc(zig_div_f##w(lhs, rhs)); \
} \
\
static inline zig_f##w zig_div_floor_f##w(zig_f##w lhs, zig_f##w rhs) { \
- return zig_libc_name_f##w(floor)(zig_div_f##w(lhs, rhs)); \
+ return zig_float_fn_f##w##_floor(zig_div_f##w(lhs, rhs)); \
} \
\
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)
/* Note that zig_atomicrmw_expected is needed to handle aliasing between res and arg. */
#define zig_atomicrmw_xchg_float(res, obj, arg, order, Type, ReprType) do { \
zig_##Type zig_atomicrmw_expected; \
- zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
- while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, memory_order_relaxed, Type, ReprType)); \
+ zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
+ while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, zig_memory_order_relaxed, Type, ReprType)); \
res = zig_atomicrmw_expected; \
} while (0)
#define zig_atomicrmw_add_float(res, obj, arg, order, Type, ReprType) do { \
zig_##Type zig_atomicrmw_expected; \
zig_##Type zig_atomicrmw_desired; \
- zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
do { \
zig_atomicrmw_desired = zig_add_##Type(zig_atomicrmw_expected, arg); \
- } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
res = zig_atomicrmw_expected; \
} while (0)
#define zig_atomicrmw_sub_float(res, obj, arg, order, Type, ReprType) do { \
zig_##Type zig_atomicrmw_expected; \
zig_##Type zig_atomicrmw_desired; \
- zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
do { \
zig_atomicrmw_desired = zig_sub_##Type(zig_atomicrmw_expected, arg); \
- } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
res = zig_atomicrmw_expected; \
} while (0)
#define zig_atomicrmw_min_float(res, obj, arg, order, Type, ReprType) do { \
zig_##Type zig_atomicrmw_expected; \
zig_##Type zig_atomicrmw_desired; \
- zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
do { \
- zig_atomicrmw_desired = zig_libc_name_##Type(fmin)(zig_atomicrmw_expected, arg); \
- } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ zig_atomicrmw_desired = zig_float_fn_##Type##_fmin(zig_atomicrmw_expected, arg); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
res = zig_atomicrmw_expected; \
} while (0)
#define zig_atomicrmw_max_float(res, obj, arg, order, Type, ReprType) do { \
zig_##Type zig_atomicrmw_expected; \
zig_##Type zig_atomicrmw_desired; \
- zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
do { \
- zig_atomicrmw_desired = zig_libc_name_##Type(fmax)(zig_atomicrmw_expected, arg); \
- } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ zig_atomicrmw_desired = zig_float_fn_##Type##_fmax(zig_atomicrmw_expected, arg); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
res = zig_atomicrmw_expected; \
} while (0)
#define zig_atomicrmw_xchg_int128(res, obj, arg, order, Type, ReprType) do { \
zig_##Type zig_atomicrmw_expected; \
- zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
- while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, memory_order_relaxed, Type, ReprType)); \
+ zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
+ while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, zig_memory_order_relaxed, Type, ReprType)); \
res = zig_atomicrmw_expected; \
} while (0)
#define zig_atomicrmw_add_int128(res, obj, arg, order, Type, ReprType) do { \
zig_##Type zig_atomicrmw_expected; \
zig_##Type zig_atomicrmw_desired; \
- zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
do { \
zig_atomicrmw_desired = zig_add_##Type(zig_atomicrmw_expected, arg); \
- } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
res = zig_atomicrmw_expected; \
} while (0)
#define zig_atomicrmw_sub_int128(res, obj, arg, order, Type, ReprType) do { \
zig_##Type zig_atomicrmw_expected; \
zig_##Type zig_atomicrmw_desired; \
- zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
do { \
zig_atomicrmw_desired = zig_sub_##Type(zig_atomicrmw_expected, arg); \
- } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
res = zig_atomicrmw_expected; \
} while (0)
#define zig_atomicrmw_and_int128(res, obj, arg, order, Type, ReprType) do { \
zig_##Type zig_atomicrmw_expected; \
zig_##Type zig_atomicrmw_desired; \
- zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
do { \
zig_atomicrmw_desired = zig_and_##Type(zig_atomicrmw_expected, arg); \
- } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
res = zig_atomicrmw_expected; \
} while (0)
#define zig_atomicrmw_nand_int128(res, obj, arg, order, Type, ReprType) do { \
zig_##Type zig_atomicrmw_expected; \
zig_##Type zig_atomicrmw_desired; \
- zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
do { \
zig_atomicrmw_desired = zig_not_##Type(zig_and_##Type(zig_atomicrmw_expected, arg), 128); \
- } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
res = zig_atomicrmw_expected; \
} while (0)
#define zig_atomicrmw_or_int128(res, obj, arg, order, Type, ReprType) do { \
zig_##Type zig_atomicrmw_expected; \
zig_##Type zig_atomicrmw_desired; \
- zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
do { \
zig_atomicrmw_desired = zig_or_##Type(zig_atomicrmw_expected, arg); \
- } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
res = zig_atomicrmw_expected; \
} while (0)
#define zig_atomicrmw_xor_int128(res, obj, arg, order, Type, ReprType) do { \
zig_##Type zig_atomicrmw_expected; \
zig_##Type zig_atomicrmw_desired; \
- zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
do { \
zig_atomicrmw_desired = zig_xor_##Type(zig_atomicrmw_expected, arg); \
- } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
res = zig_atomicrmw_expected; \
} while (0)
#define zig_atomicrmw_min_int128(res, obj, arg, order, Type, ReprType) do { \
zig_##Type zig_atomicrmw_expected; \
zig_##Type zig_atomicrmw_desired; \
- zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
do { \
zig_atomicrmw_desired = zig_min_##Type(zig_atomicrmw_expected, arg); \
- } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
res = zig_atomicrmw_expected; \
} while (0)
#define zig_atomicrmw_max_int128(res, obj, arg, order, Type, ReprType) do { \
zig_##Type zig_atomicrmw_expected; \
zig_##Type zig_atomicrmw_desired; \
- zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \
do { \
zig_atomicrmw_desired = zig_max_##Type(zig_atomicrmw_expected, arg); \
- } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \
res = zig_atomicrmw_expected; \
} while (0)
#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
#include
typedef enum memory_order zig_memory_order;
+#define zig_memory_order_relaxed memory_order_relaxed
+#define zig_memory_order_acquire memory_order_acquire
+#define zig_memory_order_release memory_order_release
+#define zig_memory_order_acq_rel memory_order_acq_rel
+#define zig_memory_order_seq_cst memory_order_seq_cst
#define zig_atomic(Type) _Atomic(Type)
#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail)
#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;
#define zig_fence(order) atomic_thread_fence(order)
#elif defined(__GNUC__)
typedef int zig_memory_order;
-#define memory_order_relaxed __ATOMIC_RELAXED
-#define memory_order_consume __ATOMIC_CONSUME
-#define memory_order_acquire __ATOMIC_ACQUIRE
-#define memory_order_release __ATOMIC_RELEASE
-#define memory_order_acq_rel __ATOMIC_ACQ_REL
-#define memory_order_seq_cst __ATOMIC_SEQ_CST
+#define zig_memory_order_relaxed __ATOMIC_RELAXED
+#define zig_memory_order_acquire __ATOMIC_ACQUIRE
+#define zig_memory_order_release __ATOMIC_RELEASE
+#define zig_memory_order_acq_rel __ATOMIC_ACQ_REL
+#define zig_memory_order_seq_cst __ATOMIC_SEQ_CST
#define zig_atomic(Type) Type
#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, &(expected), &(desired), false, succ, fail)
#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;
#define zig_atomicrmw_xchg_float zig_atomicrmw_xchg
#define zig_fence(order) __atomic_thread_fence(order)
#elif _MSC_VER && (_M_IX86 || _M_X64)
-#define memory_order_relaxed 0
-#define memory_order_consume 1
-#define memory_order_acquire 2
-#define memory_order_release 3
-#define memory_order_acq_rel 4
-#define memory_order_seq_cst 5
+#define zig_memory_order_relaxed 0
+#define zig_memory_order_acquire 2
+#define zig_memory_order_release 3
+#define zig_memory_order_acq_rel 4
+#define zig_memory_order_seq_cst 5
#define zig_atomic(Type) Type
#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_msvc_cmpxchg_##Type(obj, &(expected), desired)
#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;
#endif
/* TODO: _MSC_VER && (_M_ARM || _M_ARM64) */
#else
-#define memory_order_relaxed 0
-#define memory_order_consume 1
-#define memory_order_acquire 2
-#define memory_order_release 3
-#define memory_order_acq_rel 4
-#define memory_order_seq_cst 5
+#define zig_memory_order_relaxed 0
+#define zig_memory_order_acquire 2
+#define zig_memory_order_release 3
+#define zig_memory_order_acq_rel 4
+#define zig_memory_order_seq_cst 5
#define zig_atomic(Type) Type
#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable
#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
return _InterlockedCompareExchange128((__int64 volatile*)obj, (__int64)zig_hi_u128(desired), (__int64)zig_lo_u128(desired), (__int64*)expected);
}
+static inline zig_u128 zig_msvc_atomic_load_u128(zig_u128 volatile* obj) {
+ zig_u128 expected = zig_make_u128(UINT64_C(0), UINT64_C(0));
+ (void)zig_cmpxchg_strong(obj, expected, expected, zig_memory_order_seq_cst, zig_memory_order_seq_cst, u128, zig_u128);
+ return expected;
+}
+
+static inline void zig_msvc_atomic_store_u128(zig_u128 volatile* obj, zig_u128 arg) {
+ zig_u128 expected = zig_make_u128(UINT64_C(0), UINT64_C(0));
+ while (!zig_cmpxchg_weak(obj, expected, arg, zig_memory_order_seq_cst, zig_memory_order_seq_cst, u128, zig_u128));
+}
+
static inline bool zig_msvc_cmpxchg_i128(zig_i128 volatile* obj, zig_i128* expected, zig_i128 desired) {
return _InterlockedCompareExchange128((__int64 volatile*)obj, (__int64)zig_hi_i128(desired), (__int64)zig_lo_i128(desired), (__int64*)expected);
}
+
+static inline zig_i128 zig_msvc_atomic_load_i128(zig_i128 volatile* obj) {
+ zig_i128 expected = zig_make_i128(INT64_C(0), UINT64_C(0));
+ (void)zig_cmpxchg_strong(obj, expected, expected, zig_memory_order_seq_cst, zig_memory_order_seq_cst, i128, zig_i128);
+ return expected;
+}
+
+static inline void zig_msvc_atomic_store_i128(zig_i128 volatile* obj, zig_i128 arg) {
+ zig_i128 expected = zig_make_i128(INT64_C(0), UINT64_C(0));
+ while (!zig_cmpxchg_weak(obj, expected, arg, zig_memory_order_seq_cst, zig_memory_order_seq_cst, i128, zig_i128));
+}
+
#endif /* _M_IX86 */
#endif /* _MSC_VER && (_M_IX86 || _M_X64) */
diff --git a/stage1/zig1.wasm b/stage1/zig1.wasm
index 4d692444efab1ee22476f35ee0ff29bc02a9ac0a..c249daa0674cd74250c9fc53b1a5acf6125e105e 100644
Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ
diff --git a/test/behavior/align.zig b/test/behavior/align.zig
index e00fbe67443f0bf13281cc15d06f69653beaead3..671e46501a130f565c9a6a362b9f85acdb1decb1 100644
--- a/test/behavior/align.zig
+++ b/test/behavior/align.zig
@@ -311,12 +311,6 @@ test "page aligned array on stack" {
try expect(number2 == 43);
}
-fn derp() align(@sizeOf(usize) * 2) i32 {
- return 1234;
-}
-fn noop1() align(1) void {}
-fn noop4() align(4) void {}
-
test "function alignment" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
@@ -325,11 +319,25 @@ test "function alignment" {
// function alignment is a compile error on wasm32/wasm64
if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
- try expect(derp() == 1234);
- try expect(@TypeOf(noop1) == fn () align(1) void);
- try expect(@TypeOf(noop4) == fn () align(4) void);
- noop1();
- noop4();
+ const S = struct {
+ fn alignExpr() align(@sizeOf(usize) * 2) i32 {
+ return 1234;
+ }
+ fn align1() align(1) void {}
+ fn align4() align(4) void {}
+ };
+
+ try expect(S.alignExpr() == 1234);
+ try expect(@TypeOf(S.alignExpr) == fn () i32);
+ try expect(@TypeOf(&S.alignExpr) == *align(@sizeOf(usize) * 2) const fn () i32);
+
+ S.align1();
+ try expect(@TypeOf(S.align1) == fn () void);
+ try expect(@TypeOf(&S.align1) == *align(1) const fn () void);
+
+ S.align4();
+ try expect(@TypeOf(S.align4) == fn () void);
+ try expect(@TypeOf(&S.align4) == *align(4) const fn () void);
}
test "implicitly decreasing fn alignment" {
@@ -345,7 +353,7 @@ test "implicitly decreasing fn alignment" {
try testImplicitlyDecreaseFnAlign(alignedBig, 5678);
}
-fn testImplicitlyDecreaseFnAlign(ptr: *const fn () align(1) i32, answer: i32) !void {
+fn testImplicitlyDecreaseFnAlign(ptr: *align(1) const fn () i32, answer: i32) !void {
try expect(ptr() == answer);
}
@@ -368,10 +376,10 @@ test "@alignCast functions" {
try expect(fnExpectsOnly1(simple4) == 0x19);
}
-fn fnExpectsOnly1(ptr: *const fn () align(1) i32) i32 {
+fn fnExpectsOnly1(ptr: *align(1) const fn () i32) i32 {
return fnExpects4(@alignCast(ptr));
}
-fn fnExpects4(ptr: *const fn () align(4) i32) i32 {
+fn fnExpects4(ptr: *align(4) const fn () i32) i32 {
return ptr();
}
fn simple4() align(4) i32 {
diff --git a/test/behavior/type.zig b/test/behavior/type.zig
index da42672be6d7473a9db8c3d707549cc14ef51c19..c9290ecc31ec877f00d9f9d3895d86dccbfb98b8 100644
--- a/test/behavior/type.zig
+++ b/test/behavior/type.zig
@@ -527,7 +527,6 @@ test "Type.Fn" {
{
const fn_info = std.builtin.Type{ .Fn = .{
.calling_convention = .C,
- .alignment = 0,
.is_generic = false,
.is_var_args = false,
.return_type = void,
@@ -643,7 +642,6 @@ test "reified function type params initialized with field pointer" {
const Bar = @Type(.{
.Fn = .{
.calling_convention = .Unspecified,
- .alignment = 0,
.is_generic = false,
.is_var_args = false,
.return_type = void,
diff --git a/test/behavior/type_info.zig b/test/behavior/type_info.zig
index d4e3eb3b833cedb0ed96d2477a25323dc933d97f..0d54b14c390c9aaabeb20d04a4876ad7ba282fd4 100644
--- a/test/behavior/type_info.zig
+++ b/test/behavior/type_info.zig
@@ -356,16 +356,38 @@ test "type info: function type info" {
}
fn testFunction() !void {
- const fn_info = @typeInfo(@TypeOf(typeInfoFoo));
- try expect(fn_info == .Fn);
- try expect(fn_info.Fn.alignment > 0);
- try expect(fn_info.Fn.calling_convention == .C);
- try expect(!fn_info.Fn.is_generic);
- try expect(fn_info.Fn.params.len == 2);
- try expect(fn_info.Fn.is_var_args);
- try expect(fn_info.Fn.return_type.? == usize);
- const fn_aligned_info = @typeInfo(@TypeOf(typeInfoFooAligned));
- try expect(fn_aligned_info.Fn.alignment == 4);
+ const foo_fn_type = @TypeOf(typeInfoFoo);
+ const foo_fn_info = @typeInfo(foo_fn_type);
+ try expect(foo_fn_info.Fn.calling_convention == .C);
+ try expect(!foo_fn_info.Fn.is_generic);
+ try expect(foo_fn_info.Fn.params.len == 2);
+ try expect(foo_fn_info.Fn.is_var_args);
+ try expect(foo_fn_info.Fn.return_type.? == usize);
+ const foo_ptr_fn_info = @typeInfo(@TypeOf(&typeInfoFoo));
+ try expect(foo_ptr_fn_info.Pointer.size == .One);
+ try expect(foo_ptr_fn_info.Pointer.is_const);
+ try expect(!foo_ptr_fn_info.Pointer.is_volatile);
+ try expect(foo_ptr_fn_info.Pointer.address_space == .generic);
+ try expect(foo_ptr_fn_info.Pointer.child == foo_fn_type);
+ try expect(!foo_ptr_fn_info.Pointer.is_allowzero);
+ try expect(foo_ptr_fn_info.Pointer.sentinel == null);
+
+ const aligned_foo_fn_type = @TypeOf(typeInfoFooAligned);
+ const aligned_foo_fn_info = @typeInfo(aligned_foo_fn_type);
+ try expect(aligned_foo_fn_info.Fn.calling_convention == .C);
+ try expect(!aligned_foo_fn_info.Fn.is_generic);
+ try expect(aligned_foo_fn_info.Fn.params.len == 2);
+ try expect(aligned_foo_fn_info.Fn.is_var_args);
+ try expect(aligned_foo_fn_info.Fn.return_type.? == usize);
+ const aligned_foo_ptr_fn_info = @typeInfo(@TypeOf(&typeInfoFooAligned));
+ try expect(aligned_foo_ptr_fn_info.Pointer.size == .One);
+ try expect(aligned_foo_ptr_fn_info.Pointer.is_const);
+ try expect(!aligned_foo_ptr_fn_info.Pointer.is_volatile);
+ try expect(aligned_foo_ptr_fn_info.Pointer.alignment == 4);
+ try expect(aligned_foo_ptr_fn_info.Pointer.address_space == .generic);
+ try expect(aligned_foo_ptr_fn_info.Pointer.child == aligned_foo_fn_type);
+ try expect(!aligned_foo_ptr_fn_info.Pointer.is_allowzero);
+ try expect(aligned_foo_ptr_fn_info.Pointer.sentinel == null);
}
extern fn typeInfoFoo(a: usize, b: bool, ...) callconv(.C) usize;
diff --git a/test/behavior/typename.zig b/test/behavior/typename.zig
index 80c9a0619ea11087bad517150aac39f9e0beed75..c3eefc8de775064b5137fb85dcb4be017fa4ba71 100644
--- a/test/behavior/typename.zig
+++ b/test/behavior/typename.zig
@@ -78,11 +78,9 @@ test "basic" {
try expectEqualStrings("fn (comptime u32) void", @typeName(fn (comptime u32) void));
try expectEqualStrings("fn (noalias []u8) void", @typeName(fn (noalias []u8) void));
- try expectEqualStrings("fn () align(32) void", @typeName(fn () align(32) void));
try expectEqualStrings("fn () callconv(.C) void", @typeName(fn () callconv(.C) void));
- try expectEqualStrings("fn () align(32) callconv(.C) void", @typeName(fn () align(32) callconv(.C) void));
- try expectEqualStrings("fn (...) align(32) callconv(.C) void", @typeName(fn (...) align(32) callconv(.C) void));
- try expectEqualStrings("fn (u32, ...) align(32) callconv(.C) void", @typeName(fn (u32, ...) align(32) callconv(.C) void));
+ try expectEqualStrings("fn (...) callconv(.C) void", @typeName(fn (...) callconv(.C) void));
+ try expectEqualStrings("fn (u32, ...) callconv(.C) void", @typeName(fn (u32, ...) callconv(.C) void));
}
test "top level decl" {
diff --git a/test/cases/compile_errors/function_ptr_alignment.zig b/test/cases/compile_errors/function_ptr_alignment.zig
index 995ef8d9b1cbf8035e36a3745287146d5fe416f1..cf97e61f40147ef636bd7536d9a6cab0783a6b71 100644
--- a/test/cases/compile_errors/function_ptr_alignment.zig
+++ b/test/cases/compile_errors/function_ptr_alignment.zig
@@ -1,28 +1,16 @@
-comptime {
- var a: *align(2) @TypeOf(foo) = undefined;
- _ = &a;
-}
-fn foo() void {}
+fn align1() align(1) void {}
+fn align2() align(2) void {}
comptime {
- var a: *align(1) fn () void = undefined;
- _ = &a;
-}
-comptime {
- var a: *align(2) fn () align(2) void = undefined;
- _ = &a;
-}
-comptime {
- var a: *align(2) fn () void = undefined;
- _ = &a;
-}
-comptime {
- var a: *align(1) fn () align(2) void = undefined;
- _ = &a;
+ _ = @as(*align(1) const fn () void, &align2);
+ _ = @as(*align(1) const fn () void, &align1);
+ _ = @as(*align(2) const fn () void, &align2);
+ _ = @as(*align(2) const fn () void, &align1);
}
// error
// backend=stage2
// target=native
//
-// :20:19: error: function pointer alignment disagrees with function alignment
+// :8:41: error: expected type '*align(2) const fn () void', found '*const fn () void'
+// :8:41: note: pointer alignment '1' cannot cast into pointer alignment '2'
diff --git a/test/cases/compile_errors/inferring_error_set_of_function_pointer.zig b/test/cases/compile_errors/inferring_error_set_of_function_pointer.zig
deleted file mode 100644
index ce1b2763609a599e8597db7d91c5eb92250109f2..0000000000000000000000000000000000000000
--- a/test/cases/compile_errors/inferring_error_set_of_function_pointer.zig
+++ /dev/null
@@ -1,9 +0,0 @@
-comptime {
- const z: ?fn () !void = null;
-}
-
-// error
-// backend=stage2
-// target=native
-//
-// :2:21: error: function prototype may not have inferred error set
diff --git a/test/cases/compile_errors/invalid_function_types.zig b/test/cases/compile_errors/invalid_function_types.zig
new file mode 100644
index 0000000000000000000000000000000000000000..e4553d22f12d2a14a5483d17605ca448dc0af863
--- /dev/null
+++ b/test/cases/compile_errors/invalid_function_types.zig
@@ -0,0 +1,25 @@
+comptime {
+ _ = fn name() void;
+}
+comptime {
+ _ = fn () align(128) void;
+}
+comptime {
+ _ = fn () addrspace(.generic) void;
+}
+comptime {
+ _ = fn () linksection("section") void;
+}
+comptime {
+ _ = fn () !void;
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :2:12: error: function type cannot have a name
+// :5:21: error: function type cannot have an alignment
+// :8:26: error: function type cannot have an addrspace
+// :11:27: error: function type cannot have a linksection
+// :14:15: error: function type cannot have an inferred error set
diff --git a/test/cases/compile_errors/passing_an_under-aligned_function_pointer.zig b/test/cases/compile_errors/passing_an_under-aligned_function_pointer.zig
index c6b06f7329a9a6f17cd909f054ffe4fc4c505908..e37441563b07b77cee89c438bbbb8fb3c1c05549 100644
--- a/test/cases/compile_errors/passing_an_under-aligned_function_pointer.zig
+++ b/test/cases/compile_errors/passing_an_under-aligned_function_pointer.zig
@@ -1,7 +1,7 @@
export fn entry() void {
testImplicitlyDecreaseFnAlign(alignedSmall, 1234);
}
-fn testImplicitlyDecreaseFnAlign(ptr: *const fn () align(8) i32, answer: i32) void {
+fn testImplicitlyDecreaseFnAlign(ptr: *align(8) const fn () i32, answer: i32) void {
if (ptr() != answer) unreachable;
}
fn alignedSmall() align(4) i32 {
@@ -12,5 +12,5 @@ fn alignedSmall() align(4) i32 {
// backend=stage2
// target=x86_64-linux
//
-// :2:35: error: expected type '*const fn () align(8) i32', found '*const fn () align(4) i32'
+// :2:35: error: expected type '*align(8) const fn () i32', found '*align(4) const fn () i32'
// :2:35: note: pointer alignment '4' cannot cast into pointer alignment '8'
diff --git a/test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig b/test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig
index bb2c4bbe628278de38d5ebc2c4731930a9ee7fcb..4ac1312440bba2e8fa69c3c1de8ed09927025c20 100644
--- a/test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig
+++ b/test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig
@@ -1,7 +1,6 @@
const Foo = @Type(.{
.Fn = .{
.calling_convention = .Unspecified,
- .alignment = 0,
.is_generic = true,
.is_var_args = false,
.return_type = u0,
diff --git a/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig b/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig
index 678fbe3ed7be8a3110b5a8e73fb5a55b174cd7bc..23ea4f209521c2c69f38662e63d8cf9c0586e878 100644
--- a/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig
+++ b/test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig
@@ -1,7 +1,6 @@
const Foo = @Type(.{
.Fn = .{
.calling_convention = .Unspecified,
- .alignment = 0,
.is_generic = false,
.is_var_args = true,
.return_type = u0,
diff --git a/test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig b/test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig
index d348a0c908a042ae3ba3cfb17ee70f49d0d2fd95..073cf0f4ccf7ed617b6514bae74e9850dd6c8301 100644
--- a/test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig
+++ b/test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig
@@ -1,7 +1,6 @@
const Foo = @Type(.{
.Fn = .{
.calling_convention = .Unspecified,
- .alignment = 0,
.is_generic = false,
.is_var_args = false,
.return_type = null,