| 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 | 2780 | |
| 2781 | 2781 | test "function alignment" { |
| 2782 | 2782 | try expect(derp() == 1234); |
| 2783 | try expect(@TypeOf(noop1) == fn () align(1) void); | |
| 2784 | try expect(@TypeOf(noop4) == fn () align(4) void); | |
| 2783 | try expect(@TypeOf(derp) == fn () i32); | |
| 2784 | try expect(@TypeOf(&derp) == *align(@sizeOf(usize) * 2) const fn () i32); | |
| 2785 | ||
| 2785 | 2786 | noop1(); |
| 2787 | try expect(@TypeOf(noop1) == fn () void); | |
| 2788 | try expect(@TypeOf(&noop1) == *align(1) const fn () void); | |
| 2789 | ||
| 2786 | 2790 | noop4(); |
| 2791 | try expect(@TypeOf(noop4) == fn () void); | |
| 2792 | try expect(@TypeOf(&noop4) == *align(4) const fn () void); | |
| 2787 | 2793 | } |
| 2788 | 2794 | {#code_end#} |
| 2789 | 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 | 420 | /// therefore must be kept in sync with the compiler implementation. |
| 421 | 421 | pub const Fn = struct { |
| 422 | 422 | calling_convention: CallingConvention, |
| 423 | alignment: comptime_int, | |
| 424 | 423 | is_generic: bool, |
| 425 | 424 | is_var_args: bool, |
| 426 | 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 | 1053 | pub const empty_sigset: sigset_t = 0; |
| 1054 | 1054 | |
| 1055 | 1055 | pub const SIG = struct { |
| 1056 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | |
| 1057 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | |
| 1058 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | |
| 1059 | pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(5)); | |
| 1056 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); | |
| 1057 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); | |
| 1058 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); | |
| 1059 | pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(5); | |
| 1060 | 1060 | |
| 1061 | 1061 | /// block specified signal set |
| 1062 | 1062 | pub const BLOCK = 1; |
| ... | ... | @@ -1150,7 +1150,7 @@ pub const siginfo_t = extern struct { |
| 1150 | 1150 | |
| 1151 | 1151 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with function name. |
| 1152 | 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 | 1154 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; |
| 1155 | 1155 | |
| 1156 | 1156 | handler: extern union { |
lib/std/c/dragonfly.zig+4-4| ... | ... | @@ -616,9 +616,9 @@ pub const S = struct { |
| 616 | 616 | pub const BADSIG = SIG.ERR; |
| 617 | 617 | |
| 618 | 618 | pub const SIG = struct { |
| 619 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | |
| 620 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | |
| 621 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | |
| 619 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); | |
| 620 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); | |
| 621 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); | |
| 622 | 622 | |
| 623 | 623 | pub const BLOCK = 1; |
| 624 | 624 | pub const UNBLOCK = 2; |
| ... | ... | @@ -690,7 +690,7 @@ pub const empty_sigset = sigset_t{ .__bits = [_]c_uint{0} ** _SIG_WORDS }; |
| 690 | 690 | pub const sig_atomic_t = c_int; |
| 691 | 691 | |
| 692 | 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 | 694 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; |
| 695 | 695 | |
| 696 | 696 | /// signal handler |
lib/std/c/freebsd.zig+4-4| ... | ... | @@ -695,9 +695,9 @@ pub const SIG = struct { |
| 695 | 695 | pub const UNBLOCK = 2; |
| 696 | 696 | pub const SETMASK = 3; |
| 697 | 697 | |
| 698 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | |
| 699 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | |
| 700 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | |
| 698 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); | |
| 699 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); | |
| 700 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); | |
| 701 | 701 | |
| 702 | 702 | pub const WORDS = 4; |
| 703 | 703 | pub const MAXSIG = 128; |
| ... | ... | @@ -1171,7 +1171,7 @@ const NSIG = 32; |
| 1171 | 1171 | |
| 1172 | 1172 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. |
| 1173 | 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 | 1175 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; |
| 1176 | 1176 | |
| 1177 | 1177 | /// signal handler |
lib/std/c/haiku.zig+4-4| ... | ... | @@ -441,9 +441,9 @@ pub const SA = struct { |
| 441 | 441 | }; |
| 442 | 442 | |
| 443 | 443 | pub const SIG = struct { |
| 444 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | |
| 445 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | |
| 446 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | |
| 444 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); | |
| 445 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); | |
| 446 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); | |
| 447 | 447 | |
| 448 | 448 | pub const HUP = 1; |
| 449 | 449 | pub const INT = 2; |
| ... | ... | @@ -690,7 +690,7 @@ const NSIG = 32; |
| 690 | 690 | |
| 691 | 691 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. |
| 692 | 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 | 695 | /// signal handler |
| 696 | 696 | __sigaction_u: extern union { |
lib/std/c/netbsd.zig+4-4| ... | ... | @@ -800,9 +800,9 @@ pub const winsize = extern struct { |
| 800 | 800 | const NSIG = 32; |
| 801 | 801 | |
| 802 | 802 | pub const SIG = struct { |
| 803 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | |
| 804 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | |
| 805 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | |
| 803 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); | |
| 804 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); | |
| 805 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); | |
| 806 | 806 | |
| 807 | 807 | pub const WORDS = 4; |
| 808 | 808 | pub const MAXSIG = 128; |
| ... | ... | @@ -864,7 +864,7 @@ pub const SIG = struct { |
| 864 | 864 | |
| 865 | 865 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. |
| 866 | 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 | 868 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; |
| 869 | 869 | |
| 870 | 870 | /// signal handler |
lib/std/c/openbsd.zig+6-6| ... | ... | @@ -795,11 +795,11 @@ pub const winsize = extern struct { |
| 795 | 795 | const NSIG = 33; |
| 796 | 796 | |
| 797 | 797 | pub const SIG = struct { |
| 798 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | |
| 799 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | |
| 800 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | |
| 801 | pub const CATCH = @as(?Sigaction.handler_fn, @ptrFromInt(2)); | |
| 802 | pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(3)); | |
| 798 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); | |
| 799 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); | |
| 800 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); | |
| 801 | pub const CATCH: ?Sigaction.handler_fn = @ptrFromInt(2); | |
| 802 | pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(3); | |
| 803 | 803 | |
| 804 | 804 | pub const HUP = 1; |
| 805 | 805 | pub const INT = 2; |
| ... | ... | @@ -842,7 +842,7 @@ pub const SIG = struct { |
| 842 | 842 | |
| 843 | 843 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. |
| 844 | 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 | 846 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; |
| 847 | 847 | |
| 848 | 848 | /// signal handler |
lib/std/c/solaris.zig+5-5| ... | ... | @@ -798,10 +798,10 @@ pub const winsize = extern struct { |
| 798 | 798 | const NSIG = 75; |
| 799 | 799 | |
| 800 | 800 | pub const SIG = struct { |
| 801 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | |
| 802 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | |
| 803 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | |
| 804 | pub const HOLD = @as(?Sigaction.handler_fn, @ptrFromInt(2)); | |
| 801 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); | |
| 802 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); | |
| 803 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); | |
| 804 | pub const HOLD: ?Sigaction.handler_fn = @ptrFromInt(2); | |
| 805 | 805 | |
| 806 | 806 | pub const WORDS = 4; |
| 807 | 807 | pub const MAXSIG = 75; |
| ... | ... | @@ -874,7 +874,7 @@ pub const SIG = struct { |
| 874 | 874 | |
| 875 | 875 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. |
| 876 | 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 | 878 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; |
| 879 | 879 | |
| 880 | 880 | /// signal options |
lib/std/meta.zig+4-5| ... | ... | @@ -57,10 +57,9 @@ test stringToEnum { |
| 57 | 57 | } |
| 58 | 58 | |
| 59 | 59 | /// Returns the alignment of type T. |
| 60 | /// Note that if T is a pointer or function type the result is different than | |
| 61 | /// the one returned by @alignOf(T). | |
| 60 | /// Note that if T is a pointer type the result is different than the one | |
| 61 | /// returned by @alignOf(T). | |
| 62 | 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 | 63 | pub fn alignment(comptime T: type) comptime_int { |
| 65 | 64 | return switch (@typeInfo(T)) { |
| 66 | 65 | .Optional => |info| switch (@typeInfo(info.child)) { |
| ... | ... | @@ -68,7 +67,6 @@ pub fn alignment(comptime T: type) comptime_int { |
| 68 | 67 | else => @alignOf(T), |
| 69 | 68 | }, |
| 70 | 69 | .Pointer => |info| info.alignment, |
| 71 | .Fn => |info| info.alignment, | |
| 72 | 70 | else => @alignOf(T), |
| 73 | 71 | }; |
| 74 | 72 | } |
| ... | ... | @@ -80,7 +78,8 @@ test alignment { |
| 80 | 78 | try testing.expect(alignment([]align(1) u8) == 1); |
| 81 | 79 | try testing.expect(alignment([]align(2) u8) == 2); |
| 82 | 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 | 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 | 689 | pub const SYS = 31; |
| 690 | 690 | pub const UNUSED = SIG.SYS; |
| 691 | 691 | |
| 692 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(std.math.maxInt(usize))); | |
| 693 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | |
| 694 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | |
| 692 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(std.math.maxInt(usize)); | |
| 693 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); | |
| 694 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); | |
| 695 | 695 | }; |
| 696 | 696 | |
| 697 | 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 | 699 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; |
| 700 | 700 | |
| 701 | 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 | 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 | 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 | 1334 | pub fn clock_gettime(clk_id: i32, tp: *timespec) usize { |
| 1336 | 1335 | if (@hasDecl(VDSO, "CGT_SYM")) { |
| 1337 | const ptr = @atomicLoad(?*const anyopaque, &vdso_clock_gettime, .unordered); | |
| 1338 | if (ptr) |fn_ptr| { | |
| 1339 | const f = @as(vdso_clock_gettime_ty, @ptrCast(fn_ptr)); | |
| 1336 | const ptr = @atomicLoad(?VdsoClockGettime, &vdso_clock_gettime, .unordered); | |
| 1337 | if (ptr) |f| { | |
| 1340 | 1338 | const rc = f(clk_id, tp); |
| 1341 | 1339 | switch (rc) { |
| 1342 | 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 | 1346 | } |
| 1349 | 1347 | |
| 1350 | 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 | 1350 | // Note that we may not have a VDSO at all, update the stub address anyway |
| 1353 | 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 | 1353 | // Call into the VDSO if available |
| 1356 | if (ptr) |fn_ptr| { | |
| 1357 | const f = @as(vdso_clock_gettime_ty, @ptrCast(fn_ptr)); | |
| 1358 | return f(clk, ts); | |
| 1359 | } | |
| 1354 | if (ptr) |f| return f(clk, ts); | |
| 1360 | 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 | 2511 | pub const SYS = 31; |
| 2517 | 2512 | pub const UNUSED = SIG.SYS; |
| 2518 | 2513 | |
| 2519 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | |
| 2520 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | |
| 2521 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | |
| 2514 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); | |
| 2515 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); | |
| 2516 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); | |
| 2522 | 2517 | } else if (is_sparc) struct { |
| 2523 | 2518 | pub const BLOCK = 1; |
| 2524 | 2519 | pub const UNBLOCK = 2; |
| ... | ... | @@ -2560,9 +2555,9 @@ pub const SIG = if (is_mips) struct { |
| 2560 | 2555 | pub const PWR = LOST; |
| 2561 | 2556 | pub const IO = SIG.POLL; |
| 2562 | 2557 | |
| 2563 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | |
| 2564 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | |
| 2565 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | |
| 2558 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); | |
| 2559 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); | |
| 2560 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); | |
| 2566 | 2561 | } else struct { |
| 2567 | 2562 | pub const BLOCK = 0; |
| 2568 | 2563 | pub const UNBLOCK = 1; |
| ... | ... | @@ -2603,9 +2598,9 @@ pub const SIG = if (is_mips) struct { |
| 2603 | 2598 | pub const SYS = 31; |
| 2604 | 2599 | pub const UNUSED = SIG.SYS; |
| 2605 | 2600 | |
| 2606 | pub const ERR = @as(?Sigaction.handler_fn, @ptrFromInt(maxInt(usize))); | |
| 2607 | pub const DFL = @as(?Sigaction.handler_fn, @ptrFromInt(0)); | |
| 2608 | pub const IGN = @as(?Sigaction.handler_fn, @ptrFromInt(1)); | |
| 2601 | pub const ERR: ?Sigaction.handler_fn = @ptrFromInt(maxInt(usize)); | |
| 2602 | pub const DFL: ?Sigaction.handler_fn = @ptrFromInt(0); | |
| 2603 | pub const IGN: ?Sigaction.handler_fn = @ptrFromInt(1); | |
| 2609 | 2604 | }; |
| 2610 | 2605 | |
| 2611 | 2606 | pub const kernel_rwf = u32; |
| ... | ... | @@ -3709,7 +3704,7 @@ pub const all_mask: sigset_t = [_]u32{0xffffffff} ** @typeInfo(sigset_t).Array.l |
| 3709 | 3704 | pub const app_mask: sigset_t = [2]u32{ 0xfffffffc, 0x7fffffff } ++ [_]u32{0xffffffff} ** 30; |
| 3710 | 3705 | |
| 3711 | 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 | 3708 | const restorer = *const fn () callconv(.C) void; |
| 3714 | 3709 | }; |
| 3715 | 3710 | |
| ... | ... | @@ -3736,7 +3731,7 @@ pub const k_sigaction = switch (native_arch) { |
| 3736 | 3731 | |
| 3737 | 3732 | /// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. |
| 3738 | 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 | 3735 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; |
| 3741 | 3736 | |
| 3742 | 3737 | handler: extern union { |
lib/std/zig/AstGen.zig+7-7| ... | ... | @@ -1369,16 +1369,16 @@ fn fnProtoExpr( |
| 1369 | 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: { | |
| 1373 | break :inst try expr(&block_scope, scope, coerced_align_ri, fn_proto.ast.align_expr); | |
| 1374 | }; | |
| 1372 | if (fn_proto.ast.align_expr != 0) { | |
| 1373 | return astgen.failNode(fn_proto.ast.align_expr, "function type cannot have an alignment", .{}); | |
| 1374 | } | |
| 1375 | 1375 | |
| 1376 | 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 | 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 | 1384 | const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0) |
| ... | ... | @@ -1394,7 +1394,7 @@ fn fnProtoExpr( |
| 1394 | 1394 | const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; |
| 1395 | 1395 | const is_inferred_error = token_tags[maybe_bang] == .bang; |
| 1396 | 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 | 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 | 1403 | |
| 1404 | 1404 | .cc_ref = cc, |
| 1405 | 1405 | .cc_gz = null, |
| 1406 | .align_ref = align_ref, | |
| 1406 | .align_ref = .none, | |
| 1407 | 1407 | .align_gz = null, |
| 1408 | 1408 | .ret_ref = ret_ty, |
| 1409 | 1409 | .ret_gz = null, |
src/InternPool.zig+5-23| ... | ... | @@ -765,16 +765,10 @@ pub const Key = union(enum) { |
| 765 | 765 | /// Tells whether a parameter is noalias. See `paramIsNoalias` helper |
| 766 | 766 | /// method for accessing this. |
| 767 | 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 | 768 | cc: std.builtin.CallingConvention, |
| 774 | 769 | is_var_args: bool, |
| 775 | 770 | is_generic: bool, |
| 776 | 771 | is_noinline: bool, |
| 777 | align_is_generic: bool, | |
| 778 | 772 | cc_is_generic: bool, |
| 779 | 773 | section_is_generic: bool, |
| 780 | 774 | addrspace_is_generic: bool, |
| ... | ... | @@ -794,7 +788,6 @@ pub const Key = union(enum) { |
| 794 | 788 | a.return_type == b.return_type and |
| 795 | 789 | a.comptime_bits == b.comptime_bits and |
| 796 | 790 | a.noalias_bits == b.noalias_bits and |
| 797 | a.alignment == b.alignment and | |
| 798 | 791 | a.cc == b.cc and |
| 799 | 792 | a.is_var_args == b.is_var_args and |
| 800 | 793 | a.is_generic == b.is_generic and |
| ... | ... | @@ -808,7 +801,6 @@ pub const Key = union(enum) { |
| 808 | 801 | std.hash.autoHash(hasher, self.return_type); |
| 809 | 802 | std.hash.autoHash(hasher, self.comptime_bits); |
| 810 | 803 | std.hash.autoHash(hasher, self.noalias_bits); |
| 811 | std.hash.autoHash(hasher, self.alignment); | |
| 812 | 804 | std.hash.autoHash(hasher, self.cc); |
| 813 | 805 | std.hash.autoHash(hasher, self.is_var_args); |
| 814 | 806 | std.hash.autoHash(hasher, self.is_generic); |
| ... | ... | @@ -3587,18 +3579,16 @@ pub const Tag = enum(u8) { |
| 3587 | 3579 | flags: Flags, |
| 3588 | 3580 | |
| 3589 | 3581 | pub const Flags = packed struct(u32) { |
| 3590 | alignment: Alignment, | |
| 3591 | 3582 | cc: std.builtin.CallingConvention, |
| 3592 | 3583 | is_var_args: bool, |
| 3593 | 3584 | is_generic: bool, |
| 3594 | 3585 | has_comptime_bits: bool, |
| 3595 | 3586 | has_noalias_bits: bool, |
| 3596 | 3587 | is_noinline: bool, |
| 3597 | align_is_generic: bool, | |
| 3598 | 3588 | cc_is_generic: bool, |
| 3599 | 3589 | section_is_generic: bool, |
| 3600 | 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 | 4908 | .return_type = type_function.data.return_type, |
| 4919 | 4909 | .comptime_bits = comptime_bits, |
| 4920 | 4910 | .noalias_bits = noalias_bits, |
| 4921 | .alignment = type_function.data.flags.alignment, | |
| 4922 | 4911 | .cc = type_function.data.flags.cc, |
| 4923 | 4912 | .is_var_args = type_function.data.flags.is_var_args, |
| 4924 | 4913 | .is_noinline = type_function.data.flags.is_noinline, |
| 4925 | .align_is_generic = type_function.data.flags.align_is_generic, | |
| 4926 | 4914 | .cc_is_generic = type_function.data.flags.cc_is_generic, |
| 4927 | 4915 | .section_is_generic = type_function.data.flags.section_is_generic, |
| 4928 | 4916 | .addrspace_is_generic = type_function.data.flags.addrspace_is_generic, |
| ... | ... | @@ -6211,8 +6199,6 @@ pub const GetFuncTypeKey = struct { |
| 6211 | 6199 | comptime_bits: u32 = 0, |
| 6212 | 6200 | noalias_bits: u32 = 0, |
| 6213 | 6201 | /// `null` means generic. |
| 6214 | alignment: ?Alignment = .none, | |
| 6215 | /// `null` means generic. | |
| 6216 | 6202 | cc: ?std.builtin.CallingConvention = .Unspecified, |
| 6217 | 6203 | is_var_args: bool = false, |
| 6218 | 6204 | is_generic: bool = false, |
| ... | ... | @@ -6242,14 +6228,12 @@ pub fn getFuncType(ip: *InternPool, gpa: Allocator, key: GetFuncTypeKey) Allocat |
| 6242 | 6228 | .params_len = params_len, |
| 6243 | 6229 | .return_type = key.return_type, |
| 6244 | 6230 | .flags = .{ |
| 6245 | .alignment = key.alignment orelse .none, | |
| 6246 | 6231 | .cc = key.cc orelse .Unspecified, |
| 6247 | 6232 | .is_var_args = key.is_var_args, |
| 6248 | 6233 | .has_comptime_bits = key.comptime_bits != 0, |
| 6249 | 6234 | .has_noalias_bits = key.noalias_bits != 0, |
| 6250 | 6235 | .is_generic = key.is_generic, |
| 6251 | 6236 | .is_noinline = key.is_noinline, |
| 6252 | .align_is_generic = key.alignment == null, | |
| 6253 | 6237 | .cc_is_generic = key.cc == null, |
| 6254 | 6238 | .section_is_generic = key.section_is_generic, |
| 6255 | 6239 | .addrspace_is_generic = key.addrspace_is_generic, |
| ... | ... | @@ -6433,14 +6417,12 @@ pub fn getFuncDeclIes(ip: *InternPool, gpa: Allocator, key: GetFuncDeclIesKey) A |
| 6433 | 6417 | .params_len = params_len, |
| 6434 | 6418 | .return_type = @enumFromInt(ip.items.len - 2), |
| 6435 | 6419 | .flags = .{ |
| 6436 | .alignment = key.alignment orelse .none, | |
| 6437 | 6420 | .cc = key.cc orelse .Unspecified, |
| 6438 | 6421 | .is_var_args = key.is_var_args, |
| 6439 | 6422 | .has_comptime_bits = key.comptime_bits != 0, |
| 6440 | 6423 | .has_noalias_bits = key.noalias_bits != 0, |
| 6441 | 6424 | .is_generic = key.is_generic, |
| 6442 | 6425 | .is_noinline = key.is_noinline, |
| 6443 | .align_is_generic = key.alignment == null, | |
| 6444 | 6426 | .cc_is_generic = key.cc == null, |
| 6445 | 6427 | .section_is_generic = key.section_is_generic, |
| 6446 | 6428 | .addrspace_is_generic = key.addrspace_is_generic, |
| ... | ... | @@ -6553,7 +6535,6 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey) |
| 6553 | 6535 | .param_types = arg.param_types, |
| 6554 | 6536 | .return_type = arg.bare_return_type, |
| 6555 | 6537 | .noalias_bits = arg.noalias_bits, |
| 6556 | .alignment = arg.alignment, | |
| 6557 | 6538 | .cc = arg.cc, |
| 6558 | 6539 | .is_noinline = arg.is_noinline, |
| 6559 | 6540 | }); |
| ... | ... | @@ -6610,6 +6591,7 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey) |
| 6610 | 6591 | func_index, |
| 6611 | 6592 | func_extra_index, |
| 6612 | 6593 | func_ty, |
| 6594 | arg.alignment, | |
| 6613 | 6595 | arg.section, |
| 6614 | 6596 | ); |
| 6615 | 6597 | } |
| ... | ... | @@ -6673,14 +6655,12 @@ pub fn getFuncInstanceIes( |
| 6673 | 6655 | .params_len = params_len, |
| 6674 | 6656 | .return_type = error_union_type, |
| 6675 | 6657 | .flags = .{ |
| 6676 | .alignment = arg.alignment, | |
| 6677 | 6658 | .cc = arg.cc, |
| 6678 | 6659 | .is_var_args = false, |
| 6679 | 6660 | .has_comptime_bits = false, |
| 6680 | 6661 | .has_noalias_bits = arg.noalias_bits != 0, |
| 6681 | 6662 | .is_generic = false, |
| 6682 | 6663 | .is_noinline = arg.is_noinline, |
| 6683 | .align_is_generic = false, | |
| 6684 | 6664 | .cc_is_generic = false, |
| 6685 | 6665 | .section_is_generic = false, |
| 6686 | 6666 | .addrspace_is_generic = false, |
| ... | ... | @@ -6741,6 +6721,7 @@ pub fn getFuncInstanceIes( |
| 6741 | 6721 | func_index, |
| 6742 | 6722 | func_extra_index, |
| 6743 | 6723 | func_ty, |
| 6724 | arg.alignment, | |
| 6744 | 6725 | arg.section, |
| 6745 | 6726 | ); |
| 6746 | 6727 | } |
| ... | ... | @@ -6752,6 +6733,7 @@ fn finishFuncInstance( |
| 6752 | 6733 | func_index: Index, |
| 6753 | 6734 | func_extra_index: u32, |
| 6754 | 6735 | func_ty: Index, |
| 6736 | alignment: Alignment, | |
| 6755 | 6737 | section: OptionalNullTerminatedString, |
| 6756 | 6738 | ) Allocator.Error!Index { |
| 6757 | 6739 | const fn_owner_decl = ip.declPtr(ip.funcDeclOwner(generic_owner)); |
| ... | ... | @@ -6764,7 +6746,7 @@ fn finishFuncInstance( |
| 6764 | 6746 | .owns_tv = true, |
| 6765 | 6747 | .ty = @import("type.zig").Type.fromInterned(func_ty), |
| 6766 | 6748 | .val = @import("Value.zig").fromInterned(func_index), |
| 6767 | .alignment = .none, | |
| 6749 | .alignment = alignment, | |
| 6768 | 6750 | .@"linksection" = section, |
| 6769 | 6751 | .@"addrspace" = fn_owner_decl.@"addrspace", |
| 6770 | 6752 | .analysis = .complete, |
src/Module.zig+72-104| ... | ... | @@ -3596,6 +3596,18 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { |
| 3596 | 3596 | |
| 3597 | 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 | 3611 | const decl_inst = decl.zir_decl_index.unwrap().?.resolve(ip); |
| 3600 | 3612 | |
| 3601 | 3613 | const gpa = mod.gpa; |
| ... | ... | @@ -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())) { | |
| 3737 | .func => |func| { | |
| 3738 | const owns_tv = func.owner_decl == decl_index; | |
| 3739 | if (owns_tv) { | |
| 3740 | var prev_type_has_bits = false; | |
| 3741 | var prev_is_inline = false; | |
| 3742 | var type_changed = true; | |
| 3743 | ||
| 3744 | if (decl.has_tv) { | |
| 3745 | prev_type_has_bits = decl.ty.isFnOrHasRuntimeBits(mod); | |
| 3746 | type_changed = !decl.ty.eql(decl_tv.ty, mod); | |
| 3747 | if (decl.getOwnedFunction(mod)) |prev_func| { | |
| 3748 | prev_is_inline = prev_func.analysis(ip).state == .inline_only; | |
| 3749 | } | |
| 3750 | } | |
| 3751 | ||
| 3752 | decl.ty = decl_tv.ty; | |
| 3753 | decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod))); | |
| 3754 | // linksection, align, and addrspace were already set by Sema | |
| 3755 | decl.has_tv = true; | |
| 3756 | decl.owns_tv = owns_tv; | |
| 3757 | decl.analysis = .complete; | |
| 3758 | ||
| 3759 | const is_inline = decl.ty.fnCallingConvention(mod) == .Inline; | |
| 3760 | if (decl.is_exported) { | |
| 3761 | const export_src: LazySrcLoc = .{ .token_offset = @intFromBool(decl.is_pub) }; | |
| 3762 | if (is_inline) { | |
| 3763 | return sema.fail(&block_scope, export_src, "export of inline function", .{}); | |
| 3764 | } | |
| 3765 | // The scope needs to have the decl in it. | |
| 3766 | try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index); | |
| 3767 | } | |
| 3768 | // TODO: align, linksection, addrspace? | |
| 3769 | const changed = type_changed or is_inline != prev_is_inline; | |
| 3770 | return .{ | |
| 3771 | .invalidate_decl_val = changed, | |
| 3772 | .invalidate_decl_ref = changed, | |
| 3773 | }; | |
| 3774 | } | |
| 3775 | }, | |
| 3776 | else => {}, | |
| 3777 | } | |
| 3778 | ||
| 3779 | decl.owns_tv = false; | |
| 3780 | var queue_linker_work = false; | |
| 3781 | var is_extern = false; | |
| 3748 | var queue_linker_work = true; | |
| 3749 | var is_func = false; | |
| 3750 | var is_inline = false; | |
| 3782 | 3751 | switch (decl_tv.val.toIntern()) { |
| 3783 | 3752 | .generic_poison => unreachable, |
| 3784 | 3753 | .unreachable_value => unreachable, |
| 3785 | 3754 | else => switch (ip.indexToKey(decl_tv.val.toIntern())) { |
| 3786 | .variable => |variable| if (variable.decl == decl_index) { | |
| 3787 | decl.owns_tv = true; | |
| 3788 | queue_linker_work = true; | |
| 3755 | .variable => |variable| { | |
| 3756 | decl.owns_tv = variable.decl == decl_index; | |
| 3757 | queue_linker_work = decl.owns_tv; | |
| 3789 | 3758 | }, |
| 3790 | 3759 | |
| 3791 | .extern_func => |extern_fn| if (extern_fn.decl == decl_index) { | |
| 3792 | decl.owns_tv = true; | |
| 3793 | queue_linker_work = true; | |
| 3794 | is_extern = true; | |
| 3760 | .extern_func => |extern_func| { | |
| 3761 | decl.owns_tv = extern_func.decl == decl_index; | |
| 3762 | queue_linker_work = decl.owns_tv; | |
| 3763 | is_func = decl.owns_tv; | |
| 3795 | 3764 | }, |
| 3796 | 3765 | |
| 3797 | .func => {}, | |
| 3798 | ||
| 3799 | else => { | |
| 3800 | queue_linker_work = true; | |
| 3766 | .func => |func| { | |
| 3767 | decl.owns_tv = func.owner_decl == decl_index; | |
| 3768 | queue_linker_work = false; | |
| 3769 | is_inline = decl.owns_tv and decl_tv.ty.fnCallingConvention(mod) == .Inline; | |
| 3770 | is_func = decl.owns_tv; | |
| 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 | 3777 | decl.ty = decl_tv.ty; |
| 3814 | 3778 | decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod))); |
| 3815 | decl.alignment = blk: { | |
| 3816 | const align_body = decl_bodies.align_body orelse break :blk .none; | |
| 3817 | const align_ref = try sema.resolveInlineBody(&block_scope, align_body, decl_inst); | |
| 3818 | break :blk try sema.analyzeAsAlign(&block_scope, align_src, align_ref); | |
| 3819 | }; | |
| 3820 | decl.@"linksection" = blk: { | |
| 3821 | const linksection_body = decl_bodies.linksection_body orelse break :blk .none; | |
| 3822 | const linksection_ref = try sema.resolveInlineBody(&block_scope, linksection_body, decl_inst); | |
| 3823 | const bytes = try sema.toConstString(&block_scope, section_src, linksection_ref, .{ | |
| 3824 | .needed_comptime_reason = "linksection must be comptime-known", | |
| 3825 | }); | |
| 3826 | if (mem.indexOfScalar(u8, bytes, 0) != null) { | |
| 3827 | return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{}); | |
| 3828 | } else if (bytes.len == 0) { | |
| 3829 | return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{}); | |
| 3830 | } | |
| 3831 | const section = try ip.getOrPutString(gpa, bytes); | |
| 3832 | break :blk section.toOptional(); | |
| 3833 | }; | |
| 3834 | decl.@"addrspace" = blk: { | |
| 3835 | const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(decl_tv.val.toIntern())) { | |
| 3836 | .variable => .variable, | |
| 3837 | .extern_func, .func => .function, | |
| 3838 | else => .constant, | |
| 3779 | // Function linksection, align, and addrspace were already set by Sema | |
| 3780 | if (!is_func) { | |
| 3781 | decl.alignment = blk: { | |
| 3782 | const align_body = decl_bodies.align_body orelse break :blk .none; | |
| 3783 | const align_ref = try sema.resolveInlineBody(&block_scope, align_body, decl_inst); | |
| 3784 | break :blk try sema.analyzeAsAlign(&block_scope, align_src, align_ref); | |
| 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) { | |
| 3844 | .function => target_util.defaultAddressSpace(target, .function), | |
| 3845 | .variable => target_util.defaultAddressSpace(target, .global_mutable), | |
| 3846 | .constant => target_util.defaultAddressSpace(target, .global_constant), | |
| 3847 | else => unreachable, | |
| 3809 | const addrspace_body = decl_bodies.addrspace_body orelse break :blk switch (addrspace_ctx) { | |
| 3810 | .function => target_util.defaultAddressSpace(target, .function), | |
| 3811 | .variable => target_util.defaultAddressSpace(target, .global_mutable), | |
| 3812 | .constant => target_util.defaultAddressSpace(target, .global_constant), | |
| 3813 | else => unreachable, | |
| 3814 | }; | |
| 3815 | const addrspace_ref = try sema.resolveInlineBody(&block_scope, addrspace_body, decl_inst); | |
| 3816 | break :blk try sema.analyzeAsAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx); | |
| 3848 | 3817 | }; |
| 3849 | const addrspace_ref = try sema.resolveInlineBody(&block_scope, addrspace_body, decl_inst); | |
| 3850 | break :blk try sema.analyzeAsAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx); | |
| 3851 | }; | |
| 3818 | } | |
| 3852 | 3819 | decl.has_tv = true; |
| 3853 | 3820 | decl.analysis = .complete; |
| 3854 | 3821 | |
| 3855 | 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 | 3826 | .invalidate_decl_ref = !decl.ty.eql(old_ty, mod) or |
| 3858 | 3827 | decl.alignment != old_align or |
| 3859 | 3828 | decl.@"linksection" != old_linksection or |
| 3860 | decl.@"addrspace" != old_addrspace, | |
| 3829 | decl.@"addrspace" != old_addrspace or | |
| 3830 | is_inline != old_is_inline, | |
| 3861 | 3831 | } else .{ |
| 3862 | 3832 | .invalidate_decl_val = true, |
| 3863 | 3833 | .invalidate_decl_ref = true, |
| 3864 | 3834 | }; |
| 3865 | 3835 | |
| 3866 | const has_runtime_bits = is_extern or | |
| 3867 | (queue_linker_work and try sema.typeHasRuntimeBits(decl.ty)); | |
| 3868 | ||
| 3836 | const has_runtime_bits = queue_linker_work and (is_func or try sema.typeHasRuntimeBits(decl.ty)); | |
| 3869 | 3837 | if (has_runtime_bits) { |
| 3870 | ||
| 3871 | 3838 | // Needed for codegen_decl which will call updateDecl and then the |
| 3872 | 3839 | // codegen backend wants full access to the Decl Type. |
| 3873 | 3840 | try sema.resolveTypeFully(decl.ty); |
| ... | ... | @@ -3881,6 +3848,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { |
| 3881 | 3848 | |
| 3882 | 3849 | if (decl.is_exported) { |
| 3883 | 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 | 3852 | // The scope needs to have the decl in it. |
| 3885 | 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 | 7605 | .param_types = new_param_types, |
| 7606 | 7606 | .return_type = owner_info.return_type, |
| 7607 | 7607 | .noalias_bits = owner_info.noalias_bits, |
| 7608 | .alignment = if (owner_info.align_is_generic) null else owner_info.alignment, | |
| 7609 | 7608 | .cc = if (owner_info.cc_is_generic) null else owner_info.cc, |
| 7610 | 7609 | .is_var_args = owner_info.is_var_args, |
| 7611 | 7610 | .is_noinline = owner_info.is_noinline, |
| ... | ... | @@ -9629,7 +9628,6 @@ fn funcCommon( |
| 9629 | 9628 | .comptime_bits = comptime_bits, |
| 9630 | 9629 | .return_type = bare_return_type.toIntern(), |
| 9631 | 9630 | .cc = cc, |
| 9632 | .alignment = alignment, | |
| 9633 | 9631 | .section_is_generic = section == .generic, |
| 9634 | 9632 | .addrspace_is_generic = address_space == null, |
| 9635 | 9633 | .is_var_args = var_args, |
| ... | ... | @@ -9640,6 +9638,7 @@ fn funcCommon( |
| 9640 | 9638 | if (is_extern) { |
| 9641 | 9639 | assert(comptime_bits == 0); |
| 9642 | 9640 | assert(cc != null); |
| 9641 | assert(alignment != null); | |
| 9643 | 9642 | assert(section != .generic); |
| 9644 | 9643 | assert(address_space != null); |
| 9645 | 9644 | assert(!is_generic); |
| ... | ... | @@ -17623,8 +17622,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17623 | 17622 | const field_values = .{ |
| 17624 | 17623 | // calling_convention: CallingConvention, |
| 17625 | 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 | 17625 | // is_generic: bool, |
| 17629 | 17626 | Value.makeBool(func_ty_info.is_generic).toIntern(), |
| 17630 | 17627 | // is_var_args: bool, |
| ... | ... | @@ -19701,12 +19698,6 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 19701 | 19698 | if (inst_data.size != .One) { |
| 19702 | 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 | 19701 | } else if (inst_data.size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) { |
| 19711 | 19702 | return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{}); |
| 19712 | 19703 | } else if (inst_data.size == .C) { |
| ... | ... | @@ -21030,7 +21021,6 @@ fn zirReify( |
| 21030 | 21021 | .needed_comptime_reason = "operand to @Type must be comptime-known", |
| 21031 | 21022 | }); |
| 21032 | 21023 | const union_val = ip.indexToKey(val.toIntern()).un; |
| 21033 | const target = mod.getTarget(); | |
| 21034 | 21024 | if (try Value.fromInterned(union_val.val).anyUndef(mod)) return sema.failWithUseOfUndef(block, src); |
| 21035 | 21025 | const tag_index = type_info_ty.unionTagFieldIndex(Value.fromInterned(union_val.tag), mod).?; |
| 21036 | 21026 | switch (@as(std.builtin.TypeId, @enumFromInt(tag_index))) { |
| ... | ... | @@ -21171,12 +21161,6 @@ fn zirReify( |
| 21171 | 21161 | if (ptr_size != .One) { |
| 21172 | 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 | 21164 | } else if (ptr_size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) { |
| 21181 | 21165 | return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{}); |
| 21182 | 21166 | } else if (ptr_size == .C) { |
| ... | ... | @@ -21429,10 +21413,6 @@ fn zirReify( |
| 21429 | 21413 | ip, |
| 21430 | 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 | 21416 | const is_generic_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex( |
| 21437 | 21417 | ip, |
| 21438 | 21418 | try ip.getOrPutString(gpa, "is_generic"), |
| ... | ... | @@ -21461,11 +21441,6 @@ fn zirReify( |
| 21461 | 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 | 21444 | const return_type = return_type_val.optionalValue(mod) orelse |
| 21470 | 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 | 21485 | .param_types = param_types, |
| 21511 | 21486 | .noalias_bits = noalias_bits, |
| 21512 | 21487 | .return_type = return_type.toIntern(), |
| 21513 | .alignment = alignment, | |
| 21514 | 21488 | .cc = cc, |
| 21515 | 21489 | .is_var_args = is_var_args, |
| 21516 | 21490 | }); |
| ... | ... | @@ -32536,16 +32510,21 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn |
| 32536 | 32510 | const mod = sema.mod; |
| 32537 | 32511 | try sema.ensureDeclAnalyzed(decl_index); |
| 32538 | 32512 | |
| 32539 | const decl = mod.declPtr(decl_index); | |
| 32540 | const decl_tv = try decl.typedValue(); | |
| 32513 | const decl_tv = try mod.declPtr(decl_index).typedValue(); | |
| 32514 | const owner_decl = mod.declPtr(switch (mod.intern_pool.indexToKey(decl_tv.val.toIntern())) { | |
| 32515 | .variable => |variable| variable.decl, | |
| 32516 | .extern_func => |extern_func| extern_func.decl, | |
| 32517 | .func => |func| func.owner_decl, | |
| 32518 | else => decl_index, | |
| 32519 | }); | |
| 32541 | 32520 | // TODO: if this is a `decl_ref` of a non-variable decl, only depend on decl type |
| 32542 | 32521 | try sema.declareDependency(.{ .decl_val = decl_index }); |
| 32543 | 32522 | const ptr_ty = try sema.ptrType(.{ |
| 32544 | 32523 | .child = decl_tv.ty.toIntern(), |
| 32545 | 32524 | .flags = .{ |
| 32546 | .alignment = decl.alignment, | |
| 32547 | .is_const = if (decl.val.getVariable(mod)) |variable| variable.is_const else true, | |
| 32548 | .address_space = decl.@"addrspace", | |
| 32525 | .alignment = owner_decl.alignment, | |
| 32526 | .is_const = if (decl_tv.val.getVariable(mod)) |variable| variable.is_const else true, | |
| 32527 | .address_space = owner_decl.@"addrspace", | |
| 32549 | 32528 | }, |
| 32550 | 32529 | }); |
| 32551 | 32530 | if (analyze_fn_body) { |
src/codegen/c.zig+2-2| ... | ... | @@ -1635,7 +1635,7 @@ pub const DeclGen = struct { |
| 1635 | 1635 | |
| 1636 | 1636 | switch (kind) { |
| 1637 | 1637 | .forward => {}, |
| 1638 | .complete => if (fn_info.alignment.toByteUnitsOptional()) |a| { | |
| 1638 | .complete => if (fn_decl.alignment.toByteUnitsOptional()) |a| { | |
| 1639 | 1639 | try w.print("{}zig_align_fn({})", .{ trailing, a }); |
| 1640 | 1640 | trailing = .maybe_space; |
| 1641 | 1641 | }, |
| ... | ... | @@ -1666,7 +1666,7 @@ pub const DeclGen = struct { |
| 1666 | 1666 | |
| 1667 | 1667 | switch (kind) { |
| 1668 | 1668 | .forward => { |
| 1669 | if (fn_info.alignment.toByteUnitsOptional()) |a| { | |
| 1669 | if (fn_decl.alignment.toByteUnitsOptional()) |a| { | |
| 1670 | 1670 | try w.print(" zig_align_fn({})", .{a}); |
| 1671 | 1671 | } |
| 1672 | 1672 | switch (name) { |
src/codegen/llvm.zig+2-2| ... | ... | @@ -2952,8 +2952,8 @@ pub const Object = struct { |
| 2952 | 2952 | else => function_index.setCallConv(toLlvmCallConv(fn_info.cc, target), &o.builder), |
| 2953 | 2953 | } |
| 2954 | 2954 | |
| 2955 | if (fn_info.alignment != .none) | |
| 2956 | function_index.setAlignment(fn_info.alignment.toLlvm(), &o.builder); | |
| 2955 | if (decl.alignment != .none) | |
| 2956 | function_index.setAlignment(decl.alignment.toLlvm(), &o.builder); | |
| 2957 | 2957 | |
| 2958 | 2958 | // Function attributes that are independent of analysis results of the function body. |
| 2959 | 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 | 4995 | } else .{ |
| 4996 | 4996 | .root = .{ |
| 4997 | 4997 | .root_dir = zig_lib_directory, |
| 4998 | .sub_path = "compiler", | |
| 4998 | 4999 | }, |
| 4999 | 5000 | .root_src_path = "build_runner.zig", |
| 5000 | 5001 | }; |
src/type.zig+1-9| ... | ... | @@ -396,9 +396,6 @@ pub const Type = struct { |
| 396 | 396 | try writer.writeAll("..."); |
| 397 | 397 | } |
| 398 | 398 | try writer.writeAll(") "); |
| 399 | if (fn_info.alignment.toByteUnitsOptional()) |a| { | |
| 400 | try writer.print("align({d}) ", .{a}); | |
| 401 | } | |
| 402 | 399 | if (fn_info.cc != .Unspecified) { |
| 403 | 400 | try writer.writeAll("callconv(."); |
| 404 | 401 | try writer.writeAll(@tagName(fn_info.cc)); |
| ... | ... | @@ -949,12 +946,7 @@ pub const Type = struct { |
| 949 | 946 | }, |
| 950 | 947 | |
| 951 | 948 | // represents machine code; not a pointer |
| 952 | .func_type => |func_type| return .{ | |
| 953 | .scalar = if (func_type.alignment != .none) | |
| 954 | func_type.alignment | |
| 955 | else | |
| 956 | target_util.defaultFunctionAlignment(target), | |
| 957 | }, | |
| 949 | .func_type => return .{ .scalar = target_util.defaultFunctionAlignment(target) }, | |
| 958 | 950 | |
| 959 | 951 | .simple_type => |t| switch (t) { |
| 960 | 952 | .bool, |
stage1/zig.h+157-92| ... | ... | @@ -25,11 +25,15 @@ typedef char bool; |
| 25 | 25 | #endif |
| 26 | 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 | 31 | #if defined(__has_builtin) |
| 29 | 32 | #define zig_has_builtin(builtin) __has_builtin(__builtin_##builtin) |
| 30 | 33 | #else |
| 31 | 34 | #define zig_has_builtin(builtin) 0 |
| 32 | 35 | #endif |
| 36 | #define zig_expand_has_builtin(b) zig_has_builtin(b) | |
| 33 | 37 | |
| 34 | 38 | #if defined(__has_attribute) |
| 35 | 39 | #define zig_has_attribute(attribute) __has_attribute(attribute) |
| ... | ... | @@ -112,7 +116,7 @@ typedef char bool; |
| 112 | 116 | #define zig_never_tail zig_never_tail_unavailable |
| 113 | 117 | #endif |
| 114 | 118 | |
| 115 | #if zig_has_attribute(always_inline) | |
| 119 | #if zig_has_attribute(musttail) | |
| 116 | 120 | #define zig_always_tail __attribute__((musttail)) |
| 117 | 121 | #else |
| 118 | 122 | #define zig_always_tail zig_always_tail_unavailable |
| ... | ... | @@ -180,20 +184,58 @@ typedef char bool; |
| 180 | 184 | #define zig_extern extern |
| 181 | 185 | #endif |
| 182 | 186 | |
| 183 | #if zig_has_attribute(alias) | |
| 184 | #define zig_export(sig, symbol, name) zig_extern sig __attribute__((alias(symbol))) | |
| 185 | #elif _MSC_VER | |
| 187 | #if _MSC_VER | |
| 186 | 188 | #if _M_X64 |
| 187 | #define zig_export(sig, symbol, name) sig;\ | |
| 188 | __pragma(comment(linker, "/alternatename:" name "=" symbol )) | |
| 189 | #define zig_mangle_c(symbol) symbol | |
| 189 | 190 | #else /*_M_X64 */ |
| 190 | #define zig_export(sig, symbol, name) sig;\ | |
| 191 | __pragma(comment(linker, "/alternatename:_" name "=_" symbol )) | |
| 191 | #define zig_mangle_c(symbol) "_" symbol | |
| 192 | 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 | 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 | 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 | 239 | #if zig_has_attribute(weak) || defined(zig_gnuc) |
| 198 | 240 | #define zig_weak_linkage __attribute__((weak)) |
| 199 | 241 | #define zig_weak_linkage_fn __attribute__((weak)) |
| ... | ... | @@ -267,9 +309,6 @@ typedef char bool; |
| 267 | 309 | #define zig_wasm_memory_grow(index, delta) zig_unimplemented() |
| 268 | 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 | 312 | #if __STDC_VERSION__ >= 201112L |
| 274 | 313 | #define zig_noreturn _Noreturn |
| 275 | 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 | 2202 | const uint8_t *rhs_bytes = rhs; |
| 2164 | 2203 | uint16_t byte_offset = 0; |
| 2165 | 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 | 2206 | bool overflow = false; |
| 2168 | 2207 | |
| 2169 | 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 | 2210 | #endif |
| 2172 | 2211 | |
| 2173 | 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 | 2215 | #if zig_big_endian |
| 2177 | 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 | 2250 | } |
| 2212 | 2251 | |
| 2213 | 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 | 2255 | #if zig_big_endian |
| 2217 | 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 | 2290 | } |
| 2252 | 2291 | |
| 2253 | 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 | 2295 | #if zig_big_endian |
| 2257 | 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 | 2330 | } |
| 2292 | 2331 | |
| 2293 | 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 | 2335 | #if zig_big_endian |
| 2297 | 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 | 2370 | } |
| 2332 | 2371 | |
| 2333 | 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 | 2375 | #if zig_big_endian |
| 2337 | 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 | 2418 | const uint8_t *rhs_bytes = rhs; |
| 2380 | 2419 | uint16_t byte_offset = 0; |
| 2381 | 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 | 2422 | bool overflow = false; |
| 2384 | 2423 | |
| 2385 | 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 | 2426 | #endif |
| 2388 | 2427 | |
| 2389 | 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 | 2431 | #if zig_big_endian |
| 2393 | 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 | 2466 | } |
| 2428 | 2467 | |
| 2429 | 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 | 2471 | #if zig_big_endian |
| 2433 | 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 | 2506 | } |
| 2468 | 2507 | |
| 2469 | 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 | 2511 | #if zig_big_endian |
| 2473 | 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 | 2546 | } |
| 2508 | 2547 | |
| 2509 | 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 | 2551 | #if zig_big_endian |
| 2513 | 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 | 2586 | } |
| 2548 | 2587 | |
| 2549 | 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 | 2591 | #if zig_big_endian |
| 2553 | 2592 | byte_offset -= 8 / CHAR_BIT; |
| ... | ... | @@ -3093,6 +3132,7 @@ ypedef uint32_t zig_f32; |
| 3093 | 3132 | |
| 3094 | 3133 | #define zig_has_f64 1 |
| 3095 | 3134 | #define zig_libc_name_f64(name) name |
| 3135 | ||
| 3096 | 3136 | #if _MSC_VER |
| 3097 | 3137 | #define zig_init_special_f64(sign, name, arg, repr) sign zig_make_f64(zig_msvc_flt_##name, ) |
| 3098 | 3138 | #else |
| ... | ... | @@ -3336,31 +3376,31 @@ zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0))) |
| 3336 | 3376 | zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, sub, -) \ |
| 3337 | 3377 | zig_expand_concat(zig_float_binary_builtin_, zig_has_f##w)(f##w, mul, *) \ |
| 3338 | 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); \ | |
| 3340 | zig_extern zig_f##w zig_libc_name_f##w(sin)(zig_f##w); \ | |
| 3341 | zig_extern zig_f##w zig_libc_name_f##w(cos)(zig_f##w); \ | |
| 3342 | zig_extern zig_f##w zig_libc_name_f##w(tan)(zig_f##w); \ | |
| 3343 | zig_extern zig_f##w zig_libc_name_f##w(exp)(zig_f##w); \ | |
| 3344 | zig_extern zig_f##w zig_libc_name_f##w(exp2)(zig_f##w); \ | |
| 3345 | zig_extern zig_f##w zig_libc_name_f##w(log)(zig_f##w); \ | |
| 3346 | zig_extern zig_f##w zig_libc_name_f##w(log2)(zig_f##w); \ | |
| 3347 | zig_extern zig_f##w zig_libc_name_f##w(log10)(zig_f##w); \ | |
| 3348 | zig_extern zig_f##w zig_libc_name_f##w(fabs)(zig_f##w); \ | |
| 3349 | zig_extern zig_f##w zig_libc_name_f##w(floor)(zig_f##w); \ | |
| 3350 | zig_extern zig_f##w zig_libc_name_f##w(ceil)(zig_f##w); \ | |
| 3351 | zig_extern zig_f##w zig_libc_name_f##w(round)(zig_f##w); \ | |
| 3352 | zig_extern zig_f##w zig_libc_name_f##w(trunc)(zig_f##w); \ | |
| 3353 | zig_extern zig_f##w zig_libc_name_f##w(fmod)(zig_f##w, zig_f##w); \ | |
| 3354 | zig_extern zig_f##w zig_libc_name_f##w(fmin)(zig_f##w, zig_f##w); \ | |
| 3355 | zig_extern zig_f##w zig_libc_name_f##w(fmax)(zig_f##w, zig_f##w); \ | |
| 3356 | zig_extern zig_f##w zig_libc_name_f##w(fma)(zig_f##w, zig_f##w, zig_f##w); \ | |
| 3379 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(sqrt)))(zig_f##w, zig_float_fn_f##w##_sqrt, zig_libc_name_f##w(sqrt), (zig_f##w x), (x)) \ | |
| 3380 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(sin)))(zig_f##w, zig_float_fn_f##w##_sin, zig_libc_name_f##w(sin), (zig_f##w x), (x)) \ | |
| 3381 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(cos)))(zig_f##w, zig_float_fn_f##w##_cos, zig_libc_name_f##w(cos), (zig_f##w x), (x)) \ | |
| 3382 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(tan)))(zig_f##w, zig_float_fn_f##w##_tan, zig_libc_name_f##w(tan), (zig_f##w x), (x)) \ | |
| 3383 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(exp)))(zig_f##w, zig_float_fn_f##w##_exp, zig_libc_name_f##w(exp), (zig_f##w x), (x)) \ | |
| 3384 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(exp2)))(zig_f##w, zig_float_fn_f##w##_exp2, zig_libc_name_f##w(exp2), (zig_f##w x), (x)) \ | |
| 3385 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(log)))(zig_f##w, zig_float_fn_f##w##_log, zig_libc_name_f##w(log), (zig_f##w x), (x)) \ | |
| 3386 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(log2)))(zig_f##w, zig_float_fn_f##w##_log2, zig_libc_name_f##w(log2), (zig_f##w x), (x)) \ | |
| 3387 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(log10)))(zig_f##w, zig_float_fn_f##w##_log10, zig_libc_name_f##w(log10), (zig_f##w x), (x)) \ | |
| 3388 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fabs)))(zig_f##w, zig_float_fn_f##w##_fabs, zig_libc_name_f##w(fabs), (zig_f##w x), (x)) \ | |
| 3389 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(floor)))(zig_f##w, zig_float_fn_f##w##_floor, zig_libc_name_f##w(floor), (zig_f##w x), (x)) \ | |
| 3390 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(ceil)))(zig_f##w, zig_float_fn_f##w##_ceil, zig_libc_name_f##w(ceil), (zig_f##w x), (x)) \ | |
| 3391 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(round)))(zig_f##w, zig_float_fn_f##w##_round, zig_libc_name_f##w(round), (zig_f##w x), (x)) \ | |
| 3392 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(trunc)))(zig_f##w, zig_float_fn_f##w##_trunc, zig_libc_name_f##w(trunc), (zig_f##w x), (x)) \ | |
| 3393 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fmod)))(zig_f##w, zig_float_fn_f##w##_fmod, zig_libc_name_f##w(fmod), (zig_f##w x, zig_f##w y), (x, y)) \ | |
| 3394 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fmin)))(zig_f##w, zig_float_fn_f##w##_fmin, zig_libc_name_f##w(fmin), (zig_f##w x, zig_f##w y), (x, y)) \ | |
| 3395 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fmax)))(zig_f##w, zig_float_fn_f##w##_fmax, zig_libc_name_f##w(fmax), (zig_f##w x, zig_f##w y), (x, y)) \ | |
| 3396 | zig_expand_concat(zig_expand_import_, zig_expand_has_builtin(zig_libc_name_f##w(fma)))(zig_f##w, zig_float_fn_f##w##_fma, zig_libc_name_f##w(fma), (zig_f##w x, zig_f##w y, zig_f##w z), (x, y, z)) \ | |
| 3357 | 3397 | \ |
| 3358 | 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 | 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 | 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 | 3477 | /* Note that zig_atomicrmw_expected is needed to handle aliasing between res and arg. */ |
| 3438 | 3478 | #define zig_atomicrmw_xchg_float(res, obj, arg, order, Type, ReprType) do { \ |
| 3439 | 3479 | zig_##Type zig_atomicrmw_expected; \ |
| 3440 | zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \ | |
| 3441 | while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, memory_order_relaxed, Type, ReprType)); \ | |
| 3480 | zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ | |
| 3481 | while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, zig_memory_order_relaxed, Type, ReprType)); \ | |
| 3442 | 3482 | res = zig_atomicrmw_expected; \ |
| 3443 | 3483 | } while (0) |
| 3444 | 3484 | #define zig_atomicrmw_add_float(res, obj, arg, order, Type, ReprType) do { \ |
| 3445 | 3485 | zig_##Type zig_atomicrmw_expected; \ |
| 3446 | 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 | 3488 | do { \ |
| 3449 | 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 | 3491 | res = zig_atomicrmw_expected; \ |
| 3452 | 3492 | } while (0) |
| 3453 | 3493 | #define zig_atomicrmw_sub_float(res, obj, arg, order, Type, ReprType) do { \ |
| 3454 | 3494 | zig_##Type zig_atomicrmw_expected; \ |
| 3455 | 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 | 3497 | do { \ |
| 3458 | 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 | 3500 | res = zig_atomicrmw_expected; \ |
| 3461 | 3501 | } while (0) |
| 3462 | 3502 | #define zig_atomicrmw_min_float(res, obj, arg, order, Type, ReprType) do { \ |
| 3463 | 3503 | zig_##Type zig_atomicrmw_expected; \ |
| 3464 | 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 | 3506 | do { \ |
| 3467 | zig_atomicrmw_desired = zig_libc_name_##Type(fmin)(zig_atomicrmw_expected, arg); \ | |
| 3468 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | |
| 3507 | zig_atomicrmw_desired = zig_float_fn_##Type##_fmin(zig_atomicrmw_expected, arg); \ | |
| 3508 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ | |
| 3469 | 3509 | res = zig_atomicrmw_expected; \ |
| 3470 | 3510 | } while (0) |
| 3471 | 3511 | #define zig_atomicrmw_max_float(res, obj, arg, order, Type, ReprType) do { \ |
| 3472 | 3512 | zig_##Type zig_atomicrmw_expected; \ |
| 3473 | 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 | 3515 | do { \ |
| 3476 | zig_atomicrmw_desired = zig_libc_name_##Type(fmax)(zig_atomicrmw_expected, arg); \ | |
| 3477 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | |
| 3516 | zig_atomicrmw_desired = zig_float_fn_##Type##_fmax(zig_atomicrmw_expected, arg); \ | |
| 3517 | } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, zig_memory_order_relaxed, Type, ReprType)); \ | |
| 3478 | 3518 | res = zig_atomicrmw_expected; \ |
| 3479 | 3519 | } while (0) |
| 3480 | 3520 | |
| 3481 | 3521 | #define zig_atomicrmw_xchg_int128(res, obj, arg, order, Type, ReprType) do { \ |
| 3482 | 3522 | zig_##Type zig_atomicrmw_expected; \ |
| 3483 | zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \ | |
| 3484 | while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, memory_order_relaxed, Type, ReprType)); \ | |
| 3523 | zig_atomic_load(zig_atomicrmw_expected, obj, zig_memory_order_relaxed, Type, ReprType); \ | |
| 3524 | while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, zig_memory_order_relaxed, Type, ReprType)); \ | |
| 3485 | 3525 | res = zig_atomicrmw_expected; \ |
| 3486 | 3526 | } while (0) |
| 3487 | 3527 | #define zig_atomicrmw_add_int128(res, obj, arg, order, Type, ReprType) do { \ |
| 3488 | 3528 | zig_##Type zig_atomicrmw_expected; \ |
| 3489 | 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 | 3531 | do { \ |
| 3492 | 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 | 3534 | res = zig_atomicrmw_expected; \ |
| 3495 | 3535 | } while (0) |
| 3496 | 3536 | #define zig_atomicrmw_sub_int128(res, obj, arg, order, Type, ReprType) do { \ |
| 3497 | 3537 | zig_##Type zig_atomicrmw_expected; \ |
| 3498 | 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 | 3540 | do { \ |
| 3501 | 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 | 3543 | res = zig_atomicrmw_expected; \ |
| 3504 | 3544 | } while (0) |
| 3505 | 3545 | #define zig_atomicrmw_and_int128(res, obj, arg, order, Type, ReprType) do { \ |
| 3506 | 3546 | zig_##Type zig_atomicrmw_expected; \ |
| 3507 | 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 | 3549 | do { \ |
| 3510 | 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 | 3552 | res = zig_atomicrmw_expected; \ |
| 3513 | 3553 | } while (0) |
| 3514 | 3554 | #define zig_atomicrmw_nand_int128(res, obj, arg, order, Type, ReprType) do { \ |
| 3515 | 3555 | zig_##Type zig_atomicrmw_expected; \ |
| 3516 | 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 | 3558 | do { \ |
| 3519 | 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 | 3561 | res = zig_atomicrmw_expected; \ |
| 3522 | 3562 | } while (0) |
| 3523 | 3563 | #define zig_atomicrmw_or_int128(res, obj, arg, order, Type, ReprType) do { \ |
| 3524 | 3564 | zig_##Type zig_atomicrmw_expected; \ |
| 3525 | 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 | 3567 | do { \ |
| 3528 | 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 | 3570 | res = zig_atomicrmw_expected; \ |
| 3531 | 3571 | } while (0) |
| 3532 | 3572 | #define zig_atomicrmw_xor_int128(res, obj, arg, order, Type, ReprType) do { \ |
| 3533 | 3573 | zig_##Type zig_atomicrmw_expected; \ |
| 3534 | 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 | 3576 | do { \ |
| 3537 | 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 | 3579 | res = zig_atomicrmw_expected; \ |
| 3540 | 3580 | } while (0) |
| 3541 | 3581 | #define zig_atomicrmw_min_int128(res, obj, arg, order, Type, ReprType) do { \ |
| 3542 | 3582 | zig_##Type zig_atomicrmw_expected; \ |
| 3543 | 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 | 3585 | do { \ |
| 3546 | 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 | 3588 | res = zig_atomicrmw_expected; \ |
| 3549 | 3589 | } while (0) |
| 3550 | 3590 | #define zig_atomicrmw_max_int128(res, obj, arg, order, Type, ReprType) do { \ |
| 3551 | 3591 | zig_##Type zig_atomicrmw_expected; \ |
| 3552 | 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 | 3594 | do { \ |
| 3555 | 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 | 3597 | res = zig_atomicrmw_expected; \ |
| 3558 | 3598 | } while (0) |
| 3559 | 3599 | |
| 3560 | 3600 | #if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) |
| 3561 | 3601 | #include <stdatomic.h> |
| 3562 | 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 | 3608 | #define zig_atomic(Type) _Atomic(Type) |
| 3564 | 3609 | #define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail) |
| 3565 | 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 | 3628 | #define zig_fence(order) atomic_thread_fence(order) |
| 3584 | 3629 | #elif defined(__GNUC__) |
| 3585 | 3630 | typedef int zig_memory_order; |
| 3586 | #define memory_order_relaxed __ATOMIC_RELAXED | |
| 3587 | #define memory_order_consume __ATOMIC_CONSUME | |
| 3588 | #define memory_order_acquire __ATOMIC_ACQUIRE | |
| 3589 | #define memory_order_release __ATOMIC_RELEASE | |
| 3590 | #define memory_order_acq_rel __ATOMIC_ACQ_REL | |
| 3591 | #define memory_order_seq_cst __ATOMIC_SEQ_CST | |
| 3631 | #define zig_memory_order_relaxed __ATOMIC_RELAXED | |
| 3632 | #define zig_memory_order_acquire __ATOMIC_ACQUIRE | |
| 3633 | #define zig_memory_order_release __ATOMIC_RELEASE | |
| 3634 | #define zig_memory_order_acq_rel __ATOMIC_ACQ_REL | |
| 3635 | #define zig_memory_order_seq_cst __ATOMIC_SEQ_CST | |
| 3592 | 3636 | #define zig_atomic(Type) Type |
| 3593 | 3637 | #define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, &(expected), &(desired), false, succ, fail) |
| 3594 | 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 | 3651 | #define zig_atomicrmw_xchg_float zig_atomicrmw_xchg |
| 3608 | 3652 | #define zig_fence(order) __atomic_thread_fence(order) |
| 3609 | 3653 | #elif _MSC_VER && (_M_IX86 || _M_X64) |
| 3610 | #define memory_order_relaxed 0 | |
| 3611 | #define memory_order_consume 1 | |
| 3612 | #define memory_order_acquire 2 | |
| 3613 | #define memory_order_release 3 | |
| 3614 | #define memory_order_acq_rel 4 | |
| 3615 | #define memory_order_seq_cst 5 | |
| 3654 | #define zig_memory_order_relaxed 0 | |
| 3655 | #define zig_memory_order_acquire 2 | |
| 3656 | #define zig_memory_order_release 3 | |
| 3657 | #define zig_memory_order_acq_rel 4 | |
| 3658 | #define zig_memory_order_seq_cst 5 | |
| 3616 | 3659 | #define zig_atomic(Type) Type |
| 3617 | 3660 | #define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_msvc_cmpxchg_##Type(obj, &(expected), desired) |
| 3618 | 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 | 3677 | #endif |
| 3635 | 3678 | /* TODO: _MSC_VER && (_M_ARM || _M_ARM64) */ |
| 3636 | 3679 | #else |
| 3637 | #define memory_order_relaxed 0 | |
| 3638 | #define memory_order_consume 1 | |
| 3639 | #define memory_order_acquire 2 | |
| 3640 | #define memory_order_release 3 | |
| 3641 | #define memory_order_acq_rel 4 | |
| 3642 | #define memory_order_seq_cst 5 | |
| 3680 | #define zig_memory_order_relaxed 0 | |
| 3681 | #define zig_memory_order_acquire 2 | |
| 3682 | #define zig_memory_order_release 3 | |
| 3683 | #define zig_memory_order_acq_rel 4 | |
| 3684 | #define zig_memory_order_seq_cst 5 | |
| 3643 | 3685 | #define zig_atomic(Type) Type |
| 3644 | 3686 | #define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable |
| 3645 | 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 | 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 | 3886 | static inline bool zig_msvc_cmpxchg_i128(zig_i128 volatile* obj, zig_i128* expected, zig_i128 desired) { |
| 3834 | 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 | 3901 | #endif /* _M_IX86 */ |
| 3837 | 3902 | |
| 3838 | 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 | 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 | 314 | test "function alignment" { |
| 321 | 315 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 322 | 316 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| ... | ... | @@ -325,11 +319,25 @@ test "function alignment" { |
| 325 | 319 | // function alignment is a compile error on wasm32/wasm64 |
| 326 | 320 | if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; |
| 327 | 321 | |
| 328 | try expect(derp() == 1234); | |
| 329 | try expect(@TypeOf(noop1) == fn () align(1) void); | |
| 330 | try expect(@TypeOf(noop4) == fn () align(4) void); | |
| 331 | noop1(); | |
| 332 | noop4(); | |
| 322 | const S = struct { | |
| 323 | fn alignExpr() align(@sizeOf(usize) * 2) i32 { | |
| 324 | return 1234; | |
| 325 | } | |
| 326 | fn align1() align(1) void {} | |
| 327 | fn align4() align(4) void {} | |
| 328 | }; | |
| 329 | ||
| 330 | try expect(S.alignExpr() == 1234); | |
| 331 | try expect(@TypeOf(S.alignExpr) == fn () i32); | |
| 332 | try expect(@TypeOf(&S.alignExpr) == *align(@sizeOf(usize) * 2) const fn () i32); | |
| 333 | ||
| 334 | S.align1(); | |
| 335 | try expect(@TypeOf(S.align1) == fn () void); | |
| 336 | try expect(@TypeOf(&S.align1) == *align(1) const fn () void); | |
| 337 | ||
| 338 | S.align4(); | |
| 339 | try expect(@TypeOf(S.align4) == fn () void); | |
| 340 | try expect(@TypeOf(&S.align4) == *align(4) const fn () void); | |
| 333 | 341 | } |
| 334 | 342 | |
| 335 | 343 | test "implicitly decreasing fn alignment" { |
| ... | ... | @@ -345,7 +353,7 @@ test "implicitly decreasing fn alignment" { |
| 345 | 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 | 357 | try expect(ptr() == answer); |
| 350 | 358 | } |
| 351 | 359 | |
| ... | ... | @@ -368,10 +376,10 @@ test "@alignCast functions" { |
| 368 | 376 | |
| 369 | 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 | 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 | 383 | return ptr(); |
| 376 | 384 | } |
| 377 | 385 | fn simple4() align(4) i32 { |
test/behavior/type.zig-2| ... | ... | @@ -527,7 +527,6 @@ test "Type.Fn" { |
| 527 | 527 | { |
| 528 | 528 | const fn_info = std.builtin.Type{ .Fn = .{ |
| 529 | 529 | .calling_convention = .C, |
| 530 | .alignment = 0, | |
| 531 | 530 | .is_generic = false, |
| 532 | 531 | .is_var_args = false, |
| 533 | 532 | .return_type = void, |
| ... | ... | @@ -643,7 +642,6 @@ test "reified function type params initialized with field pointer" { |
| 643 | 642 | const Bar = @Type(.{ |
| 644 | 643 | .Fn = .{ |
| 645 | 644 | .calling_convention = .Unspecified, |
| 646 | .alignment = 0, | |
| 647 | 645 | .is_generic = false, |
| 648 | 646 | .is_var_args = false, |
| 649 | 647 | .return_type = void, |
test/behavior/type_info.zig+32-10| ... | ... | @@ -356,16 +356,38 @@ test "type info: function type info" { |
| 356 | 356 | } |
| 357 | 357 | |
| 358 | 358 | fn testFunction() !void { |
| 359 | const fn_info = @typeInfo(@TypeOf(typeInfoFoo)); | |
| 360 | try expect(fn_info == .Fn); | |
| 361 | try expect(fn_info.Fn.alignment > 0); | |
| 362 | try expect(fn_info.Fn.calling_convention == .C); | |
| 363 | try expect(!fn_info.Fn.is_generic); | |
| 364 | try expect(fn_info.Fn.params.len == 2); | |
| 365 | try expect(fn_info.Fn.is_var_args); | |
| 366 | try expect(fn_info.Fn.return_type.? == usize); | |
| 367 | const fn_aligned_info = @typeInfo(@TypeOf(typeInfoFooAligned)); | |
| 368 | try expect(fn_aligned_info.Fn.alignment == 4); | |
| 359 | const foo_fn_type = @TypeOf(typeInfoFoo); | |
| 360 | const foo_fn_info = @typeInfo(foo_fn_type); | |
| 361 | try expect(foo_fn_info.Fn.calling_convention == .C); | |
| 362 | try expect(!foo_fn_info.Fn.is_generic); | |
| 363 | try expect(foo_fn_info.Fn.params.len == 2); | |
| 364 | try expect(foo_fn_info.Fn.is_var_args); | |
| 365 | try expect(foo_fn_info.Fn.return_type.? == usize); | |
| 366 | const foo_ptr_fn_info = @typeInfo(@TypeOf(&typeInfoFoo)); | |
| 367 | try expect(foo_ptr_fn_info.Pointer.size == .One); | |
| 368 | try expect(foo_ptr_fn_info.Pointer.is_const); | |
| 369 | try expect(!foo_ptr_fn_info.Pointer.is_volatile); | |
| 370 | try expect(foo_ptr_fn_info.Pointer.address_space == .generic); | |
| 371 | try expect(foo_ptr_fn_info.Pointer.child == foo_fn_type); | |
| 372 | try expect(!foo_ptr_fn_info.Pointer.is_allowzero); | |
| 373 | try expect(foo_ptr_fn_info.Pointer.sentinel == null); | |
| 374 | ||
| 375 | const aligned_foo_fn_type = @TypeOf(typeInfoFooAligned); | |
| 376 | const aligned_foo_fn_info = @typeInfo(aligned_foo_fn_type); | |
| 377 | try expect(aligned_foo_fn_info.Fn.calling_convention == .C); | |
| 378 | try expect(!aligned_foo_fn_info.Fn.is_generic); | |
| 379 | try expect(aligned_foo_fn_info.Fn.params.len == 2); | |
| 380 | try expect(aligned_foo_fn_info.Fn.is_var_args); | |
| 381 | try expect(aligned_foo_fn_info.Fn.return_type.? == usize); | |
| 382 | const aligned_foo_ptr_fn_info = @typeInfo(@TypeOf(&typeInfoFooAligned)); | |
| 383 | try expect(aligned_foo_ptr_fn_info.Pointer.size == .One); | |
| 384 | try expect(aligned_foo_ptr_fn_info.Pointer.is_const); | |
| 385 | try expect(!aligned_foo_ptr_fn_info.Pointer.is_volatile); | |
| 386 | try expect(aligned_foo_ptr_fn_info.Pointer.alignment == 4); | |
| 387 | try expect(aligned_foo_ptr_fn_info.Pointer.address_space == .generic); | |
| 388 | try expect(aligned_foo_ptr_fn_info.Pointer.child == aligned_foo_fn_type); | |
| 389 | try expect(!aligned_foo_ptr_fn_info.Pointer.is_allowzero); | |
| 390 | try expect(aligned_foo_ptr_fn_info.Pointer.sentinel == null); | |
| 369 | 391 | } |
| 370 | 392 | |
| 371 | 393 | extern fn typeInfoFoo(a: usize, b: bool, ...) callconv(.C) usize; |
test/behavior/typename.zig+2-4| ... | ... | @@ -78,11 +78,9 @@ test "basic" { |
| 78 | 78 | try expectEqualStrings("fn (comptime u32) void", @typeName(fn (comptime u32) void)); |
| 79 | 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 | 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)); | |
| 84 | try expectEqualStrings("fn (...) align(32) callconv(.C) void", @typeName(fn (...) align(32) callconv(.C) void)); | |
| 85 | try expectEqualStrings("fn (u32, ...) align(32) callconv(.C) void", @typeName(fn (u32, ...) align(32) callconv(.C) void)); | |
| 82 | try expectEqualStrings("fn (...) callconv(.C) void", @typeName(fn (...) callconv(.C) void)); | |
| 83 | try expectEqualStrings("fn (u32, ...) callconv(.C) void", @typeName(fn (u32, ...) callconv(.C) void)); | |
| 86 | 84 | } |
| 87 | 85 | |
| 88 | 86 | test "top level decl" { |
test/cases/compile_errors/function_ptr_alignment.zig+8-20| ... | ... | @@ -1,28 +1,16 @@ |
| 1 | comptime { | |
| 2 | var a: *align(2) @TypeOf(foo) = undefined; | |
| 3 | _ = &a; | |
| 4 | } | |
| 5 | fn foo() void {} | |
| 1 | fn align1() align(1) void {} | |
| 2 | fn align2() align(2) void {} | |
| 6 | 3 | |
| 7 | 4 | comptime { |
| 8 | var a: *align(1) fn () void = undefined; | |
| 9 | _ = &a; | |
| 10 | } | |
| 11 | comptime { | |
| 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; | |
| 5 | _ = @as(*align(1) const fn () void, &align2); | |
| 6 | _ = @as(*align(1) const fn () void, &align1); | |
| 7 | _ = @as(*align(2) const fn () void, &align2); | |
| 8 | _ = @as(*align(2) const fn () void, &align1); | |
| 22 | 9 | } |
| 23 | 10 | |
| 24 | 11 | // error |
| 25 | 12 | // backend=stage2 |
| 26 | 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 | 1 | export fn entry() void { |
| 2 | 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 | 5 | if (ptr() != answer) unreachable; |
| 6 | 6 | } |
| 7 | 7 | fn alignedSmall() align(4) i32 { |
| ... | ... | @@ -12,5 +12,5 @@ fn alignedSmall() align(4) i32 { |
| 12 | 12 | // backend=stage2 |
| 13 | 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 | 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 | 1 | const Foo = @Type(.{ |
| 2 | 2 | .Fn = .{ |
| 3 | 3 | .calling_convention = .Unspecified, |
| 4 | .alignment = 0, | |
| 5 | 4 | .is_generic = true, |
| 6 | 5 | .is_var_args = false, |
| 7 | 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 | 1 | const Foo = @Type(.{ |
| 2 | 2 | .Fn = .{ |
| 3 | 3 | .calling_convention = .Unspecified, |
| 4 | .alignment = 0, | |
| 5 | 4 | .is_generic = false, |
| 6 | 5 | .is_var_args = true, |
| 7 | 6 | .return_type = u0, |
test/cases/compile_errors/reify_type.Fn_with_return_type_null.zig-1| ... | ... | @@ -1,7 +1,6 @@ |
| 1 | 1 | const Foo = @Type(.{ |
| 2 | 2 | .Fn = .{ |
| 3 | 3 | .calling_convention = .Unspecified, |
| 4 | .alignment = 0, | |
| 5 | 4 | .is_generic = false, |
| 6 | 5 | .is_var_args = false, |
| 7 | 6 | .return_type = null, |