| author | |
| committer | |
| log | d981549d65849591749d8d9db12ddf2bf7361399 |
| tree | ced0941ad568c7bb7cddc57759e8d320a71ab7fc |
| parent | 294f51814f491ae4a09348d9e7221ae3e550c16f |
| parent | edeed592eeed151780ae8a0b13c3d4d17c3f93b2 |
| signature |
AstGen: disallow alignment on function types35 files changed, 1708 insertions(+), 1695 deletions(-)
doc/langref.html.in+8-2| ... | @@ -2780,10 +2780,16 @@ fn noop4() align(4) void {} | ... | @@ -2780,10 +2780,16 @@ fn noop4() align(4) void {} |
| 2780 | 2780 | ||
| 2781 | test "function alignment" { | 2781 | test "function alignment" { |
| 2782 | try expect(derp() == 1234); | 2782 | try expect(derp() == 1234); |
| 2783 | try expect(@TypeOf(noop1) == fn () align(1) void); | 2783 | try expect(@TypeOf(derp) == fn () i32); |
| 2784 | try expect(@TypeOf(noop4) == fn () align(4) void); | 2784 | try expect(@TypeOf(&derp) == *align(@sizeOf(usize) * 2) const fn () i32); |
| 2785 | |||
| 2785 | noop1(); | 2786 | noop1(); |
| 2787 | try expect(@TypeOf(noop1) == fn () void); | ||
| 2788 | try expect(@TypeOf(&noop1) == *align(1) const fn () void); | ||
| 2789 | |||
| 2786 | noop4(); | 2790 | noop4(); |
| 2791 | try expect(@TypeOf(noop4) == fn () void); | ||
| 2792 | try expect(@TypeOf(&noop4) == *align(4) const fn () void); | ||
| 2787 | } | 2793 | } |
| 2788 | {#code_end#} | 2794 | {#code_end#} |
| 2789 | <p> | 2795 | <p> |
lib/build_runner.zig deleted-1293| ... | @@ -1,1293 +0,0 @@ | ||
| 1 | const root = @import("@build"); | ||
| 2 | const std = @import("std"); | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | const assert = std.debug.assert; | ||
| 5 | const io = std.io; | ||
| 6 | const fmt = std.fmt; | ||
| 7 | const mem = std.mem; | ||
| 8 | const process = std.process; | ||
| 9 | const ArrayList = std.ArrayList; | ||
| 10 | const File = std.fs.File; | ||
| 11 | const Step = std.Build.Step; | ||
| 12 | |||
| 13 | pub const dependencies = @import("@dependencies"); | ||
| 14 | |||
| 15 | pub fn main() !void { | ||
| 16 | // Here we use an ArenaAllocator backed by a page allocator because a build is a short-lived, | ||
| 17 | // one shot program. We don't need to waste time freeing memory and finding places to squish | ||
| 18 | // bytes into. So we free everything all at once at the very end. | ||
| 19 | var single_threaded_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); | ||
| 20 | defer single_threaded_arena.deinit(); | ||
| 21 | |||
| 22 | var thread_safe_arena: std.heap.ThreadSafeAllocator = .{ | ||
| 23 | .child_allocator = single_threaded_arena.allocator(), | ||
| 24 | }; | ||
| 25 | const arena = thread_safe_arena.allocator(); | ||
| 26 | |||
| 27 | const args = try process.argsAlloc(arena); | ||
| 28 | |||
| 29 | // skip my own exe name | ||
| 30 | var arg_idx: usize = 1; | ||
| 31 | |||
| 32 | const zig_exe = nextArg(args, &arg_idx) orelse { | ||
| 33 | std.debug.print("Expected path to zig compiler\n", .{}); | ||
| 34 | return error.InvalidArgs; | ||
| 35 | }; | ||
| 36 | const build_root = nextArg(args, &arg_idx) orelse { | ||
| 37 | std.debug.print("Expected build root directory path\n", .{}); | ||
| 38 | return error.InvalidArgs; | ||
| 39 | }; | ||
| 40 | const cache_root = nextArg(args, &arg_idx) orelse { | ||
| 41 | std.debug.print("Expected cache root directory path\n", .{}); | ||
| 42 | return error.InvalidArgs; | ||
| 43 | }; | ||
| 44 | const global_cache_root = nextArg(args, &arg_idx) orelse { | ||
| 45 | std.debug.print("Expected global cache root directory path\n", .{}); | ||
| 46 | return error.InvalidArgs; | ||
| 47 | }; | ||
| 48 | |||
| 49 | const build_root_directory: std.Build.Cache.Directory = .{ | ||
| 50 | .path = build_root, | ||
| 51 | .handle = try std.fs.cwd().openDir(build_root, .{}), | ||
| 52 | }; | ||
| 53 | |||
| 54 | const local_cache_directory: std.Build.Cache.Directory = .{ | ||
| 55 | .path = cache_root, | ||
| 56 | .handle = try std.fs.cwd().makeOpenPath(cache_root, .{}), | ||
| 57 | }; | ||
| 58 | |||
| 59 | const global_cache_directory: std.Build.Cache.Directory = .{ | ||
| 60 | .path = global_cache_root, | ||
| 61 | .handle = try std.fs.cwd().makeOpenPath(global_cache_root, .{}), | ||
| 62 | }; | ||
| 63 | |||
| 64 | var graph: std.Build.Graph = .{ | ||
| 65 | .arena = arena, | ||
| 66 | .cache = .{ | ||
| 67 | .gpa = arena, | ||
| 68 | .manifest_dir = try local_cache_directory.handle.makeOpenPath("h", .{}), | ||
| 69 | }, | ||
| 70 | .zig_exe = zig_exe, | ||
| 71 | .env_map = try process.getEnvMap(arena), | ||
| 72 | .global_cache_root = global_cache_directory, | ||
| 73 | }; | ||
| 74 | |||
| 75 | graph.cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() }); | ||
| 76 | graph.cache.addPrefix(build_root_directory); | ||
| 77 | graph.cache.addPrefix(local_cache_directory); | ||
| 78 | graph.cache.addPrefix(global_cache_directory); | ||
| 79 | graph.cache.hash.addBytes(builtin.zig_version_string); | ||
| 80 | |||
| 81 | const builder = try std.Build.create( | ||
| 82 | &graph, | ||
| 83 | build_root_directory, | ||
| 84 | local_cache_directory, | ||
| 85 | dependencies.root_deps, | ||
| 86 | ); | ||
| 87 | |||
| 88 | var targets = ArrayList([]const u8).init(arena); | ||
| 89 | var debug_log_scopes = ArrayList([]const u8).init(arena); | ||
| 90 | var thread_pool_options: std.Thread.Pool.Options = .{ .allocator = arena }; | ||
| 91 | |||
| 92 | var install_prefix: ?[]const u8 = null; | ||
| 93 | var dir_list = std.Build.DirList{}; | ||
| 94 | var summary: ?Summary = null; | ||
| 95 | var max_rss: u64 = 0; | ||
| 96 | var skip_oom_steps: bool = false; | ||
| 97 | var color: Color = .auto; | ||
| 98 | var seed: u32 = 0; | ||
| 99 | var prominent_compile_errors: bool = false; | ||
| 100 | var help_menu: bool = false; | ||
| 101 | var steps_menu: bool = false; | ||
| 102 | var output_tmp_nonce: ?[16]u8 = null; | ||
| 103 | |||
| 104 | while (nextArg(args, &arg_idx)) |arg| { | ||
| 105 | if (mem.startsWith(u8, arg, "-Z")) { | ||
| 106 | if (arg.len != 18) fatalWithHint("bad argument: '{s}'", .{arg}); | ||
| 107 | output_tmp_nonce = arg[2..18].*; | ||
| 108 | } else if (mem.startsWith(u8, arg, "-D")) { | ||
| 109 | const option_contents = arg[2..]; | ||
| 110 | if (option_contents.len == 0) | ||
| 111 | fatalWithHint("expected option name after '-D'", .{}); | ||
| 112 | if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| { | ||
| 113 | const option_name = option_contents[0..name_end]; | ||
| 114 | const option_value = option_contents[name_end + 1 ..]; | ||
| 115 | if (try builder.addUserInputOption(option_name, option_value)) | ||
| 116 | fatal(" access the help menu with 'zig build -h'", .{}); | ||
| 117 | } else { | ||
| 118 | if (try builder.addUserInputFlag(option_contents)) | ||
| 119 | fatal(" access the help menu with 'zig build -h'", .{}); | ||
| 120 | } | ||
| 121 | } else if (mem.startsWith(u8, arg, "-")) { | ||
| 122 | if (mem.eql(u8, arg, "--verbose")) { | ||
| 123 | builder.verbose = true; | ||
| 124 | } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { | ||
| 125 | help_menu = true; | ||
| 126 | } else if (mem.eql(u8, arg, "-p") or mem.eql(u8, arg, "--prefix")) { | ||
| 127 | install_prefix = nextArgOrFatal(args, &arg_idx); | ||
| 128 | } else if (mem.eql(u8, arg, "-l") or mem.eql(u8, arg, "--list-steps")) { | ||
| 129 | steps_menu = true; | ||
| 130 | } else if (mem.startsWith(u8, arg, "-fsys=")) { | ||
| 131 | const name = arg["-fsys=".len..]; | ||
| 132 | graph.system_library_options.put(arena, name, .user_enabled) catch @panic("OOM"); | ||
| 133 | } else if (mem.startsWith(u8, arg, "-fno-sys=")) { | ||
| 134 | const name = arg["-fno-sys=".len..]; | ||
| 135 | graph.system_library_options.put(arena, name, .user_disabled) catch @panic("OOM"); | ||
| 136 | } else if (mem.eql(u8, arg, "--release")) { | ||
| 137 | builder.release_mode = .any; | ||
| 138 | } else if (mem.startsWith(u8, arg, "--release=")) { | ||
| 139 | const text = arg["--release=".len..]; | ||
| 140 | builder.release_mode = std.meta.stringToEnum(std.Build.ReleaseMode, text) orelse { | ||
| 141 | fatalWithHint("expected [off|any|fast|safe|small] in '{s}', found '{s}'", .{ | ||
| 142 | arg, text, | ||
| 143 | }); | ||
| 144 | }; | ||
| 145 | } else if (mem.eql(u8, arg, "--host-target")) { | ||
| 146 | graph.host_query_options.arch_os_abi = nextArgOrFatal(args, &arg_idx); | ||
| 147 | } else if (mem.eql(u8, arg, "--host-cpu")) { | ||
| 148 | graph.host_query_options.cpu_features = nextArgOrFatal(args, &arg_idx); | ||
| 149 | } else if (mem.eql(u8, arg, "--host-dynamic-linker")) { | ||
| 150 | graph.host_query_options.dynamic_linker = nextArgOrFatal(args, &arg_idx); | ||
| 151 | } else if (mem.eql(u8, arg, "--prefix-lib-dir")) { | ||
| 152 | dir_list.lib_dir = nextArgOrFatal(args, &arg_idx); | ||
| 153 | } else if (mem.eql(u8, arg, "--prefix-exe-dir")) { | ||
| 154 | dir_list.exe_dir = nextArgOrFatal(args, &arg_idx); | ||
| 155 | } else if (mem.eql(u8, arg, "--prefix-include-dir")) { | ||
| 156 | dir_list.include_dir = nextArgOrFatal(args, &arg_idx); | ||
| 157 | } else if (mem.eql(u8, arg, "--sysroot")) { | ||
| 158 | builder.sysroot = nextArgOrFatal(args, &arg_idx); | ||
| 159 | } else if (mem.eql(u8, arg, "--maxrss")) { | ||
| 160 | const max_rss_text = nextArgOrFatal(args, &arg_idx); | ||
| 161 | max_rss = std.fmt.parseIntSizeSuffix(max_rss_text, 10) catch |err| { | ||
| 162 | std.debug.print("invalid byte size: '{s}': {s}\n", .{ | ||
| 163 | max_rss_text, @errorName(err), | ||
| 164 | }); | ||
| 165 | process.exit(1); | ||
| 166 | }; | ||
| 167 | } else if (mem.eql(u8, arg, "--skip-oom-steps")) { | ||
| 168 | skip_oom_steps = true; | ||
| 169 | } else if (mem.eql(u8, arg, "--search-prefix")) { | ||
| 170 | const search_prefix = nextArgOrFatal(args, &arg_idx); | ||
| 171 | builder.addSearchPrefix(search_prefix); | ||
| 172 | } else if (mem.eql(u8, arg, "--libc")) { | ||
| 173 | builder.libc_file = nextArgOrFatal(args, &arg_idx); | ||
| 174 | } else if (mem.eql(u8, arg, "--color")) { | ||
| 175 | const next_arg = nextArg(args, &arg_idx) orelse | ||
| 176 | fatalWithHint("expected [auto|on|off] after '{s}'", .{arg}); | ||
| 177 | color = std.meta.stringToEnum(Color, next_arg) orelse { | ||
| 178 | fatalWithHint("expected [auto|on|off] after '{s}', found '{s}'", .{ | ||
| 179 | arg, next_arg, | ||
| 180 | }); | ||
| 181 | }; | ||
| 182 | } else if (mem.eql(u8, arg, "--summary")) { | ||
| 183 | const next_arg = nextArg(args, &arg_idx) orelse | ||
| 184 | fatalWithHint("expected [all|new|failures|none] after '{s}'", .{arg}); | ||
| 185 | summary = std.meta.stringToEnum(Summary, next_arg) orelse { | ||
| 186 | fatalWithHint("expected [all|failures|none] after '{s}', found '{s}'", .{ | ||
| 187 | arg, next_arg, | ||
| 188 | }); | ||
| 189 | }; | ||
| 190 | } else if (mem.eql(u8, arg, "--zig-lib-dir")) { | ||
| 191 | builder.zig_lib_dir = .{ .cwd_relative = nextArgOrFatal(args, &arg_idx) }; | ||
| 192 | } else if (mem.eql(u8, arg, "--seed")) { | ||
| 193 | const next_arg = nextArg(args, &arg_idx) orelse | ||
| 194 | fatalWithHint("expected u32 after '{s}'", .{arg}); | ||
| 195 | seed = std.fmt.parseUnsigned(u32, next_arg, 0) catch |err| { | ||
| 196 | fatal("unable to parse seed '{s}' as 32-bit integer: {s}\n", .{ | ||
| 197 | next_arg, @errorName(err), | ||
| 198 | }); | ||
| 199 | }; | ||
| 200 | } else if (mem.eql(u8, arg, "--debug-log")) { | ||
| 201 | const next_arg = nextArgOrFatal(args, &arg_idx); | ||
| 202 | try debug_log_scopes.append(next_arg); | ||
| 203 | } else if (mem.eql(u8, arg, "--debug-pkg-config")) { | ||
| 204 | builder.debug_pkg_config = true; | ||
| 205 | } else if (mem.eql(u8, arg, "--debug-compile-errors")) { | ||
| 206 | builder.debug_compile_errors = true; | ||
| 207 | } else if (mem.eql(u8, arg, "--system")) { | ||
| 208 | // The usage text shows another argument after this parameter | ||
| 209 | // but it is handled by the parent process. The build runner | ||
| 210 | // only sees this flag. | ||
| 211 | graph.system_package_mode = true; | ||
| 212 | } else if (mem.eql(u8, arg, "--glibc-runtimes")) { | ||
| 213 | builder.glibc_runtimes_dir = nextArgOrFatal(args, &arg_idx); | ||
| 214 | } else if (mem.eql(u8, arg, "--verbose-link")) { | ||
| 215 | builder.verbose_link = true; | ||
| 216 | } else if (mem.eql(u8, arg, "--verbose-air")) { | ||
| 217 | builder.verbose_air = true; | ||
| 218 | } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { | ||
| 219 | builder.verbose_llvm_ir = "-"; | ||
| 220 | } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) { | ||
| 221 | builder.verbose_llvm_ir = arg["--verbose-llvm-ir=".len..]; | ||
| 222 | } else if (mem.eql(u8, arg, "--verbose-llvm-bc=")) { | ||
| 223 | builder.verbose_llvm_bc = arg["--verbose-llvm-bc=".len..]; | ||
| 224 | } else if (mem.eql(u8, arg, "--verbose-cimport")) { | ||
| 225 | builder.verbose_cimport = true; | ||
| 226 | } else if (mem.eql(u8, arg, "--verbose-cc")) { | ||
| 227 | builder.verbose_cc = true; | ||
| 228 | } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) { | ||
| 229 | builder.verbose_llvm_cpu_features = true; | ||
| 230 | } else if (mem.eql(u8, arg, "--prominent-compile-errors")) { | ||
| 231 | prominent_compile_errors = true; | ||
| 232 | } else if (mem.eql(u8, arg, "-fwine")) { | ||
| 233 | builder.enable_wine = true; | ||
| 234 | } else if (mem.eql(u8, arg, "-fno-wine")) { | ||
| 235 | builder.enable_wine = false; | ||
| 236 | } else if (mem.eql(u8, arg, "-fqemu")) { | ||
| 237 | builder.enable_qemu = true; | ||
| 238 | } else if (mem.eql(u8, arg, "-fno-qemu")) { | ||
| 239 | builder.enable_qemu = false; | ||
| 240 | } else if (mem.eql(u8, arg, "-fwasmtime")) { | ||
| 241 | builder.enable_wasmtime = true; | ||
| 242 | } else if (mem.eql(u8, arg, "-fno-wasmtime")) { | ||
| 243 | builder.enable_wasmtime = false; | ||
| 244 | } else if (mem.eql(u8, arg, "-frosetta")) { | ||
| 245 | builder.enable_rosetta = true; | ||
| 246 | } else if (mem.eql(u8, arg, "-fno-rosetta")) { | ||
| 247 | builder.enable_rosetta = false; | ||
| 248 | } else if (mem.eql(u8, arg, "-fdarling")) { | ||
| 249 | builder.enable_darling = true; | ||
| 250 | } else if (mem.eql(u8, arg, "-fno-darling")) { | ||
| 251 | builder.enable_darling = false; | ||
| 252 | } else if (mem.eql(u8, arg, "-freference-trace")) { | ||
| 253 | builder.reference_trace = 256; | ||
| 254 | } else if (mem.startsWith(u8, arg, "-freference-trace=")) { | ||
| 255 | const num = arg["-freference-trace=".len..]; | ||
| 256 | builder.reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| { | ||
| 257 | std.debug.print("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) }); | ||
| 258 | process.exit(1); | ||
| 259 | }; | ||
| 260 | } else if (mem.eql(u8, arg, "-fno-reference-trace")) { | ||
| 261 | builder.reference_trace = null; | ||
| 262 | } else if (mem.startsWith(u8, arg, "-j")) { | ||
| 263 | const num = arg["-j".len..]; | ||
| 264 | const n_jobs = std.fmt.parseUnsigned(u32, num, 10) catch |err| { | ||
| 265 | std.debug.print("unable to parse jobs count '{s}': {s}", .{ | ||
| 266 | num, @errorName(err), | ||
| 267 | }); | ||
| 268 | process.exit(1); | ||
| 269 | }; | ||
| 270 | if (n_jobs < 1) { | ||
| 271 | std.debug.print("number of jobs must be at least 1\n", .{}); | ||
| 272 | process.exit(1); | ||
| 273 | } | ||
| 274 | thread_pool_options.n_jobs = n_jobs; | ||
| 275 | } else if (mem.eql(u8, arg, "--")) { | ||
| 276 | builder.args = argsRest(args, arg_idx); | ||
| 277 | break; | ||
| 278 | } else { | ||
| 279 | fatalWithHint("unrecognized argument: '{s}'", .{arg}); | ||
| 280 | } | ||
| 281 | } else { | ||
| 282 | try targets.append(arg); | ||
| 283 | } | ||
| 284 | } | ||
| 285 | |||
| 286 | const host_query = std.Build.parseTargetQuery(graph.host_query_options) catch |err| switch (err) { | ||
| 287 | error.ParseFailed => process.exit(1), | ||
| 288 | }; | ||
| 289 | builder.host = .{ | ||
| 290 | .query = .{}, | ||
| 291 | .result = try std.zig.system.resolveTargetQuery(host_query), | ||
| 292 | }; | ||
| 293 | |||
| 294 | const stderr = std.io.getStdErr(); | ||
| 295 | const ttyconf = get_tty_conf(color, stderr); | ||
| 296 | switch (ttyconf) { | ||
| 297 | .no_color => try graph.env_map.put("NO_COLOR", "1"), | ||
| 298 | .escape_codes => try graph.env_map.put("YES_COLOR", "1"), | ||
| 299 | .windows_api => {}, | ||
| 300 | } | ||
| 301 | |||
| 302 | var progress: std.Progress = .{ .dont_print_on_dumb = true }; | ||
| 303 | const main_progress_node = progress.start("", 0); | ||
| 304 | |||
| 305 | builder.debug_log_scopes = debug_log_scopes.items; | ||
| 306 | builder.resolveInstallPrefix(install_prefix, dir_list); | ||
| 307 | { | ||
| 308 | var prog_node = main_progress_node.start("user build.zig logic", 0); | ||
| 309 | defer prog_node.end(); | ||
| 310 | try builder.runBuild(root); | ||
| 311 | } | ||
| 312 | |||
| 313 | if (graph.needed_lazy_dependencies.entries.len != 0) { | ||
| 314 | var buffer: std.ArrayListUnmanaged(u8) = .{}; | ||
| 315 | for (graph.needed_lazy_dependencies.keys()) |k| { | ||
| 316 | try buffer.appendSlice(arena, k); | ||
| 317 | try buffer.append(arena, '\n'); | ||
| 318 | } | ||
| 319 | const s = std.fs.path.sep_str; | ||
| 320 | const tmp_sub_path = "tmp" ++ s ++ (output_tmp_nonce orelse fatal("missing -Z arg", .{})); | ||
| 321 | local_cache_directory.handle.writeFile2(.{ | ||
| 322 | .sub_path = tmp_sub_path, | ||
| 323 | .data = buffer.items, | ||
| 324 | .flags = .{ .exclusive = true }, | ||
| 325 | }) catch |err| { | ||
| 326 | fatal("unable to write configuration results to '{}{s}': {s}", .{ | ||
| 327 | local_cache_directory, tmp_sub_path, @errorName(err), | ||
| 328 | }); | ||
| 329 | }; | ||
| 330 | process.exit(3); // Indicate configure phase failed with meaningful stdout. | ||
| 331 | } | ||
| 332 | |||
| 333 | if (builder.validateUserInputDidItFail()) { | ||
| 334 | fatal(" access the help menu with 'zig build -h'", .{}); | ||
| 335 | } | ||
| 336 | |||
| 337 | validateSystemLibraryOptions(builder); | ||
| 338 | |||
| 339 | const stdout_writer = io.getStdOut().writer(); | ||
| 340 | |||
| 341 | if (help_menu) | ||
| 342 | return usage(builder, stdout_writer); | ||
| 343 | |||
| 344 | if (steps_menu) | ||
| 345 | return steps(builder, stdout_writer); | ||
| 346 | |||
| 347 | var run: Run = .{ | ||
| 348 | .max_rss = max_rss, | ||
| 349 | .max_rss_is_default = false, | ||
| 350 | .max_rss_mutex = .{}, | ||
| 351 | .skip_oom_steps = skip_oom_steps, | ||
| 352 | .memory_blocked_steps = std.ArrayList(*Step).init(arena), | ||
| 353 | .prominent_compile_errors = prominent_compile_errors, | ||
| 354 | |||
| 355 | .claimed_rss = 0, | ||
| 356 | .summary = summary, | ||
| 357 | .ttyconf = ttyconf, | ||
| 358 | .stderr = stderr, | ||
| 359 | }; | ||
| 360 | |||
| 361 | if (run.max_rss == 0) { | ||
| 362 | run.max_rss = process.totalSystemMemory() catch std.math.maxInt(u64); | ||
| 363 | run.max_rss_is_default = true; | ||
| 364 | } | ||
| 365 | |||
| 366 | runStepNames( | ||
| 367 | arena, | ||
| 368 | builder, | ||
| 369 | targets.items, | ||
| 370 | main_progress_node, | ||
| 371 | thread_pool_options, | ||
| 372 | &run, | ||
| 373 | seed, | ||
| 374 | ) catch |err| switch (err) { | ||
| 375 | error.UncleanExit => process.exit(1), | ||
| 376 | else => return err, | ||
| 377 | }; | ||
| 378 | } | ||
| 379 | |||
| 380 | const Run = struct { | ||
| 381 | max_rss: u64, | ||
| 382 | max_rss_is_default: bool, | ||
| 383 | max_rss_mutex: std.Thread.Mutex, | ||
| 384 | skip_oom_steps: bool, | ||
| 385 | memory_blocked_steps: std.ArrayList(*Step), | ||
| 386 | prominent_compile_errors: bool, | ||
| 387 | |||
| 388 | claimed_rss: usize, | ||
| 389 | summary: ?Summary, | ||
| 390 | ttyconf: std.io.tty.Config, | ||
| 391 | stderr: File, | ||
| 392 | }; | ||
| 393 | |||
| 394 | fn runStepNames( | ||
| 395 | arena: std.mem.Allocator, | ||
| 396 | b: *std.Build, | ||
| 397 | step_names: []const []const u8, | ||
| 398 | parent_prog_node: *std.Progress.Node, | ||
| 399 | thread_pool_options: std.Thread.Pool.Options, | ||
| 400 | run: *Run, | ||
| 401 | seed: u32, | ||
| 402 | ) !void { | ||
| 403 | const gpa = b.allocator; | ||
| 404 | var step_stack: std.AutoArrayHashMapUnmanaged(*Step, void) = .{}; | ||
| 405 | defer step_stack.deinit(gpa); | ||
| 406 | |||
| 407 | if (step_names.len == 0) { | ||
| 408 | try step_stack.put(gpa, b.default_step, {}); | ||
| 409 | } else { | ||
| 410 | try step_stack.ensureUnusedCapacity(gpa, step_names.len); | ||
| 411 | for (0..step_names.len) |i| { | ||
| 412 | const step_name = step_names[step_names.len - i - 1]; | ||
| 413 | const s = b.top_level_steps.get(step_name) orelse { | ||
| 414 | std.debug.print("no step named '{s}'\n access the help menu with 'zig build -h'\n", .{step_name}); | ||
| 415 | process.exit(1); | ||
| 416 | }; | ||
| 417 | step_stack.putAssumeCapacity(&s.step, {}); | ||
| 418 | } | ||
| 419 | } | ||
| 420 | |||
| 421 | const starting_steps = try arena.dupe(*Step, step_stack.keys()); | ||
| 422 | |||
| 423 | var rng = std.Random.DefaultPrng.init(seed); | ||
| 424 | const rand = rng.random(); | ||
| 425 | rand.shuffle(*Step, starting_steps); | ||
| 426 | |||
| 427 | for (starting_steps) |s| { | ||
| 428 | constructGraphAndCheckForDependencyLoop(b, s, &step_stack, rand) catch |err| switch (err) { | ||
| 429 | error.DependencyLoopDetected => return error.UncleanExit, | ||
| 430 | else => |e| return e, | ||
| 431 | }; | ||
| 432 | } | ||
| 433 | |||
| 434 | { | ||
| 435 | // Check that we have enough memory to complete the build. | ||
| 436 | var any_problems = false; | ||
| 437 | for (step_stack.keys()) |s| { | ||
| 438 | if (s.max_rss == 0) continue; | ||
| 439 | if (s.max_rss > run.max_rss) { | ||
| 440 | if (run.skip_oom_steps) { | ||
| 441 | s.state = .skipped_oom; | ||
| 442 | } else { | ||
| 443 | std.debug.print("{s}{s}: this step declares an upper bound of {d} bytes of memory, exceeding the available {d} bytes of memory\n", .{ | ||
| 444 | s.owner.dep_prefix, s.name, s.max_rss, run.max_rss, | ||
| 445 | }); | ||
| 446 | any_problems = true; | ||
| 447 | } | ||
| 448 | } | ||
| 449 | } | ||
| 450 | if (any_problems) { | ||
| 451 | if (run.max_rss_is_default) { | ||
| 452 | std.debug.print("note: use --maxrss to override the default", .{}); | ||
| 453 | } | ||
| 454 | return error.UncleanExit; | ||
| 455 | } | ||
| 456 | } | ||
| 457 | |||
| 458 | var thread_pool: std.Thread.Pool = undefined; | ||
| 459 | try thread_pool.init(thread_pool_options); | ||
| 460 | defer thread_pool.deinit(); | ||
| 461 | |||
| 462 | { | ||
| 463 | defer parent_prog_node.end(); | ||
| 464 | |||
| 465 | var step_prog = parent_prog_node.start("steps", step_stack.count()); | ||
| 466 | defer step_prog.end(); | ||
| 467 | |||
| 468 | var wait_group: std.Thread.WaitGroup = .{}; | ||
| 469 | defer wait_group.wait(); | ||
| 470 | |||
| 471 | // Here we spawn the initial set of tasks with a nice heuristic - | ||
| 472 | // dependency order. Each worker when it finishes a step will then | ||
| 473 | // check whether it should run any dependants. | ||
| 474 | const steps_slice = step_stack.keys(); | ||
| 475 | for (0..steps_slice.len) |i| { | ||
| 476 | const step = steps_slice[steps_slice.len - i - 1]; | ||
| 477 | if (step.state == .skipped_oom) continue; | ||
| 478 | |||
| 479 | wait_group.start(); | ||
| 480 | thread_pool.spawn(workerMakeOneStep, .{ | ||
| 481 | &wait_group, &thread_pool, b, step, &step_prog, run, | ||
| 482 | }) catch @panic("OOM"); | ||
| 483 | } | ||
| 484 | } | ||
| 485 | assert(run.memory_blocked_steps.items.len == 0); | ||
| 486 | |||
| 487 | var test_skip_count: usize = 0; | ||
| 488 | var test_fail_count: usize = 0; | ||
| 489 | var test_pass_count: usize = 0; | ||
| 490 | var test_leak_count: usize = 0; | ||
| 491 | var test_count: usize = 0; | ||
| 492 | |||
| 493 | var success_count: usize = 0; | ||
| 494 | var skipped_count: usize = 0; | ||
| 495 | var failure_count: usize = 0; | ||
| 496 | var pending_count: usize = 0; | ||
| 497 | var total_compile_errors: usize = 0; | ||
| 498 | var compile_error_steps: std.ArrayListUnmanaged(*Step) = .{}; | ||
| 499 | defer compile_error_steps.deinit(gpa); | ||
| 500 | |||
| 501 | for (step_stack.keys()) |s| { | ||
| 502 | test_fail_count += s.test_results.fail_count; | ||
| 503 | test_skip_count += s.test_results.skip_count; | ||
| 504 | test_leak_count += s.test_results.leak_count; | ||
| 505 | test_pass_count += s.test_results.passCount(); | ||
| 506 | test_count += s.test_results.test_count; | ||
| 507 | |||
| 508 | switch (s.state) { | ||
| 509 | .precheck_unstarted => unreachable, | ||
| 510 | .precheck_started => unreachable, | ||
| 511 | .running => unreachable, | ||
| 512 | .precheck_done => { | ||
| 513 | // precheck_done is equivalent to dependency_failure in the case of | ||
| 514 | // transitive dependencies. For example: | ||
| 515 | // A -> B -> C (failure) | ||
| 516 | // B will be marked as dependency_failure, while A may never be queued, and thus | ||
| 517 | // remain in the initial state of precheck_done. | ||
| 518 | s.state = .dependency_failure; | ||
| 519 | pending_count += 1; | ||
| 520 | }, | ||
| 521 | .dependency_failure => pending_count += 1, | ||
| 522 | .success => success_count += 1, | ||
| 523 | .skipped, .skipped_oom => skipped_count += 1, | ||
| 524 | .failure => { | ||
| 525 | failure_count += 1; | ||
| 526 | const compile_errors_len = s.result_error_bundle.errorMessageCount(); | ||
| 527 | if (compile_errors_len > 0) { | ||
| 528 | total_compile_errors += compile_errors_len; | ||
| 529 | try compile_error_steps.append(gpa, s); | ||
| 530 | } | ||
| 531 | }, | ||
| 532 | } | ||
| 533 | } | ||
| 534 | |||
| 535 | // A proper command line application defaults to silently succeeding. | ||
| 536 | // The user may request verbose mode if they have a different preference. | ||
| 537 | const failures_only = run.summary != .all and run.summary != .new; | ||
| 538 | if (failure_count == 0 and failures_only) return cleanExit(); | ||
| 539 | |||
| 540 | const ttyconf = run.ttyconf; | ||
| 541 | const stderr = run.stderr; | ||
| 542 | |||
| 543 | if (run.summary != Summary.none) { | ||
| 544 | const total_count = success_count + failure_count + pending_count + skipped_count; | ||
| 545 | ttyconf.setColor(stderr, .cyan) catch {}; | ||
| 546 | stderr.writeAll("Build Summary:") catch {}; | ||
| 547 | ttyconf.setColor(stderr, .reset) catch {}; | ||
| 548 | stderr.writer().print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {}; | ||
| 549 | if (skipped_count > 0) stderr.writer().print("; {d} skipped", .{skipped_count}) catch {}; | ||
| 550 | if (failure_count > 0) stderr.writer().print("; {d} failed", .{failure_count}) catch {}; | ||
| 551 | |||
| 552 | if (test_count > 0) stderr.writer().print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {}; | ||
| 553 | if (test_skip_count > 0) stderr.writer().print("; {d} skipped", .{test_skip_count}) catch {}; | ||
| 554 | if (test_fail_count > 0) stderr.writer().print("; {d} failed", .{test_fail_count}) catch {}; | ||
| 555 | if (test_leak_count > 0) stderr.writer().print("; {d} leaked", .{test_leak_count}) catch {}; | ||
| 556 | |||
| 557 | if (run.summary == null) { | ||
| 558 | ttyconf.setColor(stderr, .dim) catch {}; | ||
| 559 | stderr.writeAll(" (disable with --summary none)") catch {}; | ||
| 560 | ttyconf.setColor(stderr, .reset) catch {}; | ||
| 561 | } | ||
| 562 | stderr.writeAll("\n") catch {}; | ||
| 563 | |||
| 564 | // Print a fancy tree with build results. | ||
| 565 | var print_node: PrintNode = .{ .parent = null }; | ||
| 566 | if (step_names.len == 0) { | ||
| 567 | print_node.last = true; | ||
| 568 | printTreeStep(b, b.default_step, run, stderr, ttyconf, &print_node, &step_stack) catch {}; | ||
| 569 | } else { | ||
| 570 | const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: { | ||
| 571 | var i: usize = step_names.len; | ||
| 572 | while (i > 0) { | ||
| 573 | i -= 1; | ||
| 574 | const step = b.top_level_steps.get(step_names[i]).?.step; | ||
| 575 | const found = switch (run.summary orelse .failures) { | ||
| 576 | .all, .none => unreachable, | ||
| 577 | .failures => step.state != .success, | ||
| 578 | .new => !step.result_cached, | ||
| 579 | }; | ||
| 580 | if (found) break :blk i; | ||
| 581 | } | ||
| 582 | break :blk b.top_level_steps.count(); | ||
| 583 | }; | ||
| 584 | for (step_names, 0..) |step_name, i| { | ||
| 585 | const tls = b.top_level_steps.get(step_name).?; | ||
| 586 | print_node.last = i + 1 == last_index; | ||
| 587 | printTreeStep(b, &tls.step, run, stderr, ttyconf, &print_node, &step_stack) catch {}; | ||
| 588 | } | ||
| 589 | } | ||
| 590 | } | ||
| 591 | |||
| 592 | if (failure_count == 0) return cleanExit(); | ||
| 593 | |||
| 594 | // Finally, render compile errors at the bottom of the terminal. | ||
| 595 | // We use a separate compile_error_steps array list because step_stack is destructively | ||
| 596 | // mutated in printTreeStep above. | ||
| 597 | if (run.prominent_compile_errors and total_compile_errors > 0) { | ||
| 598 | for (compile_error_steps.items) |s| { | ||
| 599 | if (s.result_error_bundle.errorMessageCount() > 0) { | ||
| 600 | s.result_error_bundle.renderToStdErr(renderOptions(ttyconf)); | ||
| 601 | } | ||
| 602 | } | ||
| 603 | |||
| 604 | // Signal to parent process that we have printed compile errors. The | ||
| 605 | // parent process may choose to omit the "following command failed" | ||
| 606 | // line in this case. | ||
| 607 | process.exit(2); | ||
| 608 | } | ||
| 609 | |||
| 610 | process.exit(1); | ||
| 611 | } | ||
| 612 | |||
| 613 | const PrintNode = struct { | ||
| 614 | parent: ?*PrintNode, | ||
| 615 | last: bool = false, | ||
| 616 | }; | ||
| 617 | |||
| 618 | fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void { | ||
| 619 | const parent = node.parent orelse return; | ||
| 620 | if (parent.parent == null) return; | ||
| 621 | try printPrefix(parent, stderr, ttyconf); | ||
| 622 | if (parent.last) { | ||
| 623 | try stderr.writeAll(" "); | ||
| 624 | } else { | ||
| 625 | try stderr.writeAll(switch (ttyconf) { | ||
| 626 | .no_color, .windows_api => "| ", | ||
| 627 | .escape_codes => "\x1B\x28\x30\x78\x1B\x28\x42 ", // │ | ||
| 628 | }); | ||
| 629 | } | ||
| 630 | } | ||
| 631 | |||
| 632 | fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void { | ||
| 633 | try stderr.writeAll(switch (ttyconf) { | ||
| 634 | .no_color, .windows_api => "+- ", | ||
| 635 | .escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─ | ||
| 636 | }); | ||
| 637 | } | ||
| 638 | |||
| 639 | fn printStepStatus( | ||
| 640 | s: *Step, | ||
| 641 | stderr: File, | ||
| 642 | ttyconf: std.io.tty.Config, | ||
| 643 | run: *const Run, | ||
| 644 | ) !void { | ||
| 645 | switch (s.state) { | ||
| 646 | .precheck_unstarted => unreachable, | ||
| 647 | .precheck_started => unreachable, | ||
| 648 | .precheck_done => unreachable, | ||
| 649 | .running => unreachable, | ||
| 650 | |||
| 651 | .dependency_failure => { | ||
| 652 | try ttyconf.setColor(stderr, .dim); | ||
| 653 | try stderr.writeAll(" transitive failure\n"); | ||
| 654 | try ttyconf.setColor(stderr, .reset); | ||
| 655 | }, | ||
| 656 | |||
| 657 | .success => { | ||
| 658 | try ttyconf.setColor(stderr, .green); | ||
| 659 | if (s.result_cached) { | ||
| 660 | try stderr.writeAll(" cached"); | ||
| 661 | } else if (s.test_results.test_count > 0) { | ||
| 662 | const pass_count = s.test_results.passCount(); | ||
| 663 | try stderr.writer().print(" {d} passed", .{pass_count}); | ||
| 664 | if (s.test_results.skip_count > 0) { | ||
| 665 | try ttyconf.setColor(stderr, .yellow); | ||
| 666 | try stderr.writer().print(" {d} skipped", .{s.test_results.skip_count}); | ||
| 667 | } | ||
| 668 | } else { | ||
| 669 | try stderr.writeAll(" success"); | ||
| 670 | } | ||
| 671 | try ttyconf.setColor(stderr, .reset); | ||
| 672 | if (s.result_duration_ns) |ns| { | ||
| 673 | try ttyconf.setColor(stderr, .dim); | ||
| 674 | if (ns >= std.time.ns_per_min) { | ||
| 675 | try stderr.writer().print(" {d}m", .{ns / std.time.ns_per_min}); | ||
| 676 | } else if (ns >= std.time.ns_per_s) { | ||
| 677 | try stderr.writer().print(" {d}s", .{ns / std.time.ns_per_s}); | ||
| 678 | } else if (ns >= std.time.ns_per_ms) { | ||
| 679 | try stderr.writer().print(" {d}ms", .{ns / std.time.ns_per_ms}); | ||
| 680 | } else if (ns >= std.time.ns_per_us) { | ||
| 681 | try stderr.writer().print(" {d}us", .{ns / std.time.ns_per_us}); | ||
| 682 | } else { | ||
| 683 | try stderr.writer().print(" {d}ns", .{ns}); | ||
| 684 | } | ||
| 685 | try ttyconf.setColor(stderr, .reset); | ||
| 686 | } | ||
| 687 | if (s.result_peak_rss != 0) { | ||
| 688 | const rss = s.result_peak_rss; | ||
| 689 | try ttyconf.setColor(stderr, .dim); | ||
| 690 | if (rss >= 1000_000_000) { | ||
| 691 | try stderr.writer().print(" MaxRSS:{d}G", .{rss / 1000_000_000}); | ||
| 692 | } else if (rss >= 1000_000) { | ||
| 693 | try stderr.writer().print(" MaxRSS:{d}M", .{rss / 1000_000}); | ||
| 694 | } else if (rss >= 1000) { | ||
| 695 | try stderr.writer().print(" MaxRSS:{d}K", .{rss / 1000}); | ||
| 696 | } else { | ||
| 697 | try stderr.writer().print(" MaxRSS:{d}B", .{rss}); | ||
| 698 | } | ||
| 699 | try ttyconf.setColor(stderr, .reset); | ||
| 700 | } | ||
| 701 | try stderr.writeAll("\n"); | ||
| 702 | }, | ||
| 703 | .skipped, .skipped_oom => |skip| { | ||
| 704 | try ttyconf.setColor(stderr, .yellow); | ||
| 705 | try stderr.writeAll(" skipped"); | ||
| 706 | if (skip == .skipped_oom) { | ||
| 707 | try stderr.writeAll(" (not enough memory)"); | ||
| 708 | try ttyconf.setColor(stderr, .dim); | ||
| 709 | try stderr.writer().print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss }); | ||
| 710 | try ttyconf.setColor(stderr, .yellow); | ||
| 711 | } | ||
| 712 | try stderr.writeAll("\n"); | ||
| 713 | try ttyconf.setColor(stderr, .reset); | ||
| 714 | }, | ||
| 715 | .failure => try printStepFailure(s, stderr, ttyconf), | ||
| 716 | } | ||
| 717 | } | ||
| 718 | |||
| 719 | fn printStepFailure( | ||
| 720 | s: *Step, | ||
| 721 | stderr: File, | ||
| 722 | ttyconf: std.io.tty.Config, | ||
| 723 | ) !void { | ||
| 724 | if (s.result_error_bundle.errorMessageCount() > 0) { | ||
| 725 | try ttyconf.setColor(stderr, .red); | ||
| 726 | try stderr.writer().print(" {d} errors\n", .{ | ||
| 727 | s.result_error_bundle.errorMessageCount(), | ||
| 728 | }); | ||
| 729 | try ttyconf.setColor(stderr, .reset); | ||
| 730 | } else if (!s.test_results.isSuccess()) { | ||
| 731 | try stderr.writer().print(" {d}/{d} passed", .{ | ||
| 732 | s.test_results.passCount(), s.test_results.test_count, | ||
| 733 | }); | ||
| 734 | if (s.test_results.fail_count > 0) { | ||
| 735 | try stderr.writeAll(", "); | ||
| 736 | try ttyconf.setColor(stderr, .red); | ||
| 737 | try stderr.writer().print("{d} failed", .{ | ||
| 738 | s.test_results.fail_count, | ||
| 739 | }); | ||
| 740 | try ttyconf.setColor(stderr, .reset); | ||
| 741 | } | ||
| 742 | if (s.test_results.skip_count > 0) { | ||
| 743 | try stderr.writeAll(", "); | ||
| 744 | try ttyconf.setColor(stderr, .yellow); | ||
| 745 | try stderr.writer().print("{d} skipped", .{ | ||
| 746 | s.test_results.skip_count, | ||
| 747 | }); | ||
| 748 | try ttyconf.setColor(stderr, .reset); | ||
| 749 | } | ||
| 750 | if (s.test_results.leak_count > 0) { | ||
| 751 | try stderr.writeAll(", "); | ||
| 752 | try ttyconf.setColor(stderr, .red); | ||
| 753 | try stderr.writer().print("{d} leaked", .{ | ||
| 754 | s.test_results.leak_count, | ||
| 755 | }); | ||
| 756 | try ttyconf.setColor(stderr, .reset); | ||
| 757 | } | ||
| 758 | try stderr.writeAll("\n"); | ||
| 759 | } else if (s.result_error_msgs.items.len > 0) { | ||
| 760 | try ttyconf.setColor(stderr, .red); | ||
| 761 | try stderr.writeAll(" failure\n"); | ||
| 762 | try ttyconf.setColor(stderr, .reset); | ||
| 763 | } else { | ||
| 764 | assert(s.result_stderr.len > 0); | ||
| 765 | try ttyconf.setColor(stderr, .red); | ||
| 766 | try stderr.writeAll(" stderr\n"); | ||
| 767 | try ttyconf.setColor(stderr, .reset); | ||
| 768 | } | ||
| 769 | } | ||
| 770 | |||
| 771 | fn printTreeStep( | ||
| 772 | b: *std.Build, | ||
| 773 | s: *Step, | ||
| 774 | run: *const Run, | ||
| 775 | stderr: File, | ||
| 776 | ttyconf: std.io.tty.Config, | ||
| 777 | parent_node: *PrintNode, | ||
| 778 | step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void), | ||
| 779 | ) !void { | ||
| 780 | const first = step_stack.swapRemove(s); | ||
| 781 | const summary = run.summary orelse .failures; | ||
| 782 | const skip = switch (summary) { | ||
| 783 | .none => unreachable, | ||
| 784 | .all => false, | ||
| 785 | .new => s.result_cached, | ||
| 786 | .failures => s.state == .success, | ||
| 787 | }; | ||
| 788 | if (skip) return; | ||
| 789 | try printPrefix(parent_node, stderr, ttyconf); | ||
| 790 | |||
| 791 | if (!first) try ttyconf.setColor(stderr, .dim); | ||
| 792 | if (parent_node.parent != null) { | ||
| 793 | if (parent_node.last) { | ||
| 794 | try printChildNodePrefix(stderr, ttyconf); | ||
| 795 | } else { | ||
| 796 | try stderr.writeAll(switch (ttyconf) { | ||
| 797 | .no_color, .windows_api => "+- ", | ||
| 798 | .escape_codes => "\x1B\x28\x30\x74\x71\x1B\x28\x42 ", // ├─ | ||
| 799 | }); | ||
| 800 | } | ||
| 801 | } | ||
| 802 | |||
| 803 | // dep_prefix omitted here because it is redundant with the tree. | ||
| 804 | try stderr.writeAll(s.name); | ||
| 805 | |||
| 806 | if (first) { | ||
| 807 | try printStepStatus(s, stderr, ttyconf, run); | ||
| 808 | |||
| 809 | const last_index = if (summary == .all) s.dependencies.items.len -| 1 else blk: { | ||
| 810 | var i: usize = s.dependencies.items.len; | ||
| 811 | while (i > 0) { | ||
| 812 | i -= 1; | ||
| 813 | |||
| 814 | const step = s.dependencies.items[i]; | ||
| 815 | const found = switch (summary) { | ||
| 816 | .all, .none => unreachable, | ||
| 817 | .failures => step.state != .success, | ||
| 818 | .new => !step.result_cached, | ||
| 819 | }; | ||
| 820 | if (found) break :blk i; | ||
| 821 | } | ||
| 822 | break :blk s.dependencies.items.len -| 1; | ||
| 823 | }; | ||
| 824 | for (s.dependencies.items, 0..) |dep, i| { | ||
| 825 | var print_node: PrintNode = .{ | ||
| 826 | .parent = parent_node, | ||
| 827 | .last = i == last_index, | ||
| 828 | }; | ||
| 829 | try printTreeStep(b, dep, run, stderr, ttyconf, &print_node, step_stack); | ||
| 830 | } | ||
| 831 | } else { | ||
| 832 | if (s.dependencies.items.len == 0) { | ||
| 833 | try stderr.writeAll(" (reused)\n"); | ||
| 834 | } else { | ||
| 835 | try stderr.writer().print(" (+{d} more reused dependencies)\n", .{ | ||
| 836 | s.dependencies.items.len, | ||
| 837 | }); | ||
| 838 | } | ||
| 839 | try ttyconf.setColor(stderr, .reset); | ||
| 840 | } | ||
| 841 | } | ||
| 842 | |||
| 843 | /// Traverse the dependency graph depth-first and make it undirected by having | ||
| 844 | /// steps know their dependants (they only know dependencies at start). | ||
| 845 | /// Along the way, check that there is no dependency loop, and record the steps | ||
| 846 | /// in traversal order in `step_stack`. | ||
| 847 | /// Each step has its dependencies traversed in random order, this accomplishes | ||
| 848 | /// two things: | ||
| 849 | /// - `step_stack` will be in randomized-depth-first order, so the build runner | ||
| 850 | /// spawns steps in a random (but optimized) order | ||
| 851 | /// - each step's `dependants` list is also filled in a random order, so that | ||
| 852 | /// when it finishes executing in `workerMakeOneStep`, it spawns next steps | ||
| 853 | /// to run in random order | ||
| 854 | fn constructGraphAndCheckForDependencyLoop( | ||
| 855 | b: *std.Build, | ||
| 856 | s: *Step, | ||
| 857 | step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void), | ||
| 858 | rand: std.Random, | ||
| 859 | ) !void { | ||
| 860 | switch (s.state) { | ||
| 861 | .precheck_started => { | ||
| 862 | std.debug.print("dependency loop detected:\n {s}\n", .{s.name}); | ||
| 863 | return error.DependencyLoopDetected; | ||
| 864 | }, | ||
| 865 | .precheck_unstarted => { | ||
| 866 | s.state = .precheck_started; | ||
| 867 | |||
| 868 | try step_stack.ensureUnusedCapacity(b.allocator, s.dependencies.items.len); | ||
| 869 | |||
| 870 | // We dupe to avoid shuffling the steps in the summary, it depends | ||
| 871 | // on s.dependencies' order. | ||
| 872 | const deps = b.allocator.dupe(*Step, s.dependencies.items) catch @panic("OOM"); | ||
| 873 | rand.shuffle(*Step, deps); | ||
| 874 | |||
| 875 | for (deps) |dep| { | ||
| 876 | try step_stack.put(b.allocator, dep, {}); | ||
| 877 | try dep.dependants.append(b.allocator, s); | ||
| 878 | constructGraphAndCheckForDependencyLoop(b, dep, step_stack, rand) catch |err| { | ||
| 879 | if (err == error.DependencyLoopDetected) { | ||
| 880 | std.debug.print(" {s}\n", .{s.name}); | ||
| 881 | } | ||
| 882 | return err; | ||
| 883 | }; | ||
| 884 | } | ||
| 885 | |||
| 886 | s.state = .precheck_done; | ||
| 887 | }, | ||
| 888 | .precheck_done => {}, | ||
| 889 | |||
| 890 | // These don't happen until we actually run the step graph. | ||
| 891 | .dependency_failure => unreachable, | ||
| 892 | .running => unreachable, | ||
| 893 | .success => unreachable, | ||
| 894 | .failure => unreachable, | ||
| 895 | .skipped => unreachable, | ||
| 896 | .skipped_oom => unreachable, | ||
| 897 | } | ||
| 898 | } | ||
| 899 | |||
| 900 | fn workerMakeOneStep( | ||
| 901 | wg: *std.Thread.WaitGroup, | ||
| 902 | thread_pool: *std.Thread.Pool, | ||
| 903 | b: *std.Build, | ||
| 904 | s: *Step, | ||
| 905 | prog_node: *std.Progress.Node, | ||
| 906 | run: *Run, | ||
| 907 | ) void { | ||
| 908 | defer wg.finish(); | ||
| 909 | |||
| 910 | // First, check the conditions for running this step. If they are not met, | ||
| 911 | // then we return without doing the step, relying on another worker to | ||
| 912 | // queue this step up again when dependencies are met. | ||
| 913 | for (s.dependencies.items) |dep| { | ||
| 914 | switch (@atomicLoad(Step.State, &dep.state, .seq_cst)) { | ||
| 915 | .success, .skipped => continue, | ||
| 916 | .failure, .dependency_failure, .skipped_oom => { | ||
| 917 | @atomicStore(Step.State, &s.state, .dependency_failure, .seq_cst); | ||
| 918 | return; | ||
| 919 | }, | ||
| 920 | .precheck_done, .running => { | ||
| 921 | // dependency is not finished yet. | ||
| 922 | return; | ||
| 923 | }, | ||
| 924 | .precheck_unstarted => unreachable, | ||
| 925 | .precheck_started => unreachable, | ||
| 926 | } | ||
| 927 | } | ||
| 928 | |||
| 929 | if (s.max_rss != 0) { | ||
| 930 | run.max_rss_mutex.lock(); | ||
| 931 | defer run.max_rss_mutex.unlock(); | ||
| 932 | |||
| 933 | // Avoid running steps twice. | ||
| 934 | if (s.state != .precheck_done) { | ||
| 935 | // Another worker got the job. | ||
| 936 | return; | ||
| 937 | } | ||
| 938 | |||
| 939 | const new_claimed_rss = run.claimed_rss + s.max_rss; | ||
| 940 | if (new_claimed_rss > run.max_rss) { | ||
| 941 | // Running this step right now could possibly exceed the allotted RSS. | ||
| 942 | // Add this step to the queue of memory-blocked steps. | ||
| 943 | run.memory_blocked_steps.append(s) catch @panic("OOM"); | ||
| 944 | return; | ||
| 945 | } | ||
| 946 | |||
| 947 | run.claimed_rss = new_claimed_rss; | ||
| 948 | s.state = .running; | ||
| 949 | } else { | ||
| 950 | // Avoid running steps twice. | ||
| 951 | if (@cmpxchgStrong(Step.State, &s.state, .precheck_done, .running, .seq_cst, .seq_cst) != null) { | ||
| 952 | // Another worker got the job. | ||
| 953 | return; | ||
| 954 | } | ||
| 955 | } | ||
| 956 | |||
| 957 | var sub_prog_node = prog_node.start(s.name, 0); | ||
| 958 | sub_prog_node.activate(); | ||
| 959 | defer sub_prog_node.end(); | ||
| 960 | |||
| 961 | const make_result = s.make(&sub_prog_node); | ||
| 962 | |||
| 963 | // No matter the result, we want to display error/warning messages. | ||
| 964 | const show_compile_errors = !run.prominent_compile_errors and | ||
| 965 | s.result_error_bundle.errorMessageCount() > 0; | ||
| 966 | const show_error_msgs = s.result_error_msgs.items.len > 0; | ||
| 967 | const show_stderr = s.result_stderr.len > 0; | ||
| 968 | |||
| 969 | if (show_error_msgs or show_compile_errors or show_stderr) { | ||
| 970 | sub_prog_node.context.lock_stderr(); | ||
| 971 | defer sub_prog_node.context.unlock_stderr(); | ||
| 972 | |||
| 973 | printErrorMessages(b, s, run) catch {}; | ||
| 974 | } | ||
| 975 | |||
| 976 | handle_result: { | ||
| 977 | if (make_result) |_| { | ||
| 978 | @atomicStore(Step.State, &s.state, .success, .seq_cst); | ||
| 979 | } else |err| switch (err) { | ||
| 980 | error.MakeFailed => { | ||
| 981 | @atomicStore(Step.State, &s.state, .failure, .seq_cst); | ||
| 982 | break :handle_result; | ||
| 983 | }, | ||
| 984 | error.MakeSkipped => @atomicStore(Step.State, &s.state, .skipped, .seq_cst), | ||
| 985 | } | ||
| 986 | |||
| 987 | // Successful completion of a step, so we queue up its dependants as well. | ||
| 988 | for (s.dependants.items) |dep| { | ||
| 989 | wg.start(); | ||
| 990 | thread_pool.spawn(workerMakeOneStep, .{ | ||
| 991 | wg, thread_pool, b, dep, prog_node, run, | ||
| 992 | }) catch @panic("OOM"); | ||
| 993 | } | ||
| 994 | } | ||
| 995 | |||
| 996 | // If this is a step that claims resources, we must now queue up other | ||
| 997 | // steps that are waiting for resources. | ||
| 998 | if (s.max_rss != 0) { | ||
| 999 | run.max_rss_mutex.lock(); | ||
| 1000 | defer run.max_rss_mutex.unlock(); | ||
| 1001 | |||
| 1002 | // Give the memory back to the scheduler. | ||
| 1003 | run.claimed_rss -= s.max_rss; | ||
| 1004 | // Avoid kicking off too many tasks that we already know will not have | ||
| 1005 | // enough resources. | ||
| 1006 | var remaining = run.max_rss - run.claimed_rss; | ||
| 1007 | var i: usize = 0; | ||
| 1008 | var j: usize = 0; | ||
| 1009 | while (j < run.memory_blocked_steps.items.len) : (j += 1) { | ||
| 1010 | const dep = run.memory_blocked_steps.items[j]; | ||
| 1011 | assert(dep.max_rss != 0); | ||
| 1012 | if (dep.max_rss <= remaining) { | ||
| 1013 | remaining -= dep.max_rss; | ||
| 1014 | |||
| 1015 | wg.start(); | ||
| 1016 | thread_pool.spawn(workerMakeOneStep, .{ | ||
| 1017 | wg, thread_pool, b, dep, prog_node, run, | ||
| 1018 | }) catch @panic("OOM"); | ||
| 1019 | } else { | ||
| 1020 | run.memory_blocked_steps.items[i] = dep; | ||
| 1021 | i += 1; | ||
| 1022 | } | ||
| 1023 | } | ||
| 1024 | run.memory_blocked_steps.shrinkRetainingCapacity(i); | ||
| 1025 | } | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | fn printErrorMessages(b: *std.Build, failing_step: *Step, run: *const Run) !void { | ||
| 1029 | const gpa = b.allocator; | ||
| 1030 | const stderr = run.stderr; | ||
| 1031 | const ttyconf = run.ttyconf; | ||
| 1032 | |||
| 1033 | // Provide context for where these error messages are coming from by | ||
| 1034 | // printing the corresponding Step subtree. | ||
| 1035 | |||
| 1036 | var step_stack: std.ArrayListUnmanaged(*Step) = .{}; | ||
| 1037 | defer step_stack.deinit(gpa); | ||
| 1038 | try step_stack.append(gpa, failing_step); | ||
| 1039 | while (step_stack.items[step_stack.items.len - 1].dependants.items.len != 0) { | ||
| 1040 | try step_stack.append(gpa, step_stack.items[step_stack.items.len - 1].dependants.items[0]); | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | // Now, `step_stack` has the subtree that we want to print, in reverse order. | ||
| 1044 | try ttyconf.setColor(stderr, .dim); | ||
| 1045 | var indent: usize = 0; | ||
| 1046 | while (step_stack.popOrNull()) |s| : (indent += 1) { | ||
| 1047 | if (indent > 0) { | ||
| 1048 | try stderr.writer().writeByteNTimes(' ', (indent - 1) * 3); | ||
| 1049 | try printChildNodePrefix(stderr, ttyconf); | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | try stderr.writeAll(s.name); | ||
| 1053 | |||
| 1054 | if (s == failing_step) { | ||
| 1055 | try printStepFailure(s, stderr, ttyconf); | ||
| 1056 | } else { | ||
| 1057 | try stderr.writeAll("\n"); | ||
| 1058 | } | ||
| 1059 | } | ||
| 1060 | try ttyconf.setColor(stderr, .reset); | ||
| 1061 | |||
| 1062 | if (failing_step.result_stderr.len > 0) { | ||
| 1063 | try stderr.writeAll(failing_step.result_stderr); | ||
| 1064 | if (!mem.endsWith(u8, failing_step.result_stderr, "\n")) { | ||
| 1065 | try stderr.writeAll("\n"); | ||
| 1066 | } | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | if (!run.prominent_compile_errors and failing_step.result_error_bundle.errorMessageCount() > 0) | ||
| 1070 | try failing_step.result_error_bundle.renderToWriter(renderOptions(ttyconf), stderr.writer()); | ||
| 1071 | |||
| 1072 | for (failing_step.result_error_msgs.items) |msg| { | ||
| 1073 | try ttyconf.setColor(stderr, .red); | ||
| 1074 | try stderr.writeAll("error: "); | ||
| 1075 | try ttyconf.setColor(stderr, .reset); | ||
| 1076 | try stderr.writeAll(msg); | ||
| 1077 | try stderr.writeAll("\n"); | ||
| 1078 | } | ||
| 1079 | } | ||
| 1080 | |||
| 1081 | fn steps(builder: *std.Build, out_stream: anytype) !void { | ||
| 1082 | const allocator = builder.allocator; | ||
| 1083 | for (builder.top_level_steps.values()) |top_level_step| { | ||
| 1084 | const name = if (&top_level_step.step == builder.default_step) | ||
| 1085 | try fmt.allocPrint(allocator, "{s} (default)", .{top_level_step.step.name}) | ||
| 1086 | else | ||
| 1087 | top_level_step.step.name; | ||
| 1088 | try out_stream.print(" {s:<28} {s}\n", .{ name, top_level_step.description }); | ||
| 1089 | } | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | fn usage(b: *std.Build, out_stream: anytype) !void { | ||
| 1093 | try out_stream.print( | ||
| 1094 | \\Usage: {s} build [steps] [options] | ||
| 1095 | \\ | ||
| 1096 | \\Steps: | ||
| 1097 | \\ | ||
| 1098 | , .{b.graph.zig_exe}); | ||
| 1099 | try steps(b, out_stream); | ||
| 1100 | |||
| 1101 | try out_stream.writeAll( | ||
| 1102 | \\ | ||
| 1103 | \\General Options: | ||
| 1104 | \\ -p, --prefix [path] Where to install files (default: zig-out) | ||
| 1105 | \\ --prefix-lib-dir [path] Where to install libraries | ||
| 1106 | \\ --prefix-exe-dir [path] Where to install executables | ||
| 1107 | \\ --prefix-include-dir [path] Where to install C header files | ||
| 1108 | \\ | ||
| 1109 | \\ --release[=mode] Request release mode, optionally specifying a | ||
| 1110 | \\ preferred optimization mode: fast, safe, small | ||
| 1111 | \\ | ||
| 1112 | \\ -fdarling, -fno-darling Integration with system-installed Darling to | ||
| 1113 | \\ execute macOS programs on Linux hosts | ||
| 1114 | \\ (default: no) | ||
| 1115 | \\ -fqemu, -fno-qemu Integration with system-installed QEMU to execute | ||
| 1116 | \\ foreign-architecture programs on Linux hosts | ||
| 1117 | \\ (default: no) | ||
| 1118 | \\ --glibc-runtimes [path] Enhances QEMU integration by providing glibc built | ||
| 1119 | \\ for multiple foreign architectures, allowing | ||
| 1120 | \\ execution of non-native programs that link with glibc. | ||
| 1121 | \\ -frosetta, -fno-rosetta Rely on Rosetta to execute x86_64 programs on | ||
| 1122 | \\ ARM64 macOS hosts. (default: no) | ||
| 1123 | \\ -fwasmtime, -fno-wasmtime Integration with system-installed wasmtime to | ||
| 1124 | \\ execute WASI binaries. (default: no) | ||
| 1125 | \\ -fwine, -fno-wine Integration with system-installed Wine to execute | ||
| 1126 | \\ Windows programs on Linux hosts. (default: no) | ||
| 1127 | \\ | ||
| 1128 | \\ -h, --help Print this help and exit | ||
| 1129 | \\ -l, --list-steps Print available steps | ||
| 1130 | \\ --verbose Print commands before executing them | ||
| 1131 | \\ --color [auto|off|on] Enable or disable colored error messages | ||
| 1132 | \\ --prominent-compile-errors Buffer compile errors and display at end | ||
| 1133 | \\ --summary [mode] Control the printing of the build summary | ||
| 1134 | \\ all Print the build summary in its entirety | ||
| 1135 | \\ new Omit cached steps | ||
| 1136 | \\ failures (Default) Only print failed steps | ||
| 1137 | \\ none Do not print the build summary | ||
| 1138 | \\ -j<N> Limit concurrent jobs (default is to use all CPU cores) | ||
| 1139 | \\ --maxrss <bytes> Limit memory usage (default is to use available memory) | ||
| 1140 | \\ --skip-oom-steps Instead of failing, skip steps that would exceed --maxrss | ||
| 1141 | \\ --fetch Exit after fetching dependency tree | ||
| 1142 | \\ | ||
| 1143 | \\Project-Specific Options: | ||
| 1144 | \\ | ||
| 1145 | ); | ||
| 1146 | |||
| 1147 | const arena = b.allocator; | ||
| 1148 | if (b.available_options_list.items.len == 0) { | ||
| 1149 | try out_stream.print(" (none)\n", .{}); | ||
| 1150 | } else { | ||
| 1151 | for (b.available_options_list.items) |option| { | ||
| 1152 | const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{ | ||
| 1153 | option.name, | ||
| 1154 | @tagName(option.type_id), | ||
| 1155 | }); | ||
| 1156 | try out_stream.print("{s:<30} {s}\n", .{ name, option.description }); | ||
| 1157 | if (option.enum_options) |enum_options| { | ||
| 1158 | const padding = " " ** 33; | ||
| 1159 | try out_stream.writeAll(padding ++ "Supported Values:\n"); | ||
| 1160 | for (enum_options) |enum_option| { | ||
| 1161 | try out_stream.print(padding ++ " {s}\n", .{enum_option}); | ||
| 1162 | } | ||
| 1163 | } | ||
| 1164 | } | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | try out_stream.writeAll( | ||
| 1168 | \\ | ||
| 1169 | \\System Integration Options: | ||
| 1170 | \\ --search-prefix [path] Add a path to look for binaries, libraries, headers | ||
| 1171 | \\ --sysroot [path] Set the system root directory (usually /) | ||
| 1172 | \\ --libc [file] Provide a file which specifies libc paths | ||
| 1173 | \\ | ||
| 1174 | \\ --host-target [triple] Use the provided target as the host | ||
| 1175 | \\ --host-cpu [cpu] Use the provided CPU as the host | ||
| 1176 | \\ --host-dynamic-linker [path] Use the provided dynamic linker as the host | ||
| 1177 | \\ | ||
| 1178 | \\ --system [pkgdir] Disable package fetching; enable all integrations | ||
| 1179 | \\ -fsys=[name] Enable a system integration | ||
| 1180 | \\ -fno-sys=[name] Disable a system integration | ||
| 1181 | \\ | ||
| 1182 | \\ Available System Integrations: Enabled: | ||
| 1183 | \\ | ||
| 1184 | ); | ||
| 1185 | if (b.graph.system_library_options.entries.len == 0) { | ||
| 1186 | try out_stream.writeAll(" (none) -\n"); | ||
| 1187 | } else { | ||
| 1188 | for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| { | ||
| 1189 | const status = switch (v) { | ||
| 1190 | .declared_enabled => "yes", | ||
| 1191 | .declared_disabled => "no", | ||
| 1192 | .user_enabled, .user_disabled => unreachable, // already emitted error | ||
| 1193 | }; | ||
| 1194 | try out_stream.print(" {s:<43} {s}\n", .{ k, status }); | ||
| 1195 | } | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | try out_stream.writeAll( | ||
| 1199 | \\ | ||
| 1200 | \\Advanced Options: | ||
| 1201 | \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error | ||
| 1202 | \\ -fno-reference-trace Disable reference trace | ||
| 1203 | \\ --build-file [file] Override path to build.zig | ||
| 1204 | \\ --cache-dir [path] Override path to local Zig cache directory | ||
| 1205 | \\ --global-cache-dir [path] Override path to global Zig cache directory | ||
| 1206 | \\ --zig-lib-dir [arg] Override path to Zig lib directory | ||
| 1207 | \\ --build-runner [file] Override path to build runner | ||
| 1208 | \\ --seed [integer] For shuffling dependency traversal order (default: random) | ||
| 1209 | \\ --debug-log [scope] Enable debugging the compiler | ||
| 1210 | \\ --debug-pkg-config Fail if unknown pkg-config flags encountered | ||
| 1211 | \\ --verbose-link Enable compiler debug output for linking | ||
| 1212 | \\ --verbose-air Enable compiler debug output for Zig AIR | ||
| 1213 | \\ --verbose-llvm-ir[=file] Enable compiler debug output for LLVM IR | ||
| 1214 | \\ --verbose-llvm-bc=[file] Enable compiler debug output for LLVM BC | ||
| 1215 | \\ --verbose-cimport Enable compiler debug output for C imports | ||
| 1216 | \\ --verbose-cc Enable compiler debug output for C compilation | ||
| 1217 | \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features | ||
| 1218 | \\ | ||
| 1219 | ); | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | fn nextArg(args: [][:0]const u8, idx: *usize) ?[:0]const u8 { | ||
| 1223 | if (idx.* >= args.len) return null; | ||
| 1224 | defer idx.* += 1; | ||
| 1225 | return args[idx.*]; | ||
| 1226 | } | ||
| 1227 | |||
| 1228 | fn nextArgOrFatal(args: [][:0]const u8, idx: *usize) [:0]const u8 { | ||
| 1229 | return nextArg(args, idx) orelse { | ||
| 1230 | std.debug.print("expected argument after '{s}'\n access the help menu with 'zig build -h'\n", .{args[idx.*]}); | ||
| 1231 | process.exit(1); | ||
| 1232 | }; | ||
| 1233 | } | ||
| 1234 | |||
| 1235 | fn argsRest(args: [][:0]const u8, idx: usize) ?[][:0]const u8 { | ||
| 1236 | if (idx >= args.len) return null; | ||
| 1237 | return args[idx..]; | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | fn cleanExit() void { | ||
| 1241 | // Perhaps in the future there could be an Advanced Options flag such as | ||
| 1242 | // --debug-build-runner-leaks which would make this function return instead | ||
| 1243 | // of calling exit. | ||
| 1244 | process.exit(0); | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | const Color = enum { auto, off, on }; | ||
| 1248 | const Summary = enum { all, new, failures, none }; | ||
| 1249 | |||
| 1250 | fn get_tty_conf(color: Color, stderr: File) std.io.tty.Config { | ||
| 1251 | return switch (color) { | ||
| 1252 | .auto => std.io.tty.detectConfig(stderr), | ||
| 1253 | .on => .escape_codes, | ||
| 1254 | .off => .no_color, | ||
| 1255 | }; | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | fn renderOptions(ttyconf: std.io.tty.Config) std.zig.ErrorBundle.RenderOptions { | ||
| 1259 | return .{ | ||
| 1260 | .ttyconf = ttyconf, | ||
| 1261 | .include_source_line = ttyconf != .no_color, | ||
| 1262 | .include_reference_trace = ttyconf != .no_color, | ||
| 1263 | }; | ||
| 1264 | } | ||
| 1265 | |||
| 1266 | fn fatalWithHint(comptime f: []const u8, args: anytype) noreturn { | ||
| 1267 | std.debug.print(f ++ "\n access the help menu with 'zig build -h'\n", args); | ||
| 1268 | process.exit(1); | ||
| 1269 | } | ||
| 1270 | |||
| 1271 | fn fatal(comptime f: []const u8, args: anytype) noreturn { | ||
| 1272 | std.debug.print(f ++ "\n", args); | ||
| 1273 | process.exit(1); | ||
| 1274 | } | ||
| 1275 | |||
| 1276 | fn validateSystemLibraryOptions(b: *std.Build) void { | ||
| 1277 | var bad = false; | ||
| 1278 | for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| { | ||
| 1279 | switch (v) { | ||
| 1280 | .user_disabled, .user_enabled => { | ||
| 1281 | // The user tried to enable or disable a system library integration, but | ||
| 1282 | // the build script did not recognize that option. | ||
| 1283 | std.debug.print("system library name not recognized by build script: '{s}'\n", .{k}); | ||
| 1284 | bad = true; | ||
| 1285 | }, | ||
| 1286 | .declared_disabled, .declared_enabled => {}, | ||
| 1287 | } | ||
| 1288 | } | ||
| 1289 | if (bad) { | ||
| 1290 | std.debug.print(" access the help menu with 'zig build -h'\n", .{}); | ||
| 1291 | process.exit(1); | ||
| 1292 | } | ||
| 1293 | } | ||
lib/compiler/build_runner.zig created+1293| ... | @@ -0,0 +1,1293 @@ | ||
| 1 | const root = @import("@build"); | ||
| 2 | const std = @import("std"); | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | const assert = std.debug.assert; | ||
| 5 | const io = std.io; | ||
| 6 | const fmt = std.fmt; | ||
| 7 | const mem = std.mem; | ||
| 8 | const process = std.process; | ||
| 9 | const ArrayList = std.ArrayList; | ||
| 10 | const File = std.fs.File; | ||
| 11 | const Step = std.Build.Step; | ||
| 12 | |||
| 13 | pub const dependencies = @import("@dependencies"); | ||
| 14 | |||
| 15 | pub fn main() !void { | ||
| 16 | // Here we use an ArenaAllocator backed by a page allocator because a build is a short-lived, | ||
| 17 | // one shot program. We don't need to waste time freeing memory and finding places to squish | ||
| 18 | // bytes into. So we free everything all at once at the very end. | ||
| 19 | var single_threaded_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); | ||
| 20 | defer single_threaded_arena.deinit(); | ||
| 21 | |||
| 22 | var thread_safe_arena: std.heap.ThreadSafeAllocator = .{ | ||
| 23 | .child_allocator = single_threaded_arena.allocator(), | ||
| 24 | }; | ||
| 25 | const arena = thread_safe_arena.allocator(); | ||
| 26 | |||
| 27 | const args = try process.argsAlloc(arena); | ||
| 28 | |||
| 29 | // skip my own exe name | ||
| 30 | var arg_idx: usize = 1; | ||
| 31 | |||
| 32 | const zig_exe = nextArg(args, &arg_idx) orelse { | ||
| 33 | std.debug.print("Expected path to zig compiler\n", .{}); | ||
| 34 | return error.InvalidArgs; | ||
| 35 | }; | ||
| 36 | const build_root = nextArg(args, &arg_idx) orelse { | ||
| 37 | std.debug.print("Expected build root directory path\n", .{}); | ||
| 38 | return error.InvalidArgs; | ||
| 39 | }; | ||
| 40 | const cache_root = nextArg(args, &arg_idx) orelse { | ||
| 41 | std.debug.print("Expected cache root directory path\n", .{}); | ||
| 42 | return error.InvalidArgs; | ||
| 43 | }; | ||
| 44 | const global_cache_root = nextArg(args, &arg_idx) orelse { | ||
| 45 | std.debug.print("Expected global cache root directory path\n", .{}); | ||
| 46 | return error.InvalidArgs; | ||
| 47 | }; | ||
| 48 | |||
| 49 | const build_root_directory: std.Build.Cache.Directory = .{ | ||
| 50 | .path = build_root, | ||
| 51 | .handle = try std.fs.cwd().openDir(build_root, .{}), | ||
| 52 | }; | ||
| 53 | |||
| 54 | const local_cache_directory: std.Build.Cache.Directory = .{ | ||
| 55 | .path = cache_root, | ||
| 56 | .handle = try std.fs.cwd().makeOpenPath(cache_root, .{}), | ||
| 57 | }; | ||
| 58 | |||
| 59 | const global_cache_directory: std.Build.Cache.Directory = .{ | ||
| 60 | .path = global_cache_root, | ||
| 61 | .handle = try std.fs.cwd().makeOpenPath(global_cache_root, .{}), | ||
| 62 | }; | ||
| 63 | |||
| 64 | var graph: std.Build.Graph = .{ | ||
| 65 | .arena = arena, | ||
| 66 | .cache = .{ | ||
| 67 | .gpa = arena, | ||
| 68 | .manifest_dir = try local_cache_directory.handle.makeOpenPath("h", .{}), | ||
| 69 | }, | ||
| 70 | .zig_exe = zig_exe, | ||
| 71 | .env_map = try process.getEnvMap(arena), | ||
| 72 | .global_cache_root = global_cache_directory, | ||
| 73 | }; | ||
| 74 | |||
| 75 | graph.cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() }); | ||
| 76 | graph.cache.addPrefix(build_root_directory); | ||
| 77 | graph.cache.addPrefix(local_cache_directory); | ||
| 78 | graph.cache.addPrefix(global_cache_directory); | ||
| 79 | graph.cache.hash.addBytes(builtin.zig_version_string); | ||
| 80 | |||
| 81 | const builder = try std.Build.create( | ||
| 82 | &graph, | ||
| 83 | build_root_directory, | ||
| 84 | local_cache_directory, | ||
| 85 | dependencies.root_deps, | ||
| 86 | ); | ||
| 87 | |||
| 88 | var targets = ArrayList([]const u8).init(arena); | ||
| 89 | var debug_log_scopes = ArrayList([]const u8).init(arena); | ||
| 90 | var thread_pool_options: std.Thread.Pool.Options = .{ .allocator = arena }; | ||
| 91 | |||
| 92 | var install_prefix: ?[]const u8 = null; | ||
| 93 | var dir_list = std.Build.DirList{}; | ||
| 94 | var summary: ?Summary = null; | ||
| 95 | var max_rss: u64 = 0; | ||
| 96 | var skip_oom_steps: bool = false; | ||
| 97 | var color: Color = .auto; | ||
| 98 | var seed: u32 = 0; | ||
| 99 | var prominent_compile_errors: bool = false; | ||
| 100 | var help_menu: bool = false; | ||
| 101 | var steps_menu: bool = false; | ||
| 102 | var output_tmp_nonce: ?[16]u8 = null; | ||
| 103 | |||
| 104 | while (nextArg(args, &arg_idx)) |arg| { | ||
| 105 | if (mem.startsWith(u8, arg, "-Z")) { | ||
| 106 | if (arg.len != 18) fatalWithHint("bad argument: '{s}'", .{arg}); | ||
| 107 | output_tmp_nonce = arg[2..18].*; | ||
| 108 | } else if (mem.startsWith(u8, arg, "-D")) { | ||
| 109 | const option_contents = arg[2..]; | ||
| 110 | if (option_contents.len == 0) | ||
| 111 | fatalWithHint("expected option name after '-D'", .{}); | ||
| 112 | if (mem.indexOfScalar(u8, option_contents, '=')) |name_end| { | ||
| 113 | const option_name = option_contents[0..name_end]; | ||
| 114 | const option_value = option_contents[name_end + 1 ..]; | ||
| 115 | if (try builder.addUserInputOption(option_name, option_value)) | ||
| 116 | fatal(" access the help menu with 'zig build -h'", .{}); | ||
| 117 | } else { | ||
| 118 | if (try builder.addUserInputFlag(option_contents)) | ||
| 119 | fatal(" access the help menu with 'zig build -h'", .{}); | ||
| 120 | } | ||
| 121 | } else if (mem.startsWith(u8, arg, "-")) { | ||
| 122 | if (mem.eql(u8, arg, "--verbose")) { | ||
| 123 | builder.verbose = true; | ||
| 124 | } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) { | ||
| 125 | help_menu = true; | ||
| 126 | } else if (mem.eql(u8, arg, "-p") or mem.eql(u8, arg, "--prefix")) { | ||
| 127 | install_prefix = nextArgOrFatal(args, &arg_idx); | ||
| 128 | } else if (mem.eql(u8, arg, "-l") or mem.eql(u8, arg, "--list-steps")) { | ||
| 129 | steps_menu = true; | ||
| 130 | } else if (mem.startsWith(u8, arg, "-fsys=")) { | ||
| 131 | const name = arg["-fsys=".len..]; | ||
| 132 | graph.system_library_options.put(arena, name, .user_enabled) catch @panic("OOM"); | ||
| 133 | } else if (mem.startsWith(u8, arg, "-fno-sys=")) { | ||
| 134 | const name = arg["-fno-sys=".len..]; | ||
| 135 | graph.system_library_options.put(arena, name, .user_disabled) catch @panic("OOM"); | ||
| 136 | } else if (mem.eql(u8, arg, "--release")) { | ||
| 137 | builder.release_mode = .any; | ||
| 138 | } else if (mem.startsWith(u8, arg, "--release=")) { | ||
| 139 | const text = arg["--release=".len..]; | ||
| 140 | builder.release_mode = std.meta.stringToEnum(std.Build.ReleaseMode, text) orelse { | ||
| 141 | fatalWithHint("expected [off|any|fast|safe|small] in '{s}', found '{s}'", .{ | ||
| 142 | arg, text, | ||
| 143 | }); | ||
| 144 | }; | ||
| 145 | } else if (mem.eql(u8, arg, "--host-target")) { | ||
| 146 | graph.host_query_options.arch_os_abi = nextArgOrFatal(args, &arg_idx); | ||
| 147 | } else if (mem.eql(u8, arg, "--host-cpu")) { | ||
| 148 | graph.host_query_options.cpu_features = nextArgOrFatal(args, &arg_idx); | ||
| 149 | } else if (mem.eql(u8, arg, "--host-dynamic-linker")) { | ||
| 150 | graph.host_query_options.dynamic_linker = nextArgOrFatal(args, &arg_idx); | ||
| 151 | } else if (mem.eql(u8, arg, "--prefix-lib-dir")) { | ||
| 152 | dir_list.lib_dir = nextArgOrFatal(args, &arg_idx); | ||
| 153 | } else if (mem.eql(u8, arg, "--prefix-exe-dir")) { | ||
| 154 | dir_list.exe_dir = nextArgOrFatal(args, &arg_idx); | ||
| 155 | } else if (mem.eql(u8, arg, "--prefix-include-dir")) { | ||
| 156 | dir_list.include_dir = nextArgOrFatal(args, &arg_idx); | ||
| 157 | } else if (mem.eql(u8, arg, "--sysroot")) { | ||
| 158 | builder.sysroot = nextArgOrFatal(args, &arg_idx); | ||
| 159 | } else if (mem.eql(u8, arg, "--maxrss")) { | ||
| 160 | const max_rss_text = nextArgOrFatal(args, &arg_idx); | ||
| 161 | max_rss = std.fmt.parseIntSizeSuffix(max_rss_text, 10) catch |err| { | ||
| 162 | std.debug.print("invalid byte size: '{s}': {s}\n", .{ | ||
| 163 | max_rss_text, @errorName(err), | ||
| 164 | }); | ||
| 165 | process.exit(1); | ||
| 166 | }; | ||
| 167 | } else if (mem.eql(u8, arg, "--skip-oom-steps")) { | ||
| 168 | skip_oom_steps = true; | ||
| 169 | } else if (mem.eql(u8, arg, "--search-prefix")) { | ||
| 170 | const search_prefix = nextArgOrFatal(args, &arg_idx); | ||
| 171 | builder.addSearchPrefix(search_prefix); | ||
| 172 | } else if (mem.eql(u8, arg, "--libc")) { | ||
| 173 | builder.libc_file = nextArgOrFatal(args, &arg_idx); | ||
| 174 | } else if (mem.eql(u8, arg, "--color")) { | ||
| 175 | const next_arg = nextArg(args, &arg_idx) orelse | ||
| 176 | fatalWithHint("expected [auto|on|off] after '{s}'", .{arg}); | ||
| 177 | color = std.meta.stringToEnum(Color, next_arg) orelse { | ||
| 178 | fatalWithHint("expected [auto|on|off] after '{s}', found '{s}'", .{ | ||
| 179 | arg, next_arg, | ||
| 180 | }); | ||
| 181 | }; | ||
| 182 | } else if (mem.eql(u8, arg, "--summary")) { | ||
| 183 | const next_arg = nextArg(args, &arg_idx) orelse | ||
| 184 | fatalWithHint("expected [all|new|failures|none] after '{s}'", .{arg}); | ||
| 185 | summary = std.meta.stringToEnum(Summary, next_arg) orelse { | ||
| 186 | fatalWithHint("expected [all|failures|none] after '{s}', found '{s}'", .{ | ||
| 187 | arg, next_arg, | ||
| 188 | }); | ||
| 189 | }; | ||
| 190 | } else if (mem.eql(u8, arg, "--zig-lib-dir")) { | ||
| 191 | builder.zig_lib_dir = .{ .cwd_relative = nextArgOrFatal(args, &arg_idx) }; | ||
| 192 | } else if (mem.eql(u8, arg, "--seed")) { | ||
| 193 | const next_arg = nextArg(args, &arg_idx) orelse | ||
| 194 | fatalWithHint("expected u32 after '{s}'", .{arg}); | ||
| 195 | seed = std.fmt.parseUnsigned(u32, next_arg, 0) catch |err| { | ||
| 196 | fatal("unable to parse seed '{s}' as 32-bit integer: {s}\n", .{ | ||
| 197 | next_arg, @errorName(err), | ||
| 198 | }); | ||
| 199 | }; | ||
| 200 | } else if (mem.eql(u8, arg, "--debug-log")) { | ||
| 201 | const next_arg = nextArgOrFatal(args, &arg_idx); | ||
| 202 | try debug_log_scopes.append(next_arg); | ||
| 203 | } else if (mem.eql(u8, arg, "--debug-pkg-config")) { | ||
| 204 | builder.debug_pkg_config = true; | ||
| 205 | } else if (mem.eql(u8, arg, "--debug-compile-errors")) { | ||
| 206 | builder.debug_compile_errors = true; | ||
| 207 | } else if (mem.eql(u8, arg, "--system")) { | ||
| 208 | // The usage text shows another argument after this parameter | ||
| 209 | // but it is handled by the parent process. The build runner | ||
| 210 | // only sees this flag. | ||
| 211 | graph.system_package_mode = true; | ||
| 212 | } else if (mem.eql(u8, arg, "--glibc-runtimes")) { | ||
| 213 | builder.glibc_runtimes_dir = nextArgOrFatal(args, &arg_idx); | ||
| 214 | } else if (mem.eql(u8, arg, "--verbose-link")) { | ||
| 215 | builder.verbose_link = true; | ||
| 216 | } else if (mem.eql(u8, arg, "--verbose-air")) { | ||
| 217 | builder.verbose_air = true; | ||
| 218 | } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { | ||
| 219 | builder.verbose_llvm_ir = "-"; | ||
| 220 | } else if (mem.startsWith(u8, arg, "--verbose-llvm-ir=")) { | ||
| 221 | builder.verbose_llvm_ir = arg["--verbose-llvm-ir=".len..]; | ||
| 222 | } else if (mem.eql(u8, arg, "--verbose-llvm-bc=")) { | ||
| 223 | builder.verbose_llvm_bc = arg["--verbose-llvm-bc=".len..]; | ||
| 224 | } else if (mem.eql(u8, arg, "--verbose-cimport")) { | ||
| 225 | builder.verbose_cimport = true; | ||
| 226 | } else if (mem.eql(u8, arg, "--verbose-cc")) { | ||
| 227 | builder.verbose_cc = true; | ||
| 228 | } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) { | ||
| 229 | builder.verbose_llvm_cpu_features = true; | ||
| 230 | } else if (mem.eql(u8, arg, "--prominent-compile-errors")) { | ||
| 231 | prominent_compile_errors = true; | ||
| 232 | } else if (mem.eql(u8, arg, "-fwine")) { | ||
| 233 | builder.enable_wine = true; | ||
| 234 | } else if (mem.eql(u8, arg, "-fno-wine")) { | ||
| 235 | builder.enable_wine = false; | ||
| 236 | } else if (mem.eql(u8, arg, "-fqemu")) { | ||
| 237 | builder.enable_qemu = true; | ||
| 238 | } else if (mem.eql(u8, arg, "-fno-qemu")) { | ||
| 239 | builder.enable_qemu = false; | ||
| 240 | } else if (mem.eql(u8, arg, "-fwasmtime")) { | ||
| 241 | builder.enable_wasmtime = true; | ||
| 242 | } else if (mem.eql(u8, arg, "-fno-wasmtime")) { | ||
| 243 | builder.enable_wasmtime = false; | ||
| 244 | } else if (mem.eql(u8, arg, "-frosetta")) { | ||
| 245 | builder.enable_rosetta = true; | ||
| 246 | } else if (mem.eql(u8, arg, "-fno-rosetta")) { | ||
| 247 | builder.enable_rosetta = false; | ||
| 248 | } else if (mem.eql(u8, arg, "-fdarling")) { | ||
| 249 | builder.enable_darling = true; | ||
| 250 | } else if (mem.eql(u8, arg, "-fno-darling")) { | ||
| 251 | builder.enable_darling = false; | ||
| 252 | } else if (mem.eql(u8, arg, "-freference-trace")) { | ||
| 253 | builder.reference_trace = 256; | ||
| 254 | } else if (mem.startsWith(u8, arg, "-freference-trace=")) { | ||
| 255 | const num = arg["-freference-trace=".len..]; | ||
| 256 | builder.reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| { | ||
| 257 | std.debug.print("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) }); | ||
| 258 | process.exit(1); | ||
| 259 | }; | ||
| 260 | } else if (mem.eql(u8, arg, "-fno-reference-trace")) { | ||
| 261 | builder.reference_trace = null; | ||
| 262 | } else if (mem.startsWith(u8, arg, "-j")) { | ||
| 263 | const num = arg["-j".len..]; | ||
| 264 | const n_jobs = std.fmt.parseUnsigned(u32, num, 10) catch |err| { | ||
| 265 | std.debug.print("unable to parse jobs count '{s}': {s}", .{ | ||
| 266 | num, @errorName(err), | ||
| 267 | }); | ||
| 268 | process.exit(1); | ||
| 269 | }; | ||
| 270 | if (n_jobs < 1) { | ||
| 271 | std.debug.print("number of jobs must be at least 1\n", .{}); | ||
| 272 | process.exit(1); | ||
| 273 | } | ||
| 274 | thread_pool_options.n_jobs = n_jobs; | ||
| 275 | } else if (mem.eql(u8, arg, "--")) { | ||
| 276 | builder.args = argsRest(args, arg_idx); | ||
| 277 | break; | ||
| 278 | } else { | ||
| 279 | fatalWithHint("unrecognized argument: '{s}'", .{arg}); | ||
| 280 | } | ||
| 281 | } else { | ||
| 282 | try targets.append(arg); | ||
| 283 | } | ||
| 284 | } | ||
| 285 | |||
| 286 | const host_query = std.Build.parseTargetQuery(graph.host_query_options) catch |err| switch (err) { | ||
| 287 | error.ParseFailed => process.exit(1), | ||
| 288 | }; | ||
| 289 | builder.host = .{ | ||
| 290 | .query = .{}, | ||
| 291 | .result = try std.zig.system.resolveTargetQuery(host_query), | ||
| 292 | }; | ||
| 293 | |||
| 294 | const stderr = std.io.getStdErr(); | ||
| 295 | const ttyconf = get_tty_conf(color, stderr); | ||
| 296 | switch (ttyconf) { | ||
| 297 | .no_color => try graph.env_map.put("NO_COLOR", "1"), | ||
| 298 | .escape_codes => try graph.env_map.put("YES_COLOR", "1"), | ||
| 299 | .windows_api => {}, | ||
| 300 | } | ||
| 301 | |||
| 302 | var progress: std.Progress = .{ .dont_print_on_dumb = true }; | ||
| 303 | const main_progress_node = progress.start("", 0); | ||
| 304 | |||
| 305 | builder.debug_log_scopes = debug_log_scopes.items; | ||
| 306 | builder.resolveInstallPrefix(install_prefix, dir_list); | ||
| 307 | { | ||
| 308 | var prog_node = main_progress_node.start("user build.zig logic", 0); | ||
| 309 | defer prog_node.end(); | ||
| 310 | try builder.runBuild(root); | ||
| 311 | } | ||
| 312 | |||
| 313 | if (graph.needed_lazy_dependencies.entries.len != 0) { | ||
| 314 | var buffer: std.ArrayListUnmanaged(u8) = .{}; | ||
| 315 | for (graph.needed_lazy_dependencies.keys()) |k| { | ||
| 316 | try buffer.appendSlice(arena, k); | ||
| 317 | try buffer.append(arena, '\n'); | ||
| 318 | } | ||
| 319 | const s = std.fs.path.sep_str; | ||
| 320 | const tmp_sub_path = "tmp" ++ s ++ (output_tmp_nonce orelse fatal("missing -Z arg", .{})); | ||
| 321 | local_cache_directory.handle.writeFile2(.{ | ||
| 322 | .sub_path = tmp_sub_path, | ||
| 323 | .data = buffer.items, | ||
| 324 | .flags = .{ .exclusive = true }, | ||
| 325 | }) catch |err| { | ||
| 326 | fatal("unable to write configuration results to '{}{s}': {s}", .{ | ||
| 327 | local_cache_directory, tmp_sub_path, @errorName(err), | ||
| 328 | }); | ||
| 329 | }; | ||
| 330 | process.exit(3); // Indicate configure phase failed with meaningful stdout. | ||
| 331 | } | ||
| 332 | |||
| 333 | if (builder.validateUserInputDidItFail()) { | ||
| 334 | fatal(" access the help menu with 'zig build -h'", .{}); | ||
| 335 | } | ||
| 336 | |||
| 337 | validateSystemLibraryOptions(builder); | ||
| 338 | |||
| 339 | const stdout_writer = io.getStdOut().writer(); | ||
| 340 | |||
| 341 | if (help_menu) | ||
| 342 | return usage(builder, stdout_writer); | ||
| 343 | |||
| 344 | if (steps_menu) | ||
| 345 | return steps(builder, stdout_writer); | ||
| 346 | |||
| 347 | var run: Run = .{ | ||
| 348 | .max_rss = max_rss, | ||
| 349 | .max_rss_is_default = false, | ||
| 350 | .max_rss_mutex = .{}, | ||
| 351 | .skip_oom_steps = skip_oom_steps, | ||
| 352 | .memory_blocked_steps = std.ArrayList(*Step).init(arena), | ||
| 353 | .prominent_compile_errors = prominent_compile_errors, | ||
| 354 | |||
| 355 | .claimed_rss = 0, | ||
| 356 | .summary = summary, | ||
| 357 | .ttyconf = ttyconf, | ||
| 358 | .stderr = stderr, | ||
| 359 | }; | ||
| 360 | |||
| 361 | if (run.max_rss == 0) { | ||
| 362 | run.max_rss = process.totalSystemMemory() catch std.math.maxInt(u64); | ||
| 363 | run.max_rss_is_default = true; | ||
| 364 | } | ||
| 365 | |||
| 366 | runStepNames( | ||
| 367 | arena, | ||
| 368 | builder, | ||
| 369 | targets.items, | ||
| 370 | main_progress_node, | ||
| 371 | thread_pool_options, | ||
| 372 | &run, | ||
| 373 | seed, | ||
| 374 | ) catch |err| switch (err) { | ||
| 375 | error.UncleanExit => process.exit(1), | ||
| 376 | else => return err, | ||
| 377 | }; | ||
| 378 | } | ||
| 379 | |||
| 380 | const Run = struct { | ||
| 381 | max_rss: u64, | ||
| 382 | max_rss_is_default: bool, | ||
| 383 | max_rss_mutex: std.Thread.Mutex, | ||
| 384 | skip_oom_steps: bool, | ||
| 385 | memory_blocked_steps: std.ArrayList(*Step), | ||
| 386 | prominent_compile_errors: bool, | ||
| 387 | |||
| 388 | claimed_rss: usize, | ||
| 389 | summary: ?Summary, | ||
| 390 | ttyconf: std.io.tty.Config, | ||
| 391 | stderr: File, | ||
| 392 | }; | ||
| 393 | |||
| 394 | fn runStepNames( | ||
| 395 | arena: std.mem.Allocator, | ||
| 396 | b: *std.Build, | ||
| 397 | step_names: []const []const u8, | ||
| 398 | parent_prog_node: *std.Progress.Node, | ||
| 399 | thread_pool_options: std.Thread.Pool.Options, | ||
| 400 | run: *Run, | ||
| 401 | seed: u32, | ||
| 402 | ) !void { | ||
| 403 | const gpa = b.allocator; | ||
| 404 | var step_stack: std.AutoArrayHashMapUnmanaged(*Step, void) = .{}; | ||
| 405 | defer step_stack.deinit(gpa); | ||
| 406 | |||
| 407 | if (step_names.len == 0) { | ||
| 408 | try step_stack.put(gpa, b.default_step, {}); | ||
| 409 | } else { | ||
| 410 | try step_stack.ensureUnusedCapacity(gpa, step_names.len); | ||
| 411 | for (0..step_names.len) |i| { | ||
| 412 | const step_name = step_names[step_names.len - i - 1]; | ||
| 413 | const s = b.top_level_steps.get(step_name) orelse { | ||
| 414 | std.debug.print("no step named '{s}'\n access the help menu with 'zig build -h'\n", .{step_name}); | ||
| 415 | process.exit(1); | ||
| 416 | }; | ||
| 417 | step_stack.putAssumeCapacity(&s.step, {}); | ||
| 418 | } | ||
| 419 | } | ||
| 420 | |||
| 421 | const starting_steps = try arena.dupe(*Step, step_stack.keys()); | ||
| 422 | |||
| 423 | var rng = std.Random.DefaultPrng.init(seed); | ||
| 424 | const rand = rng.random(); | ||
| 425 | rand.shuffle(*Step, starting_steps); | ||
| 426 | |||
| 427 | for (starting_steps) |s| { | ||
| 428 | constructGraphAndCheckForDependencyLoop(b, s, &step_stack, rand) catch |err| switch (err) { | ||
| 429 | error.DependencyLoopDetected => return error.UncleanExit, | ||
| 430 | else => |e| return e, | ||
| 431 | }; | ||
| 432 | } | ||
| 433 | |||
| 434 | { | ||
| 435 | // Check that we have enough memory to complete the build. | ||
| 436 | var any_problems = false; | ||
| 437 | for (step_stack.keys()) |s| { | ||
| 438 | if (s.max_rss == 0) continue; | ||
| 439 | if (s.max_rss > run.max_rss) { | ||
| 440 | if (run.skip_oom_steps) { | ||
| 441 | s.state = .skipped_oom; | ||
| 442 | } else { | ||
| 443 | std.debug.print("{s}{s}: this step declares an upper bound of {d} bytes of memory, exceeding the available {d} bytes of memory\n", .{ | ||
| 444 | s.owner.dep_prefix, s.name, s.max_rss, run.max_rss, | ||
| 445 | }); | ||
| 446 | any_problems = true; | ||
| 447 | } | ||
| 448 | } | ||
| 449 | } | ||
| 450 | if (any_problems) { | ||
| 451 | if (run.max_rss_is_default) { | ||
| 452 | std.debug.print("note: use --maxrss to override the default", .{}); | ||
| 453 | } | ||
| 454 | return error.UncleanExit; | ||
| 455 | } | ||
| 456 | } | ||
| 457 | |||
| 458 | var thread_pool: std.Thread.Pool = undefined; | ||
| 459 | try thread_pool.init(thread_pool_options); | ||
| 460 | defer thread_pool.deinit(); | ||
| 461 | |||
| 462 | { | ||
| 463 | defer parent_prog_node.end(); | ||
| 464 | |||
| 465 | var step_prog = parent_prog_node.start("steps", step_stack.count()); | ||
| 466 | defer step_prog.end(); | ||
| 467 | |||
| 468 | var wait_group: std.Thread.WaitGroup = .{}; | ||
| 469 | defer wait_group.wait(); | ||
| 470 | |||
| 471 | // Here we spawn the initial set of tasks with a nice heuristic - | ||
| 472 | // dependency order. Each worker when it finishes a step will then | ||
| 473 | // check whether it should run any dependants. | ||
| 474 | const steps_slice = step_stack.keys(); | ||
| 475 | for (0..steps_slice.len) |i| { | ||
| 476 | const step = steps_slice[steps_slice.len - i - 1]; | ||
| 477 | if (step.state == .skipped_oom) continue; | ||
| 478 | |||
| 479 | wait_group.start(); | ||
| 480 | thread_pool.spawn(workerMakeOneStep, .{ | ||
| 481 | &wait_group, &thread_pool, b, step, &step_prog, run, | ||
| 482 | }) catch @panic("OOM"); | ||
| 483 | } | ||
| 484 | } | ||
| 485 | assert(run.memory_blocked_steps.items.len == 0); | ||
| 486 | |||
| 487 | var test_skip_count: usize = 0; | ||
| 488 | var test_fail_count: usize = 0; | ||
| 489 | var test_pass_count: usize = 0; | ||
| 490 | var test_leak_count: usize = 0; | ||
| 491 | var test_count: usize = 0; | ||
| 492 | |||
| 493 | var success_count: usize = 0; | ||
| 494 | var skipped_count: usize = 0; | ||
| 495 | var failure_count: usize = 0; | ||
| 496 | var pending_count: usize = 0; | ||
| 497 | var total_compile_errors: usize = 0; | ||
| 498 | var compile_error_steps: std.ArrayListUnmanaged(*Step) = .{}; | ||
| 499 | defer compile_error_steps.deinit(gpa); | ||
| 500 | |||
| 501 | for (step_stack.keys()) |s| { | ||
| 502 | test_fail_count += s.test_results.fail_count; | ||
| 503 | test_skip_count += s.test_results.skip_count; | ||
| 504 | test_leak_count += s.test_results.leak_count; | ||
| 505 | test_pass_count += s.test_results.passCount(); | ||
| 506 | test_count += s.test_results.test_count; | ||
| 507 | |||
| 508 | switch (s.state) { | ||
| 509 | .precheck_unstarted => unreachable, | ||
| 510 | .precheck_started => unreachable, | ||
| 511 | .running => unreachable, | ||
| 512 | .precheck_done => { | ||
| 513 | // precheck_done is equivalent to dependency_failure in the case of | ||
| 514 | // transitive dependencies. For example: | ||
| 515 | // A -> B -> C (failure) | ||
| 516 | // B will be marked as dependency_failure, while A may never be queued, and thus | ||
| 517 | // remain in the initial state of precheck_done. | ||
| 518 | s.state = .dependency_failure; | ||
| 519 | pending_count += 1; | ||
| 520 | }, | ||
| 521 | .dependency_failure => pending_count += 1, | ||
| 522 | .success => success_count += 1, | ||
| 523 | .skipped, .skipped_oom => skipped_count += 1, | ||
| 524 | .failure => { | ||
| 525 | failure_count += 1; | ||
| 526 | const compile_errors_len = s.result_error_bundle.errorMessageCount(); | ||
| 527 | if (compile_errors_len > 0) { | ||
| 528 | total_compile_errors += compile_errors_len; | ||
| 529 | try compile_error_steps.append(gpa, s); | ||
| 530 | } | ||
| 531 | }, | ||
| 532 | } | ||
| 533 | } | ||
| 534 | |||
| 535 | // A proper command line application defaults to silently succeeding. | ||
| 536 | // The user may request verbose mode if they have a different preference. | ||
| 537 | const failures_only = run.summary != .all and run.summary != .new; | ||
| 538 | if (failure_count == 0 and failures_only) return cleanExit(); | ||
| 539 | |||
| 540 | const ttyconf = run.ttyconf; | ||
| 541 | const stderr = run.stderr; | ||
| 542 | |||
| 543 | if (run.summary != Summary.none) { | ||
| 544 | const total_count = success_count + failure_count + pending_count + skipped_count; | ||
| 545 | ttyconf.setColor(stderr, .cyan) catch {}; | ||
| 546 | stderr.writeAll("Build Summary:") catch {}; | ||
| 547 | ttyconf.setColor(stderr, .reset) catch {}; | ||
| 548 | stderr.writer().print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {}; | ||
| 549 | if (skipped_count > 0) stderr.writer().print("; {d} skipped", .{skipped_count}) catch {}; | ||
| 550 | if (failure_count > 0) stderr.writer().print("; {d} failed", .{failure_count}) catch {}; | ||
| 551 | |||
| 552 | if (test_count > 0) stderr.writer().print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {}; | ||
| 553 | if (test_skip_count > 0) stderr.writer().print("; {d} skipped", .{test_skip_count}) catch {}; | ||
| 554 | if (test_fail_count > 0) stderr.writer().print("; {d} failed", .{test_fail_count}) catch {}; | ||
| 555 | if (test_leak_count > 0) stderr.writer().print("; {d} leaked", .{test_leak_count}) catch {}; | ||
| 556 | |||
| 557 | if (run.summary == null) { | ||
| 558 | ttyconf.setColor(stderr, .dim) catch {}; | ||
| 559 | stderr.writeAll(" (disable with --summary none)") catch {}; | ||
| 560 | ttyconf.setColor(stderr, .reset) catch {}; | ||
| 561 | } | ||
| 562 | stderr.writeAll("\n") catch {}; | ||
| 563 | |||
| 564 | // Print a fancy tree with build results. | ||
| 565 | var print_node: PrintNode = .{ .parent = null }; | ||
| 566 | if (step_names.len == 0) { | ||
| 567 | print_node.last = true; | ||
| 568 | printTreeStep(b, b.default_step, run, stderr, ttyconf, &print_node, &step_stack) catch {}; | ||
| 569 | } else { | ||
| 570 | const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: { | ||
| 571 | var i: usize = step_names.len; | ||
| 572 | while (i > 0) { | ||
| 573 | i -= 1; | ||
| 574 | const step = b.top_level_steps.get(step_names[i]).?.step; | ||
| 575 | const found = switch (run.summary orelse .failures) { | ||
| 576 | .all, .none => unreachable, | ||
| 577 | .failures => step.state != .success, | ||
| 578 | .new => !step.result_cached, | ||
| 579 | }; | ||
| 580 | if (found) break :blk i; | ||
| 581 | } | ||
| 582 | break :blk b.top_level_steps.count(); | ||
| 583 | }; | ||
| 584 | for (step_names, 0..) |step_name, i| { | ||
| 585 | const tls = b.top_level_steps.get(step_name).?; | ||
| 586 | print_node.last = i + 1 == last_index; | ||
| 587 | printTreeStep(b, &tls.step, run, stderr, ttyconf, &print_node, &step_stack) catch {}; | ||
| 588 | } | ||
| 589 | } | ||
| 590 | } | ||
| 591 | |||
| 592 | if (failure_count == 0) return cleanExit(); | ||
| 593 | |||
| 594 | // Finally, render compile errors at the bottom of the terminal. | ||
| 595 | // We use a separate compile_error_steps array list because step_stack is destructively | ||
| 596 | // mutated in printTreeStep above. | ||
| 597 | if (run.prominent_compile_errors and total_compile_errors > 0) { | ||
| 598 | for (compile_error_steps.items) |s| { | ||
| 599 | if (s.result_error_bundle.errorMessageCount() > 0) { | ||
| 600 | s.result_error_bundle.renderToStdErr(renderOptions(ttyconf)); | ||
| 601 | } | ||
| 602 | } | ||
| 603 | |||
| 604 | // Signal to parent process that we have printed compile errors. The | ||
| 605 | // parent process may choose to omit the "following command failed" | ||
| 606 | // line in this case. | ||
| 607 | process.exit(2); | ||
| 608 | } | ||
| 609 | |||
| 610 | process.exit(1); | ||
| 611 | } | ||
| 612 | |||
| 613 | const PrintNode = struct { | ||
| 614 | parent: ?*PrintNode, | ||
| 615 | last: bool = false, | ||
| 616 | }; | ||
| 617 | |||
| 618 | fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void { | ||
| 619 | const parent = node.parent orelse return; | ||
| 620 | if (parent.parent == null) return; | ||
| 621 | try printPrefix(parent, stderr, ttyconf); | ||
| 622 | if (parent.last) { | ||
| 623 | try stderr.writeAll(" "); | ||
| 624 | } else { | ||
| 625 | try stderr.writeAll(switch (ttyconf) { | ||
| 626 | .no_color, .windows_api => "| ", | ||
| 627 | .escape_codes => "\x1B\x28\x30\x78\x1B\x28\x42 ", // │ | ||
| 628 | }); | ||
| 629 | } | ||
| 630 | } | ||
| 631 | |||
| 632 | fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void { | ||
| 633 | try stderr.writeAll(switch (ttyconf) { | ||
| 634 | .no_color, .windows_api => "+- ", | ||
| 635 | .escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─ | ||
| 636 | }); | ||
| 637 | } | ||
| 638 | |||
| 639 | fn printStepStatus( | ||
| 640 | s: *Step, | ||
| 641 | stderr: File, | ||
| 642 | ttyconf: std.io.tty.Config, | ||
| 643 | run: *const Run, | ||
| 644 | ) !void { | ||
| 645 | switch (s.state) { | ||
| 646 | .precheck_unstarted => unreachable, | ||
| 647 | .precheck_started => unreachable, | ||
| 648 | .precheck_done => unreachable, | ||
| 649 | .running => unreachable, | ||
| 650 | |||
| 651 | .dependency_failure => { | ||
| 652 | try ttyconf.setColor(stderr, .dim); | ||
| 653 | try stderr.writeAll(" transitive failure\n"); | ||
| 654 | try ttyconf.setColor(stderr, .reset); | ||
| 655 | }, | ||
| 656 | |||
| 657 | .success => { | ||
| 658 | try ttyconf.setColor(stderr, .green); | ||
| 659 | if (s.result_cached) { | ||
| 660 | try stderr.writeAll(" cached"); | ||
| 661 | } else if (s.test_results.test_count > 0) { | ||
| 662 | const pass_count = s.test_results.passCount(); | ||
| 663 | try stderr.writer().print(" {d} passed", .{pass_count}); | ||
| 664 | if (s.test_results.skip_count > 0) { | ||
| 665 | try ttyconf.setColor(stderr, .yellow); | ||
| 666 | try stderr.writer().print(" {d} skipped", .{s.test_results.skip_count}); | ||
| 667 | } | ||
| 668 | } else { | ||
| 669 | try stderr.writeAll(" success"); | ||
| 670 | } | ||
| 671 | try ttyconf.setColor(stderr, .reset); | ||
| 672 | if (s.result_duration_ns) |ns| { | ||
| 673 | try ttyconf.setColor(stderr, .dim); | ||
| 674 | if (ns >= std.time.ns_per_min) { | ||
| 675 | try stderr.writer().print(" {d}m", .{ns / std.time.ns_per_min}); | ||
| 676 | } else if (ns >= std.time.ns_per_s) { | ||
| 677 | try stderr.writer().print(" {d}s", .{ns / std.time.ns_per_s}); | ||
| 678 | } else if (ns >= std.time.ns_per_ms) { | ||
| 679 | try stderr.writer().print(" {d}ms", .{ns / std.time.ns_per_ms}); | ||
| 680 | } else if (ns >= std.time.ns_per_us) { | ||
| 681 | try stderr.writer().print(" {d}us", .{ns / std.time.ns_per_us}); | ||
| 682 | } else { | ||
| 683 | try stderr.writer().print(" {d}ns", .{ns}); | ||
| 684 | } | ||
| 685 | try ttyconf.setColor(stderr, .reset); | ||
| 686 | } | ||
| 687 | if (s.result_peak_rss != 0) { | ||
| 688 | const rss = s.result_peak_rss; | ||
| 689 | try ttyconf.setColor(stderr, .dim); | ||
| 690 | if (rss >= 1000_000_000) { | ||
| 691 | try stderr.writer().print(" MaxRSS:{d}G", .{rss / 1000_000_000}); | ||
| 692 | } else if (rss >= 1000_000) { | ||
| 693 | try stderr.writer().print(" MaxRSS:{d}M", .{rss / 1000_000}); | ||
| 694 | } else if (rss >= 1000) { | ||
| 695 | try stderr.writer().print(" MaxRSS:{d}K", .{rss / 1000}); | ||
| 696 | } else { | ||
| 697 | try stderr.writer().print(" MaxRSS:{d}B", .{rss}); | ||
| 698 | } | ||
| 699 | try ttyconf.setColor(stderr, .reset); | ||
| 700 | } | ||
| 701 | try stderr.writeAll("\n"); | ||
| 702 | }, | ||
| 703 | .skipped, .skipped_oom => |skip| { | ||
| 704 | try ttyconf.setColor(stderr, .yellow); | ||
| 705 | try stderr.writeAll(" skipped"); | ||
| 706 | if (skip == .skipped_oom) { | ||
| 707 | try stderr.writeAll(" (not enough memory)"); | ||
| 708 | try ttyconf.setColor(stderr, .dim); | ||
| 709 | try stderr.writer().print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss }); | ||
| 710 | try ttyconf.setColor(stderr, .yellow); | ||
| 711 | } | ||
| 712 | try stderr.writeAll("\n"); | ||
| 713 | try ttyconf.setColor(stderr, .reset); | ||
| 714 | }, | ||
| 715 | .failure => try printStepFailure(s, stderr, ttyconf), | ||
| 716 | } | ||
| 717 | } | ||
| 718 | |||
| 719 | fn printStepFailure( | ||
| 720 | s: *Step, | ||
| 721 | stderr: File, | ||
| 722 | ttyconf: std.io.tty.Config, | ||
| 723 | ) !void { | ||
| 724 | if (s.result_error_bundle.errorMessageCount() > 0) { | ||
| 725 | try ttyconf.setColor(stderr, .red); | ||
| 726 | try stderr.writer().print(" {d} errors\n", .{ | ||
| 727 | s.result_error_bundle.errorMessageCount(), | ||
| 728 | }); | ||
| 729 | try ttyconf.setColor(stderr, .reset); | ||
| 730 | } else if (!s.test_results.isSuccess()) { | ||
| 731 | try stderr.writer().print(" {d}/{d} passed", .{ | ||
| 732 | s.test_results.passCount(), s.test_results.test_count, | ||
| 733 | }); | ||
| 734 | if (s.test_results.fail_count > 0) { | ||
| 735 | try stderr.writeAll(", "); | ||
| 736 | try ttyconf.setColor(stderr, .red); | ||
| 737 | try stderr.writer().print("{d} failed", .{ | ||
| 738 | s.test_results.fail_count, | ||
| 739 | }); | ||
| 740 | try ttyconf.setColor(stderr, .reset); | ||
| 741 | } | ||
| 742 | if (s.test_results.skip_count > 0) { | ||
| 743 | try stderr.writeAll(", "); | ||
| 744 | try ttyconf.setColor(stderr, .yellow); | ||
| 745 | try stderr.writer().print("{d} skipped", .{ | ||
| 746 | s.test_results.skip_count, | ||
| 747 | }); | ||
| 748 | try ttyconf.setColor(stderr, .reset); | ||
| 749 | } | ||
| 750 | if (s.test_results.leak_count > 0) { | ||
| 751 | try stderr.writeAll(", "); | ||
| 752 | try ttyconf.setColor(stderr, .red); | ||
| 753 | try stderr.writer().print("{d} leaked", .{ | ||
| 754 | s.test_results.leak_count, | ||
| 755 | }); | ||
| 756 | try ttyconf.setColor(stderr, .reset); | ||
| 757 | } | ||
| 758 | try stderr.writeAll("\n"); | ||
| 759 | } else if (s.result_error_msgs.items.len > 0) { | ||
| 760 | try ttyconf.setColor(stderr, .red); | ||
| 761 | try stderr.writeAll(" failure\n"); | ||
| 762 | try ttyconf.setColor(stderr, .reset); | ||
| 763 | } else { | ||
| 764 | assert(s.result_stderr.len > 0); | ||
| 765 | try ttyconf.setColor(stderr, .red); | ||
| 766 | try stderr.writeAll(" stderr\n"); | ||
| 767 | try ttyconf.setColor(stderr, .reset); | ||
| 768 | } | ||
| 769 | } | ||
| 770 | |||
| 771 | fn printTreeStep( | ||
| 772 | b: *std.Build, | ||
| 773 | s: *Step, | ||
| 774 | run: *const Run, | ||
| 775 | stderr: File, | ||
| 776 | ttyconf: std.io.tty.Config, | ||
| 777 | parent_node: *PrintNode, | ||
| 778 | step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void), | ||
| 779 | ) !void { | ||
| 780 | const first = step_stack.swapRemove(s); | ||
| 781 | const summary = run.summary orelse .failures; | ||
| 782 | const skip = switch (summary) { | ||
| 783 | .none => unreachable, | ||
| 784 | .all => false, | ||
| 785 | .new => s.result_cached, | ||
| 786 | .failures => s.state == .success, | ||
| 787 | }; | ||
| 788 | if (skip) return; | ||
| 789 | try printPrefix(parent_node, stderr, ttyconf); | ||
| 790 | |||
| 791 | if (!first) try ttyconf.setColor(stderr, .dim); | ||
| 792 | if (parent_node.parent != null) { | ||
| 793 | if (parent_node.last) { | ||
| 794 | try printChildNodePrefix(stderr, ttyconf); | ||
| 795 | } else { | ||
| 796 | try stderr.writeAll(switch (ttyconf) { | ||
| 797 | .no_color, .windows_api => "+- ", | ||
| 798 | .escape_codes => "\x1B\x28\x30\x74\x71\x1B\x28\x42 ", // ├─ | ||
| 799 | }); | ||
| 800 | } | ||
| 801 | } | ||
| 802 | |||
| 803 | // dep_prefix omitted here because it is redundant with the tree. | ||
| 804 | try stderr.writeAll(s.name); | ||
| 805 | |||
| 806 | if (first) { | ||
| 807 | try printStepStatus(s, stderr, ttyconf, run); | ||
| 808 | |||
| 809 | const last_index = if (summary == .all) s.dependencies.items.len -| 1 else blk: { | ||
| 810 | var i: usize = s.dependencies.items.len; | ||
| 811 | while (i > 0) { | ||
| 812 | i -= 1; | ||
| 813 | |||
| 814 | const step = s.dependencies.items[i]; | ||
| 815 | const found = switch (summary) { | ||
| 816 | .all, .none => unreachable, | ||
| 817 | .failures => step.state != .success, | ||
| 818 | .new => !step.result_cached, | ||
| 819 | }; | ||
| 820 | if (found) break :blk i; | ||
| 821 | } | ||
| 822 | break :blk s.dependencies.items.len -| 1; | ||
| 823 | }; | ||
| 824 | for (s.dependencies.items, 0..) |dep, i| { | ||
| 825 | var print_node: PrintNode = .{ | ||
| 826 | .parent = parent_node, | ||
| 827 | .last = i == last_index, | ||
| 828 | }; | ||
| 829 | try printTreeStep(b, dep, run, stderr, ttyconf, &print_node, step_stack); | ||
| 830 | } | ||
| 831 | } else { | ||
| 832 | if (s.dependencies.items.len == 0) { | ||
| 833 | try stderr.writeAll(" (reused)\n"); | ||
| 834 | } else { | ||
| 835 | try stderr.writer().print(" (+{d} more reused dependencies)\n", .{ | ||
| 836 | s.dependencies.items.len, | ||
| 837 | }); | ||
| 838 | } | ||
| 839 | try ttyconf.setColor(stderr, .reset); | ||
| 840 | } | ||
| 841 | } | ||
| 842 | |||
| 843 | /// Traverse the dependency graph depth-first and make it undirected by having | ||
| 844 | /// steps know their dependants (they only know dependencies at start). | ||
| 845 | /// Along the way, check that there is no dependency loop, and record the steps | ||
| 846 | /// in traversal order in `step_stack`. | ||
| 847 | /// Each step has its dependencies traversed in random order, this accomplishes | ||
| 848 | /// two things: | ||
| 849 | /// - `step_stack` will be in randomized-depth-first order, so the build runner | ||
| 850 | /// spawns steps in a random (but optimized) order | ||
| 851 | /// - each step's `dependants` list is also filled in a random order, so that | ||
| 852 | /// when it finishes executing in `workerMakeOneStep`, it spawns next steps | ||
| 853 | /// to run in random order | ||
| 854 | fn constructGraphAndCheckForDependencyLoop( | ||
| 855 | b: *std.Build, | ||
| 856 | s: *Step, | ||
| 857 | step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void), | ||
| 858 | rand: std.Random, | ||
| 859 | ) !void { | ||
| 860 | switch (s.state) { | ||
| 861 | .precheck_started => { | ||
| 862 | std.debug.print("dependency loop detected:\n {s}\n", .{s.name}); | ||
| 863 | return error.DependencyLoopDetected; | ||
| 864 | }, | ||
| 865 | .precheck_unstarted => { | ||
| 866 | s.state = .precheck_started; | ||
| 867 | |||
| 868 | try step_stack.ensureUnusedCapacity(b.allocator, s.dependencies.items.len); | ||
| 869 | |||
| 870 | // We dupe to avoid shuffling the steps in the summary, it depends | ||
| 871 | // on s.dependencies' order. | ||
| 872 | const deps = b.allocator.dupe(*Step, s.dependencies.items) catch @panic("OOM"); | ||
| 873 | rand.shuffle(*Step, deps); | ||
| 874 | |||
| 875 | for (deps) |dep| { | ||
| 876 | try step_stack.put(b.allocator, dep, {}); | ||
| 877 | try dep.dependants.append(b.allocator, s); | ||
| 878 | constructGraphAndCheckForDependencyLoop(b, dep, step_stack, rand) catch |err| { | ||
| 879 | if (err == error.DependencyLoopDetected) { | ||
| 880 | std.debug.print(" {s}\n", .{s.name}); | ||
| 881 | } | ||
| 882 | return err; | ||
| 883 | }; | ||
| 884 | } | ||
| 885 | |||
| 886 | s.state = .precheck_done; | ||
| 887 | }, | ||
| 888 | .precheck_done => {}, | ||
| 889 | |||
| 890 | // These don't happen until we actually run the step graph. | ||
| 891 | .dependency_failure => unreachable, | ||
| 892 | .running => unreachable, | ||
| 893 | .success => unreachable, | ||
| 894 | .failure => unreachable, | ||
| 895 | .skipped => unreachable, | ||
| 896 | .skipped_oom => unreachable, | ||
| 897 | } | ||
| 898 | } | ||
| 899 | |||
| 900 | fn workerMakeOneStep( | ||
| 901 | wg: *std.Thread.WaitGroup, | ||
| 902 | thread_pool: *std.Thread.Pool, | ||
| 903 | b: *std.Build, | ||
| 904 | s: *Step, | ||
| 905 | prog_node: *std.Progress.Node, | ||
| 906 | run: *Run, | ||
| 907 | ) void { | ||
| 908 | defer wg.finish(); | ||
| 909 | |||
| 910 | // First, check the conditions for running this step. If they are not met, | ||
| 911 | // then we return without doing the step, relying on another worker to | ||
| 912 | // queue this step up again when dependencies are met. | ||
| 913 | for (s.dependencies.items) |dep| { | ||
| 914 | switch (@atomicLoad(Step.State, &dep.state, .seq_cst)) { | ||
| 915 | .success, .skipped => continue, | ||
| 916 | .failure, .dependency_failure, .skipped_oom => { | ||
| 917 | @atomicStore(Step.State, &s.state, .dependency_failure, .seq_cst); | ||
| 918 | return; | ||
| 919 | }, | ||
| 920 | .precheck_done, .running => { | ||
| 921 | // dependency is not finished yet. | ||
| 922 | return; | ||
| 923 | }, | ||
| 924 | .precheck_unstarted => unreachable, | ||
| 925 | .precheck_started => unreachable, | ||
| 926 | } | ||
| 927 | } | ||
| 928 | |||
| 929 | if (s.max_rss != 0) { | ||
| 930 | run.max_rss_mutex.lock(); | ||
| 931 | defer run.max_rss_mutex.unlock(); | ||
| 932 | |||
| 933 | // Avoid running steps twice. | ||
| 934 | if (s.state != .precheck_done) { | ||
| 935 | // Another worker got the job. | ||
| 936 | return; | ||
| 937 | } | ||
| 938 | |||
| 939 | const new_claimed_rss = run.claimed_rss + s.max_rss; | ||
| 940 | if (new_claimed_rss > run.max_rss) { | ||
| 941 | // Running this step right now could possibly exceed the allotted RSS. | ||
| 942 | // Add this step to the queue of memory-blocked steps. | ||
| 943 | run.memory_blocked_steps.append(s) catch @panic("OOM"); | ||
| 944 | return; | ||
| 945 | } | ||
| 946 | |||
| 947 | run.claimed_rss = new_claimed_rss; | ||
| 948 | s.state = .running; | ||
| 949 | } else { | ||
| 950 | // Avoid running steps twice. | ||
| 951 | if (@cmpxchgStrong(Step.State, &s.state, .precheck_done, .running, .seq_cst, .seq_cst) != null) { | ||
| 952 | // Another worker got the job. | ||
| 953 | return; | ||
| 954 | } | ||
| 955 | } | ||
| 956 | |||
| 957 | var sub_prog_node = prog_node.start(s.name, 0); | ||
| 958 | sub_prog_node.activate(); | ||
| 959 | defer sub_prog_node.end(); | ||
| 960 | |||
| 961 | const make_result = s.make(&sub_prog_node); | ||
| 962 | |||
| 963 | // No matter the result, we want to display error/warning messages. | ||
| 964 | const show_compile_errors = !run.prominent_compile_errors and | ||
| 965 | s.result_error_bundle.errorMessageCount() > 0; | ||
| 966 | const show_error_msgs = s.result_error_msgs.items.len > 0; | ||
| 967 | const show_stderr = s.result_stderr.len > 0; | ||
| 968 | |||
| 969 | if (show_error_msgs or show_compile_errors or show_stderr) { | ||
| 970 | sub_prog_node.context.lock_stderr(); | ||
| 971 | defer sub_prog_node.context.unlock_stderr(); | ||
| 972 | |||
| 973 | printErrorMessages(b, s, run) catch {}; | ||
| 974 | } | ||
| 975 | |||
| 976 | handle_result: { | ||
| 977 | if (make_result) |_| { | ||
| 978 | @atomicStore(Step.State, &s.state, .success, .seq_cst); | ||
| 979 | } else |err| switch (err) { | ||
| 980 | error.MakeFailed => { | ||
| 981 | @atomicStore(Step.State, &s.state, .failure, .seq_cst); | ||
| 982 | break :handle_result; | ||
| 983 | }, | ||
| 984 | error.MakeSkipped => @atomicStore(Step.State, &s.state, .skipped, .seq_cst), | ||
| 985 | } | ||
| 986 | |||
| 987 | // Successful completion of a step, so we queue up its dependants as well. | ||
| 988 | for (s.dependants.items) |dep| { | ||
| 989 | wg.start(); | ||
| 990 | thread_pool.spawn(workerMakeOneStep, .{ | ||
| 991 | wg, thread_pool, b, dep, prog_node, run, | ||
| 992 | }) catch @panic("OOM"); | ||
| 993 | } | ||
| 994 | } | ||
| 995 | |||
| 996 | // If this is a step that claims resources, we must now queue up other | ||
| 997 | // steps that are waiting for resources. | ||
| 998 | if (s.max_rss != 0) { | ||
| 999 | run.max_rss_mutex.lock(); | ||
| 1000 | defer run.max_rss_mutex.unlock(); | ||
| 1001 | |||
| 1002 | // Give the memory back to the scheduler. | ||
| 1003 | run.claimed_rss -= s.max_rss; | ||
| 1004 | // Avoid kicking off too many tasks that we already know will not have | ||
| 1005 | // enough resources. | ||
| 1006 | var remaining = run.max_rss - run.claimed_rss; | ||
| 1007 | var i: usize = 0; | ||
| 1008 | var j: usize = 0; | ||
| 1009 | while (j < run.memory_blocked_steps.items.len) : (j += 1) { | ||
| 1010 | const dep = run.memory_blocked_steps.items[j]; | ||
| 1011 | assert(dep.max_rss != 0); | ||
| 1012 | if (dep.max_rss <= remaining) { | ||
| 1013 | remaining -= dep.max_rss; | ||
| 1014 | |||
| 1015 | wg.start(); | ||
| 1016 | thread_pool.spawn(workerMakeOneStep, .{ | ||
| 1017 | wg, thread_pool, b, dep, prog_node, run, | ||
| 1018 | }) catch @panic("OOM"); | ||
| 1019 | } else { | ||
| 1020 | run.memory_blocked_steps.items[i] = dep; | ||
| 1021 | i += 1; | ||
| 1022 | } | ||
| 1023 | } | ||
| 1024 | run.memory_blocked_steps.shrinkRetainingCapacity(i); | ||
| 1025 | } | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | fn printErrorMessages(b: *std.Build, failing_step: *Step, run: *const Run) !void { | ||
| 1029 | const gpa = b.allocator; | ||
| 1030 | const stderr = run.stderr; | ||
| 1031 | const ttyconf = run.ttyconf; | ||
| 1032 | |||
| 1033 | // Provide context for where these error messages are coming from by | ||
| 1034 | // printing the corresponding Step subtree. | ||
| 1035 | |||
| 1036 | var step_stack: std.ArrayListUnmanaged(*Step) = .{}; | ||
| 1037 | defer step_stack.deinit(gpa); | ||
| 1038 | try step_stack.append(gpa, failing_step); | ||
| 1039 | while (step_stack.items[step_stack.items.len - 1].dependants.items.len != 0) { | ||
| 1040 | try step_stack.append(gpa, step_stack.items[step_stack.items.len - 1].dependants.items[0]); | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | // Now, `step_stack` has the subtree that we want to print, in reverse order. | ||
| 1044 | try ttyconf.setColor(stderr, .dim); | ||
| 1045 | var indent: usize = 0; | ||
| 1046 | while (step_stack.popOrNull()) |s| : (indent += 1) { | ||
| 1047 | if (indent > 0) { | ||
| 1048 | try stderr.writer().writeByteNTimes(' ', (indent - 1) * 3); | ||
| 1049 | try printChildNodePrefix(stderr, ttyconf); | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | try stderr.writeAll(s.name); | ||
| 1053 | |||
| 1054 | if (s == failing_step) { | ||
| 1055 | try printStepFailure(s, stderr, ttyconf); | ||
| 1056 | } else { | ||
| 1057 | try stderr.writeAll("\n"); | ||
| 1058 | } | ||
| 1059 | } | ||
| 1060 | try ttyconf.setColor(stderr, .reset); | ||
| 1061 | |||
| 1062 | if (failing_step.result_stderr.len > 0) { | ||
| 1063 | try stderr.writeAll(failing_step.result_stderr); | ||
| 1064 | if (!mem.endsWith(u8, failing_step.result_stderr, "\n")) { | ||
| 1065 | try stderr.writeAll("\n"); | ||
| 1066 | } | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | if (!run.prominent_compile_errors and failing_step.result_error_bundle.errorMessageCount() > 0) | ||
| 1070 | try failing_step.result_error_bundle.renderToWriter(renderOptions(ttyconf), stderr.writer()); | ||
| 1071 | |||
| 1072 | for (failing_step.result_error_msgs.items) |msg| { | ||
| 1073 | try ttyconf.setColor(stderr, .red); | ||
| 1074 | try stderr.writeAll("error: "); | ||
| 1075 | try ttyconf.setColor(stderr, .reset); | ||
| 1076 | try stderr.writeAll(msg); | ||
| 1077 | try stderr.writeAll("\n"); | ||
| 1078 | } | ||
| 1079 | } | ||
| 1080 | |||
| 1081 | fn steps(builder: *std.Build, out_stream: anytype) !void { | ||
| 1082 | const allocator = builder.allocator; | ||
| 1083 | for (builder.top_level_steps.values()) |top_level_step| { | ||
| 1084 | const name = if (&top_level_step.step == builder.default_step) | ||
| 1085 | try fmt.allocPrint(allocator, "{s} (default)", .{top_level_step.step.name}) | ||
| 1086 | else | ||
| 1087 | top_level_step.step.name; | ||
| 1088 | try out_stream.print(" {s:<28} {s}\n", .{ name, top_level_step.description }); | ||
| 1089 | } | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | fn usage(b: *std.Build, out_stream: anytype) !void { | ||
| 1093 | try out_stream.print( | ||
| 1094 | \\Usage: {s} build [steps] [options] | ||
| 1095 | \\ | ||
| 1096 | \\Steps: | ||
| 1097 | \\ | ||
| 1098 | , .{b.graph.zig_exe}); | ||
| 1099 | try steps(b, out_stream); | ||
| 1100 | |||
| 1101 | try out_stream.writeAll( | ||
| 1102 | \\ | ||
| 1103 | \\General Options: | ||
| 1104 | \\ -p, --prefix [path] Where to install files (default: zig-out) | ||
| 1105 | \\ --prefix-lib-dir [path] Where to install libraries | ||
| 1106 | \\ --prefix-exe-dir [path] Where to install executables | ||
| 1107 | \\ --prefix-include-dir [path] Where to install C header files | ||
| 1108 | \\ | ||
| 1109 | \\ --release[=mode] Request release mode, optionally specifying a | ||
| 1110 | \\ preferred optimization mode: fast, safe, small | ||
| 1111 | \\ | ||
| 1112 | \\ -fdarling, -fno-darling Integration with system-installed Darling to | ||
| 1113 | \\ execute macOS programs on Linux hosts | ||
| 1114 | \\ (default: no) | ||
| 1115 | \\ -fqemu, -fno-qemu Integration with system-installed QEMU to execute | ||
| 1116 | \\ foreign-architecture programs on Linux hosts | ||
| 1117 | \\ (default: no) | ||
| 1118 | \\ --glibc-runtimes [path] Enhances QEMU integration by providing glibc built | ||
| 1119 | \\ for multiple foreign architectures, allowing | ||
| 1120 | \\ execution of non-native programs that link with glibc. | ||
| 1121 | \\ -frosetta, -fno-rosetta Rely on Rosetta to execute x86_64 programs on | ||
| 1122 | \\ ARM64 macOS hosts. (default: no) | ||
| 1123 | \\ -fwasmtime, -fno-wasmtime Integration with system-installed wasmtime to | ||
| 1124 | \\ execute WASI binaries. (default: no) | ||
| 1125 | \\ -fwine, -fno-wine Integration with system-installed Wine to execute | ||
| 1126 | \\ Windows programs on Linux hosts. (default: no) | ||
| 1127 | \\ | ||
| 1128 | \\ -h, --help Print this help and exit | ||
| 1129 | \\ -l, --list-steps Print available steps | ||
| 1130 | \\ --verbose Print commands before executing them | ||
| 1131 | \\ --color [auto|off|on] Enable or disable colored error messages | ||
| 1132 | \\ --prominent-compile-errors Buffer compile errors and display at end | ||
| 1133 | \\ --summary [mode] Control the printing of the build summary | ||
| 1134 | \\ all Print the build summary in its entirety | ||
| 1135 | \\ new Omit cached steps | ||
| 1136 | \\ failures (Default) Only print failed steps | ||
| 1137 | \\ none Do not print the build summary | ||
| 1138 | \\ -j<N> Limit concurrent jobs (default is to use all CPU cores) | ||
| 1139 | \\ --maxrss <bytes> Limit memory usage (default is to use available memory) | ||
| 1140 | \\ --skip-oom-steps Instead of failing, skip steps that would exceed --maxrss | ||
| 1141 | \\ --fetch Exit after fetching dependency tree | ||
| 1142 | \\ | ||
| 1143 | \\Project-Specific Options: | ||
| 1144 | \\ | ||
| 1145 | ); | ||
| 1146 | |||
| 1147 | const arena = b.allocator; | ||
| 1148 | if (b.available_options_list.items.len == 0) { | ||
| 1149 | try out_stream.print(" (none)\n", .{}); | ||
| 1150 | } else { | ||
| 1151 | for (b.available_options_list.items) |option| { | ||
| 1152 | const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{ | ||
| 1153 | option.name, | ||
| 1154 | @tagName(option.type_id), | ||
| 1155 | }); | ||
| 1156 | try out_stream.print("{s:<30} {s}\n", .{ name, option.description }); | ||
| 1157 | if (option.enum_options) |enum_options| { | ||
| 1158 | const padding = " " ** 33; | ||
| 1159 | try out_stream.writeAll(padding ++ "Supported Values:\n"); | ||
| 1160 | for (enum_options) |enum_option| { | ||
| 1161 | try out_stream.print(padding ++ " {s}\n", .{enum_option}); | ||
| 1162 | } | ||
| 1163 | } | ||
| 1164 | } | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | try out_stream.writeAll( | ||
| 1168 | \\ | ||
| 1169 | \\System Integration Options: | ||
| 1170 | \\ --search-prefix [path] Add a path to look for binaries, libraries, headers | ||
| 1171 | \\ --sysroot [path] Set the system root directory (usually /) | ||
| 1172 | \\ --libc [file] Provide a file which specifies libc paths | ||
| 1173 | \\ | ||
| 1174 | \\ --host-target [triple] Use the provided target as the host | ||
| 1175 | \\ --host-cpu [cpu] Use the provided CPU as the host | ||
| 1176 | \\ --host-dynamic-linker [path] Use the provided dynamic linker as the host | ||
| 1177 | \\ | ||
| 1178 | \\ --system [pkgdir] Disable package fetching; enable all integrations | ||
| 1179 | \\ -fsys=[name] Enable a system integration | ||
| 1180 | \\ -fno-sys=[name] Disable a system integration | ||
| 1181 | \\ | ||
| 1182 | \\ Available System Integrations: Enabled: | ||
| 1183 | \\ | ||
| 1184 | ); | ||
| 1185 | if (b.graph.system_library_options.entries.len == 0) { | ||
| 1186 | try out_stream.writeAll(" (none) -\n"); | ||
| 1187 | } else { | ||
| 1188 | for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| { | ||
| 1189 | const status = switch (v) { | ||
| 1190 | .declared_enabled => "yes", | ||
| 1191 | .declared_disabled => "no", | ||
| 1192 | .user_enabled, .user_disabled => unreachable, // already emitted error | ||
| 1193 | }; | ||
| 1194 | try out_stream.print(" {s:<43} {s}\n", .{ k, status }); | ||
| 1195 | } | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | try out_stream.writeAll( | ||
| 1199 | \\ | ||
| 1200 | \\Advanced Options: | ||
| 1201 | \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error | ||
| 1202 | \\ -fno-reference-trace Disable reference trace | ||
| 1203 | \\ --build-file [file] Override path to build.zig | ||
| 1204 | \\ --cache-dir [path] Override path to local Zig cache directory | ||
| 1205 | \\ --global-cache-dir [path] Override path to global Zig cache directory | ||
| 1206 | \\ --zig-lib-dir [arg] Override path to Zig lib directory | ||
| 1207 | \\ --build-runner [file] Override path to build runner | ||
| 1208 | \\ --seed [integer] For shuffling dependency traversal order (default: random) | ||
| 1209 | \\ --debug-log [scope] Enable debugging the compiler | ||
| 1210 | \\ --debug-pkg-config Fail if unknown pkg-config flags encountered | ||
| 1211 | \\ --verbose-link Enable compiler debug output for linking | ||
| 1212 | \\ --verbose-air Enable compiler debug output for Zig AIR | ||
| 1213 | \\ --verbose-llvm-ir[=file] Enable compiler debug output for LLVM IR | ||
| 1214 | \\ --verbose-llvm-bc=[file] Enable compiler debug output for LLVM BC | ||
| 1215 | \\ --verbose-cimport Enable compiler debug output for C imports | ||
| 1216 | \\ --verbose-cc Enable compiler debug output for C compilation | ||
| 1217 | \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features | ||
| 1218 | \\ | ||
| 1219 | ); | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | fn nextArg(args: [][:0]const u8, idx: *usize) ?[:0]const u8 { | ||
| 1223 | if (idx.* >= args.len) return null; | ||
| 1224 | defer idx.* += 1; | ||
| 1225 | return args[idx.*]; | ||
| 1226 | } | ||
| 1227 | |||
| 1228 | fn nextArgOrFatal(args: [][:0]const u8, idx: *usize) [:0]const u8 { | ||
| 1229 | return nextArg(args, idx) orelse { | ||
| 1230 | std.debug.print("expected argument after '{s}'\n access the help menu with 'zig build -h'\n", .{args[idx.*]}); | ||
| 1231 | process.exit(1); | ||
| 1232 | }; | ||
| 1233 | } | ||
| 1234 | |||
| 1235 | fn argsRest(args: [][:0]const u8, idx: usize) ?[][:0]const u8 { | ||
| 1236 | if (idx >= args.len) return null; | ||
| 1237 | return args[idx..]; | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | fn cleanExit() void { | ||
| 1241 | // Perhaps in the future there could be an Advanced Options flag such as | ||
| 1242 | // --debug-build-runner-leaks which would make this function return instead | ||
| 1243 | // of calling exit. | ||
| 1244 | process.exit(0); | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | const Color = enum { auto, off, on }; | ||
| 1248 | const Summary = enum { all, new, failures, none }; | ||
| 1249 | |||
| 1250 | fn get_tty_conf(color: Color, stderr: File) std.io.tty.Config { | ||
| 1251 | return switch (color) { | ||
| 1252 | .auto => std.io.tty.detectConfig(stderr), | ||
| 1253 | .on => .escape_codes, | ||
| 1254 | .off => .no_color, | ||
| 1255 | }; | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | fn renderOptions(ttyconf: std.io.tty.Config) std.zig.ErrorBundle.RenderOptions { | ||
| 1259 | return .{ | ||
| 1260 | .ttyconf = ttyconf, | ||
| 1261 | .include_source_line = ttyconf != .no_color, | ||
| 1262 | .include_reference_trace = ttyconf != .no_color, | ||
| 1263 | }; | ||
| 1264 | } | ||
| 1265 | |||
| 1266 | fn fatalWithHint(comptime f: []const u8, args: anytype) noreturn { | ||
| 1267 | std.debug.print(f ++ "\n access the help menu with 'zig build -h'\n", args); | ||
| 1268 | process.exit(1); | ||
| 1269 | } | ||
| 1270 | |||
| 1271 | fn fatal(comptime f: []const u8, args: anytype) noreturn { | ||
| 1272 | std.debug.print(f ++ "\n", args); | ||
| 1273 | process.exit(1); | ||
| 1274 | } | ||
| 1275 | |||
| 1276 | fn validateSystemLibraryOptions(b: *std.Build) void { | ||
| 1277 | var bad = false; | ||
| 1278 | for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| { | ||
| 1279 | switch (v) { | ||
| 1280 | .user_disabled, .user_enabled => { | ||
| 1281 | // The user tried to enable or disable a system library integration, but | ||
| 1282 | // the build script did not recognize that option. | ||
| 1283 | std.debug.print("system library name not recognized by build script: '{s}'\n", .{k}); | ||
| 1284 | bad = true; | ||
| 1285 | }, | ||
| 1286 | .declared_disabled, .declared_enabled => {}, | ||
| 1287 | } | ||
| 1288 | } | ||
| 1289 | if (bad) { | ||
| 1290 | std.debug.print(" access the help menu with 'zig build -h'\n", .{}); | ||
| 1291 | process.exit(1); | ||
| 1292 | } | ||
| 1293 | } | ||
lib/std/builtin.zig-1| ... | @@ -420,7 +420,6 @@ pub const Type = union(enum) { | ... | @@ -420,7 +420,6 @@ pub const Type = union(enum) { |
| 420 | /// therefore must be kept in sync with the compiler implementation. | 420 | /// therefore must be kept in sync with the compiler implementation. |
| 421 | pub const Fn = struct { | 421 | pub const Fn = struct { |
| 422 | calling_convention: CallingConvention, | 422 | calling_convention: CallingConvention, |
| 423 | alignment: comptime_int, | ||
| 424 | is_generic: bool, | 423 | is_generic: bool, |
| 425 | is_var_args: bool, | 424 | is_var_args: bool, |
| 426 | /// TODO change the language spec to make this not optional. | 425 | /// TODO change the language spec to make this not optional. |
lib/std/c/darwin.zig+5-5| ... | @@ -1053,10 +1053,10 @@ pub const sigset_t = u32; | ... | @@ -1053,10 +1053,10 @@ pub const sigset_t = u32; |
| 1053 | pub const empty_sigset: sigset_t = 0; | 1053 | pub const empty_sigset: sigset_t = 0; |
| 1054 | 1054 | ||
| 1055 | pub const SIG = struct { | 1055 | pub const SIG = struct { |
| 1056 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | 1056 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); |
| 1057 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | 1057 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); |
| 1058 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | 1058 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); |
| 1059 | pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(5)); | 1059 | pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(5); |
| 1060 | 1060 | ||
| 1061 | /// block specified signal set | 1061 | /// block specified signal set |
| 1062 | pub const BLOCK = 1; | 1062 | pub const BLOCK = 1; |
| ... | @@ -1150,7 +1150,7 @@ pub const siginfo_t = extern struct { | ... | @@ -1150,7 +1150,7 @@ pub const siginfo_t = extern struct { |
| 1150 | 1150 | ||
| 1151 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name. | 1151 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name. |
| 1152 | pub const Sigaction = extern struct { | 1152 | pub const Sigaction = extern struct { |
| 1153 | pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void; | 1153 | pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void; |
| 1154 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; | 1154 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; |
| 1155 | 1155 | ||
| 1156 | handler: extern union { | 1156 | handler: extern union { |
lib/std/c/dragonfly.zig+4-4| ... | @@ -616,9 +616,9 @@ pub const S = struct { | ... | @@ -616,9 +616,9 @@ pub const S = struct { |
| 616 | pub const BADSIG = SIG.ERR; | 616 | pub const BADSIG = SIG.ERR; |
| 617 | 617 | ||
| 618 | pub const SIG = struct { | 618 | pub const SIG = struct { |
| 619 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | 619 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); |
| 620 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | 620 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); |
| 621 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | 621 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); |
| 622 | 622 | ||
| 623 | pub const BLOCK = 1; | 623 | pub const BLOCK = 1; |
| 624 | pub const UNBLOCK = 2; | 624 | pub const UNBLOCK = 2; |
| ... | @@ -690,7 +690,7 @@ pub const empty_sigset = sigset_t{ .__bits = [_]c_uint{0} ** _SIG_WORDS }; | ... | @@ -690,7 +690,7 @@ pub const empty_sigset = sigset_t{ .__bits = [_]c_uint{0} ** _SIG_WORDS }; |
| 690 | pub const sig_atomic_t = c_int; | 690 | pub const sig_atomic_t = c_int; |
| 691 | 691 | ||
| 692 | pub const Sigaction = extern struct { | 692 | pub const Sigaction = extern struct { |
| 693 | pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void; | 693 | pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void; |
| 694 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; | 694 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; |
| 695 | 695 | ||
| 696 | /// signal handler | 696 | /// signal handler |
lib/std/c/freebsd.zig+4-4| ... | @@ -695,9 +695,9 @@ pub const SIG = struct { | ... | @@ -695,9 +695,9 @@ pub const SIG = struct { |
| 695 | pub const UNBLOCK = 2; | 695 | pub const UNBLOCK = 2; |
| 696 | pub const SETMASK = 3; | 696 | pub const SETMASK = 3; |
| 697 | 697 | ||
| 698 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | 698 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); |
| 699 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | 699 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); |
| 700 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | 700 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); |
| 701 | 701 | ||
| 702 | pub const WORDS = 4; | 702 | pub const WORDS = 4; |
| 703 | pub const MAXSIG = 128; | 703 | pub const MAXSIG = 128; |
| ... | @@ -1171,7 +1171,7 @@ const NSIG = 32; | ... | @@ -1171,7 +1171,7 @@ const NSIG = 32; |
| 1171 | 1171 | ||
| 1172 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. | 1172 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. |
| 1173 | pub const Sigaction = extern struct { | 1173 | pub const Sigaction = extern struct { |
| 1174 | pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void; | 1174 | pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void; |
| 1175 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; | 1175 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; |
| 1176 | 1176 | ||
| 1177 | /// signal handler | 1177 | /// signal handler |
lib/std/c/haiku.zig+4-4| ... | @@ -441,9 +441,9 @@ pub const SA = struct { | ... | @@ -441,9 +441,9 @@ pub const SA = struct { |
| 441 | }; | 441 | }; |
| 442 | 442 | ||
| 443 | pub const SIG = struct { | 443 | pub const SIG = struct { |
| 444 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | 444 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); |
| 445 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | 445 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); |
| 446 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | 446 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); |
| 447 | 447 | ||
| 448 | pub const HUP = 1; | 448 | pub const HUP = 1; |
| 449 | pub const INT = 2; | 449 | pub const INT = 2; |
| ... | @@ -690,7 +690,7 @@ const NSIG = 32; | ... | @@ -690,7 +690,7 @@ const NSIG = 32; |
| 690 | 690 | ||
| 691 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. | 691 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. |
| 692 | pub const Sigaction = extern struct { | 692 | pub const Sigaction = extern struct { |
| 693 | pub const handler_fn = *const fn (i32) align(1) callconv(.C) void; | 693 | pub const handler_fn = *align(1) const fn (i32) callconv(.C) void; |
| 694 | 694 | ||
| 695 | /// signal handler | 695 | /// signal handler |
| 696 | __sigaction_u: extern union { | 696 | __sigaction_u: extern union { |
lib/std/c/netbsd.zig+4-4| ... | @@ -800,9 +800,9 @@ pub const winsize = extern struct { | ... | @@ -800,9 +800,9 @@ pub const winsize = extern struct { |
| 800 | const NSIG = 32; | 800 | const NSIG = 32; |
| 801 | 801 | ||
| 802 | pub const SIG = struct { | 802 | pub const SIG = struct { |
| 803 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | 803 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); |
| 804 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | 804 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); |
| 805 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | 805 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); |
| 806 | 806 | ||
| 807 | pub const WORDS = 4; | 807 | pub const WORDS = 4; |
| 808 | pub const MAXSIG = 128; | 808 | pub const MAXSIG = 128; |
| ... | @@ -864,7 +864,7 @@ pub const SIG = struct { | ... | @@ -864,7 +864,7 @@ pub const SIG = struct { |
| 864 | 864 | ||
| 865 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. | 865 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. |
| 866 | pub const Sigaction = extern struct { | 866 | pub const Sigaction = extern struct { |
| 867 | pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void; | 867 | pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void; |
| 868 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; | 868 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; |
| 869 | 869 | ||
| 870 | /// signal handler | 870 | /// signal handler |
lib/std/c/openbsd.zig+6-6| ... | @@ -795,11 +795,11 @@ pub const winsize = extern struct { | ... | @@ -795,11 +795,11 @@ pub const winsize = extern struct { |
| 795 | const NSIG = 33; | 795 | const NSIG = 33; |
| 796 | 796 | ||
| 797 | pub const SIG = struct { | 797 | pub const SIG = struct { |
| 798 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | 798 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); |
| 799 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | 799 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); |
| 800 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | 800 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); |
| 801 | pub const CATCH = @as(?Sigaction.handler_fn, @ptrFromInt(2)); | 801 | pub const CATCH: ?Sigaction.handler_fn = @ptrFromInt(2); |
| 802 | pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(3)); | 802 | pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(3); |
| 803 | 803 | ||
| 804 | pub const HUP = 1; | 804 | pub const HUP = 1; |
| 805 | pub const INT = 2; | 805 | pub const INT = 2; |
| ... | @@ -842,7 +842,7 @@ pub const SIG = struct { | ... | @@ -842,7 +842,7 @@ pub const SIG = struct { |
| 842 | 842 | ||
| 843 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. | 843 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. |
| 844 | pub const Sigaction = extern struct { | 844 | pub const Sigaction = extern struct { |
| 845 | pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void; | 845 | pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void; |
| 846 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; | 846 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; |
| 847 | 847 | ||
| 848 | /// signal handler | 848 | /// signal handler |
lib/std/c/solaris.zig+5-5| ... | @@ -798,10 +798,10 @@ pub const winsize = extern struct { | ... | @@ -798,10 +798,10 @@ pub const winsize = extern struct { |
| 798 | const NSIG = 75; | 798 | const NSIG = 75; |
| 799 | 799 | ||
| 800 | pub const SIG = struct { | 800 | pub const SIG = struct { |
| 801 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | 801 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); |
| 802 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | 802 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); |
| 803 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | 803 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); |
| 804 | pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(2)); | 804 | pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(2); |
| 805 | 805 | ||
| 806 | pub const WORDS = 4; | 806 | pub const WORDS = 4; |
| 807 | pub const MAXSIG = 75; | 807 | pub const MAXSIG = 75; |
| ... | @@ -874,7 +874,7 @@ pub const SIG = struct { | ... | @@ -874,7 +874,7 @@ pub const SIG = struct { |
| 874 | 874 | ||
| 875 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. | 875 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. |
| 876 | pub const Sigaction = extern struct { | 876 | pub const Sigaction = extern struct { |
| 877 | pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void; | 877 | pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void; |
| 878 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; | 878 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; |
| 879 | 879 | ||
| 880 | /// signal options | 880 | /// signal options |
lib/std/meta.zig+4-5| ... | @@ -57,10 +57,9 @@ test stringToEnum { | ... | @@ -57,10 +57,9 @@ test stringToEnum { |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | /// Returns the alignment of type T. | 59 | /// Returns the alignment of type T. |
| 60 | /// Note that if T is a pointer or function type the result is different than | 60 | /// Note that if T is a pointer type the result is different than the one |
| 61 | /// the one returned by @alignOf(T). | 61 | /// returned by @alignOf(T). |
| 62 | /// If T is a pointer type the alignment of the type it points to is returned. | 62 | /// If T is a pointer type the alignment of the type it points to is returned. |
| 63 | /// If T is a function type the alignment a target-dependent value is returned. | ||
| 64 | pub fn alignment(comptime T: type) comptime_int { | 63 | pub fn alignment(comptime T: type) comptime_int { |
| 65 | return switch (@typeInfo(T)) { | 64 | return switch (@typeInfo(T)) { |
| 66 | .Optional => |info| switch (@typeInfo(info.child)) { | 65 | .Optional => |info| switch (@typeInfo(info.child)) { |
| ... | @@ -68,7 +67,6 @@ pub fn alignment(comptime T: type) comptime_int { | ... | @@ -68,7 +67,6 @@ pub fn alignment(comptime T: type) comptime_int { |
| 68 | else => @alignOf(T), | 67 | else => @alignOf(T), |
| 69 | }, | 68 | }, |
| 70 | .Pointer => |info| info.alignment, | 69 | .Pointer => |info| info.alignment, |
| 71 | .Fn => |info| info.alignment, | ||
| 72 | else => @alignOf(T), | 70 | else => @alignOf(T), |
| 73 | }; | 71 | }; |
| 74 | } | 72 | } |
| ... | @@ -80,7 +78,8 @@ test alignment { | ... | @@ -80,7 +78,8 @@ test alignment { |
| 80 | try testing.expect(alignment([]align(1) u8) == 1); | 78 | try testing.expect(alignment([]align(1) u8) == 1); |
| 81 | try testing.expect(alignment([]align(2) u8) == 2); | 79 | try testing.expect(alignment([]align(2) u8) == 2); |
| 82 | try testing.expect(alignment(fn () void) > 0); | 80 | try testing.expect(alignment(fn () void) > 0); |
| 83 | try testing.expect(alignment(fn () align(128) void) == 128); | 81 | try testing.expect(alignment(*const fn () void) > 0); |
| 82 | try testing.expect(alignment(*align(128) const fn () void) == 128); | ||
| 84 | } | 83 | } |
| 85 | 84 | ||
| 86 | /// Given a parameterized type (array, vector, pointer, optional), returns the "child type". | 85 | /// Given a parameterized type (array, vector, pointer, optional), returns the "child type". |
lib/std/os/emscripten.zig+4-4| ... | @@ -689,13 +689,13 @@ pub const SIG = struct { | ... | @@ -689,13 +689,13 @@ pub const SIG = struct { |
| 689 | pub const SYS = 31; | 689 | pub const SYS = 31; |
| 690 | pub const UNUSED = SIG.SYS; | 690 | pub const UNUSED = SIG.SYS; |
| 691 | 691 | ||
| 692 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(std.math.maxInt(usize))); | 692 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(std.math.maxInt(usize)); |
| 693 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | 693 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); |
| 694 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | 694 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); |
| 695 | }; | 695 | }; |
| 696 | 696 | ||
| 697 | pub const Sigaction = extern struct { | 697 | pub const Sigaction = extern struct { |
| 698 | pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void; | 698 | pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void; |
| 699 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; | 699 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; |
| 700 | 700 | ||
| 701 | handler: extern union { | 701 | handler: extern union { |
lib/std/os/linux.zig+18-23| ... | @@ -1327,16 +1327,14 @@ pub fn flock(fd: fd_t, operation: i32) usize { | ... | @@ -1327,16 +1327,14 @@ pub fn flock(fd: fd_t, operation: i32) usize { |
| 1327 | return syscall2(.flock, @as(usize, @bitCast(@as(isize, fd))), @as(usize, @bitCast(@as(isize, operation)))); | 1327 | return syscall2(.flock, @as(usize, @bitCast(@as(isize, fd))), @as(usize, @bitCast(@as(isize, operation)))); |
| 1328 | } | 1328 | } |
| 1329 | 1329 | ||
| 1330 | var vdso_clock_gettime = @as(?*const anyopaque, @ptrCast(&init_vdso_clock_gettime)); | ||
| 1331 | |||
| 1332 | // We must follow the C calling convention when we call into the VDSO | 1330 | // We must follow the C calling convention when we call into the VDSO |
| 1333 | const vdso_clock_gettime_ty = *align(1) const fn (i32, *timespec) callconv(.C) usize; | 1331 | const VdsoClockGettime = *align(1) const fn (i32, *timespec) callconv(.C) usize; |
| 1332 | var vdso_clock_gettime: ?VdsoClockGettime = &init_vdso_clock_gettime; | ||
| 1334 | 1333 | ||
| 1335 | pub fn clock_gettime(clk_id: i32, tp: *timespec) usize { | 1334 | pub fn clock_gettime(clk_id: i32, tp: *timespec) usize { |
| 1336 | if (@hasDecl(VDSO, "CGT_SYM")) { | 1335 | if (@hasDecl(VDSO, "CGT_SYM")) { |
| 1337 | const ptr = @atomicLoad(?*const anyopaque, &vdso_clock_gettime, .unordered); | 1336 | const ptr = @atomicLoad(?VdsoClockGettime, &vdso_clock_gettime, .unordered); |
| 1338 | if (ptr) |fn_ptr| { | 1337 | if (ptr) |f| { |
| 1339 | const f = @as(vdso_clock_gettime_ty, @ptrCast(fn_ptr)); | ||
| 1340 | const rc = f(clk_id, tp); | 1338 | const rc = f(clk_id, tp); |
| 1341 | switch (rc) { | 1339 | switch (rc) { |
| 1342 | 0, @as(usize, @bitCast(-@as(isize, @intFromEnum(E.INVAL)))) => return rc, | 1340 | 0, @as(usize, @bitCast(-@as(isize, @intFromEnum(E.INVAL)))) => return rc, |
| ... | @@ -1348,15 +1346,12 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) usize { | ... | @@ -1348,15 +1346,12 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) usize { |
| 1348 | } | 1346 | } |
| 1349 | 1347 | ||
| 1350 | fn init_vdso_clock_gettime(clk: i32, ts: *timespec) callconv(.C) usize { | 1348 | fn init_vdso_clock_gettime(clk: i32, ts: *timespec) callconv(.C) usize { |
| 1351 | const ptr = @as(?*const anyopaque, @ptrFromInt(vdso.lookup(VDSO.CGT_VER, VDSO.CGT_SYM))); | 1349 | const ptr: ?VdsoClockGettime = @ptrFromInt(vdso.lookup(VDSO.CGT_VER, VDSO.CGT_SYM)); |
| 1352 | // Note that we may not have a VDSO at all, update the stub address anyway | 1350 | // Note that we may not have a VDSO at all, update the stub address anyway |
| 1353 | // so that clock_gettime will fall back on the good old (and slow) syscall | 1351 | // so that clock_gettime will fall back on the good old (and slow) syscall |
| 1354 | @atomicStore(?*const anyopaque, &vdso_clock_gettime, ptr, .monotonic); | 1352 | @atomicStore(?VdsoClockGettime, &vdso_clock_gettime, ptr, .monotonic); |
| 1355 | // Call into the VDSO if available | 1353 | // Call into the VDSO if available |
| 1356 | if (ptr) |fn_ptr| { | 1354 | if (ptr) |f| return f(clk, ts); |
| 1357 | const f = @as(vdso_clock_gettime_ty, @ptrCast(fn_ptr)); | ||
| 1358 | return f(clk, ts); | ||
| 1359 | } | ||
| 1360 | return @as(usize, @bitCast(-@as(isize, @intFromEnum(E.NOSYS)))); | 1355 | return @as(usize, @bitCast(-@as(isize, @intFromEnum(E.NOSYS)))); |
| 1361 | } | 1356 | } |
| 1362 | 1357 | ||
| ... | @@ -2516,9 +2511,9 @@ pub const SIG = if (is_mips) struct { | ... | @@ -2516,9 +2511,9 @@ pub const SIG = if (is_mips) struct { |
| 2516 | pub const SYS = 31; | 2511 | pub const SYS = 31; |
| 2517 | pub const UNUSED = SIG.SYS; | 2512 | pub const UNUSED = SIG.SYS; |
| 2518 | 2513 | ||
| 2519 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | 2514 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); |
| 2520 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | 2515 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); |
| 2521 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | 2516 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); |
| 2522 | } else if (is_sparc) struct { | 2517 | } else if (is_sparc) struct { |
| 2523 | pub const BLOCK = 1; | 2518 | pub const BLOCK = 1; |
| 2524 | pub const UNBLOCK = 2; | 2519 | pub const UNBLOCK = 2; |
| ... | @@ -2560,9 +2555,9 @@ pub const SIG = if (is_mips) struct { | ... | @@ -2560,9 +2555,9 @@ pub const SIG = if (is_mips) struct { |
| 2560 | pub const PWR = LOST; | 2555 | pub const PWR = LOST; |
| 2561 | pub const IO = SIG.POLL; | 2556 | pub const IO = SIG.POLL; |
| 2562 | 2557 | ||
| 2563 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | 2558 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); |
| 2564 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | 2559 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); |
| 2565 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | 2560 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); |
| 2566 | } else struct { | 2561 | } else struct { |
| 2567 | pub const BLOCK = 0; | 2562 | pub const BLOCK = 0; |
| 2568 | pub const UNBLOCK = 1; | 2563 | pub const UNBLOCK = 1; |
| ... | @@ -2603,9 +2598,9 @@ pub const SIG = if (is_mips) struct { | ... | @@ -2603,9 +2598,9 @@ pub const SIG = if (is_mips) struct { |
| 2603 | pub const SYS = 31; | 2598 | pub const SYS = 31; |
| 2604 | pub const UNUSED = SIG.SYS; | 2599 | pub const UNUSED = SIG.SYS; |
| 2605 | 2600 | ||
| 2606 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | 2601 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); |
| 2607 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | 2602 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); |
| 2608 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | 2603 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); |
| 2609 | }; | 2604 | }; |
| 2610 | 2605 | ||
| 2611 | pub const kernel_rwf = u32; | 2606 | pub const kernel_rwf = u32; |
| ... | @@ -3709,7 +3704,7 @@ pub const all_mask: sigset_t = [_]u32{0xffffffff} ** @typeInfo(sigset_t).Array.l | ... | @@ -3709,7 +3704,7 @@ pub const all_mask: sigset_t = [_]u32{0xffffffff} ** @typeInfo(sigset_t).Array.l |
| 3709 | pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffffffff} ** 30; | 3704 | pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffffffff} ** 30; |
| 3710 | 3705 | ||
| 3711 | const k_sigaction_funcs = struct { | 3706 | const k_sigaction_funcs = struct { |
| 3712 | const handler = ?*const fn (c_int) align(1) callconv(.C) void; | 3707 | const handler = ?*align(1) const fn (c_int) callconv(.C) void; |
| 3713 | const restorer = *const fn () callconv(.C) void; | 3708 | const restorer = *const fn () callconv(.C) void; |
| 3714 | }; | 3709 | }; |
| 3715 | 3710 | ||
| ... | @@ -3736,7 +3731,7 @@ pub const k_sigaction = switch (native_arch) { | ... | @@ -3736,7 +3731,7 @@ pub const k_sigaction = switch (native_arch) { |
| 3736 | 3731 | ||
| 3737 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. | 3732 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. |
| 3738 | pub const Sigaction = extern struct { | 3733 | pub const Sigaction = extern struct { |
| 3739 | pub const handler_fn = *const fn (c_int) align(1) callconv(.C) void; | 3734 | pub const handler_fn = *align(1) const fn (c_int) callconv(.C) void; |
| 3740 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; | 3735 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; |
| 3741 | 3736 | ||
| 3742 | handler: extern union { | 3737 | handler: extern union { |
lib/std/zig/AstGen.zig+7-7| ... | @@ -1369,16 +1369,16 @@ fn fnProtoExpr( | ... | @@ -1369,16 +1369,16 @@ fn fnProtoExpr( |
| 1369 | break :is_var_args false; | 1369 | break :is_var_args false; |
| 1370 | }; | 1370 | }; |
| 1371 | 1371 | ||
| 1372 | const align_ref: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: { | 1372 | if (fn_proto.ast.align_expr != 0) { |
| 1373 | break :inst try expr(&block_scope, scope, coerced_align_ri, fn_proto.ast.align_expr); | 1373 | return astgen.failNode(fn_proto.ast.align_expr, "function type cannot have an alignment", .{}); |
| 1374 | }; | 1374 | } |
| 1375 | 1375 | ||
| 1376 | if (fn_proto.ast.addrspace_expr != 0) { | 1376 | if (fn_proto.ast.addrspace_expr != 0) { |
| 1377 | return astgen.failNode(fn_proto.ast.addrspace_expr, "addrspace not allowed on function prototypes", .{}); | 1377 | return astgen.failNode(fn_proto.ast.addrspace_expr, "function type cannot have an addrspace", .{}); |
| 1378 | } | 1378 | } |
| 1379 | 1379 | ||
| 1380 | if (fn_proto.ast.section_expr != 0) { | 1380 | if (fn_proto.ast.section_expr != 0) { |
| 1381 | return astgen.failNode(fn_proto.ast.section_expr, "linksection not allowed on function prototypes", .{}); | 1381 | return astgen.failNode(fn_proto.ast.section_expr, "function type cannot have a linksection", .{}); |
| 1382 | } | 1382 | } |
| 1383 | 1383 | ||
| 1384 | const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0) | 1384 | const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0) |
| ... | @@ -1394,7 +1394,7 @@ fn fnProtoExpr( | ... | @@ -1394,7 +1394,7 @@ fn fnProtoExpr( |
| 1394 | const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; | 1394 | const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; |
| 1395 | const is_inferred_error = token_tags[maybe_bang] == .bang; | 1395 | const is_inferred_error = token_tags[maybe_bang] == .bang; |
| 1396 | if (is_inferred_error) { | 1396 | if (is_inferred_error) { |
| 1397 | return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{}); | 1397 | return astgen.failTok(maybe_bang, "function type cannot have an inferred error set", .{}); |
| 1398 | } | 1398 | } |
| 1399 | const ret_ty = try expr(&block_scope, scope, coerced_type_ri, fn_proto.ast.return_type); | 1399 | const ret_ty = try expr(&block_scope, scope, coerced_type_ri, fn_proto.ast.return_type); |
| 1400 | 1400 | ||
| ... | @@ -1403,7 +1403,7 @@ fn fnProtoExpr( | ... | @@ -1403,7 +1403,7 @@ fn fnProtoExpr( |
| 1403 | 1403 | ||
| 1404 | .cc_ref = cc, | 1404 | .cc_ref = cc, |
| 1405 | .cc_gz = null, | 1405 | .cc_gz = null, |
| 1406 | .align_ref = align_ref, | 1406 | .align_ref = .none, |
| 1407 | .align_gz = null, | 1407 | .align_gz = null, |
| 1408 | .ret_ref = ret_ty, | 1408 | .ret_ref = ret_ty, |
| 1409 | .ret_gz = null, | 1409 | .ret_gz = null, |
src/InternPool.zig+5-23| ... | @@ -765,16 +765,10 @@ pub const Key = union(enum) { | ... | @@ -765,16 +765,10 @@ pub const Key = union(enum) { |
| 765 | /// Tells whether a parameter is noalias. See `paramIsNoalias` helper | 765 | /// Tells whether a parameter is noalias. See `paramIsNoalias` helper |
| 766 | /// method for accessing this. | 766 | /// method for accessing this. |
| 767 | noalias_bits: u32, | 767 | noalias_bits: u32, |
| 768 | /// `none` indicates the function has the default alignment for | ||
| 769 | /// function code on the target. In this case, this field *must* be set | ||
| 770 | /// to `none`, otherwise the `InternPool` equality and hashing | ||
| 771 | /// functions will return incorrect results. | ||
| 772 | alignment: Alignment, | ||
| 773 | cc: std.builtin.CallingConvention, | 768 | cc: std.builtin.CallingConvention, |
| 774 | is_var_args: bool, | 769 | is_var_args: bool, |
| 775 | is_generic: bool, | 770 | is_generic: bool, |
| 776 | is_noinline: bool, | 771 | is_noinline: bool, |
| 777 | align_is_generic: bool, | ||
| 778 | cc_is_generic: bool, | 772 | cc_is_generic: bool, |
| 779 | section_is_generic: bool, | 773 | section_is_generic: bool, |
| 780 | addrspace_is_generic: bool, | 774 | addrspace_is_generic: bool, |
| ... | @@ -794,7 +788,6 @@ pub const Key = union(enum) { | ... | @@ -794,7 +788,6 @@ pub const Key = union(enum) { |
| 794 | a.return_type == b.return_type and | 788 | a.return_type == b.return_type and |
| 795 | a.comptime_bits == b.comptime_bits and | 789 | a.comptime_bits == b.comptime_bits and |
| 796 | a.noalias_bits == b.noalias_bits and | 790 | a.noalias_bits == b.noalias_bits and |
| 797 | a.alignment == b.alignment and | ||
| 798 | a.cc == b.cc and | 791 | a.cc == b.cc and |
| 799 | a.is_var_args == b.is_var_args and | 792 | a.is_var_args == b.is_var_args and |
| 800 | a.is_generic == b.is_generic and | 793 | a.is_generic == b.is_generic and |
| ... | @@ -808,7 +801,6 @@ pub const Key = union(enum) { | ... | @@ -808,7 +801,6 @@ pub const Key = union(enum) { |
| 808 | std.hash.autoHash(hasher, self.return_type); | 801 | std.hash.autoHash(hasher, self.return_type); |
| 809 | std.hash.autoHash(hasher, self.comptime_bits); | 802 | std.hash.autoHash(hasher, self.comptime_bits); |
| 810 | std.hash.autoHash(hasher, self.noalias_bits); | 803 | std.hash.autoHash(hasher, self.noalias_bits); |
| 811 | std.hash.autoHash(hasher, self.alignment); | ||
| 812 | std.hash.autoHash(hasher, self.cc); | 804 | std.hash.autoHash(hasher, self.cc); |
| 813 | std.hash.autoHash(hasher, self.is_var_args); | 805 | std.hash.autoHash(hasher, self.is_var_args); |
| 814 | std.hash.autoHash(hasher, self.is_generic); | 806 | std.hash.autoHash(hasher, self.is_generic); |
| ... | @@ -3587,18 +3579,16 @@ pub const Tag = enum(u8) { | ... | @@ -3587,18 +3579,16 @@ pub const Tag = enum(u8) { |
| 3587 | flags: Flags, | 3579 | flags: Flags, |
| 3588 | 3580 | ||
| 3589 | pub const Flags = packed struct(u32) { | 3581 | pub const Flags = packed struct(u32) { |
| 3590 | alignment: Alignment, | ||
| 3591 | cc: std.builtin.CallingConvention, | 3582 | cc: std.builtin.CallingConvention, |
| 3592 | is_var_args: bool, | 3583 | is_var_args: bool, |
| 3593 | is_generic: bool, | 3584 | is_generic: bool, |
| 3594 | has_comptime_bits: bool, | 3585 | has_comptime_bits: bool, |
| 3595 | has_noalias_bits: bool, | 3586 | has_noalias_bits: bool, |
| 3596 | is_noinline: bool, | 3587 | is_noinline: bool, |
| 3597 | align_is_generic: bool, | ||
| 3598 | cc_is_generic: bool, | 3588 | cc_is_generic: bool, |
| 3599 | section_is_generic: bool, | 3589 | section_is_generic: bool, |
| 3600 | addrspace_is_generic: bool, | 3590 | addrspace_is_generic: bool, |
| 3601 | _: u9 = 0, | 3591 | _: u16 = 0, |
| 3602 | }; | 3592 | }; |
| 3603 | }; | 3593 | }; |
| 3604 | 3594 | ||
| ... | @@ -4918,11 +4908,9 @@ fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType { | ... | @@ -4918,11 +4908,9 @@ fn extraFuncType(ip: *const InternPool, extra_index: u32) Key.FuncType { |
| 4918 | .return_type = type_function.data.return_type, | 4908 | .return_type = type_function.data.return_type, |
| 4919 | .comptime_bits = comptime_bits, | 4909 | .comptime_bits = comptime_bits, |
| 4920 | .noalias_bits = noalias_bits, | 4910 | .noalias_bits = noalias_bits, |
| 4921 | .alignment = type_function.data.flags.alignment, | ||
| 4922 | .cc = type_function.data.flags.cc, | 4911 | .cc = type_function.data.flags.cc, |
| 4923 | .is_var_args = type_function.data.flags.is_var_args, | 4912 | .is_var_args = type_function.data.flags.is_var_args, |
| 4924 | .is_noinline = type_function.data.flags.is_noinline, | 4913 | .is_noinline = type_function.data.flags.is_noinline, |
| 4925 | .align_is_generic = type_function.data.flags.align_is_generic, | ||
| 4926 | .cc_is_generic = type_function.data.flags.cc_is_generic, | 4914 | .cc_is_generic = type_function.data.flags.cc_is_generic, |
| 4927 | .section_is_generic = type_function.data.flags.section_is_generic, | 4915 | .section_is_generic = type_function.data.flags.section_is_generic, |
| 4928 | .addrspace_is_generic = type_function.data.flags.addrspace_is_generic, | 4916 | .addrspace_is_generic = type_function.data.flags.addrspace_is_generic, |
| ... | @@ -6211,8 +6199,6 @@ pub const GetFuncTypeKey = struct { | ... | @@ -6211,8 +6199,6 @@ pub const GetFuncTypeKey = struct { |
| 6211 | comptime_bits: u32 = 0, | 6199 | comptime_bits: u32 = 0, |
| 6212 | noalias_bits: u32 = 0, | 6200 | noalias_bits: u32 = 0, |
| 6213 | /// `null` means generic. | 6201 | /// `null` means generic. |
| 6214 | alignment: ?Alignment = .none, | ||
| 6215 | /// `null` means generic. | ||
| 6216 | cc: ?std.builtin.CallingConvention = .Unspecified, | 6202 | cc: ?std.builtin.CallingConvention = .Unspecified, |
| 6217 | is_var_args: bool = false, | 6203 | is_var_args: bool = false, |
| 6218 | is_generic: bool = false, | 6204 | is_generic: bool = false, |
| ... | @@ -6242,14 +6228,12 @@ pub fn getFuncType(ip: *InternPool, gpa: Allocator, key: GetFuncTypeKey) Allocat | ... | @@ -6242,14 +6228,12 @@ pub fn getFuncType(ip: *InternPool, gpa: Allocator, key: GetFuncTypeKey) Allocat |
| 6242 | .params_len = params_len, | 6228 | .params_len = params_len, |
| 6243 | .return_type = key.return_type, | 6229 | .return_type = key.return_type, |
| 6244 | .flags = .{ | 6230 | .flags = .{ |
| 6245 | .alignment = key.alignment orelse .none, | ||
| 6246 | .cc = key.cc orelse .Unspecified, | 6231 | .cc = key.cc orelse .Unspecified, |
| 6247 | .is_var_args = key.is_var_args, | 6232 | .is_var_args = key.is_var_args, |
| 6248 | .has_comptime_bits = key.comptime_bits != 0, | 6233 | .has_comptime_bits = key.comptime_bits != 0, |
| 6249 | .has_noalias_bits = key.noalias_bits != 0, | 6234 | .has_noalias_bits = key.noalias_bits != 0, |
| 6250 | .is_generic = key.is_generic, | 6235 | .is_generic = key.is_generic, |
| 6251 | .is_noinline = key.is_noinline, | 6236 | .is_noinline = key.is_noinline, |
| 6252 | .align_is_generic = key.alignment == null, | ||
| 6253 | .cc_is_generic = key.cc == null, | 6237 | .cc_is_generic = key.cc == null, |
| 6254 | .section_is_generic = key.section_is_generic, | 6238 | .section_is_generic = key.section_is_generic, |
| 6255 | .addrspace_is_generic = key.addrspace_is_generic, | 6239 | .addrspace_is_generic = key.addrspace_is_generic, |
| ... | @@ -6433,14 +6417,12 @@ pub fn getFuncDeclIes(ip: *InternPool, gpa: Allocator, key: GetFuncDeclIesKey) A | ... | @@ -6433,14 +6417,12 @@ pub fn getFuncDeclIes(ip: *InternPool, gpa: Allocator, key: GetFuncDeclIesKey) A |
| 6433 | .params_len = params_len, | 6417 | .params_len = params_len, |
| 6434 | .return_type = @enumFromInt(ip.items.len - 2), | 6418 | .return_type = @enumFromInt(ip.items.len - 2), |
| 6435 | .flags = .{ | 6419 | .flags = .{ |
| 6436 | .alignment = key.alignment orelse .none, | ||
| 6437 | .cc = key.cc orelse .Unspecified, | 6420 | .cc = key.cc orelse .Unspecified, |
| 6438 | .is_var_args = key.is_var_args, | 6421 | .is_var_args = key.is_var_args, |
| 6439 | .has_comptime_bits = key.comptime_bits != 0, | 6422 | .has_comptime_bits = key.comptime_bits != 0, |
| 6440 | .has_noalias_bits = key.noalias_bits != 0, | 6423 | .has_noalias_bits = key.noalias_bits != 0, |
| 6441 | .is_generic = key.is_generic, | 6424 | .is_generic = key.is_generic, |
| 6442 | .is_noinline = key.is_noinline, | 6425 | .is_noinline = key.is_noinline, |
| 6443 | .align_is_generic = key.alignment == null, | ||
| 6444 | .cc_is_generic = key.cc == null, | 6426 | .cc_is_generic = key.cc == null, |
| 6445 | .section_is_generic = key.section_is_generic, | 6427 | .section_is_generic = key.section_is_generic, |
| 6446 | .addrspace_is_generic = key.addrspace_is_generic, | 6428 | .addrspace_is_generic = key.addrspace_is_generic, |
| ... | @@ -6553,7 +6535,6 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey) | ... | @@ -6553,7 +6535,6 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey) |
| 6553 | .param_types = arg.param_types, | 6535 | .param_types = arg.param_types, |
| 6554 | .return_type = arg.bare_return_type, | 6536 | .return_type = arg.bare_return_type, |
| 6555 | .noalias_bits = arg.noalias_bits, | 6537 | .noalias_bits = arg.noalias_bits, |
| 6556 | .alignment = arg.alignment, | ||
| 6557 | .cc = arg.cc, | 6538 | .cc = arg.cc, |
| 6558 | .is_noinline = arg.is_noinline, | 6539 | .is_noinline = arg.is_noinline, |
| 6559 | }); | 6540 | }); |
| ... | @@ -6610,6 +6591,7 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey) | ... | @@ -6610,6 +6591,7 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey) |
| 6610 | func_index, | 6591 | func_index, |
| 6611 | func_extra_index, | 6592 | func_extra_index, |
| 6612 | func_ty, | 6593 | func_ty, |
| 6594 | arg.alignment, | ||
| 6613 | arg.section, | 6595 | arg.section, |
| 6614 | ); | 6596 | ); |
| 6615 | } | 6597 | } |
| ... | @@ -6673,14 +6655,12 @@ pub fn getFuncInstanceIes( | ... | @@ -6673,14 +6655,12 @@ pub fn getFuncInstanceIes( |
| 6673 | .params_len = params_len, | 6655 | .params_len = params_len, |
| 6674 | .return_type = error_union_type, | 6656 | .return_type = error_union_type, |
| 6675 | .flags = .{ | 6657 | .flags = .{ |
| 6676 | .alignment = arg.alignment, | ||
| 6677 | .cc = arg.cc, | 6658 | .cc = arg.cc, |
| 6678 | .is_var_args = false, | 6659 | .is_var_args = false, |
| 6679 | .has_comptime_bits = false, | 6660 | .has_comptime_bits = false, |
| 6680 | .has_noalias_bits = arg.noalias_bits != 0, | 6661 | .has_noalias_bits = arg.noalias_bits != 0, |
| 6681 | .is_generic = false, | 6662 | .is_generic = false, |
| 6682 | .is_noinline = arg.is_noinline, | 6663 | .is_noinline = arg.is_noinline, |
| 6683 | .align_is_generic = false, | ||
| 6684 | .cc_is_generic = false, | 6664 | .cc_is_generic = false, |
| 6685 | .section_is_generic = false, | 6665 | .section_is_generic = false, |
| 6686 | .addrspace_is_generic = false, | 6666 | .addrspace_is_generic = false, |
| ... | @@ -6741,6 +6721,7 @@ pub fn getFuncInstanceIes( | ... | @@ -6741,6 +6721,7 @@ pub fn getFuncInstanceIes( |
| 6741 | func_index, | 6721 | func_index, |
| 6742 | func_extra_index, | 6722 | func_extra_index, |
| 6743 | func_ty, | 6723 | func_ty, |
| 6724 | arg.alignment, | ||
| 6744 | arg.section, | 6725 | arg.section, |
| 6745 | ); | 6726 | ); |
| 6746 | } | 6727 | } |
| ... | @@ -6752,6 +6733,7 @@ fn finishFuncInstance( | ... | @@ -6752,6 +6733,7 @@ fn finishFuncInstance( |
| 6752 | func_index: Index, | 6733 | func_index: Index, |
| 6753 | func_extra_index: u32, | 6734 | func_extra_index: u32, |
| 6754 | func_ty: Index, | 6735 | func_ty: Index, |
| 6736 | alignment: Alignment, | ||
| 6755 | section: OptionalNullTerminatedString, | 6737 | section: OptionalNullTerminatedString, |
| 6756 | ) Allocator.Error!Index { | 6738 | ) Allocator.Error!Index { |
| 6757 | const fn_owner_decl = ip.declPtr(ip.funcDeclOwner(generic_owner)); | 6739 | const fn_owner_decl = ip.declPtr(ip.funcDeclOwner(generic_owner)); |
| ... | @@ -6764,7 +6746,7 @@ fn finishFuncInstance( | ... | @@ -6764,7 +6746,7 @@ fn finishFuncInstance( |
| 6764 | .owns_tv = true, | 6746 | .owns_tv = true, |
| 6765 | .ty = @import("type.zig").Type.fromInterned(func_ty), | 6747 | .ty = @import("type.zig").Type.fromInterned(func_ty), |
| 6766 | .val = @import("Value.zig").fromInterned(func_index), | 6748 | .val = @import("Value.zig").fromInterned(func_index), |
| 6767 | .alignment = .none, | 6749 | .alignment = alignment, |
| 6768 | .@"linksection" = section, | 6750 | .@"linksection" = section, |
| 6769 | .@"addrspace" = fn_owner_decl.@"addrspace", | 6751 | .@"addrspace" = fn_owner_decl.@"addrspace", |
| 6770 | .analysis = .complete, | 6752 | .analysis = .complete, |
src/Module.zig+72-104| ... | @@ -3596,6 +3596,18 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { | ... | @@ -3596,6 +3596,18 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { |
| 3596 | 3596 | ||
| 3597 | log.debug("semaDecl '{d}'", .{@intFromEnum(decl_index)}); | 3597 | log.debug("semaDecl '{d}'", .{@intFromEnum(decl_index)}); |
| 3598 | 3598 | ||
| 3599 | const old_has_tv = decl.has_tv; | ||
| 3600 | // The following values are ignored if `!old_has_tv` | ||
| 3601 | const old_ty = decl.ty; | ||
| 3602 | const old_val = decl.val; | ||
| 3603 | const old_align = decl.alignment; | ||
| 3604 | const old_linksection = decl.@"linksection"; | ||
| 3605 | const old_addrspace = decl.@"addrspace"; | ||
| 3606 | const old_is_inline = if (decl.getOwnedFunction(mod)) |prev_func| | ||
| 3607 | prev_func.analysis(ip).state == .inline_only | ||
| 3608 | else | ||
| 3609 | false; | ||
| 3610 | |||
| 3599 | const decl_inst = decl.zir_decl_index.unwrap().?.resolve(ip); | 3611 | const decl_inst = decl.zir_decl_index.unwrap().?.resolve(ip); |
| 3600 | 3612 | ||
| 3601 | const gpa = mod.gpa; | 3613 | const gpa = mod.gpa; |
| ... | @@ -3733,141 +3745,96 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { | ... | @@ -3733,141 +3745,96 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { |
| 3733 | }; | 3745 | }; |
| 3734 | } | 3746 | } |
| 3735 | 3747 | ||
| 3736 | switch (ip.indexToKey(decl_tv.val.toIntern())) { | 3748 | var queue_linker_work = true; |
| 3737 | .func => |func| { | 3749 | var is_func = false; |
| 3738 | const owns_tv = func.owner_decl == decl_index; | 3750 | var is_inline = false; |
| 3739 | if (owns_tv) { | ||
| 3740 | var prev_type_has_bits = false; | ||
| 3741 | var prev_is_inline = false; | ||
| 3742 | var type_changed = true; | ||
| 3743 | |||
| 3744 | if (decl.has_tv) { | ||
| 3745 | prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits(mod); | ||
| 3746 | type_changed = !decl.ty.eql(decl_tv.ty, mod); | ||
| 3747 | if (decl.getOwnedFunction(mod)) |prev_func| { | ||
| 3748 | prev_is_inline = prev_func.analysis(ip).state == .inline_only; | ||
| 3749 | } | ||
| 3750 | } | ||
| 3751 | |||
| 3752 | decl.ty = decl_tv.ty; | ||
| 3753 | decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod))); | ||
| 3754 | // linksection, align, and addrspace were already set by Sema | ||
| 3755 | decl.has_tv = true; | ||
| 3756 | decl.owns_tv = owns_tv; | ||
| 3757 | decl.analysis = .complete; | ||
| 3758 | |||
| 3759 | const is_inline = decl.ty.fnCallingConvention(mod) == .Inline; | ||
| 3760 | if (decl.is_exported) { | ||
| 3761 | const export_src: LazySrcLoc = .{ .token_offset = @intFromBool(decl.is_pub) }; | ||
| 3762 | if (is_inline) { | ||
| 3763 | return sema.fail(&block_scope, export_src, "export of inline function", .{}); | ||
| 3764 | } | ||
| 3765 | // The scope needs to have the decl in it. | ||
| 3766 | try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index); | ||
| 3767 | } | ||
| 3768 | // TODO: align, linksection, addrspace? | ||
| 3769 | const changed = type_changed or is_inline != prev_is_inline; | ||
| 3770 | return .{ | ||
| 3771 | .invalidate_decl_val = changed, | ||
| 3772 | .invalidate_decl_ref = changed, | ||
| 3773 | }; | ||
| 3774 | } | ||
| 3775 | }, | ||
| 3776 | else => {}, | ||
| 3777 | } | ||
| 3778 | |||
| 3779 | decl.owns_tv = false; | ||
| 3780 | var queue_linker_work = false; | ||
| 3781 | var is_extern = false; | ||
| 3782 | switch (decl_tv.val.toIntern()) { | 3751 | switch (decl_tv.val.toIntern()) { |
| 3783 | .generic_poison => unreachable, | 3752 | .generic_poison => unreachable, |
| 3784 | .unreachable_value => unreachable, | 3753 | .unreachable_value => unreachable, |
| 3785 | else => switch (ip.indexToKey(decl_tv.val.toIntern())) { | 3754 | else => switch (ip.indexToKey(decl_tv.val.toIntern())) { |
| 3786 | .variable => |variable| if (variable.decl == decl_index) { | 3755 | .variable => |variable| { |
| 3787 | decl.owns_tv = true; | 3756 | decl.owns_tv = variable.decl == decl_index; |
| 3788 | queue_linker_work = true; | 3757 | queue_linker_work = decl.owns_tv; |
| 3789 | }, | 3758 | }, |
| 3790 | 3759 | ||
| 3791 | .extern_func => |extern_fn| if (extern_fn.decl == decl_index) { | 3760 | .extern_func => |extern_func| { |
| 3792 | decl.owns_tv = true; | 3761 | decl.owns_tv = extern_func.decl == decl_index; |
| 3793 | queue_linker_work = true; | 3762 | queue_linker_work = decl.owns_tv; |
| 3794 | is_extern = true; | 3763 | is_func = decl.owns_tv; |
| 3795 | }, | 3764 | }, |
| 3796 | 3765 | ||
| 3797 | .func => {}, | 3766 | .func => |func| { |
| 3798 | 3767 | decl.owns_tv = func.owner_decl == decl_index; | |
| 3799 | else => { | 3768 | queue_linker_work = false; |
| 3800 | queue_linker_work = true; | 3769 | is_inline = decl.owns_tv and decl_tv.ty.fnCallingConvention(mod) == .Inline; |
| 3770 | is_func = decl.owns_tv; | ||
| 3801 | }, | 3771 | }, |
| 3772 | |||
| 3773 | else => {}, | ||
| 3802 | }, | 3774 | }, |
| 3803 | } | 3775 | } |
| 3804 | 3776 | ||
| 3805 | const old_has_tv = decl.has_tv; | ||
| 3806 | // The following values are ignored if `!old_has_tv` | ||
| 3807 | const old_ty = decl.ty; | ||
| 3808 | const old_val = decl.val; | ||
| 3809 | const old_align = decl.alignment; | ||
| 3810 | const old_linksection = decl.@"linksection"; | ||
| 3811 | const old_addrspace = decl.@"addrspace"; | ||
| 3812 | |||
| 3813 | decl.ty = decl_tv.ty; | 3777 | decl.ty = decl_tv.ty; |
| 3814 | decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod))); | 3778 | decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod))); |
| 3815 | decl.alignment = blk: { | 3779 | // Function linksection, align, and addrspace were already set by Sema |
| 3816 | const align_body = decl_bodies.align_body orelse break :blk .none; | 3780 | if (!is_func) { |
| 3817 | const align_ref = try sema.resolveInlineBody(&block_scope, align_body, decl_inst); | 3781 | decl.alignment = blk: { |
| 3818 | break :blk try sema.analyzeAsAlign(&block_scope, align_src, align_ref); | 3782 | const align_body = decl_bodies.align_body orelse break :blk .none; |
| 3819 | }; | 3783 | const align_ref = try sema.resolveInlineBody(&block_scope, align_body, decl_inst); |
| 3820 | decl.@"linksection" = blk: { | 3784 | break :blk try sema.analyzeAsAlign(&block_scope, align_src, align_ref); |
| 3821 | const linksection_body = decl_bodies.linksection_body orelse break :blk .none; | ||
| 3822 | const linksection_ref = try sema.resolveInlineBody(&block_scope, linksection_body, decl_inst); | ||
| 3823 | const bytes = try sema.toConstString(&block_scope, section_src, linksection_ref, .{ | ||
| 3824 | .needed_comptime_reason = "linksection must be comptime-known", | ||
| 3825 | }); | ||
| 3826 | if (mem.indexOfScalar(u8, bytes, 0) != null) { | ||
| 3827 | return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{}); | ||
| 3828 | } else if (bytes.len == 0) { | ||
| 3829 | return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{}); | ||
| 3830 | } | ||
| 3831 | const section = try ip.getOrPutString(gpa, bytes); | ||
| 3832 | break :blk section.toOptional(); | ||
| 3833 | }; | ||
| 3834 | decl.@"addrspace" = blk: { | ||
| 3835 | const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(decl_tv.val.toIntern())) { | ||
| 3836 | .variable => .variable, | ||
| 3837 | .extern_func, .func => .function, | ||
| 3838 | else => .constant, | ||
| 3839 | }; | 3785 | }; |
| 3786 | decl.@"linksection" = blk: { | ||
| 3787 | const linksection_body = decl_bodies.linksection_body orelse break :blk .none; | ||
| 3788 | const linksection_ref = try sema.resolveInlineBody(&block_scope, linksection_body, decl_inst); | ||
| 3789 | const bytes = try sema.toConstString(&block_scope, section_src, linksection_ref, .{ | ||
| 3790 | .needed_comptime_reason = "linksection must be comptime-known", | ||
| 3791 | }); | ||
| 3792 | if (mem.indexOfScalar(u8, bytes, 0) != null) { | ||
| 3793 | return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{}); | ||
| 3794 | } else if (bytes.len == 0) { | ||
| 3795 | return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{}); | ||
| 3796 | } | ||
| 3797 | const section = try ip.getOrPutString(gpa, bytes); | ||
| 3798 | break :blk section.toOptional(); | ||
| 3799 | }; | ||
| 3800 | decl.@"addrspace" = blk: { | ||
| 3801 | const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(decl_tv.val.toIntern())) { | ||
| 3802 | .variable => .variable, | ||
| 3803 | .extern_func, .func => .function, | ||
| 3804 | else => .constant, | ||
| 3805 | }; | ||
| 3840 | 3806 | ||
| 3841 | const target = sema.mod.getTarget(); | 3807 | const target = sema.mod.getTarget(); |
| 3842 | 3808 | ||
| 3843 | const addrspace_body = decl_bodies.addrspace_body orelse break :blk switch (addrspace_ctx) { | 3809 | const addrspace_body = decl_bodies.addrspace_body orelse break :blk switch (addrspace_ctx) { |
| 3844 | .function => target_util.defaultAddressSpace(target, .function), | 3810 | .function => target_util.defaultAddressSpace(target, .function), |
| 3845 | .variable => target_util.defaultAddressSpace(target, .global_mutable), | 3811 | .variable => target_util.defaultAddressSpace(target, .global_mutable), |
| 3846 | .constant => target_util.defaultAddressSpace(target, .global_constant), | 3812 | .constant => target_util.defaultAddressSpace(target, .global_constant), |
| 3847 | else => unreachable, | 3813 | else => unreachable, |
| 3814 | }; | ||
| 3815 | const addrspace_ref = try sema.resolveInlineBody(&block_scope, addrspace_body, decl_inst); | ||
| 3816 | break :blk try sema.analyzeAsAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx); | ||
| 3848 | }; | 3817 | }; |
| 3849 | const addrspace_ref = try sema.resolveInlineBody(&block_scope, addrspace_body, decl_inst); | 3818 | } |
| 3850 | break :blk try sema.analyzeAsAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx); | ||
| 3851 | }; | ||
| 3852 | decl.has_tv = true; | 3819 | decl.has_tv = true; |
| 3853 | decl.analysis = .complete; | 3820 | decl.analysis = .complete; |
| 3854 | 3821 | ||
| 3855 | const result: SemaDeclResult = if (old_has_tv) .{ | 3822 | const result: SemaDeclResult = if (old_has_tv) .{ |
| 3856 | .invalidate_decl_val = !decl.ty.eql(old_ty, mod) or !decl.val.eql(old_val, decl.ty, mod), | 3823 | .invalidate_decl_val = !decl.ty.eql(old_ty, mod) or |
| 3824 | !decl.val.eql(old_val, decl.ty, mod) or | ||
| 3825 | is_inline != old_is_inline, | ||
| 3857 | .invalidate_decl_ref = !decl.ty.eql(old_ty, mod) or | 3826 | .invalidate_decl_ref = !decl.ty.eql(old_ty, mod) or |
| 3858 | decl.alignment != old_align or | 3827 | decl.alignment != old_align or |
| 3859 | decl.@"linksection" != old_linksection or | 3828 | decl.@"linksection" != old_linksection or |
| 3860 | decl.@"addrspace" != old_addrspace, | 3829 | decl.@"addrspace" != old_addrspace or |
| 3830 | is_inline != old_is_inline, | ||
| 3861 | } else .{ | 3831 | } else .{ |
| 3862 | .invalidate_decl_val = true, | 3832 | .invalidate_decl_val = true, |
| 3863 | .invalidate_decl_ref = true, | 3833 | .invalidate_decl_ref = true, |
| 3864 | }; | 3834 | }; |
| 3865 | 3835 | ||
| 3866 | const has_runtime_bits = is_extern or | 3836 | const has_runtime_bits = queue_linker_work and (is_func or try sema.typeHasRuntimeBits(decl.ty)); |
| 3867 | (queue_linker_work and try sema.typeHasRuntimeBits(decl.ty)); | ||
| 3868 | |||
| 3869 | if (has_runtime_bits) { | 3837 | if (has_runtime_bits) { |
| 3870 | |||
| 3871 | // Needed for codegen_decl which will call updateDecl and then the | 3838 | // Needed for codegen_decl which will call updateDecl and then the |
| 3872 | // codegen backend wants full access to the Decl Type. | 3839 | // codegen backend wants full access to the Decl Type. |
| 3873 | try sema.resolveTypeFully(decl.ty); | 3840 | try sema.resolveTypeFully(decl.ty); |
| ... | @@ -3881,6 +3848,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { | ... | @@ -3881,6 +3848,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { |
| 3881 | 3848 | ||
| 3882 | if (decl.is_exported) { | 3849 | if (decl.is_exported) { |
| 3883 | const export_src: LazySrcLoc = .{ .token_offset = @intFromBool(decl.is_pub) }; | 3850 | const export_src: LazySrcLoc = .{ .token_offset = @intFromBool(decl.is_pub) }; |
| 3851 | if (is_inline) return sema.fail(&block_scope, export_src, "export of inline function", .{}); | ||
| 3884 | // The scope needs to have the decl in it. | 3852 | // The scope needs to have the decl in it. |
| 3885 | try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index); | 3853 | try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index); |
| 3886 | } | 3854 | } |
src/Sema.zig+11-32| ... | @@ -7605,7 +7605,6 @@ fn analyzeCall( | ... | @@ -7605,7 +7605,6 @@ fn analyzeCall( |
| 7605 | .param_types = new_param_types, | 7605 | .param_types = new_param_types, |
| 7606 | .return_type = owner_info.return_type, | 7606 | .return_type = owner_info.return_type, |
| 7607 | .noalias_bits = owner_info.noalias_bits, | 7607 | .noalias_bits = owner_info.noalias_bits, |
| 7608 | .alignment = if (owner_info.align_is_generic) null else owner_info.alignment, | ||
| 7609 | .cc = if (owner_info.cc_is_generic) null else owner_info.cc, | 7608 | .cc = if (owner_info.cc_is_generic) null else owner_info.cc, |
| 7610 | .is_var_args = owner_info.is_var_args, | 7609 | .is_var_args = owner_info.is_var_args, |
| 7611 | .is_noinline = owner_info.is_noinline, | 7610 | .is_noinline = owner_info.is_noinline, |
| ... | @@ -9629,7 +9628,6 @@ fn funcCommon( | ... | @@ -9629,7 +9628,6 @@ fn funcCommon( |
| 9629 | .comptime_bits = comptime_bits, | 9628 | .comptime_bits = comptime_bits, |
| 9630 | .return_type = bare_return_type.toIntern(), | 9629 | .return_type = bare_return_type.toIntern(), |
| 9631 | .cc = cc, | 9630 | .cc = cc, |
| 9632 | .alignment = alignment, | ||
| 9633 | .section_is_generic = section == .generic, | 9631 | .section_is_generic = section == .generic, |
| 9634 | .addrspace_is_generic = address_space == null, | 9632 | .addrspace_is_generic = address_space == null, |
| 9635 | .is_var_args = var_args, | 9633 | .is_var_args = var_args, |
| ... | @@ -9640,6 +9638,7 @@ fn funcCommon( | ... | @@ -9640,6 +9638,7 @@ fn funcCommon( |
| 9640 | if (is_extern) { | 9638 | if (is_extern) { |
| 9641 | assert(comptime_bits == 0); | 9639 | assert(comptime_bits == 0); |
| 9642 | assert(cc != null); | 9640 | assert(cc != null); |
| 9641 | assert(alignment != null); | ||
| 9643 | assert(section != .generic); | 9642 | assert(section != .generic); |
| 9644 | assert(address_space != null); | 9643 | assert(address_space != null); |
| 9645 | assert(!is_generic); | 9644 | assert(!is_generic); |
| ... | @@ -17623,8 +17622,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -17623,8 +17622,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17623 | const field_values = .{ | 17622 | const field_values = .{ |
| 17624 | // calling_convention: CallingConvention, | 17623 | // calling_convention: CallingConvention, |
| 17625 | (try mod.enumValueFieldIndex(callconv_ty, @intFromEnum(func_ty_info.cc))).toIntern(), | 17624 | (try mod.enumValueFieldIndex(callconv_ty, @intFromEnum(func_ty_info.cc))).toIntern(), |
| 17626 | // alignment: comptime_int, | ||
| 17627 | (try mod.intValue(Type.comptime_int, ty.abiAlignment(mod).toByteUnits(0))).toIntern(), | ||
| 17628 | // is_generic: bool, | 17625 | // is_generic: bool, |
| 17629 | Value.makeBool(func_ty_info.is_generic).toIntern(), | 17626 | Value.makeBool(func_ty_info.is_generic).toIntern(), |
| 17630 | // is_var_args: bool, | 17627 | // is_var_args: bool, |
| ... | @@ -19701,12 +19698,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -19701,12 +19698,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 19701 | if (inst_data.size != .One) { | 19698 | if (inst_data.size != .One) { |
| 19702 | return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{}); | 19699 | return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{}); |
| 19703 | } | 19700 | } |
| 19704 | const fn_align = mod.typeToFunc(elem_ty).?.alignment; | ||
| 19705 | if (inst_data.flags.has_align and abi_align != .none and fn_align != .none and | ||
| 19706 | abi_align != fn_align) | ||
| 19707 | { | ||
| 19708 | return sema.fail(block, align_src, "function pointer alignment disagrees with function alignment", .{}); | ||
| 19709 | } | ||
| 19710 | } else if (inst_data.size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) { | 19701 | } else if (inst_data.size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) { |
| 19711 | return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{}); | 19702 | return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{}); |
| 19712 | } else if (inst_data.size == .C) { | 19703 | } else if (inst_data.size == .C) { |
| ... | @@ -21030,7 +21021,6 @@ fn zirReify( | ... | @@ -21030,7 +21021,6 @@ fn zirReify( |
| 21030 | .needed_comptime_reason = "operand to @Type must be comptime-known", | 21021 | .needed_comptime_reason = "operand to @Type must be comptime-known", |
| 21031 | }); | 21022 | }); |
| 21032 | const union_val = ip.indexToKey(val.toIntern()).un; | 21023 | const union_val = ip.indexToKey(val.toIntern()).un; |
| 21033 | const target = mod.getTarget(); | ||
| 21034 | if (try Value.fromInterned(union_val.val).anyUndef(mod)) return sema.failWithUseOfUndef(block, src); | 21024 | if (try Value.fromInterned(union_val.val).anyUndef(mod)) return sema.failWithUseOfUndef(block, src); |
| 21035 | const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?; | 21025 | const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?; |
| 21036 | switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) { | 21026 | switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) { |
| ... | @@ -21171,12 +21161,6 @@ fn zirReify( | ... | @@ -21171,12 +21161,6 @@ fn zirReify( |
| 21171 | if (ptr_size != .One) { | 21161 | if (ptr_size != .One) { |
| 21172 | return sema.fail(block, src, "function pointers must be single pointers", .{}); | 21162 | return sema.fail(block, src, "function pointers must be single pointers", .{}); |
| 21173 | } | 21163 | } |
| 21174 | const fn_align = mod.typeToFunc(elem_ty).?.alignment; | ||
| 21175 | if (abi_align != .none and fn_align != .none and | ||
| 21176 | abi_align != fn_align) | ||
| 21177 | { | ||
| 21178 | return sema.fail(block, src, "function pointer alignment disagrees with function alignment", .{}); | ||
| 21179 | } | ||
| 21180 | } else if (ptr_size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) { | 21164 | } else if (ptr_size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) { |
| 21181 | return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{}); | 21165 | return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{}); |
| 21182 | } else if (ptr_size == .C) { | 21166 | } else if (ptr_size == .C) { |
| ... | @@ -21429,10 +21413,6 @@ fn zirReify( | ... | @@ -21429,10 +21413,6 @@ fn zirReify( |
| 21429 | ip, | 21413 | ip, |
| 21430 | try ip.getOrPutString(gpa, "calling_convention"), | 21414 | try ip.getOrPutString(gpa, "calling_convention"), |
| 21431 | ).?); | 21415 | ).?); |
| 21432 | const alignment_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex( | ||
| 21433 | ip, | ||
| 21434 | try ip.getOrPutString(gpa, "alignment"), | ||
| 21435 | ).?); | ||
| 21436 | const is_generic_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex( | 21416 | const is_generic_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex( |
| 21437 | ip, | 21417 | ip, |
| 21438 | try ip.getOrPutString(gpa, "is_generic"), | 21418 | try ip.getOrPutString(gpa, "is_generic"), |
| ... | @@ -21461,11 +21441,6 @@ fn zirReify( | ... | @@ -21461,11 +21441,6 @@ fn zirReify( |
| 21461 | try sema.checkCallConvSupportsVarArgs(block, src, cc); | 21441 | try sema.checkCallConvSupportsVarArgs(block, src, cc); |
| 21462 | } | 21442 | } |
| 21463 | 21443 | ||
| 21464 | const alignment = alignment: { | ||
| 21465 | const alignment = try sema.validateAlignAllowZero(block, src, try alignment_val.toUnsignedIntAdvanced(sema)); | ||
| 21466 | const default = target_util.defaultFunctionAlignment(target); | ||
| 21467 | break :alignment if (alignment == default) .none else alignment; | ||
| 21468 | }; | ||
| 21469 | const return_type = return_type_val.optionalValue(mod) orelse | 21444 | const return_type = return_type_val.optionalValue(mod) orelse |
| 21470 | return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); | 21445 | return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{}); |
| 21471 | 21446 | ||
| ... | @@ -21510,7 +21485,6 @@ fn zirReify( | ... | @@ -21510,7 +21485,6 @@ fn zirReify( |
| 21510 | .param_types = param_types, | 21485 | .param_types = param_types, |
| 21511 | .noalias_bits = noalias_bits, | 21486 | .noalias_bits = noalias_bits, |
| 21512 | .return_type = return_type.toIntern(), | 21487 | .return_type = return_type.toIntern(), |
| 21513 | .alignment = alignment, | ||
| 21514 | .cc = cc, | 21488 | .cc = cc, |
| 21515 | .is_var_args = is_var_args, | 21489 | .is_var_args = is_var_args, |
| 21516 | }); | 21490 | }); |
| ... | @@ -32536,16 +32510,21 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn | ... | @@ -32536,16 +32510,21 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn |
| 32536 | const mod = sema.mod; | 32510 | const mod = sema.mod; |
| 32537 | try sema.ensureDeclAnalyzed(decl_index); | 32511 | try sema.ensureDeclAnalyzed(decl_index); |
| 32538 | 32512 | ||
| 32539 | const decl = mod.declPtr(decl_index); | 32513 | const decl_tv = try mod.declPtr(decl_index).typedValue(); |
| 32540 | const decl_tv = try decl.typedValue(); | 32514 | const owner_decl = mod.declPtr(switch (mod.intern_pool.indexToKey(decl_tv.val.toIntern())) { |
| 32515 | .variable => |variable| variable.decl, | ||
| 32516 | .extern_func => |extern_func| extern_func.decl, | ||
| 32517 | .func => |func| func.owner_decl, | ||
| 32518 | else => decl_index, | ||
| 32519 | }); | ||
| 32541 | // TODO: if this is a `decl_ref` of a non-variable decl, only depend on decl type | 32520 | // TODO: if this is a `decl_ref` of a non-variable decl, only depend on decl type |
| 32542 | try sema.declareDependency(.{ .decl_val = decl_index }); | 32521 | try sema.declareDependency(.{ .decl_val = decl_index }); |
| 32543 | const ptr_ty = try sema.ptrType(.{ | 32522 | const ptr_ty = try sema.ptrType(.{ |
| 32544 | .child = decl_tv.ty.toIntern(), | 32523 | .child = decl_tv.ty.toIntern(), |
| 32545 | .flags = .{ | 32524 | .flags = .{ |
| 32546 | .alignment = decl.alignment, | 32525 | .alignment = owner_decl.alignment, |
| 32547 | .is_const = if (decl.val.getVariable(mod)) |variable| variable.is_const else true, | 32526 | .is_const = if (decl_tv.val.getVariable(mod)) |variable| variable.is_const else true, |
| 32548 | .address_space = decl.@"addrspace", | 32527 | .address_space = owner_decl.@"addrspace", |
| 32549 | }, | 32528 | }, |
| 32550 | }); | 32529 | }); |
| 32551 | if (analyze_fn_body) { | 32530 | if (analyze_fn_body) { |
src/codegen/c.zig+2-2| ... | @@ -1635,7 +1635,7 @@ pub const DeclGen = struct { | ... | @@ -1635,7 +1635,7 @@ pub const DeclGen = struct { |
| 1635 | 1635 | ||
| 1636 | switch (kind) { | 1636 | switch (kind) { |
| 1637 | .forward => {}, | 1637 | .forward => {}, |
| 1638 | .complete => if (fn_info.alignment.toByteUnitsOptional()) |a| { | 1638 | .complete => if (fn_decl.alignment.toByteUnitsOptional()) |a| { |
| 1639 | try w.print("{}zig_align_fn({})", .{ trailing, a }); | 1639 | try w.print("{}zig_align_fn({})", .{ trailing, a }); |
| 1640 | trailing = .maybe_space; | 1640 | trailing = .maybe_space; |
| 1641 | }, | 1641 | }, |
| ... | @@ -1666,7 +1666,7 @@ pub const DeclGen = struct { | ... | @@ -1666,7 +1666,7 @@ pub const DeclGen = struct { |
| 1666 | 1666 | ||
| 1667 | switch (kind) { | 1667 | switch (kind) { |
| 1668 | .forward => { | 1668 | .forward => { |
| 1669 | if (fn_info.alignment.toByteUnitsOptional()) |a| { | 1669 | if (fn_decl.alignment.toByteUnitsOptional()) |a| { |
| 1670 | try w.print(" zig_align_fn({})", .{a}); | 1670 | try w.print(" zig_align_fn({})", .{a}); |
| 1671 | } | 1671 | } |
| 1672 | switch (name) { | 1672 | switch (name) { |
src/codegen/llvm.zig+2-2| ... | @@ -2952,8 +2952,8 @@ pub const Object = struct { | ... | @@ -2952,8 +2952,8 @@ pub const Object = struct { |
| 2952 | else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder), | 2952 | else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder), |
| 2953 | } | 2953 | } |
| 2954 | 2954 | ||
| 2955 | if (fn_info.alignment != .none) | 2955 | if (decl.alignment != .none) |
| 2956 | function_index.setAlignment(fn_info.alignment.toLlvm(), &o.builder); | 2956 | function_index.setAlignment(decl.alignment.toLlvm(), &o.builder); |
| 2957 | 2957 | ||
| 2958 | // Function attributes that are independent of analysis results of the function body. | 2958 | // Function attributes that are independent of analysis results of the function body. |
| 2959 | try o.addCommonFnAttributes(&attributes, owner_mod); | 2959 | try o.addCommonFnAttributes(&attributes, owner_mod); |
src/main.zig+1| ... | @@ -4995,6 +4995,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -4995,6 +4995,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 4995 | } else .{ | 4995 | } else .{ |
| 4996 | .root = .{ | 4996 | .root = .{ |
| 4997 | .root_dir = zig_lib_directory, | 4997 | .root_dir = zig_lib_directory, |
| 4998 | .sub_path = "compiler", | ||
| 4998 | }, | 4999 | }, |
| 4999 | .root_src_path = "build_runner.zig", | 5000 | .root_src_path = "build_runner.zig", |
| 5000 | }; | 5001 | }; |
src/type.zig+1-9| ... | @@ -396,9 +396,6 @@ pub const Type = struct { | ... | @@ -396,9 +396,6 @@ pub const Type = struct { |
| 396 | try writer.writeAll("..."); | 396 | try writer.writeAll("..."); |
| 397 | } | 397 | } |
| 398 | try writer.writeAll(") "); | 398 | try writer.writeAll(") "); |
| 399 | if (fn_info.alignment.toByteUnitsOptional()) |a| { | ||
| 400 | try writer.print("align({d}) ", .{a}); | ||
| 401 | } | ||
| 402 | if (fn_info.cc != .Unspecified) { | 399 | if (fn_info.cc != .Unspecified) { |
| 403 | try writer.writeAll("callconv(."); | 400 | try writer.writeAll("callconv(."); |
| 404 | try writer.writeAll(@tagName(fn_info.cc)); | 401 | try writer.writeAll(@tagName(fn_info.cc)); |
| ... | @@ -949,12 +946,7 @@ pub const Type = struct { | ... | @@ -949,12 +946,7 @@ pub const Type = struct { |
| 949 | }, | 946 | }, |
| 950 | 947 | ||
| 951 | // represents machine code; not a pointer | 948 | // represents machine code; not a pointer |
| 952 | .func_type => |func_type| return .{ | 949 | .func_type => return .{ .scalar = target_util.defaultFunctionAlignment(target) }, |
| 953 | .scalar = if (func_type.alignment != .none) | ||
| 954 | func_type.alignment | ||
| 955 | else | ||
| 956 | target_util.defaultFunctionAlignment(target), | ||
| 957 | }, | ||
| 958 | 950 | ||
| 959 | .simple_type => |t| switch (t) { | 951 | .simple_type => |t| switch (t) { |
| 960 | .bool, | 952 | .bool, |
stage1/zig.h+157-92| ... | @@ -25,11 +25,15 @@ typedef char bool; | ... | @@ -25,11 +25,15 @@ typedef char bool; |
| 25 | #endif | 25 | #endif |
| 26 | #endif | 26 | #endif |
| 27 | 27 | ||
| 28 | #define zig_concat(lhs, rhs) lhs##rhs | ||
| 29 | #define zig_expand_concat(lhs, rhs) zig_concat(lhs, rhs) | ||
| 30 | |||
| 28 | #if defined(__has_builtin) | 31 | #if defined(__has_builtin) |
| 29 | #define zig_has_builtin(builtin) __has_builtin(__builtin_##builtin) | 32 | #define zig_has_builtin(builtin) __has_builtin(__builtin_##builtin) |
| 30 | #else | 33 | #else |
| 31 | #define zig_has_builtin(builtin) 0 | 34 | #define zig_has_builtin(builtin) 0 |
| 32 | #endif | 35 | #endif |
| 36 | #define zig_expand_has_builtin(b) zig_has_builtin(b) | ||
| 33 | 37 | ||
| 34 | #if defined(__has_attribute) | 38 | #if defined(__has_attribute) |
| 35 | #define zig_has_attribute(attribute) __has_attribute(attribute) | 39 | #define zig_has_attribute(attribute) __has_attribute(attribute) |
| ... | @@ -112,7 +116,7 @@ typedef char bool; | ... | @@ -112,7 +116,7 @@ typedef char bool; |
| 112 | #define zig_never_tail zig_never_tail_unavailable | 116 | #define zig_never_tail zig_never_tail_unavailable |
| 113 | #endif | 117 | #endif |
| 114 | 118 | ||
| 115 | #if zig_has_attribute(always_inline) | 119 | #if zig_has_attribute(musttail) |
| 116 | #define zig_always_tail __attribute__((musttail)) | 120 | #define zig_always_tail __attribute__((musttail)) |
| 117 | #else | 121 | #else |
| 118 | #define zig_always_tail zig_always_tail_unavailable | 122 | #define zig_always_tail zig_always_tail_unavailable |
| ... | @@ -180,20 +184,58 @@ typedef char bool; | ... | @@ -180,20 +184,58 @@ typedef char bool; |
| 180 | #define zig_extern extern | 184 | #define zig_extern extern |
| 181 | #endif | 185 | #endif |
| 182 | 186 | ||
| 183 | #if zig_has_attribute(alias) | 187 | #if _MSC_VER |
| 184 | #define zig_export(sig, symbol, name) zig_extern sig __attribute__((alias(symbol))) | ||
| 185 | #elif _MSC_VER | ||
| 186 | #if _M_X64 | 188 | #if _M_X64 |
| 187 | #define zig_export(sig, symbol, name) sig;\ | 189 | #define zig_mangle_c(symbol) symbol |
| 188 | __pragma(comment(linker, "/alternatename:" name "=" symbol )) | ||
| 189 | #else /*_M_X64 */ | 190 | #else /*_M_X64 */ |
| 190 | #define zig_export(sig, symbol, name) sig;\ | 191 | #define zig_mangle_c(symbol) "_" symbol |
| 191 | __pragma(comment(linker, "/alternatename:_" name "=_" symbol )) | ||
| 192 | #endif /*_M_X64 */ | 192 | #endif /*_M_X64 */ |
| 193 | #else /* _MSC_VER */ | ||
| 194 | #if __APPLE__ | ||
| 195 | #define zig_mangle_c(symbol) "_" symbol | ||
| 196 | #else /* __APPLE__ */ | ||
| 197 | #define zig_mangle_c(symbol) symbol | ||
| 198 | #endif /* __APPLE__ */ | ||
| 199 | #endif /* _MSC_VER */ | ||
| 200 | |||
| 201 | #if zig_has_attribute(alias) && !__APPLE__ | ||
| 202 | #define zig_export(symbol, name) __attribute__((alias(symbol))) | ||
| 203 | #elif _MSC_VER | ||
| 204 | #define zig_export(symbol, name) ; \ | ||
| 205 | __pragma(comment(linker, "/alternatename:" zig_mangle_c(name) "=" zig_mangle_c(symbol))) | ||
| 193 | #else | 206 | #else |
| 194 | #define zig_export(sig, symbol, name) __asm(name " = " symbol) | 207 | #define zig_export(symbol, name) ; \ |
| 208 | __asm(zig_mangle_c(name) " = " zig_mangle_c(symbol)) | ||
| 195 | #endif | 209 | #endif |
| 196 | 210 | ||
| 211 | #if _MSC_VER | ||
| 212 | #define zig_mangled_tentative(mangled, unmangled) | ||
| 213 | #define zig_mangled_final(mangled, unmangled) ; \ | ||
| 214 | zig_export(#mangled, unmangled) | ||
| 215 | #define zig_mangled_export(mangled, unmangled, symbol) \ | ||
| 216 | zig_export(unmangled, #mangled) \ | ||
| 217 | zig_export(symbol, unmangled) | ||
| 218 | #else /* _MSC_VER */ | ||
| 219 | #define zig_mangled_tentative(mangled, unmangled) __asm(zig_mangle_c(unmangled)) | ||
| 220 | #define zig_mangled_final(mangled, unmangled) zig_mangled_tentative(mangled, unmangled) | ||
| 221 | #define zig_mangled_export(mangled, unmangled, symbol) \ | ||
| 222 | zig_mangled_final(mangled, unmangled) \ | ||
| 223 | zig_export(symbol, unmangled) | ||
| 224 | #endif /* _MSC_VER */ | ||
| 225 | |||
| 226 | #if _MSC_VER | ||
| 227 | #define zig_import(Type, fn_name, libc_name, sig_args, call_args) zig_extern Type fn_name sig_args;\ | ||
| 228 | __pragma(comment(linker, "/alternatename:" zig_mangle_c(#fn_name) "=" zig_mangle_c(#libc_name))); | ||
| 229 | #define zig_import_builtin(Type, fn_name, libc_name, sig_args, call_args) zig_import(Type, fn_name, sig_args, call_args) | ||
| 230 | #else /* _MSC_VER */ | ||
| 231 | #define zig_import(Type, fn_name, libc_name, sig_args, call_args) zig_extern Type fn_name sig_args __asm(zig_mangle_c(#libc_name)); | ||
| 232 | #define zig_import_builtin(Type, fn_name, libc_name, sig_args, call_args) zig_extern Type libc_name sig_args; \ | ||
| 233 | static inline Type fn_name sig_args { return libc_name call_args; } | ||
| 234 | #endif | ||
| 235 | |||
| 236 | #define zig_expand_import_0(Type, fn_name, libc_name, sig_args, call_args) zig_import(Type, fn_name, libc_name, sig_args, call_args) | ||
| 237 | #define zig_expand_import_1(Type, fn_name, libc_name, sig_args, call_args) zig_import_builtin(Type, fn_name, libc_name, sig_args, call_args) | ||
| 238 | |||
| 197 | #if zig_has_attribute(weak) || defined(zig_gnuc) | 239 | #if zig_has_attribute(weak) || defined(zig_gnuc) |
| 198 | #define zig_weak_linkage __attribute__((weak)) | 240 | #define zig_weak_linkage __attribute__((weak)) |
| 199 | #define zig_weak_linkage_fn __attribute__((weak)) | 241 | #define zig_weak_linkage_fn __attribute__((weak)) |
| ... | @@ -267,9 +309,6 @@ typedef char bool; | ... | @@ -267,9 +309,6 @@ typedef char bool; |
| 267 | #define zig_wasm_memory_grow(index, delta) zig_unimplemented() | 309 | #define zig_wasm_memory_grow(index, delta) zig_unimplemented() |
| 268 | #endif | 310 | #endif |
| 269 | 311 | ||
| 270 | #define zig_concat(lhs, rhs) lhs##rhs | ||
| 271 | #define zig_expand_concat(lhs, rhs) zig_concat(lhs, rhs) | ||
| 272 | |||
| 273 | #if __STDC_VERSION__ >= 201112L | 312 | #if __STDC_VERSION__ >= 201112L |
| 274 | #define zig_noreturn _Noreturn | 313 | #define zig_noreturn _Noreturn |
| 275 | #elif zig_has_attribute(noreturn) || defined(zig_gnuc) | 314 | #elif zig_has_attribute(noreturn) || defined(zig_gnuc) |
| ... | @@ -2163,7 +2202,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo | ... | @@ -2163,7 +2202,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo |
| 2163 | const uint8_t *rhs_bytes = rhs; | 2202 | const uint8_t *rhs_bytes = rhs; |
| 2164 | uint16_t byte_offset = 0; | 2203 | uint16_t byte_offset = 0; |
| 2165 | uint16_t remaining_bytes = zig_int_bytes(bits); | 2204 | uint16_t remaining_bytes = zig_int_bytes(bits); |
| 2166 | uint16_t top_bits = remaining_bytes * 8 - bits; | 2205 | uint8_t top_bits = (uint8_t)(remaining_bytes * 8 - bits); |
| 2167 | bool overflow = false; | 2206 | bool overflow = false; |
| 2168 | 2207 | ||
| 2169 | #if zig_big_endian | 2208 | #if zig_big_endian |
| ... | @@ -2171,7 +2210,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo | ... | @@ -2171,7 +2210,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo |
| 2171 | #endif | 2210 | #endif |
| 2172 | 2211 | ||
| 2173 | while (remaining_bytes >= 128 / CHAR_BIT) { | 2212 | while (remaining_bytes >= 128 / CHAR_BIT) { |
| 2174 | uint16_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); | 2213 | uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); |
| 2175 | 2214 | ||
| 2176 | #if zig_big_endian | 2215 | #if zig_big_endian |
| 2177 | byte_offset -= 128 / CHAR_BIT; | 2216 | byte_offset -= 128 / CHAR_BIT; |
| ... | @@ -2211,7 +2250,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo | ... | @@ -2211,7 +2250,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo |
| 2211 | } | 2250 | } |
| 2212 | 2251 | ||
| 2213 | while (remaining_bytes >= 64 / CHAR_BIT) { | 2252 | while (remaining_bytes >= 64 / CHAR_BIT) { |
| 2214 | uint16_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); | 2253 | uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); |
| 2215 | 2254 | ||
| 2216 | #if zig_big_endian | 2255 | #if zig_big_endian |
| 2217 | byte_offset -= 64 / CHAR_BIT; | 2256 | byte_offset -= 64 / CHAR_BIT; |
| ... | @@ -2251,7 +2290,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo | ... | @@ -2251,7 +2290,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo |
| 2251 | } | 2290 | } |
| 2252 | 2291 | ||
| 2253 | while (remaining_bytes >= 32 / CHAR_BIT) { | 2292 | while (remaining_bytes >= 32 / CHAR_BIT) { |
| 2254 | uint16_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); | 2293 | uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); |
| 2255 | 2294 | ||
| 2256 | #if zig_big_endian | 2295 | #if zig_big_endian |
| 2257 | byte_offset -= 32 / CHAR_BIT; | 2296 | byte_offset -= 32 / CHAR_BIT; |
| ... | @@ -2291,7 +2330,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo | ... | @@ -2291,7 +2330,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo |
| 2291 | } | 2330 | } |
| 2292 | 2331 | ||
| 2293 | while (remaining_bytes >= 16 / CHAR_BIT) { | 2332 | while (remaining_bytes >= 16 / CHAR_BIT) { |
| 2294 | uint16_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); | 2333 | uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); |
| 2295 | 2334 | ||
| 2296 | #if zig_big_endian | 2335 | #if zig_big_endian |
| 2297 | byte_offset -= 16 / CHAR_BIT; | 2336 | byte_offset -= 16 / CHAR_BIT; |
| ... | @@ -2331,7 +2370,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo | ... | @@ -2331,7 +2370,7 @@ static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, boo |
| 2331 | } | 2370 | } |
| 2332 | 2371 | ||
| 2333 | while (remaining_bytes >= 8 / CHAR_BIT) { | 2372 | while (remaining_bytes >= 8 / CHAR_BIT) { |
| 2334 | uint16_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); | 2373 | uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); |
| 2335 | 2374 | ||
| 2336 | #if zig_big_endian | 2375 | #if zig_big_endian |
| 2337 | byte_offset -= 8 / CHAR_BIT; | 2376 | byte_offset -= 8 / CHAR_BIT; |
| ... | @@ -2379,7 +2418,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo | ... | @@ -2379,7 +2418,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo |
| 2379 | const uint8_t *rhs_bytes = rhs; | 2418 | const uint8_t *rhs_bytes = rhs; |
| 2380 | uint16_t byte_offset = 0; | 2419 | uint16_t byte_offset = 0; |
| 2381 | uint16_t remaining_bytes = zig_int_bytes(bits); | 2420 | uint16_t remaining_bytes = zig_int_bytes(bits); |
| 2382 | uint16_t top_bits = remaining_bytes * 8 - bits; | 2421 | uint8_t top_bits = (uint8_t)(remaining_bytes * 8 - bits); |
| 2383 | bool overflow = false; | 2422 | bool overflow = false; |
| 2384 | 2423 | ||
| 2385 | #if zig_big_endian | 2424 | #if zig_big_endian |
| ... | @@ -2387,7 +2426,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo | ... | @@ -2387,7 +2426,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo |
| 2387 | #endif | 2426 | #endif |
| 2388 | 2427 | ||
| 2389 | while (remaining_bytes >= 128 / CHAR_BIT) { | 2428 | while (remaining_bytes >= 128 / CHAR_BIT) { |
| 2390 | uint16_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); | 2429 | uint8_t limb_bits = 128 - (remaining_bytes == 128 / CHAR_BIT ? top_bits : 0); |
| 2391 | 2430 | ||
| 2392 | #if zig_big_endian | 2431 | #if zig_big_endian |
| 2393 | byte_offset -= 128 / CHAR_BIT; | 2432 | byte_offset -= 128 / CHAR_BIT; |
| ... | @@ -2427,7 +2466,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo | ... | @@ -2427,7 +2466,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo |
| 2427 | } | 2466 | } |
| 2428 | 2467 | ||
| 2429 | while (remaining_bytes >= 64 / CHAR_BIT) { | 2468 | while (remaining_bytes >= 64 / CHAR_BIT) { |
| 2430 | uint16_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); | 2469 | uint8_t limb_bits = 64 - (remaining_bytes == 64 / CHAR_BIT ? top_bits : 0); |
| 2431 | 2470 | ||
| 2432 | #if zig_big_endian | 2471 | #if zig_big_endian |
| 2433 | byte_offset -= 64 / CHAR_BIT; | 2472 | byte_offset -= 64 / CHAR_BIT; |
| ... | @@ -2467,7 +2506,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo | ... | @@ -2467,7 +2506,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo |
| 2467 | } | 2506 | } |
| 2468 | 2507 | ||
| 2469 | while (remaining_bytes >= 32 / CHAR_BIT) { | 2508 | while (remaining_bytes >= 32 / CHAR_BIT) { |
| 2470 | uint16_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); | 2509 | uint8_t limb_bits = 32 - (remaining_bytes == 32 / CHAR_BIT ? top_bits : 0); |
| 2471 | 2510 | ||
| 2472 | #if zig_big_endian | 2511 | #if zig_big_endian |
| 2473 | byte_offset -= 32 / CHAR_BIT; | 2512 | byte_offset -= 32 / CHAR_BIT; |
| ... | @@ -2507,7 +2546,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo | ... | @@ -2507,7 +2546,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo |
| 2507 | } | 2546 | } |
| 2508 | 2547 | ||
| 2509 | while (remaining_bytes >= 16 / CHAR_BIT) { | 2548 | while (remaining_bytes >= 16 / CHAR_BIT) { |
| 2510 | uint16_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); | 2549 | uint8_t limb_bits = 16 - (remaining_bytes == 16 / CHAR_BIT ? top_bits : 0); |
| 2511 | 2550 | ||
| 2512 | #if zig_big_endian | 2551 | #if zig_big_endian |
| 2513 | byte_offset -= 16 / CHAR_BIT; | 2552 | byte_offset -= 16 / CHAR_BIT; |
| ... | @@ -2547,7 +2586,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo | ... | @@ -2547,7 +2586,7 @@ static inline bool zig_subo_big(void *res, const void *lhs, const void *rhs, boo |
| 2547 | } | 2586 | } |
| 2548 | 2587 | ||
| 2549 | while (remaining_bytes >= 8 / CHAR_BIT) { | 2588 | while (remaining_bytes >= 8 / CHAR_BIT) { |
| 2550 | uint16_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); | 2589 | uint8_t limb_bits = 8 - (remaining_bytes == 8 / CHAR_BIT ? top_bits : 0); |
| 2551 | 2590 | ||
| 2552 | #if zig_big_endian | 2591 | #if zig_big_endian |
| 2553 | byte_offset -= 8 / CHAR_BIT; | 2592 | byte_offset -= 8 / CHAR_BIT; |
| ... | @@ -3093,6 +3132,7 @@ ypedef uint32_t zig_f32; | ... | @@ -3093,6 +3132,7 @@ ypedef uint32_t zig_f32; |
| 3093 | 3132 | ||
| 3094 | #define zig_has_f64 1 | 3133 | #define zig_has_f64 1 |
| 3095 | #define zig_libc_name_f64(name) name | 3134 | #define zig_libc_name_f64(name) name |
| 3135 | |||
| 3096 | #if _MSC_VER | 3136 | #if _MSC_VER |
| 3097 | #define zig_init_special_f64(sign, name, arg, repr) sign zig_make_f64(zig_msvc_flt_##name, ) | 3137 | #define zig_init_special_f64(sign, name, arg, repr) sign zig_make_f64(zig_msvc_flt_##name, ) |
| 3098 | #else | 3138 | #else |
| ... | @@ -3336,31 +3376,31 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) | ... | @@ -3336,31 +3376,31 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) |
| 3336 | zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, sub, -) \ | 3376 | zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, sub, -) \ |
| 3337 | zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, mul, *) \ | 3377 | zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, mul, *) \ |
| 3338 | zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, div, /) \ | 3378 | zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, div, /) \ |
| 3339 | zig_extern zig_f##w zig_libc_name_f##w(sqrt)(zig_f##w); \ | 3379 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(sqrt)))(zig_f##w, zig_float_fn_f##w##_sqrt, zig_libc_name_f##w(sqrt), (zig_f##w x), (x)) \ |
| 3340 | zig_extern zig_f##w zig_libc_name_f##w(sin)(zig_f##w); \ | 3380 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(sin)))(zig_f##w, zig_float_fn_f##w##_sin, zig_libc_name_f##w(sin), (zig_f##w x), (x)) \ |
| 3341 | zig_extern zig_f##w zig_libc_name_f##w(cos)(zig_f##w); \ | 3381 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(cos)))(zig_f##w, zig_float_fn_f##w##_cos, zig_libc_name_f##w(cos), (zig_f##w x), (x)) \ |
| 3342 | zig_extern zig_f##w zig_libc_name_f##w(tan)(zig_f##w); \ | 3382 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(tan)))(zig_f##w, zig_float_fn_f##w##_tan, zig_libc_name_f##w(tan), (zig_f##w x), (x)) \ |
| 3343 | zig_extern zig_f##w zig_libc_name_f##w(exp)(zig_f##w); \ | 3383 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(exp)))(zig_f##w, zig_float_fn_f##w##_exp, zig_libc_name_f##w(exp), (zig_f##w x), (x)) \ |
| 3344 | zig_extern zig_f##w zig_libc_name_f##w(exp2)(zig_f##w); \ | 3384 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(exp2)))(zig_f##w, zig_float_fn_f##w##_exp2, zig_libc_name_f##w(exp2), (zig_f##w x), (x)) \ |
| 3345 | zig_extern zig_f##w zig_libc_name_f##w(log)(zig_f##w); \ | 3385 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(log)))(zig_f##w, zig_float_fn_f##w##_log, zig_libc_name_f##w(log), (zig_f##w x), (x)) \ |
| 3346 | zig_extern zig_f##w zig_libc_name_f##w(log2)(zig_f##w); \ | 3386 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(log2)))(zig_f##w, zig_float_fn_f##w##_log2, zig_libc_name_f##w(log2), (zig_f##w x), (x)) \ |
| 3347 | zig_extern zig_f##w zig_libc_name_f##w(log10)(zig_f##w); \ | 3387 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(log10)))(zig_f##w, zig_float_fn_f##w##_log10, zig_libc_name_f##w(log10), (zig_f##w x), (x)) \ |
| 3348 | zig_extern zig_f##w zig_libc_name_f##w(fabs)(zig_f##w); \ | 3388 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fabs)))(zig_f##w, zig_float_fn_f##w##_fabs, zig_libc_name_f##w(fabs), (zig_f##w x), (x)) \ |
| 3349 | zig_extern zig_f##w zig_libc_name_f##w(floor)(zig_f##w); \ | 3389 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(floor)))(zig_f##w, zig_float_fn_f##w##_floor, zig_libc_name_f##w(floor), (zig_f##w x), (x)) \ |
| 3350 | zig_extern zig_f##w zig_libc_name_f##w(ceil)(zig_f##w); \ | 3390 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(ceil)))(zig_f##w, zig_float_fn_f##w##_ceil, zig_libc_name_f##w(ceil), (zig_f##w x), (x)) \ |
| 3351 | zig_extern zig_f##w zig_libc_name_f##w(round)(zig_f##w); \ | 3391 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(round)))(zig_f##w, zig_float_fn_f##w##_round, zig_libc_name_f##w(round), (zig_f##w x), (x)) \ |
| 3352 | zig_extern zig_f##w zig_libc_name_f##w(trunc)(zig_f##w); \ | 3392 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(trunc)))(zig_f##w, zig_float_fn_f##w##_trunc, zig_libc_name_f##w(trunc), (zig_f##w x), (x)) \ |
| 3353 | zig_extern zig_f##w zig_libc_name_f##w(fmod)(zig_f##w, zig_f##w); \ | 3393 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fmod)))(zig_f##w, zig_float_fn_f##w##_fmod, zig_libc_name_f##w(fmod), (zig_f##w x, zig_f##w y), (x, y)) \ |
| 3354 | zig_extern zig_f##w zig_libc_name_f##w(fmin)(zig_f##w, zig_f##w); \ | 3394 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fmin)))(zig_f##w, zig_float_fn_f##w##_fmin, zig_libc_name_f##w(fmin), (zig_f##w x, zig_f##w y), (x, y)) \ |
| 3355 | zig_extern zig_f##w zig_libc_name_f##w(fmax)(zig_f##w, zig_f##w); \ | 3395 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fmax)))(zig_f##w, zig_float_fn_f##w##_fmax, zig_libc_name_f##w(fmax), (zig_f##w x, zig_f##w y), (x, y)) \ |
| 3356 | zig_extern zig_f##w zig_libc_name_f##w(fma)(zig_f##w, zig_f##w, zig_f##w); \ | 3396 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fma)))(zig_f##w, zig_float_fn_f##w##_fma, zig_libc_name_f##w(fma), (zig_f##w x, zig_f##w y, zig_f##w z), (x, y, z)) \ |
| 3357 | \ | 3397 | \ |
| 3358 | static inline zig_f##w zig_div_trunc_f##w(zig_f##w lhs, zig_f##w rhs) { \ | 3398 | static inline zig_f##w zig_div_trunc_f##w(zig_f##w lhs, zig_f##w rhs) { \ |
| 3359 | return zig_libc_name_f##w(trunc)(zig_div_f##w(lhs, rhs)); \ | 3399 | return zig_float_fn_f##w##_trunc(zig_div_f##w(lhs, rhs)); \ |
| 3360 | } \ | 3400 | } \ |
| 3361 | \ | 3401 | \ |
| 3362 | static inline zig_f##w zig_div_floor_f##w(zig_f##w lhs, zig_f##w rhs) { \ | 3402 | static inline zig_f##w zig_div_floor_f##w(zig_f##w lhs, zig_f##w rhs) { \ |
| 3363 | return zig_libc_name_f##w(floor)(zig_div_f##w(lhs, rhs)); \ | 3403 | return zig_float_fn_f##w##_floor(zig_div_f##w(lhs, rhs)); \ |
| 3364 | } \ | 3404 | } \ |
| 3365 | \ | 3405 | \ |
| 3366 | static inline zig_f##w zig_mod_f##w(zig_f##w lhs, zig_f##w rhs) { \ | 3406 | static inline zig_f##w zig_mod_f##w(zig_f##w lhs, zig_f##w rhs) { \ |
| ... | @@ -3437,129 +3477,134 @@ zig_float_builtins(64) | ... | @@ -3437,129 +3477,134 @@ zig_float_builtins(64) |
| 3437 | /* Note that zig_atomicrmw_expected is needed to handle aliasing between res and arg. */ | 3477 | /* Note that zig_atomicrmw_expected is needed to handle aliasing between res and arg. */ |
| 3438 | #define zig_atomicrmw_xchg_float(res, obj, arg, order, Type, ReprType) do { \ | 3478 | #define zig_atomicrmw_xchg_float(res, obj, arg, order, Type, ReprType) do { \ |
| 3439 | zig_##Type zig_atomicrmw_expected; \ | 3479 | zig_##Type zig_atomicrmw_expected; \ |
| 3440 | zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \ | 3480 | zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ |
| 3441 | while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, memory_order_relaxed, Type, ReprType)); \ | 3481 | while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, zig_memory_order_relaxed, Type, ReprType)); \ |
| 3442 | res = zig_atomicrmw_expected; \ | 3482 | res = zig_atomicrmw_expected; \ |
| 3443 | } while (0) | 3483 | } while (0) |
| 3444 | #define zig_atomicrmw_add_float(res, obj, arg, order, Type, ReprType) do { \ | 3484 | #define zig_atomicrmw_add_float(res, obj, arg, order, Type, ReprType) do { \ |
| 3445 | zig_##Type zig_atomicrmw_expected; \ | 3485 | zig_##Type zig_atomicrmw_expected; \ |
| 3446 | zig_##Type zig_atomicrmw_desired; \ | 3486 | zig_##Type zig_atomicrmw_desired; \ |
| 3447 | zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \ | 3487 | zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ |
| 3448 | do { \ | 3488 | do { \ |
| 3449 | zig_atomicrmw_desired = zig_add_##Type(zig_atomicrmw_expected, arg); \ | 3489 | zig_atomicrmw_desired = zig_add_##Type(zig_atomicrmw_expected, arg); \ |
| 3450 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | 3490 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ |
| 3451 | res = zig_atomicrmw_expected; \ | 3491 | res = zig_atomicrmw_expected; \ |
| 3452 | } while (0) | 3492 | } while (0) |
| 3453 | #define zig_atomicrmw_sub_float(res, obj, arg, order, Type, ReprType) do { \ | 3493 | #define zig_atomicrmw_sub_float(res, obj, arg, order, Type, ReprType) do { \ |
| 3454 | zig_##Type zig_atomicrmw_expected; \ | 3494 | zig_##Type zig_atomicrmw_expected; \ |
| 3455 | zig_##Type zig_atomicrmw_desired; \ | 3495 | zig_##Type zig_atomicrmw_desired; \ |
| 3456 | zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \ | 3496 | zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ |
| 3457 | do { \ | 3497 | do { \ |
| 3458 | zig_atomicrmw_desired = zig_sub_##Type(zig_atomicrmw_expected, arg); \ | 3498 | zig_atomicrmw_desired = zig_sub_##Type(zig_atomicrmw_expected, arg); \ |
| 3459 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | 3499 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ |
| 3460 | res = zig_atomicrmw_expected; \ | 3500 | res = zig_atomicrmw_expected; \ |
| 3461 | } while (0) | 3501 | } while (0) |
| 3462 | #define zig_atomicrmw_min_float(res, obj, arg, order, Type, ReprType) do { \ | 3502 | #define zig_atomicrmw_min_float(res, obj, arg, order, Type, ReprType) do { \ |
| 3463 | zig_##Type zig_atomicrmw_expected; \ | 3503 | zig_##Type zig_atomicrmw_expected; \ |
| 3464 | zig_##Type zig_atomicrmw_desired; \ | 3504 | zig_##Type zig_atomicrmw_desired; \ |
| 3465 | zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \ | 3505 | zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ |
| 3466 | do { \ | 3506 | do { \ |
| 3467 | zig_atomicrmw_desired = zig_libc_name_##Type(fmin)(zig_atomicrmw_expected, arg); \ | 3507 | zig_atomicrmw_desired = zig_float_fn_##Type##_fmin(zig_atomicrmw_expected, arg); \ |
| 3468 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | 3508 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ |
| 3469 | res = zig_atomicrmw_expected; \ | 3509 | res = zig_atomicrmw_expected; \ |
| 3470 | } while (0) | 3510 | } while (0) |
| 3471 | #define zig_atomicrmw_max_float(res, obj, arg, order, Type, ReprType) do { \ | 3511 | #define zig_atomicrmw_max_float(res, obj, arg, order, Type, ReprType) do { \ |
| 3472 | zig_##Type zig_atomicrmw_expected; \ | 3512 | zig_##Type zig_atomicrmw_expected; \ |
| 3473 | zig_##Type zig_atomicrmw_desired; \ | 3513 | zig_##Type zig_atomicrmw_desired; \ |
| 3474 | zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \ | 3514 | zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ |
| 3475 | do { \ | 3515 | do { \ |
| 3476 | zig_atomicrmw_desired = zig_libc_name_##Type(fmax)(zig_atomicrmw_expected, arg); \ | 3516 | zig_atomicrmw_desired = zig_float_fn_##Type##_fmax(zig_atomicrmw_expected, arg); \ |
| 3477 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | 3517 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ |
| 3478 | res = zig_atomicrmw_expected; \ | 3518 | res = zig_atomicrmw_expected; \ |
| 3479 | } while (0) | 3519 | } while (0) |
| 3480 | 3520 | ||
| 3481 | #define zig_atomicrmw_xchg_int128(res, obj, arg, order, Type, ReprType) do { \ | 3521 | #define zig_atomicrmw_xchg_int128(res, obj, arg, order, Type, ReprType) do { \ |
| 3482 | zig_##Type zig_atomicrmw_expected; \ | 3522 | zig_##Type zig_atomicrmw_expected; \ |
| 3483 | zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \ | 3523 | zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ |
| 3484 | while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, memory_order_relaxed, Type, ReprType)); \ | 3524 | while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, zig_memory_order_relaxed, Type, ReprType)); \ |
| 3485 | res = zig_atomicrmw_expected; \ | 3525 | res = zig_atomicrmw_expected; \ |
| 3486 | } while (0) | 3526 | } while (0) |
| 3487 | #define zig_atomicrmw_add_int128(res, obj, arg, order, Type, ReprType) do { \ | 3527 | #define zig_atomicrmw_add_int128(res, obj, arg, order, Type, ReprType) do { \ |
| 3488 | zig_##Type zig_atomicrmw_expected; \ | 3528 | zig_##Type zig_atomicrmw_expected; \ |
| 3489 | zig_##Type zig_atomicrmw_desired; \ | 3529 | zig_##Type zig_atomicrmw_desired; \ |
| 3490 | zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \ | 3530 | zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ |
| 3491 | do { \ | 3531 | do { \ |
| 3492 | zig_atomicrmw_desired = zig_add_##Type(zig_atomicrmw_expected, arg); \ | 3532 | zig_atomicrmw_desired = zig_add_##Type(zig_atomicrmw_expected, arg); \ |
| 3493 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | 3533 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ |
| 3494 | res = zig_atomicrmw_expected; \ | 3534 | res = zig_atomicrmw_expected; \ |
| 3495 | } while (0) | 3535 | } while (0) |
| 3496 | #define zig_atomicrmw_sub_int128(res, obj, arg, order, Type, ReprType) do { \ | 3536 | #define zig_atomicrmw_sub_int128(res, obj, arg, order, Type, ReprType) do { \ |
| 3497 | zig_##Type zig_atomicrmw_expected; \ | 3537 | zig_##Type zig_atomicrmw_expected; \ |
| 3498 | zig_##Type zig_atomicrmw_desired; \ | 3538 | zig_##Type zig_atomicrmw_desired; \ |
| 3499 | zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \ | 3539 | zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ |
| 3500 | do { \ | 3540 | do { \ |
| 3501 | zig_atomicrmw_desired = zig_sub_##Type(zig_atomicrmw_expected, arg); \ | 3541 | zig_atomicrmw_desired = zig_sub_##Type(zig_atomicrmw_expected, arg); \ |
| 3502 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | 3542 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ |
| 3503 | res = zig_atomicrmw_expected; \ | 3543 | res = zig_atomicrmw_expected; \ |
| 3504 | } while (0) | 3544 | } while (0) |
| 3505 | #define zig_atomicrmw_and_int128(res, obj, arg, order, Type, ReprType) do { \ | 3545 | #define zig_atomicrmw_and_int128(res, obj, arg, order, Type, ReprType) do { \ |
| 3506 | zig_##Type zig_atomicrmw_expected; \ | 3546 | zig_##Type zig_atomicrmw_expected; \ |
| 3507 | zig_##Type zig_atomicrmw_desired; \ | 3547 | zig_##Type zig_atomicrmw_desired; \ |
| 3508 | zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \ | 3548 | zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ |
| 3509 | do { \ | 3549 | do { \ |
| 3510 | zig_atomicrmw_desired = zig_and_##Type(zig_atomicrmw_expected, arg); \ | 3550 | zig_atomicrmw_desired = zig_and_##Type(zig_atomicrmw_expected, arg); \ |
| 3511 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | 3551 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ |
| 3512 | res = zig_atomicrmw_expected; \ | 3552 | res = zig_atomicrmw_expected; \ |
| 3513 | } while (0) | 3553 | } while (0) |
| 3514 | #define zig_atomicrmw_nand_int128(res, obj, arg, order, Type, ReprType) do { \ | 3554 | #define zig_atomicrmw_nand_int128(res, obj, arg, order, Type, ReprType) do { \ |
| 3515 | zig_##Type zig_atomicrmw_expected; \ | 3555 | zig_##Type zig_atomicrmw_expected; \ |
| 3516 | zig_##Type zig_atomicrmw_desired; \ | 3556 | zig_##Type zig_atomicrmw_desired; \ |
| 3517 | zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \ | 3557 | zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ |
| 3518 | do { \ | 3558 | do { \ |
| 3519 | zig_atomicrmw_desired = zig_not_##Type(zig_and_##Type(zig_atomicrmw_expected, arg), 128); \ | 3559 | zig_atomicrmw_desired = zig_not_##Type(zig_and_##Type(zig_atomicrmw_expected, arg), 128); \ |
| 3520 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | 3560 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ |
| 3521 | res = zig_atomicrmw_expected; \ | 3561 | res = zig_atomicrmw_expected; \ |
| 3522 | } while (0) | 3562 | } while (0) |
| 3523 | #define zig_atomicrmw_or_int128(res, obj, arg, order, Type, ReprType) do { \ | 3563 | #define zig_atomicrmw_or_int128(res, obj, arg, order, Type, ReprType) do { \ |
| 3524 | zig_##Type zig_atomicrmw_expected; \ | 3564 | zig_##Type zig_atomicrmw_expected; \ |
| 3525 | zig_##Type zig_atomicrmw_desired; \ | 3565 | zig_##Type zig_atomicrmw_desired; \ |
| 3526 | zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \ | 3566 | zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ |
| 3527 | do { \ | 3567 | do { \ |
| 3528 | zig_atomicrmw_desired = zig_or_##Type(zig_atomicrmw_expected, arg); \ | 3568 | zig_atomicrmw_desired = zig_or_##Type(zig_atomicrmw_expected, arg); \ |
| 3529 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | 3569 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ |
| 3530 | res = zig_atomicrmw_expected; \ | 3570 | res = zig_atomicrmw_expected; \ |
| 3531 | } while (0) | 3571 | } while (0) |
| 3532 | #define zig_atomicrmw_xor_int128(res, obj, arg, order, Type, ReprType) do { \ | 3572 | #define zig_atomicrmw_xor_int128(res, obj, arg, order, Type, ReprType) do { \ |
| 3533 | zig_##Type zig_atomicrmw_expected; \ | 3573 | zig_##Type zig_atomicrmw_expected; \ |
| 3534 | zig_##Type zig_atomicrmw_desired; \ | 3574 | zig_##Type zig_atomicrmw_desired; \ |
| 3535 | zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \ | 3575 | zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ |
| 3536 | do { \ | 3576 | do { \ |
| 3537 | zig_atomicrmw_desired = zig_xor_##Type(zig_atomicrmw_expected, arg); \ | 3577 | zig_atomicrmw_desired = zig_xor_##Type(zig_atomicrmw_expected, arg); \ |
| 3538 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | 3578 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ |
| 3539 | res = zig_atomicrmw_expected; \ | 3579 | res = zig_atomicrmw_expected; \ |
| 3540 | } while (0) | 3580 | } while (0) |
| 3541 | #define zig_atomicrmw_min_int128(res, obj, arg, order, Type, ReprType) do { \ | 3581 | #define zig_atomicrmw_min_int128(res, obj, arg, order, Type, ReprType) do { \ |
| 3542 | zig_##Type zig_atomicrmw_expected; \ | 3582 | zig_##Type zig_atomicrmw_expected; \ |
| 3543 | zig_##Type zig_atomicrmw_desired; \ | 3583 | zig_##Type zig_atomicrmw_desired; \ |
| 3544 | zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \ | 3584 | zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ |
| 3545 | do { \ | 3585 | do { \ |
| 3546 | zig_atomicrmw_desired = zig_min_##Type(zig_atomicrmw_expected, arg); \ | 3586 | zig_atomicrmw_desired = zig_min_##Type(zig_atomicrmw_expected, arg); \ |
| 3547 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | 3587 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ |
| 3548 | res = zig_atomicrmw_expected; \ | 3588 | res = zig_atomicrmw_expected; \ |
| 3549 | } while (0) | 3589 | } while (0) |
| 3550 | #define zig_atomicrmw_max_int128(res, obj, arg, order, Type, ReprType) do { \ | 3590 | #define zig_atomicrmw_max_int128(res, obj, arg, order, Type, ReprType) do { \ |
| 3551 | zig_##Type zig_atomicrmw_expected; \ | 3591 | zig_##Type zig_atomicrmw_expected; \ |
| 3552 | zig_##Type zig_atomicrmw_desired; \ | 3592 | zig_##Type zig_atomicrmw_desired; \ |
| 3553 | zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \ | 3593 | zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ |
| 3554 | do { \ | 3594 | do { \ |
| 3555 | zig_atomicrmw_desired = zig_max_##Type(zig_atomicrmw_expected, arg); \ | 3595 | zig_atomicrmw_desired = zig_max_##Type(zig_atomicrmw_expected, arg); \ |
| 3556 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | 3596 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ |
| 3557 | res = zig_atomicrmw_expected; \ | 3597 | res = zig_atomicrmw_expected; \ |
| 3558 | } while (0) | 3598 | } while (0) |
| 3559 | 3599 | ||
| 3560 | #if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) | 3600 | #if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) |
| 3561 | #include <stdatomic.h> | 3601 | #include <stdatomic.h> |
| 3562 | typedef enum memory_order zig_memory_order; | 3602 | typedef enum memory_order zig_memory_order; |
| 3603 | #define zig_memory_order_relaxed memory_order_relaxed | ||
| 3604 | #define zig_memory_order_acquire memory_order_acquire | ||
| 3605 | #define zig_memory_order_release memory_order_release | ||
| 3606 | #define zig_memory_order_acq_rel memory_order_acq_rel | ||
| 3607 | #define zig_memory_order_seq_cst memory_order_seq_cst | ||
| 3563 | #define zig_atomic(Type) _Atomic(Type) | 3608 | #define zig_atomic(Type) _Atomic(Type) |
| 3564 | #define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail) | 3609 | #define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail) |
| 3565 | #define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_weak_explicit (obj, &(expected), desired, succ, fail) | 3610 | #define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_weak_explicit (obj, &(expected), desired, succ, fail) |
| ... | @@ -3583,12 +3628,11 @@ typedef enum memory_order zig_memory_order; | ... | @@ -3583,12 +3628,11 @@ typedef enum memory_order zig_memory_order; |
| 3583 | #define zig_fence(order) atomic_thread_fence(order) | 3628 | #define zig_fence(order) atomic_thread_fence(order) |
| 3584 | #elif defined(__GNUC__) | 3629 | #elif defined(__GNUC__) |
| 3585 | typedef int zig_memory_order; | 3630 | typedef int zig_memory_order; |
| 3586 | #define memory_order_relaxed __ATOMIC_RELAXED | 3631 | #define zig_memory_order_relaxed __ATOMIC_RELAXED |
| 3587 | #define memory_order_consume __ATOMIC_CONSUME | 3632 | #define zig_memory_order_acquire __ATOMIC_ACQUIRE |
| 3588 | #define memory_order_acquire __ATOMIC_ACQUIRE | 3633 | #define zig_memory_order_release __ATOMIC_RELEASE |
| 3589 | #define memory_order_release __ATOMIC_RELEASE | 3634 | #define zig_memory_order_acq_rel __ATOMIC_ACQ_REL |
| 3590 | #define memory_order_acq_rel __ATOMIC_ACQ_REL | 3635 | #define zig_memory_order_seq_cst __ATOMIC_SEQ_CST |
| 3591 | #define memory_order_seq_cst __ATOMIC_SEQ_CST | ||
| 3592 | #define zig_atomic(Type) Type | 3636 | #define zig_atomic(Type) Type |
| 3593 | #define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, &(expected), &(desired), false, succ, fail) | 3637 | #define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, &(expected), &(desired), false, succ, fail) |
| 3594 | #define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, &(expected), &(desired), true, succ, fail) | 3638 | #define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, &(expected), &(desired), true, succ, fail) |
| ... | @@ -3607,12 +3651,11 @@ typedef int zig_memory_order; | ... | @@ -3607,12 +3651,11 @@ typedef int zig_memory_order; |
| 3607 | #define zig_atomicrmw_xchg_float zig_atomicrmw_xchg | 3651 | #define zig_atomicrmw_xchg_float zig_atomicrmw_xchg |
| 3608 | #define zig_fence(order) __atomic_thread_fence(order) | 3652 | #define zig_fence(order) __atomic_thread_fence(order) |
| 3609 | #elif _MSC_VER && (_M_IX86 || _M_X64) | 3653 | #elif _MSC_VER && (_M_IX86 || _M_X64) |
| 3610 | #define memory_order_relaxed 0 | 3654 | #define zig_memory_order_relaxed 0 |
| 3611 | #define memory_order_consume 1 | 3655 | #define zig_memory_order_acquire 2 |
| 3612 | #define memory_order_acquire 2 | 3656 | #define zig_memory_order_release 3 |
| 3613 | #define memory_order_release 3 | 3657 | #define zig_memory_order_acq_rel 4 |
| 3614 | #define memory_order_acq_rel 4 | 3658 | #define zig_memory_order_seq_cst 5 |
| 3615 | #define memory_order_seq_cst 5 | ||
| 3616 | #define zig_atomic(Type) Type | 3659 | #define zig_atomic(Type) Type |
| 3617 | #define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_msvc_cmpxchg_##Type(obj, &(expected), desired) | 3660 | #define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_msvc_cmpxchg_##Type(obj, &(expected), desired) |
| 3618 | #define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) zig_cmpxchg_strong(obj, expected, desired, succ, fail, Type, ReprType) | 3661 | #define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) zig_cmpxchg_strong(obj, expected, desired, succ, fail, Type, ReprType) |
| ... | @@ -3634,12 +3677,11 @@ typedef int zig_memory_order; | ... | @@ -3634,12 +3677,11 @@ typedef int zig_memory_order; |
| 3634 | #endif | 3677 | #endif |
| 3635 | /* TODO: _MSC_VER && (_M_ARM || _M_ARM64) */ | 3678 | /* TODO: _MSC_VER && (_M_ARM || _M_ARM64) */ |
| 3636 | #else | 3679 | #else |
| 3637 | #define memory_order_relaxed 0 | 3680 | #define zig_memory_order_relaxed 0 |
| 3638 | #define memory_order_consume 1 | 3681 | #define zig_memory_order_acquire 2 |
| 3639 | #define memory_order_acquire 2 | 3682 | #define zig_memory_order_release 3 |
| 3640 | #define memory_order_release 3 | 3683 | #define zig_memory_order_acq_rel 4 |
| 3641 | #define memory_order_acq_rel 4 | 3684 | #define zig_memory_order_seq_cst 5 |
| 3642 | #define memory_order_seq_cst 5 | ||
| 3643 | #define zig_atomic(Type) Type | 3685 | #define zig_atomic(Type) Type |
| 3644 | #define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable | 3686 | #define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable |
| 3645 | #define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable | 3687 | #define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable |
| ... | @@ -3830,9 +3872,32 @@ static inline bool zig_msvc_cmpxchg_u128(zig_u128 volatile* obj, zig_u128* expec | ... | @@ -3830,9 +3872,32 @@ static inline bool zig_msvc_cmpxchg_u128(zig_u128 volatile* obj, zig_u128* expec |
| 3830 | return _InterlockedCompareExchange128((__int64 volatile*)obj, (__int64)zig_hi_u128(desired), (__int64)zig_lo_u128(desired), (__int64*)expected); | 3872 | return _InterlockedCompareExchange128((__int64 volatile*)obj, (__int64)zig_hi_u128(desired), (__int64)zig_lo_u128(desired), (__int64*)expected); |
| 3831 | } | 3873 | } |
| 3832 | 3874 | ||
| 3875 | static inline zig_u128 zig_msvc_atomic_load_u128(zig_u128 volatile* obj) { | ||
| 3876 | zig_u128 expected = zig_make_u128(UINT64_C(0), UINT64_C(0)); | ||
| 3877 | (void)zig_cmpxchg_strong(obj, expected, expected, zig_memory_order_seq_cst, zig_memory_order_seq_cst, u128, zig_u128); | ||
| 3878 | return expected; | ||
| 3879 | } | ||
| 3880 | |||
| 3881 | static inline void zig_msvc_atomic_store_u128(zig_u128 volatile* obj, zig_u128 arg) { | ||
| 3882 | zig_u128 expected = zig_make_u128(UINT64_C(0), UINT64_C(0)); | ||
| 3883 | while (!zig_cmpxchg_weak(obj, expected, arg, zig_memory_order_seq_cst, zig_memory_order_seq_cst, u128, zig_u128)); | ||
| 3884 | } | ||
| 3885 | |||
| 3833 | static inline bool zig_msvc_cmpxchg_i128(zig_i128 volatile* obj, zig_i128* expected, zig_i128 desired) { | 3886 | static inline bool zig_msvc_cmpxchg_i128(zig_i128 volatile* obj, zig_i128* expected, zig_i128 desired) { |
| 3834 | return _InterlockedCompareExchange128((__int64 volatile*)obj, (__int64)zig_hi_i128(desired), (__int64)zig_lo_i128(desired), (__int64*)expected); | 3887 | return _InterlockedCompareExchange128((__int64 volatile*)obj, (__int64)zig_hi_i128(desired), (__int64)zig_lo_i128(desired), (__int64*)expected); |
| 3835 | } | 3888 | } |
| 3889 | |||
| 3890 | static inline zig_i128 zig_msvc_atomic_load_i128(zig_i128 volatile* obj) { | ||
| 3891 | zig_i128 expected = zig_make_i128(INT64_C(0), UINT64_C(0)); | ||
| 3892 | (void)zig_cmpxchg_strong(obj, expected, expected, zig_memory_order_seq_cst, zig_memory_order_seq_cst, i128, zig_i128); | ||
| 3893 | return expected; | ||
| 3894 | } | ||
| 3895 | |||
| 3896 | static inline void zig_msvc_atomic_store_i128(zig_i128 volatile* obj, zig_i128 arg) { | ||
| 3897 | zig_i128 expected = zig_make_i128(INT64_C(0), UINT64_C(0)); | ||
| 3898 | while (!zig_cmpxchg_weak(obj, expected, arg, zig_memory_order_seq_cst, zig_memory_order_seq_cst, i128, zig_i128)); | ||
| 3899 | } | ||
| 3900 | |||
| 3836 | #endif /* _M_IX86 */ | 3901 | #endif /* _M_IX86 */ |
| 3837 | 3902 | ||
| 3838 | #endif /* _MSC_VER && (_M_IX86 || _M_X64) */ | 3903 | #endif /* _MSC_VER && (_M_IX86 || _M_X64) */ |
stage1/zig1.wasm| Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ | |||
test/behavior/align.zig+22-14| ... | @@ -311,12 +311,6 @@ test "page aligned array on stack" { | ... | @@ -311,12 +311,6 @@ test "page aligned array on stack" { |
| 311 | try expect(number2 == 43); | 311 | try expect(number2 == 43); |
| 312 | } | 312 | } |
| 313 | 313 | ||
| 314 | fn derp() align(@sizeOf(usize) * 2) i32 { | ||
| 315 | return 1234; | ||
| 316 | } | ||
| 317 | fn noop1() align(1) void {} | ||
| 318 | fn noop4() align(4) void {} | ||
| 319 | |||
| 320 | test "function alignment" { | 314 | test "function alignment" { |
| 321 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 315 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 322 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 316 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| ... | @@ -325,11 +319,25 @@ test "function alignment" { | ... | @@ -325,11 +319,25 @@ test "function alignment" { |
| 325 | // function alignment is a compile error on wasm32/wasm64 | 319 | // function alignment is a compile error on wasm32/wasm64 |
| 326 | if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; | 320 | if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; |
| 327 | 321 | ||
| 328 | try expect(derp() == 1234); | 322 | const S = struct { |
| 329 | try expect(@TypeOf(noop1) == fn () align(1) void); | 323 | fn alignExpr() align(@sizeOf(usize) * 2) i32 { |
| 330 | try expect(@TypeOf(noop4) == fn () align(4) void); | 324 | return 1234; |
| 331 | noop1(); | 325 | } |
| 332 | noop4(); | 326 | fn align1() align(1) void {} |
| 327 | fn align4() align(4) void {} | ||
| 328 | }; | ||
| 329 | |||
| 330 | try expect(S.alignExpr() == 1234); | ||
| 331 | try expect(@TypeOf(S.alignExpr) == fn () i32); | ||
| 332 | try expect(@TypeOf(&S.alignExpr) == *align(@sizeOf(usize) * 2) const fn () i32); | ||
| 333 | |||
| 334 | S.align1(); | ||
| 335 | try expect(@TypeOf(S.align1) == fn () void); | ||
| 336 | try expect(@TypeOf(&S.align1) == *align(1) const fn () void); | ||
| 337 | |||
| 338 | S.align4(); | ||
| 339 | try expect(@TypeOf(S.align4) == fn () void); | ||
| 340 | try expect(@TypeOf(&S.align4) == *align(4) const fn () void); | ||
| 333 | } | 341 | } |
| 334 | 342 | ||
| 335 | test "implicitly decreasing fn alignment" { | 343 | test "implicitly decreasing fn alignment" { |
| ... | @@ -345,7 +353,7 @@ test "implicitly decreasing fn alignment" { | ... | @@ -345,7 +353,7 @@ test "implicitly decreasing fn alignment" { |
| 345 | try testImplicitlyDecreaseFnAlign(alignedBig, 5678); | 353 | try testImplicitlyDecreaseFnAlign(alignedBig, 5678); |
| 346 | } | 354 | } |
| 347 | 355 | ||
| 348 | fn testImplicitlyDecreaseFnAlign(ptr: *const fn () align(1) i32, answer: i32) !void { | 356 | fn testImplicitlyDecreaseFnAlign(ptr: *align(1) const fn () i32, answer: i32) !void { |
| 349 | try expect(ptr() == answer); | 357 | try expect(ptr() == answer); |
| 350 | } | 358 | } |
| 351 | 359 | ||
| ... | @@ -368,10 +376,10 @@ test "@alignCast functions" { | ... | @@ -368,10 +376,10 @@ test "@alignCast functions" { |
| 368 | 376 | ||
| 369 | try expect(fnExpectsOnly1(simple4) == 0x19); | 377 | try expect(fnExpectsOnly1(simple4) == 0x19); |
| 370 | } | 378 | } |
| 371 | fn fnExpectsOnly1(ptr: *const fn () align(1) i32) i32 { | 379 | fn fnExpectsOnly1(ptr: *align(1) const fn () i32) i32 { |
| 372 | return fnExpects4(@alignCast(ptr)); | 380 | return fnExpects4(@alignCast(ptr)); |
| 373 | } | 381 | } |
| 374 | fn fnExpects4(ptr: *const fn () align(4) i32) i32 { | 382 | fn fnExpects4(ptr: *align(4) const fn () i32) i32 { |
| 375 | return ptr(); | 383 | return ptr(); |
| 376 | } | 384 | } |
| 377 | fn simple4() align(4) i32 { | 385 | fn simple4() align(4) i32 { |
test/behavior/type.zig-2| ... | @@ -527,7 +527,6 @@ test "Type.Fn" { | ... | @@ -527,7 +527,6 @@ test "Type.Fn" { |
| 527 | { | 527 | { |
| 528 | const fn_info = std.builtin.Type{ .Fn = .{ | 528 | const fn_info = std.builtin.Type{ .Fn = .{ |
| 529 | .calling_convention = .C, | 529 | .calling_convention = .C, |
| 530 | .alignment = 0, | ||
| 531 | .is_generic = false, | 530 | .is_generic = false, |
| 532 | .is_var_args = false, | 531 | .is_var_args = false, |
| 533 | .return_type = void, | 532 | .return_type = void, |
| ... | @@ -643,7 +642,6 @@ test "reified function type params initialized with field pointer" { | ... | @@ -643,7 +642,6 @@ test "reified function type params initialized with field pointer" { |
| 643 | const Bar = @Type(.{ | 642 | const Bar = @Type(.{ |
| 644 | .Fn = .{ | 643 | .Fn = .{ |
| 645 | .calling_convention = .Unspecified, | 644 | .calling_convention = .Unspecified, |
| 646 | .alignment = 0, | ||
| 647 | .is_generic = false, | 645 | .is_generic = false, |
| 648 | .is_var_args = false, | 646 | .is_var_args = false, |
| 649 | .return_type = void, | 647 | .return_type = void, |
test/behavior/type_info.zig+32-10| ... | @@ -356,16 +356,38 @@ test "type info: function type info" { | ... | @@ -356,16 +356,38 @@ test "type info: function type info" { |
| 356 | } | 356 | } |
| 357 | 357 | ||
| 358 | fn testFunction() !void { | 358 | fn testFunction() !void { |
| 359 | const fn_info = @typeInfo(@TypeOf(typeInfoFoo)); | 359 | const foo_fn_type = @TypeOf(typeInfoFoo); |
| 360 | try expect(fn_info == .Fn); | 360 | const foo_fn_info = @typeInfo(foo_fn_type); |
| 361 | try expect(fn_info.Fn.alignment > 0); | 361 | try expect(foo_fn_info.Fn.calling_convention == .C); |
| 362 | try expect(fn_info.Fn.calling_convention == .C); | 362 | try expect(!foo_fn_info.Fn.is_generic); |
| 363 | try expect(!fn_info.Fn.is_generic); | 363 | try expect(foo_fn_info.Fn.params.len == 2); |
| 364 | try expect(fn_info.Fn.params.len == 2); | 364 | try expect(foo_fn_info.Fn.is_var_args); |
| 365 | try expect(fn_info.Fn.is_var_args); | 365 | try expect(foo_fn_info.Fn.return_type.? == usize); |
| 366 | try expect(fn_info.Fn.return_type.? == usize); | 366 | const foo_ptr_fn_info = @typeInfo(@TypeOf(&typeInfoFoo)); |
| 367 | const fn_aligned_info = @typeInfo(@TypeOf(typeInfoFooAligned)); | 367 | try expect(foo_ptr_fn_info.Pointer.size == .One); |
| 368 | try expect(fn_aligned_info.Fn.alignment == 4); | 368 | try expect(foo_ptr_fn_info.Pointer.is_const); |
| 369 | try expect(!foo_ptr_fn_info.Pointer.is_volatile); | ||
| 370 | try expect(foo_ptr_fn_info.Pointer.address_space == .generic); | ||
| 371 | try expect(foo_ptr_fn_info.Pointer.child == foo_fn_type); | ||
| 372 | try expect(!foo_ptr_fn_info.Pointer.is_allowzero); | ||
| 373 | try expect(foo_ptr_fn_info.Pointer.sentinel == null); | ||
| 374 | |||
| 375 | const aligned_foo_fn_type = @TypeOf(typeInfoFooAligned); | ||
| 376 | const aligned_foo_fn_info = @typeInfo(aligned_foo_fn_type); | ||
| 377 | try expect(aligned_foo_fn_info.Fn.calling_convention == .C); | ||
| 378 | try expect(!aligned_foo_fn_info.Fn.is_generic); | ||
| 379 | try expect(aligned_foo_fn_info.Fn.params.len == 2); | ||
| 380 | try expect(aligned_foo_fn_info.Fn.is_var_args); | ||
| 381 | try expect(aligned_foo_fn_info.Fn.return_type.? == usize); | ||
| 382 | const aligned_foo_ptr_fn_info = @typeInfo(@TypeOf(&typeInfoFooAligned)); | ||
| 383 | try expect(aligned_foo_ptr_fn_info.Pointer.size == .One); | ||
| 384 | try expect(aligned_foo_ptr_fn_info.Pointer.is_const); | ||
| 385 | try expect(!aligned_foo_ptr_fn_info.Pointer.is_volatile); | ||
| 386 | try expect(aligned_foo_ptr_fn_info.Pointer.alignment == 4); | ||
| 387 | try expect(aligned_foo_ptr_fn_info.Pointer.address_space == .generic); | ||
| 388 | try expect(aligned_foo_ptr_fn_info.Pointer.child == aligned_foo_fn_type); | ||
| 389 | try expect(!aligned_foo_ptr_fn_info.Pointer.is_allowzero); | ||
| 390 | try expect(aligned_foo_ptr_fn_info.Pointer.sentinel == null); | ||
| 369 | } | 391 | } |
| 370 | 392 | ||
| 371 | extern fn typeInfoFoo(a: usize, b: bool, ...) callconv(.C) usize; | 393 | extern fn typeInfoFoo(a: usize, b: bool, ...) callconv(.C) usize; |
test/behavior/typename.zig+2-4| ... | @@ -78,11 +78,9 @@ test "basic" { | ... | @@ -78,11 +78,9 @@ test "basic" { |
| 78 | try expectEqualStrings("fn (comptime u32) void", @typeName(fn (comptime u32) void)); | 78 | try expectEqualStrings("fn (comptime u32) void", @typeName(fn (comptime u32) void)); |
| 79 | try expectEqualStrings("fn (noalias []u8) void", @typeName(fn (noalias []u8) void)); | 79 | try expectEqualStrings("fn (noalias []u8) void", @typeName(fn (noalias []u8) void)); |
| 80 | 80 | ||
| 81 | try expectEqualStrings("fn () align(32) void", @typeName(fn () align(32) void)); | ||
| 82 | try expectEqualStrings("fn () callconv(.C) void", @typeName(fn () callconv(.C) void)); | 81 | try expectEqualStrings("fn () callconv(.C) void", @typeName(fn () callconv(.C) void)); |
| 83 | try expectEqualStrings("fn () align(32) callconv(.C) void", @typeName(fn () align(32) callconv(.C) void)); | 82 | try expectEqualStrings("fn (...) callconv(.C) void", @typeName(fn (...) callconv(.C) void)); |
| 84 | try expectEqualStrings("fn (...) align(32) callconv(.C) void", @typeName(fn (...) align(32) callconv(.C) void)); | 83 | try expectEqualStrings("fn (u32, ...) callconv(.C) void", @typeName(fn (u32, ...) callconv(.C) void)); |
| 85 | try expectEqualStrings("fn (u32, ...) align(32) callconv(.C) void", @typeName(fn (u32, ...) align(32) callconv(.C) void)); | ||
| 86 | } | 84 | } |
| 87 | 85 | ||
| 88 | test "top level decl" { | 86 | test "top level decl" { |
test/cases/compile_errors/function_ptr_alignment.zig+8-20| ... | @@ -1,28 +1,16 @@ | ... | @@ -1,28 +1,16 @@ |
| 1 | comptime { | 1 | fn align1() align(1) void {} |
| 2 | var a: *align(2) @TypeOf(foo) = undefined; | 2 | fn align2() align(2) void {} |
| 3 | _ = &a; | ||
| 4 | } | ||
| 5 | fn foo() void {} | ||
| 6 | 3 | ||
| 7 | comptime { | 4 | comptime { |
| 8 | var a: *align(1) fn () void = undefined; | 5 | _ = @as(*align(1) const fn () void, &align2); |
| 9 | _ = &a; | 6 | _ = @as(*align(1) const fn () void, &align1); |
| 10 | } | 7 | _ = @as(*align(2) const fn () void, &align2); |
| 11 | comptime { | 8 | _ = @as(*align(2) const fn () void, &align1); |
| 12 | var a: *align(2) fn () align(2) void = undefined; | ||
| 13 | _ = &a; | ||
| 14 | } | ||
| 15 | comptime { | ||
| 16 | var a: *align(2) fn () void = undefined; | ||
| 17 | _ = &a; | ||
| 18 | } | ||
| 19 | comptime { | ||
| 20 | var a: *align(1) fn () align(2) void = undefined; | ||
| 21 | _ = &a; | ||
| 22 | } | 9 | } |
| 23 | 10 | ||
| 24 | // error | 11 | // error |
| 25 | // backend=stage2 | 12 | // backend=stage2 |
| 26 | // target=native | 13 | // target=native |
| 27 | // | 14 | // |
| 28 | // :20:19: error: function pointer alignment disagrees with function alignment | 15 | // :8:41: error: expected type '*align(2) const fn () void', found '*const fn () void' |
| 16 | // :8:41: note: pointer alignment '1' cannot cast into pointer alignment '2' |
test/cases/compile_errors/inferring_error_set_of_function_pointer.zig deleted-9| ... | @@ -1,9 +0,0 @@ | ||
| 1 | comptime { | ||
| 2 | const z: ?fn () !void = null; | ||
| 3 | } | ||
| 4 | |||
| 5 | // error | ||
| 6 | // backend=stage2 | ||
| 7 | // target=native | ||
| 8 | // | ||
| 9 | // :2:21: error: function prototype may not have inferred error set | ||
test/cases/compile_errors/invalid_function_types.zig created+25| ... | @@ -0,0 +1,25 @@ | ||
| 1 | comptime { | ||
| 2 | _ = fn name() void; | ||
| 3 | } | ||
| 4 | comptime { | ||
| 5 | _ = fn () align(128) void; | ||
| 6 | } | ||
| 7 | comptime { | ||
| 8 | _ = fn () addrspace(.generic) void; | ||
| 9 | } | ||
| 10 | comptime { | ||
| 11 | _ = fn () linksection("section") void; | ||
| 12 | } | ||
| 13 | comptime { | ||
| 14 | _ = fn () !void; | ||
| 15 | } | ||
| 16 | |||
| 17 | // error | ||
| 18 | // backend=stage2 | ||
| 19 | // target=native | ||
| 20 | // | ||
| 21 | // :2:12: error: function type cannot have a name | ||
| 22 | // :5:21: error: function type cannot have an alignment | ||
| 23 | // :8:26: error: function type cannot have an addrspace | ||
| 24 | // :11:27: error: function type cannot have a linksection | ||
| 25 | // :14:15: error: function type cannot have an inferred error set | ||
test/cases/compile_errors/passing_an_under-aligned_function_pointer.zig+2-2| ... | @@ -1,7 +1,7 @@ | ... | @@ -1,7 +1,7 @@ |
| 1 | export fn entry() void { | 1 | export fn entry() void { |
| 2 | testImplicitlyDecreaseFnAlign(alignedSmall, 1234); | 2 | testImplicitlyDecreaseFnAlign(alignedSmall, 1234); |
| 3 | } | 3 | } |
| 4 | fn testImplicitlyDecreaseFnAlign(ptr: *const fn () align(8) i32, answer: i32) void { | 4 | fn testImplicitlyDecreaseFnAlign(ptr: *align(8) const fn () i32, answer: i32) void { |
| 5 | if (ptr() != answer) unreachable; | 5 | if (ptr() != answer) unreachable; |
| 6 | } | 6 | } |
| 7 | fn alignedSmall() align(4) i32 { | 7 | fn alignedSmall() align(4) i32 { |
| ... | @@ -12,5 +12,5 @@ fn alignedSmall() align(4) i32 { | ... | @@ -12,5 +12,5 @@ fn alignedSmall() align(4) i32 { |
| 12 | // backend=stage2 | 12 | // backend=stage2 |
| 13 | // target=x86_64-linux | 13 | // target=x86_64-linux |
| 14 | // | 14 | // |
| 15 | // :2:35: error: expected type '*const fn () align(8) i32', found '*const fn () align(4) i32' | 15 | // :2:35: error: expected type '*align(8) const fn () i32', found '*align(4) const fn () i32' |
| 16 | // :2:35: note: pointer alignment '4' cannot cast into pointer alignment '8' | 16 | // :2:35: note: pointer alignment '4' cannot cast into pointer alignment '8' |
test/cases/compile_errors/reify_type.Fn_with_is_generic_true.zig-1| ... | @@ -1,7 +1,6 @@ | ... | @@ -1,7 +1,6 @@ |
| 1 | const Foo = @Type(.{ | 1 | const Foo = @Type(.{ |
| 2 | .Fn = .{ | 2 | .Fn = .{ |
| 3 | .calling_convention = .Unspecified, | 3 | .calling_convention = .Unspecified, |
| 4 | .alignment = 0, | ||
| 5 | .is_generic = true, | 4 | .is_generic = true, |
| 6 | .is_var_args = false, | 5 | .is_var_args = false, |
| 7 | .return_type = u0, | 6 | .return_type = u0, |
test/cases/compile_errors/reify_type.Fn_with_is_var_args_true_and_non-C_callconv.zig-1| ... | @@ -1,7 +1,6 @@ | ... | @@ -1,7 +1,6 @@ |
| 1 | const Foo = @Type(.{ | 1 | const Foo = @Type(.{ |
| 2 | .Fn = .{ | 2 | .Fn = .{ |
| 3 | .calling_convention = .Unspecified, | 3 | .calling_convention = .Unspecified, |
| 4 | .alignment = 0, | ||
| 5 | .is_generic = false, | 4 | .is_generic = false, |
| 6 | .is_var_args = true, | 5 | .is_var_args = true, |
| 7 | .return_type = u0, | 6 | .return_type = u0, |
test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig-1| ... | @@ -1,7 +1,6 @@ | ... | @@ -1,7 +1,6 @@ |
| 1 | const Foo = @Type(.{ | 1 | const Foo = @Type(.{ |
| 2 | .Fn = .{ | 2 | .Fn = .{ |
| 3 | .calling_convention = .Unspecified, | 3 | .calling_convention = .Unspecified, |
| 4 | .alignment = 0, | ||
| 5 | .is_generic = false, | 4 | .is_generic = false, |
| 6 | .is_var_args = false, | 5 | .is_var_args = false, |
| 7 | .return_type = null, | 6 | .return_type = null, |