diff --git a/CMakeLists.txt b/CMakeLists.txt index a3d6a7fb68..6f2a88d34b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -622,7 +622,6 @@ set(BUILD_LIBSTAGE2_ARGS "build-lib" --cache on --output-dir "${CMAKE_BINARY_DIR}" ${LIBSTAGE2_RELEASE_ARG} - --disable-gen-h --bundle-compiler-rt -fPIC -lc diff --git a/build.zig b/build.zig index 7de4f50702..f8b41f2dc4 100644 --- a/build.zig +++ b/build.zig @@ -134,7 +134,8 @@ pub fn build(b: *Builder) !void { test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes)); test_step.dependOn(tests.addTranslateCTests(b, test_filter)); test_step.dependOn(tests.addRunTranslatedCTests(b, test_filter)); - test_step.dependOn(tests.addGenHTests(b, test_filter)); + // tests for this feature are disabled until we have the self-hosted compiler available + //test_step.dependOn(tests.addGenHTests(b, test_filter)); test_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes)); test_step.dependOn(docs_step); } @@ -298,10 +299,14 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { dependOnLib(b, exe, ctx.llvm); if (exe.target.getOsTag() == .linux) { - try addCxxKnownPath(b, ctx, exe, "libstdc++.a", - \\Unable to determine path to libstdc++.a - \\On Fedora, install libstdc++-static and try again. - ); + // First we try to static link against gcc libstdc++. If that doesn't work, + // we fall back to -lc++ and cross our fingers. + addCxxKnownPath(b, ctx, exe, "libstdc++.a", "") catch |err| switch (err) { + error.RequiredLibraryNotFound => { + exe.linkSystemLibrary("c++"); + }, + else => |e| return e, + }; exe.linkSystemLibrary("pthread"); } else if (exe.target.isFreeBSD()) { @@ -320,7 +325,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { // System compiler, not gcc. exe.linkSystemLibrary("c++"); }, - else => return err, + else => |e| return e, } } diff --git a/ci/drone/linux_script b/ci/drone/linux_script index 61a5908dee..a0d2406f89 100755 --- a/ci/drone/linux_script +++ b/ci/drone/linux_script @@ -26,7 +26,8 @@ make -j$(nproc) install # TODO test-cli is hitting https://github.com/ziglang/zig/issues/3526 ./zig build test-asm-link test-runtime-safety # TODO test-translate-c is hitting https://github.com/ziglang/zig/issues/3526 -./zig build test-gen-h +# TODO disabled until we are shipping self-hosted +#./zig build test-gen-h # TODO test-compile-errors is hitting https://github.com/ziglang/zig/issues/3526 # TODO building docs is hitting https://github.com/ziglang/zig/issues/3526 diff --git a/ci/srht/freebsd_script b/ci/srht/freebsd_script index 12cd2d5406..6cf4cb7582 100755 --- a/ci/srht/freebsd_script +++ b/ci/srht/freebsd_script @@ -42,7 +42,8 @@ release/bin/zig build test-asm-link release/bin/zig build test-runtime-safety release/bin/zig build test-translate-c release/bin/zig build test-run-translated-c -release/bin/zig build test-gen-h +# TODO disabled until we are shipping self-hosted +#release/bin/zig build test-gen-h release/bin/zig build test-compile-errors release/bin/zig build docs diff --git a/doc/docgen.zig b/doc/docgen.zig index 4d2625f54f..32ad0cdc5d 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -48,7 +48,7 @@ pub fn main() !void { var toc = try genToc(allocator, &tokenizer); try fs.cwd().makePath(tmp_dir_name); - defer fs.deleteTree(tmp_dir_name) catch {}; + defer fs.cwd().deleteTree(tmp_dir_name) catch {}; try genHtml(allocator, &tokenizer, &toc, buffered_out_stream.outStream(), zig_exe); try buffered_out_stream.flush(); @@ -1096,6 +1096,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var try build_args.append("-lc"); try out.print(" -lc", .{}); } + const target = try std.zig.CrossTarget.parse(.{ + .arch_os_abi = code.target_str orelse "native", + }); if (code.target_str) |triple| { try build_args.appendSlice(&[_][]const u8{ "-target", triple }); if (!code.is_inline) { @@ -1150,7 +1153,15 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var } } - const path_to_exe = mem.trim(u8, exec_result.stdout, " \r\n"); + const path_to_exe_dir = mem.trim(u8, exec_result.stdout, " \r\n"); + const path_to_exe_basename = try std.fmt.allocPrint(allocator, "{}{}", .{ + code.name, + target.exeFileExt(), + }); + const path_to_exe = try fs.path.join(allocator, &[_][]const u8{ + path_to_exe_dir, + path_to_exe_basename, + }); const run_args = &[_][]const u8{path_to_exe}; var exited_with_signal = false; @@ -1486,7 +1497,12 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var } fn exec(allocator: *mem.Allocator, env_map: *std.BufMap, args: []const []const u8) !ChildProcess.ExecResult { - const result = try ChildProcess.exec(allocator, args, null, env_map, max_doc_file_size); + const result = try ChildProcess.exec2(.{ + .allocator = allocator, + .argv = args, + .env_map = env_map, + .max_output_bytes = max_doc_file_size, + }); switch (result.term) { .Exited => |exit_code| { if (exit_code != 0) { diff --git a/doc/langref.html.in b/doc/langref.html.in index 3a7892fd45..73a6368fe2 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -885,6 +885,12 @@ const hex_int = 0xff; const another_hex_int = 0xFF; const octal_int = 0o755; const binary_int = 0b11110000; + +// underscores may be placed between two digits as a visual separator +const one_billion = 1_000_000_000; +const binary_mask = 0b1_1111_1111; +const permissions = 0o7_5_5; +const big_address = 0xFF80_0000_0000_0000; {#code_end#} {#header_close#} {#header_open|Runtime Integer Values#} @@ -947,6 +953,11 @@ const yet_another = 123.0e+77; const hex_floating_point = 0x103.70p-5; const another_hex_float = 0x103.70; const yet_another_hex_float = 0x103.70P-5; + +// underscores may be placed between two digits as a visual separator +const lightspeed = 299_792_458.000_000; +const nanosecond = 0.000_000_001; +const more_hex = 0x1234_5678.9ABC_CDEFp-10; {#code_end#}

There is no syntax for NaN, infinity, or negative infinity. For these special values, @@ -2093,8 +2104,9 @@ var foo: u8 align(4) = 100; test "global variable alignment" { assert(@TypeOf(&foo).alignment == 4); assert(@TypeOf(&foo) == *align(4) u8); - const slice = @as(*[1]u8, &foo)[0..]; - assert(@TypeOf(slice) == []align(4) u8); + const as_pointer_to_array: *[1]u8 = &foo; + const as_slice: []u8 = as_pointer_to_array; + assert(@TypeOf(as_slice) == []align(4) u8); } fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; } @@ -2187,7 +2199,8 @@ test "basic slices" { // a slice is that the array's length is part of the type and known at // compile-time, whereas the slice's length is known at runtime. // Both can be accessed with the `len` field. - const slice = array[0..array.len]; + var known_at_runtime_zero: usize = 0; + const slice = array[known_at_runtime_zero..array.len]; assert(&slice[0] == &array[0]); assert(slice.len == array.len); @@ -2207,13 +2220,15 @@ test "basic slices" { {#code_end#}

This is one reason we prefer slices to pointers.

{#code_begin|test|slices#} -const assert = @import("std").debug.assert; -const mem = @import("std").mem; -const fmt = @import("std").fmt; +const std = @import("std"); +const assert = std.debug.assert; +const mem = std.mem; +const fmt = std.fmt; test "using slices for strings" { - // Zig has no concept of strings. String literals are arrays of u8, and - // in general the string type is []u8 (slice of u8). + // Zig has no concept of strings. String literals are const pointers to + // arrays of u8, and by convention parameters that are "strings" are + // expected to be UTF-8 encoded slices of u8. // Here we coerce [5]u8 to []const u8 const hello: []const u8 = "hello"; const world: []const u8 = "世界"; @@ -2222,7 +2237,7 @@ test "using slices for strings" { // You can use slice syntax on an array to convert an array into a slice. const all_together_slice = all_together[0..]; // String concatenation example. - const hello_world = try fmt.bufPrint(all_together_slice, "{} {}", .{hello, world}); + const hello_world = try fmt.bufPrint(all_together_slice, "{} {}", .{ hello, world }); // Generally, you can use UTF-8 and not worry about whether something is a // string. If you don't need to deal with individual characters, no need @@ -2239,23 +2254,15 @@ test "slice pointer" { slice[2] = 3; assert(slice[2] == 3); // The slice is mutable because we sliced a mutable pointer. - assert(@TypeOf(slice) == []u8); + // Furthermore, it is actually a pointer to an array, since the start + // and end indexes were both comptime-known. + assert(@TypeOf(slice) == *[5]u8); // You can also slice a slice: const slice2 = slice[2..3]; assert(slice2.len == 1); assert(slice2[0] == 3); } - -test "slice widening" { - // Zig supports slice widening and slice narrowing. Cast a slice of u8 - // to a slice of anything else, and Zig will perform the length conversion. - const array align(@alignOf(u32)) = [_]u8{ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13 }; - const slice = mem.bytesAsSlice(u32, array[0..]); - assert(slice.len == 2); - assert(slice[0] == 0x12121212); - assert(slice[1] == 0x13131313); -} {#code_end#} {#see_also|Pointers|for|Arrays#} diff --git a/lib/libc/glibc/abi.txt b/lib/libc/glibc/abi.txt index 089b9c077e..4d8d6f5255 100644 --- a/lib/libc/glibc/abi.txt +++ b/lib/libc/glibc/abi.txt @@ -193,6 +193,7 @@ aarch64-linux-gnu aarch64_be-linux-gnu 29 + 29 29 @@ -514,6 +515,7 @@ aarch64-linux-gnu aarch64_be-linux-gnu 29 29 29 +29 29 @@ -697,6 +699,7 @@ aarch64-linux-gnu aarch64_be-linux-gnu 29 29 29 + 29 29 29 @@ -819,6 +822,7 @@ aarch64-linux-gnu aarch64_be-linux-gnu 29 29 29 +29 29 29 @@ -904,6 +908,9 @@ aarch64-linux-gnu aarch64_be-linux-gnu 29 29 29 +29 + + 29 29 29 @@ -1004,6 +1011,7 @@ aarch64-linux-gnu aarch64_be-linux-gnu 29 29 29 +29 29 29 @@ -1033,6 +1041,7 @@ aarch64-linux-gnu aarch64_be-linux-gnu 29 29 29 +29 29 29 @@ -3920,6 +3929,7 @@ s390x-linux-gnu 5 + 27 27 @@ -4241,6 +4251,7 @@ s390x-linux-gnu 5 5 5 +5 11 27 @@ -4424,6 +4435,7 @@ s390x-linux-gnu 19 19 5 + 5 5 28 @@ -4543,6 +4555,7 @@ s390x-linux-gnu 27 16 + 5 5 15 @@ -4631,6 +4644,9 @@ s390x-linux-gnu 16 5 5 + + +12 5 5 5 @@ -4731,6 +4747,7 @@ s390x-linux-gnu 5 5 5 +5 5 5 @@ -4756,6 +4773,7 @@ s390x-linux-gnu 5 5 5 +5 31 5 24 5 12 16 24 5 12 16 @@ -7645,6 +7663,7 @@ arm-linux-gnueabi armeb-linux-gnueabi arm-linux-gnueabihf armeb-linux-gnueabihf + 27 @@ -7968,6 +7987,7 @@ arm-linux-gnueabi armeb-linux-gnueabi arm-linux-gnueabihf armeb-linux-gnueabihf 16 16 16 +16 27 @@ -8151,6 +8171,7 @@ arm-linux-gnueabi armeb-linux-gnueabi arm-linux-gnueabihf armeb-linux-gnueabihf 19 19 16 + 16 16 28 @@ -8273,6 +8294,7 @@ arm-linux-gnueabi armeb-linux-gnueabi arm-linux-gnueabihf armeb-linux-gnueabihf 16 16 16 +16 16 16 @@ -8358,6 +8380,9 @@ arm-linux-gnueabi armeb-linux-gnueabi arm-linux-gnueabihf armeb-linux-gnueabihf 16 16 16 +16 + + 16 16 16 @@ -8458,6 +8483,7 @@ arm-linux-gnueabi armeb-linux-gnueabi arm-linux-gnueabihf armeb-linux-gnueabihf 16 16 16 +16 16 16 @@ -8484,6 +8510,7 @@ arm-linux-gnueabi armeb-linux-gnueabi arm-linux-gnueabihf armeb-linux-gnueabihf 16 16 16 +16 24 16 24 16 16 @@ -11374,6 +11401,7 @@ sparc-linux-gnu sparcel-linux-gnu 0 + 27 27 @@ -11693,6 +11721,7 @@ sparc-linux-gnu sparcel-linux-gnu 0 0 1 +1 0 0 3 11 @@ -11878,6 +11907,7 @@ sparc-linux-gnu sparcel-linux-gnu 19 19 0 + 0 1 28 @@ -11997,6 +12027,7 @@ sparc-linux-gnu sparcel-linux-gnu 33 16 + 5 0 15 @@ -12085,6 +12116,9 @@ sparc-linux-gnu sparcel-linux-gnu 16 0 0 +12 + + 1 1 1 @@ -12183,6 +12217,7 @@ sparc-linux-gnu sparcel-linux-gnu 1 1 1 +1 0 0 @@ -12207,6 +12242,7 @@ sparc-linux-gnu sparcel-linux-gnu 0 0 0 +0 5 0 0 @@ -15101,6 +15137,7 @@ sparcv9-linux-gnu 5 5 + 27 27 @@ -15422,6 +15459,7 @@ sparcv9-linux-gnu 5 5 5 +5 11 27 @@ -15605,6 +15643,7 @@ sparcv9-linux-gnu 19 19 5 + 5 5 28 @@ -15724,6 +15763,7 @@ sparcv9-linux-gnu 27 16 + 5 5 15 @@ -15812,6 +15852,9 @@ sparcv9-linux-gnu 16 5 5 +12 + + 5 5 5 @@ -15912,6 +15955,7 @@ sparcv9-linux-gnu 5 5 5 +5 5 5 @@ -15938,6 +15982,7 @@ sparcv9-linux-gnu 5 5 5 +5 24 28 5 12 16 24 28 5 12 16 5 14 @@ -18828,6 +18873,7 @@ mips64el-linux-gnuabi64 mips64-linux-gnuabi64 0 + 27 27 @@ -19147,6 +19193,7 @@ mips64el-linux-gnuabi64 mips64-linux-gnuabi64 0 0 5 +5 0 0 11 @@ -19332,6 +19379,7 @@ mips64el-linux-gnuabi64 mips64-linux-gnuabi64 19 19 0 + 0 5 28 @@ -19450,6 +19498,7 @@ mips64el-linux-gnuabi64 mips64-linux-gnuabi64 27 27 +16 16 5 0 @@ -19539,6 +19588,9 @@ mips64el-linux-gnuabi64 mips64-linux-gnuabi64 16 0 0 +12 + + 5 5 5 @@ -19637,6 +19689,7 @@ mips64el-linux-gnuabi64 mips64-linux-gnuabi64 5 5 5 +5 0 0 0 @@ -19661,6 +19714,7 @@ mips64el-linux-gnuabi64 mips64-linux-gnuabi64 0 0 0 +0 5 0 0 @@ -22555,6 +22609,7 @@ mips64el-linux-gnuabin32 mips64-linux-gnuabin32 0 + 27 27 @@ -22874,6 +22929,7 @@ mips64el-linux-gnuabin32 mips64-linux-gnuabin32 0 0 5 +5 0 0 11 @@ -23059,6 +23115,7 @@ mips64el-linux-gnuabin32 mips64-linux-gnuabin32 19 19 0 + 0 5 28 @@ -23177,6 +23234,7 @@ mips64el-linux-gnuabin32 mips64-linux-gnuabin32 27 27 +16 16 5 0 @@ -23266,6 +23324,9 @@ mips64el-linux-gnuabin32 mips64-linux-gnuabin32 16 0 0 +12 + + 5 5 5 @@ -23364,6 +23425,7 @@ mips64el-linux-gnuabin32 mips64-linux-gnuabin32 5 5 5 +5 0 0 0 @@ -23388,6 +23450,7 @@ mips64el-linux-gnuabin32 mips64-linux-gnuabin32 0 0 0 +0 5 0 0 @@ -26282,6 +26345,7 @@ mipsel-linux-gnueabihf mips-linux-gnueabihf 0 + 27 27 @@ -26601,6 +26665,7 @@ mipsel-linux-gnueabihf mips-linux-gnueabihf 0 0 5 +5 0 0 11 @@ -26786,6 +26851,7 @@ mipsel-linux-gnueabihf mips-linux-gnueabihf 19 19 0 + 0 5 28 @@ -26904,6 +26970,7 @@ mipsel-linux-gnueabihf mips-linux-gnueabihf 27 +16 16 5 0 @@ -26993,6 +27060,9 @@ mipsel-linux-gnueabihf mips-linux-gnueabihf 16 0 0 +12 + + 5 5 5 @@ -27091,6 +27161,7 @@ mipsel-linux-gnueabihf mips-linux-gnueabihf 5 5 5 +5 0 0 0 @@ -27115,6 +27186,7 @@ mipsel-linux-gnueabihf mips-linux-gnueabihf 0 0 0 +0 5 0 0 @@ -30009,6 +30081,7 @@ mipsel-linux-gnueabi mips-linux-gnueabi 0 + 27 27 @@ -30328,6 +30401,7 @@ mipsel-linux-gnueabi mips-linux-gnueabi 0 0 5 +5 0 0 11 @@ -30513,6 +30587,7 @@ mipsel-linux-gnueabi mips-linux-gnueabi 19 19 0 + 0 5 28 @@ -30631,6 +30706,7 @@ mipsel-linux-gnueabi mips-linux-gnueabi 27 +16 16 5 0 @@ -30720,6 +30796,9 @@ mipsel-linux-gnueabi mips-linux-gnueabi 16 0 0 +12 + + 5 5 5 @@ -30818,6 +30897,7 @@ mipsel-linux-gnueabi mips-linux-gnueabi 5 5 5 +5 0 0 0 @@ -30842,6 +30922,7 @@ mipsel-linux-gnueabi mips-linux-gnueabi 0 0 0 +0 5 0 0 @@ -33734,6 +33815,7 @@ x86_64-linux-gnu + 27 @@ -34057,6 +34139,7 @@ x86_64-linux-gnu 10 10 10 +10 11 27 36 @@ -34240,6 +34323,7 @@ x86_64-linux-gnu 19 19 10 + 10 10 28 @@ -34359,6 +34443,7 @@ x86_64-linux-gnu 27 16 + 10 10 15 @@ -34447,6 +34532,9 @@ x86_64-linux-gnu 16 10 10 +12 + + 10 10 10 @@ -34547,6 +34635,7 @@ x86_64-linux-gnu 10 10 10 +10 10 10 @@ -34573,6 +34662,7 @@ x86_64-linux-gnu 10 10 10 +10 24 10 12 16 24 10 12 16 10 14 @@ -37461,6 +37551,7 @@ x86_64-linux-gnux32 + 28 @@ -37784,6 +37875,7 @@ x86_64-linux-gnux32 28 28 28 +28 28 36 @@ -37967,6 +38059,7 @@ x86_64-linux-gnux32 28 28 28 + 28 28 28 @@ -38086,6 +38179,7 @@ x86_64-linux-gnux32 28 28 + 28 28 28 @@ -38174,6 +38268,9 @@ x86_64-linux-gnux32 28 28 28 +28 + + 28 28 28 @@ -38274,6 +38371,7 @@ x86_64-linux-gnux32 28 28 28 +28 28 28 @@ -38303,6 +38401,7 @@ x86_64-linux-gnux32 28 28 28 +28 28 28 @@ -41190,6 +41289,7 @@ i386-linux-gnu 0 +12 27 36 27 @@ -41509,6 +41609,7 @@ i386-linux-gnu 0 0 1 +1 0 0 3 11 @@ -41694,6 +41795,7 @@ i386-linux-gnu 19 19 0 + 0 1 28 @@ -41813,6 +41915,7 @@ i386-linux-gnu 27 16 + 5 0 15 @@ -41901,6 +42004,9 @@ i386-linux-gnu 16 0 0 +12 + + 1 1 1 @@ -41999,6 +42105,7 @@ i386-linux-gnu 1 1 1 +1 0 0 @@ -42023,6 +42130,7 @@ i386-linux-gnu 0 0 0 +0 5 0 0 @@ -44915,6 +45023,7 @@ powerpc64le-linux-gnu + 29 @@ -45238,6 +45347,7 @@ powerpc64le-linux-gnu 29 29 29 +29 29 36 @@ -45421,6 +45531,7 @@ powerpc64le-linux-gnu 29 29 29 +33 29 29 29 @@ -45540,6 +45651,7 @@ powerpc64le-linux-gnu 29 29 + 29 29 29 @@ -45628,6 +45740,9 @@ powerpc64le-linux-gnu 29 29 29 +29 +32 + 29 29 29 @@ -45728,6 +45843,7 @@ powerpc64le-linux-gnu 29 29 29 +29 29 29 @@ -45757,6 +45873,7 @@ powerpc64le-linux-gnu 29 29 29 +29 29 29 @@ -48642,6 +48759,7 @@ powerpc64-linux-gnu + 27 @@ -48965,6 +49083,7 @@ powerpc64-linux-gnu 12 12 12 +12 27 @@ -49148,6 +49267,7 @@ powerpc64-linux-gnu 19 19 12 +33 12 12 28 @@ -49267,6 +49387,7 @@ powerpc64-linux-gnu 27 16 + 12 12 15 @@ -49355,6 +49476,9 @@ powerpc64-linux-gnu 16 12 12 +12 +32 + 12 12 12 @@ -49455,6 +49579,7 @@ powerpc64-linux-gnu 12 12 12 +12 12 12 @@ -49480,6 +49605,7 @@ powerpc64-linux-gnu 12 12 12 +12 12 15 24 12 16 24 12 16 @@ -52369,6 +52495,7 @@ powerpc-linux-gnueabi powerpc-linux-gnueabihf + 27 @@ -52690,6 +52817,7 @@ powerpc-linux-gnueabi powerpc-linux-gnueabihf 0 0 1 +1 0 0 3 11 @@ -52875,6 +53003,7 @@ powerpc-linux-gnueabi powerpc-linux-gnueabihf 19 19 0 +33 0 1 28 @@ -52994,6 +53123,7 @@ powerpc-linux-gnueabi powerpc-linux-gnueabihf 27 13 16 + 5 0 15 @@ -53082,6 +53212,9 @@ powerpc-linux-gnueabi powerpc-linux-gnueabihf 16 0 0 +12 +32 + 1 1 1 @@ -53180,6 +53313,7 @@ powerpc-linux-gnueabi powerpc-linux-gnueabihf 1 1 1 +1 0 0 @@ -53204,6 +53338,7 @@ powerpc-linux-gnueabi powerpc-linux-gnueabihf 0 0 0 +0 5 0 0 diff --git a/lib/libc/glibc/fns.txt b/lib/libc/glibc/fns.txt index 32dc37ce17..4e2e126b0e 100644 --- a/lib/libc/glibc/fns.txt +++ b/lib/libc/glibc/fns.txt @@ -192,6 +192,7 @@ _Qp_uitoq c _Qp_uxtoq c _Qp_xtoq c ___brk_addr c +___tls_get_addr ld __acos_finite m __acosf128_finite m __acosf_finite m @@ -511,6 +512,7 @@ __libc_memalign c __libc_pvalloc c __libc_realloc c __libc_sa_len c +__libc_stack_end ld __libc_start_main c __libc_valloc c __libpthread_version_placeholder pthread @@ -696,6 +698,7 @@ __open_2 c __openat64_2 c __openat_2 c __overflow c +__parse_hwcap_and_convert_at_platform ld __pipe c __poll c __poll_chk c @@ -815,6 +818,7 @@ __sqrtf_finite m __sqrtl_finite m __sqrtsf2 c __stack_chk_fail c +__stack_chk_guard ld __statfs c __stpcpy c __stpcpy_chk c @@ -903,6 +907,9 @@ __sysctl c __syslog_chk c __sysv_signal c __timezone c +__tls_get_addr ld +__tls_get_addr_opt ld +__tls_get_offset ld __toascii_l c __tolower_l c __toupper_l c @@ -999,6 +1006,7 @@ __ynf128_finite m __ynf_finite m __ynl_finite m _authenticate c +_dl_mcount ld _dl_mcount_wrapper c _dl_mcount_wrapper_check c _environ c @@ -1024,6 +1032,7 @@ _pthread_cleanup_pop pthread _pthread_cleanup_pop_restore pthread _pthread_cleanup_push pthread _pthread_cleanup_push_defer pthread +_r_debug ld _res c _res_hconf c _rpc_dtablesize c diff --git a/lib/std/build.zig b/lib/std/build.zig index e8484e9d1c..c603fd861b 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -377,7 +377,7 @@ pub const Builder = struct { if (self.verbose) { warn("rm {}\n", .{full_path}); } - fs.deleteTree(full_path) catch {}; + fs.cwd().deleteTree(full_path) catch {}; } // TODO remove empty directories @@ -847,7 +847,8 @@ pub const Builder = struct { if (self.verbose) { warn("cp {} {} ", .{ source_path, dest_path }); } - const prev_status = try fs.updateFile(source_path, dest_path); + const cwd = fs.cwd(); + const prev_status = try fs.Dir.updateFile(cwd, source_path, cwd, dest_path, .{}); if (self.verbose) switch (prev_status) { .stale => warn("# installed\n", .{}), .fresh => warn("# up-to-date\n", .{}), @@ -1120,7 +1121,7 @@ pub const LibExeObjStep = struct { emit_llvm_ir: bool = false, emit_asm: bool = false, emit_bin: bool = true, - disable_gen_h: bool, + emit_h: bool = false, bundle_compiler_rt: bool, disable_stack_probing: bool, disable_sanitize_c: bool, @@ -1157,8 +1158,14 @@ pub const LibExeObjStep = struct { valgrind_support: ?bool = null, + /// Create a .eh_frame_hdr section and a PT_GNU_EH_FRAME segment in the ELF + /// file. link_eh_frame_hdr: bool = false, + /// Place every function in its own section so that unused ones may be + /// safely garbage-collected during the linking phase. + link_function_sections: bool = false, + /// Uses system Wine installation to run cross compiled Windows build artifacts. enable_wine: bool = false, @@ -1274,7 +1281,6 @@ pub const LibExeObjStep = struct { .exec_cmd_args = null, .name_prefix = "", .filter = null, - .disable_gen_h = false, .bundle_compiler_rt = false, .disable_stack_probing = false, .disable_sanitize_c = false, @@ -1593,8 +1599,9 @@ pub const LibExeObjStep = struct { self.main_pkg_path = dir_path; } - pub fn setDisableGenH(self: *LibExeObjStep, value: bool) void { - self.disable_gen_h = value; + /// Deprecated; just set the field directly. + pub fn setDisableGenH(self: *LibExeObjStep, is_disabled: bool) void { + self.emit_h = !is_disabled; } pub fn setLibCFile(self: *LibExeObjStep, libc_file: ?[]const u8) void { @@ -1625,7 +1632,7 @@ pub const LibExeObjStep = struct { /// the make step, from a step that has declared a dependency on this one. pub fn getOutputHPath(self: *LibExeObjStep) []const u8 { assert(self.kind != Kind.Exe); - assert(!self.disable_gen_h); + assert(self.emit_h); return fs.path.join( self.builder.allocator, &[_][]const u8{ self.output_dir.?, self.out_h_filename }, @@ -1672,7 +1679,7 @@ pub const LibExeObjStep = struct { } pub fn addBuildOption(self: *LibExeObjStep, comptime T: type, name: []const u8, value: T) void { - const out = &std.io.BufferOutStream.init(&self.build_options_contents).stream; + const out = self.build_options_contents.outStream(); out.print("pub const {} = {};\n", .{ name, value }) catch unreachable; } @@ -1877,6 +1884,7 @@ pub const LibExeObjStep = struct { if (self.emit_llvm_ir) try zig_args.append("-femit-llvm-ir"); if (self.emit_asm) try zig_args.append("-femit-asm"); if (!self.emit_bin) try zig_args.append("-fno-emit-bin"); + if (self.emit_h) try zig_args.append("-femit-h"); if (self.strip) { try zig_args.append("--strip"); @@ -1884,7 +1892,9 @@ pub const LibExeObjStep = struct { if (self.link_eh_frame_hdr) { try zig_args.append("--eh-frame-hdr"); } - + if (self.link_function_sections) { + try zig_args.append("-ffunction-sections"); + } if (self.single_threaded) { try zig_args.append("--single-threaded"); } @@ -1920,9 +1930,6 @@ pub const LibExeObjStep = struct { if (self.is_dynamic) { try zig_args.append("-dynamic"); } - if (self.disable_gen_h) { - try zig_args.append("--disable-gen-h"); - } if (self.bundle_compiler_rt) { try zig_args.append("--bundle-compiler-rt"); } @@ -2060,7 +2067,7 @@ pub const LibExeObjStep = struct { try zig_args.append("-isystem"); try zig_args.append(self.builder.pathFromRoot(include_path)); }, - .OtherStep => |other| if (!other.disable_gen_h) { + .OtherStep => |other| if (other.emit_h) { const h_path = other.getOutputHPath(); try zig_args.append("-isystem"); try zig_args.append(fs.path.dirname(h_path).?); @@ -2144,17 +2151,22 @@ pub const LibExeObjStep = struct { try zig_args.append("--cache"); try zig_args.append("on"); - const output_path_nl = try builder.execFromStep(zig_args.toSliceConst(), &self.step); - const output_path = mem.trimRight(u8, output_path_nl, "\r\n"); + const output_dir_nl = try builder.execFromStep(zig_args.toSliceConst(), &self.step); + const build_output_dir = mem.trimRight(u8, output_dir_nl, "\r\n"); if (self.output_dir) |output_dir| { - const full_dest = try fs.path.join(builder.allocator, &[_][]const u8{ - output_dir, - fs.path.basename(output_path), - }); - try builder.updateFile(output_path, full_dest); + var src_dir = try std.fs.cwd().openDir(build_output_dir, .{ .iterate = true }); + defer src_dir.close(); + + var dest_dir = try std.fs.cwd().openDir(output_dir, .{}); + defer dest_dir.close(); + + var it = src_dir.iterate(); + while (try it.next()) |entry| { + _ = try src_dir.updateFile(entry.name, dest_dir, entry.name, .{}); + } } else { - self.output_dir = fs.path.dirname(output_path).?; + self.output_dir = build_output_dir; } } @@ -2195,7 +2207,7 @@ const InstallArtifactStep = struct { break :blk InstallDir.Lib; } } else null, - .h_dir = if (artifact.kind == .Lib and !artifact.disable_gen_h) .Header else null, + .h_dir = if (artifact.kind == .Lib and artifact.emit_h) .Header else null, }; self.step.dependOn(&artifact.step); artifact.install_step = self; @@ -2352,7 +2364,7 @@ pub const RemoveDirStep = struct { const self = @fieldParentPtr(RemoveDirStep, "step", step); const full_path = self.builder.pathFromRoot(self.dir_path); - fs.deleteTree(full_path) catch |err| { + fs.cwd().deleteTree(full_path) catch |err| { warn("Unable to remove {}: {}\n", .{ full_path, @errorName(err) }); return err; }; diff --git a/lib/std/build/run.zig b/lib/std/build/run.zig index 91ecd56c3a..3276de9d19 100644 --- a/lib/std/build/run.zig +++ b/lib/std/build/run.zig @@ -29,6 +29,8 @@ pub const RunStep = struct { stdout_action: StdIoAction = .inherit, stderr_action: StdIoAction = .inherit, + stdin_behavior: std.ChildProcess.StdIo = .Inherit, + expected_exit_code: u8 = 0, pub const StdIoAction = union(enum) { @@ -159,7 +161,7 @@ pub const RunStep = struct { child.cwd = cwd; child.env_map = self.env_map orelse self.builder.env_map; - child.stdin_behavior = .Ignore; + child.stdin_behavior = self.stdin_behavior; child.stdout_behavior = stdIoActionToBehavior(self.stdout_action); child.stderr_behavior = stdIoActionToBehavior(self.stderr_action); diff --git a/lib/std/build/write_file.zig b/lib/std/build/write_file.zig index 60c54336e0..0c3f628457 100644 --- a/lib/std/build/write_file.zig +++ b/lib/std/build/write_file.zig @@ -78,7 +78,7 @@ pub const WriteFileStep = struct { warn("unable to make path {}: {}\n", .{ self.output_dir, @errorName(err) }); return err; }; - var dir = try fs.cwd().openDirTraverse(self.output_dir); + var dir = try fs.cwd().openDir(self.output_dir, .{}); defer dir.close(); for (self.files.toSliceConst()) |file| { dir.writeFile(file.basename, file.bytes) catch |err| { diff --git a/lib/std/c.zig b/lib/std/c.zig index 39a865ebbc..43b3d7f317 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -106,6 +106,7 @@ pub extern "c" fn mkdir(path: [*:0]const u8, mode: c_uint) c_int; pub extern "c" fn mkdirat(dirfd: fd_t, path: [*:0]const u8, mode: u32) c_int; pub extern "c" fn symlink(existing: [*:0]const u8, new: [*:0]const u8) c_int; pub extern "c" fn rename(old: [*:0]const u8, new: [*:0]const u8) c_int; +pub extern "c" fn renameat(olddirfd: fd_t, old: [*:0]const u8, newdirfd: fd_t, new: [*:0]const u8) c_int; pub extern "c" fn chdir(path: [*:0]const u8) c_int; pub extern "c" fn fchdir(fd: fd_t) c_int; pub extern "c" fn execve(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) c_int; diff --git a/lib/std/crypto/aes.zig b/lib/std/crypto/aes.zig index 1cc166f943..81dc56f0b3 100644 --- a/lib/std/crypto/aes.zig +++ b/lib/std/crypto/aes.zig @@ -15,10 +15,10 @@ fn rotw(w: u32) u32 { // Encrypt one block from src into dst, using the expanded key xk. fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { - var s0 = mem.readIntSliceBig(u32, src[0..4]); - var s1 = mem.readIntSliceBig(u32, src[4..8]); - var s2 = mem.readIntSliceBig(u32, src[8..12]); - var s3 = mem.readIntSliceBig(u32, src[12..16]); + var s0 = mem.readIntBig(u32, src[0..4]); + var s1 = mem.readIntBig(u32, src[4..8]); + var s2 = mem.readIntBig(u32, src[8..12]); + var s3 = mem.readIntBig(u32, src[12..16]); // First round just XORs input with key. s0 ^= xk[0]; @@ -58,18 +58,18 @@ fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { s2 ^= xk[k + 2]; s3 ^= xk[k + 3]; - mem.writeIntSliceBig(u32, dst[0..4], s0); - mem.writeIntSliceBig(u32, dst[4..8], s1); - mem.writeIntSliceBig(u32, dst[8..12], s2); - mem.writeIntSliceBig(u32, dst[12..16], s3); + mem.writeIntBig(u32, dst[0..4], s0); + mem.writeIntBig(u32, dst[4..8], s1); + mem.writeIntBig(u32, dst[8..12], s2); + mem.writeIntBig(u32, dst[12..16], s3); } // Decrypt one block from src into dst, using the expanded key xk. pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { - var s0 = mem.readIntSliceBig(u32, src[0..4]); - var s1 = mem.readIntSliceBig(u32, src[4..8]); - var s2 = mem.readIntSliceBig(u32, src[8..12]); - var s3 = mem.readIntSliceBig(u32, src[12..16]); + var s0 = mem.readIntBig(u32, src[0..4]); + var s1 = mem.readIntBig(u32, src[4..8]); + var s2 = mem.readIntBig(u32, src[8..12]); + var s3 = mem.readIntBig(u32, src[12..16]); // First round just XORs input with key. s0 ^= xk[0]; @@ -109,10 +109,10 @@ pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { s2 ^= xk[k + 2]; s3 ^= xk[k + 3]; - mem.writeIntSliceBig(u32, dst[0..4], s0); - mem.writeIntSliceBig(u32, dst[4..8], s1); - mem.writeIntSliceBig(u32, dst[8..12], s2); - mem.writeIntSliceBig(u32, dst[12..16], s3); + mem.writeIntBig(u32, dst[0..4], s0); + mem.writeIntBig(u32, dst[4..8], s1); + mem.writeIntBig(u32, dst[8..12], s2); + mem.writeIntBig(u32, dst[12..16], s3); } fn xorBytes(dst: []u8, a: []const u8, b: []const u8) usize { @@ -154,8 +154,8 @@ fn AES(comptime keysize: usize) type { var n: usize = 0; while (n < src.len) { ctx.encrypt(keystream[0..], ctrbuf[0..]); - var ctr_i = std.mem.readIntSliceBig(u128, ctrbuf[0..]); - std.mem.writeIntSliceBig(u128, ctrbuf[0..], ctr_i +% 1); + var ctr_i = std.mem.readIntBig(u128, ctrbuf[0..]); + std.mem.writeIntBig(u128, ctrbuf[0..], ctr_i +% 1); n += xorBytes(dst[n..], src[n..], &keystream); } @@ -251,7 +251,7 @@ fn expandKey(key: []const u8, enc: []u32, dec: []u32) void { var i: usize = 0; var nk = key.len / 4; while (i < nk) : (i += 1) { - enc[i] = mem.readIntSliceBig(u32, key[4 * i .. 4 * i + 4]); + enc[i] = mem.readIntBig(u32, key[4 * i ..][0..4]); } while (i < enc.len) : (i += 1) { var t = enc[i - 1]; diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig index e03d8f7dab..fc1d59290e 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -123,8 +123,7 @@ fn Blake2s(comptime out_len: usize) type { const rr = d.h[0 .. out_len / 32]; for (rr) |s, j| { - // TODO https://github.com/ziglang/zig/issues/863 - mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s); + mem.writeIntLittle(u32, out[4 * j ..][0..4], s); } } @@ -135,8 +134,7 @@ fn Blake2s(comptime out_len: usize) type { var v: [16]u32 = undefined; for (m) |*r, i| { - // TODO https://github.com/ziglang/zig/issues/863 - r.* = mem.readIntSliceLittle(u32, b[4 * i .. 4 * i + 4]); + r.* = mem.readIntLittle(u32, b[4 * i ..][0..4]); } var k: usize = 0; @@ -358,8 +356,7 @@ fn Blake2b(comptime out_len: usize) type { const rr = d.h[0 .. out_len / 64]; for (rr) |s, j| { - // TODO https://github.com/ziglang/zig/issues/863 - mem.writeIntSliceLittle(u64, out[8 * j .. 8 * j + 8], s); + mem.writeIntLittle(u64, out[8 * j ..][0..8], s); } } @@ -370,7 +367,7 @@ fn Blake2b(comptime out_len: usize) type { var v: [16]u64 = undefined; for (m) |*r, i| { - r.* = mem.readIntSliceLittle(u64, b[8 * i .. 8 * i + 8]); + r.* = mem.readIntLittle(u64, b[8 * i ..][0..8]); } var k: usize = 0; diff --git a/lib/std/crypto/chacha20.zig b/lib/std/crypto/chacha20.zig index d67877b051..f6008745af 100644 --- a/lib/std/crypto/chacha20.zig +++ b/lib/std/crypto/chacha20.zig @@ -61,8 +61,7 @@ fn salsa20_wordtobyte(out: []u8, input: [16]u32) void { } for (x) |_, i| { - // TODO https://github.com/ziglang/zig/issues/863 - mem.writeIntSliceLittle(u32, out[4 * i .. 4 * i + 4], x[i] +% input[i]); + mem.writeIntLittle(u32, out[4 * i ..][0..4], x[i] +% input[i]); } } @@ -73,10 +72,10 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo const c = "expand 32-byte k"; const constant_le = [_]u32{ - mem.readIntSliceLittle(u32, c[0..4]), - mem.readIntSliceLittle(u32, c[4..8]), - mem.readIntSliceLittle(u32, c[8..12]), - mem.readIntSliceLittle(u32, c[12..16]), + mem.readIntLittle(u32, c[0..4]), + mem.readIntLittle(u32, c[4..8]), + mem.readIntLittle(u32, c[8..12]), + mem.readIntLittle(u32, c[12..16]), }; mem.copy(u32, ctx[0..], constant_le[0..4]); @@ -120,19 +119,19 @@ pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: var k: [8]u32 = undefined; var c: [4]u32 = undefined; - k[0] = mem.readIntSliceLittle(u32, key[0..4]); - k[1] = mem.readIntSliceLittle(u32, key[4..8]); - k[2] = mem.readIntSliceLittle(u32, key[8..12]); - k[3] = mem.readIntSliceLittle(u32, key[12..16]); - k[4] = mem.readIntSliceLittle(u32, key[16..20]); - k[5] = mem.readIntSliceLittle(u32, key[20..24]); - k[6] = mem.readIntSliceLittle(u32, key[24..28]); - k[7] = mem.readIntSliceLittle(u32, key[28..32]); + k[0] = mem.readIntLittle(u32, key[0..4]); + k[1] = mem.readIntLittle(u32, key[4..8]); + k[2] = mem.readIntLittle(u32, key[8..12]); + k[3] = mem.readIntLittle(u32, key[12..16]); + k[4] = mem.readIntLittle(u32, key[16..20]); + k[5] = mem.readIntLittle(u32, key[20..24]); + k[6] = mem.readIntLittle(u32, key[24..28]); + k[7] = mem.readIntLittle(u32, key[28..32]); c[0] = counter; - c[1] = mem.readIntSliceLittle(u32, nonce[0..4]); - c[2] = mem.readIntSliceLittle(u32, nonce[4..8]); - c[3] = mem.readIntSliceLittle(u32, nonce[8..12]); + c[1] = mem.readIntLittle(u32, nonce[0..4]); + c[2] = mem.readIntLittle(u32, nonce[4..8]); + c[3] = mem.readIntLittle(u32, nonce[8..12]); chaCha20_internal(out, in, k, c); } @@ -147,19 +146,19 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32] var k: [8]u32 = undefined; var c: [4]u32 = undefined; - k[0] = mem.readIntSliceLittle(u32, key[0..4]); - k[1] = mem.readIntSliceLittle(u32, key[4..8]); - k[2] = mem.readIntSliceLittle(u32, key[8..12]); - k[3] = mem.readIntSliceLittle(u32, key[12..16]); - k[4] = mem.readIntSliceLittle(u32, key[16..20]); - k[5] = mem.readIntSliceLittle(u32, key[20..24]); - k[6] = mem.readIntSliceLittle(u32, key[24..28]); - k[7] = mem.readIntSliceLittle(u32, key[28..32]); + k[0] = mem.readIntLittle(u32, key[0..4]); + k[1] = mem.readIntLittle(u32, key[4..8]); + k[2] = mem.readIntLittle(u32, key[8..12]); + k[3] = mem.readIntLittle(u32, key[12..16]); + k[4] = mem.readIntLittle(u32, key[16..20]); + k[5] = mem.readIntLittle(u32, key[20..24]); + k[6] = mem.readIntLittle(u32, key[24..28]); + k[7] = mem.readIntLittle(u32, key[28..32]); c[0] = @truncate(u32, counter); c[1] = @truncate(u32, counter >> 32); - c[2] = mem.readIntSliceLittle(u32, nonce[0..4]); - c[3] = mem.readIntSliceLittle(u32, nonce[4..8]); + c[2] = mem.readIntLittle(u32, nonce[0..4]); + c[3] = mem.readIntLittle(u32, nonce[4..8]); const block_size = (1 << 6); // The full block size is greater than the address space on a 32bit machine @@ -463,8 +462,8 @@ pub fn chacha20poly1305Seal(dst: []u8, plaintext: []const u8, data: []const u8, mac.update(zeros[0..padding]); } var lens: [16]u8 = undefined; - mem.writeIntSliceLittle(u64, lens[0..8], data.len); - mem.writeIntSliceLittle(u64, lens[8..16], plaintext.len); + mem.writeIntLittle(u64, lens[0..8], data.len); + mem.writeIntLittle(u64, lens[8..16], plaintext.len); mac.update(lens[0..]); mac.final(dst[plaintext.len..]); } @@ -500,8 +499,8 @@ pub fn chacha20poly1305Open(dst: []u8, msgAndTag: []const u8, data: []const u8, mac.update(zeros[0..padding]); } var lens: [16]u8 = undefined; - mem.writeIntSliceLittle(u64, lens[0..8], data.len); - mem.writeIntSliceLittle(u64, lens[8..16], ciphertext.len); + mem.writeIntLittle(u64, lens[0..8], data.len); + mem.writeIntLittle(u64, lens[8..16], ciphertext.len); mac.update(lens[0..]); var computedTag: [16]u8 = undefined; mac.final(computedTag[0..]); diff --git a/lib/std/crypto/md5.zig b/lib/std/crypto/md5.zig index d9dd08c904..ac8948ca20 100644 --- a/lib/std/crypto/md5.zig +++ b/lib/std/crypto/md5.zig @@ -112,8 +112,7 @@ pub const Md5 = struct { d.round(d.buf[0..]); for (d.s) |s, j| { - // TODO https://github.com/ziglang/zig/issues/863 - mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s); + mem.writeIntLittle(u32, out[4 * j ..][0..4], s); } } diff --git a/lib/std/crypto/poly1305.zig b/lib/std/crypto/poly1305.zig index 2395b1c7aa..fda978307d 100644 --- a/lib/std/crypto/poly1305.zig +++ b/lib/std/crypto/poly1305.zig @@ -3,11 +3,11 @@ // https://monocypher.org/ const std = @import("../std.zig"); -const builtin = @import("builtin"); +const builtin = std.builtin; const Endian = builtin.Endian; -const readIntSliceLittle = std.mem.readIntSliceLittle; -const writeIntSliceLittle = std.mem.writeIntSliceLittle; +const readIntLittle = std.mem.readIntLittle; +const writeIntLittle = std.mem.writeIntLittle; pub const Poly1305 = struct { const Self = @This(); @@ -59,19 +59,19 @@ pub const Poly1305 = struct { { var i: usize = 0; while (i < 1) : (i += 1) { - ctx.r[0] = readIntSliceLittle(u32, key[0..4]) & 0x0fffffff; + ctx.r[0] = readIntLittle(u32, key[0..4]) & 0x0fffffff; } } { var i: usize = 1; while (i < 4) : (i += 1) { - ctx.r[i] = readIntSliceLittle(u32, key[i * 4 .. i * 4 + 4]) & 0x0ffffffc; + ctx.r[i] = readIntLittle(u32, key[i * 4 ..][0..4]) & 0x0ffffffc; } } { var i: usize = 0; while (i < 4) : (i += 1) { - ctx.pad[i] = readIntSliceLittle(u32, key[i * 4 + 16 .. i * 4 + 16 + 4]); + ctx.pad[i] = readIntLittle(u32, key[i * 4 + 16 ..][0..4]); } } @@ -168,10 +168,10 @@ pub const Poly1305 = struct { const nb_blocks = nmsg.len >> 4; var i: usize = 0; while (i < nb_blocks) : (i += 1) { - ctx.c[0] = readIntSliceLittle(u32, nmsg[0..4]); - ctx.c[1] = readIntSliceLittle(u32, nmsg[4..8]); - ctx.c[2] = readIntSliceLittle(u32, nmsg[8..12]); - ctx.c[3] = readIntSliceLittle(u32, nmsg[12..16]); + ctx.c[0] = readIntLittle(u32, nmsg[0..4]); + ctx.c[1] = readIntLittle(u32, nmsg[4..8]); + ctx.c[2] = readIntLittle(u32, nmsg[8..12]); + ctx.c[3] = readIntLittle(u32, nmsg[12..16]); polyBlock(ctx); nmsg = nmsg[16..]; } @@ -210,11 +210,10 @@ pub const Poly1305 = struct { const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000 const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000 - // TODO https://github.com/ziglang/zig/issues/863 - writeIntSliceLittle(u32, out[0..], @truncate(u32, uu0)); - writeIntSliceLittle(u32, out[4..], @truncate(u32, uu1)); - writeIntSliceLittle(u32, out[8..], @truncate(u32, uu2)); - writeIntSliceLittle(u32, out[12..], @truncate(u32, uu3)); + writeIntLittle(u32, out[0..4], @truncate(u32, uu0)); + writeIntLittle(u32, out[4..8], @truncate(u32, uu1)); + writeIntLittle(u32, out[8..12], @truncate(u32, uu2)); + writeIntLittle(u32, out[12..16], @truncate(u32, uu3)); ctx.secureZero(); } diff --git a/lib/std/crypto/sha1.zig b/lib/std/crypto/sha1.zig index 5be42180a1..6edf7b745e 100644 --- a/lib/std/crypto/sha1.zig +++ b/lib/std/crypto/sha1.zig @@ -109,8 +109,7 @@ pub const Sha1 = struct { d.round(d.buf[0..]); for (d.s) |s, j| { - // TODO https://github.com/ziglang/zig/issues/863 - mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s); + mem.writeIntBig(u32, out[4 * j ..][0..4], s); } } diff --git a/lib/std/crypto/sha2.zig b/lib/std/crypto/sha2.zig index fd7ad532a3..f004bceac3 100644 --- a/lib/std/crypto/sha2.zig +++ b/lib/std/crypto/sha2.zig @@ -167,8 +167,7 @@ fn Sha2_32(comptime params: Sha2Params32) type { const rr = d.s[0 .. params.out_len / 32]; for (rr) |s, j| { - // TODO https://github.com/ziglang/zig/issues/863 - mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s); + mem.writeIntBig(u32, out[4 * j ..][0..4], s); } } @@ -509,8 +508,7 @@ fn Sha2_64(comptime params: Sha2Params64) type { const rr = d.s[0 .. params.out_len / 64]; for (rr) |s, j| { - // TODO https://github.com/ziglang/zig/issues/863 - mem.writeIntSliceBig(u64, out[8 * j .. 8 * j + 8], s); + mem.writeIntBig(u64, out[8 * j ..][0..8], s); } } diff --git a/lib/std/crypto/sha3.zig b/lib/std/crypto/sha3.zig index d7b2fbe256..7c60674d75 100644 --- a/lib/std/crypto/sha3.zig +++ b/lib/std/crypto/sha3.zig @@ -120,7 +120,7 @@ fn keccak_f(comptime F: usize, d: []u8) void { var c = [_]u64{0} ** 5; for (s) |*r, i| { - r.* = mem.readIntSliceLittle(u64, d[8 * i .. 8 * i + 8]); + r.* = mem.readIntLittle(u64, d[8 * i ..][0..8]); } comptime var x: usize = 0; @@ -167,8 +167,7 @@ fn keccak_f(comptime F: usize, d: []u8) void { } for (s) |r, i| { - // TODO https://github.com/ziglang/zig/issues/863 - mem.writeIntSliceLittle(u64, d[8 * i .. 8 * i + 8], r); + mem.writeIntLittle(u64, d[8 * i ..][0..8], r); } } diff --git a/lib/std/crypto/x25519.zig b/lib/std/crypto/x25519.zig index 16e3f073f8..e2e2bf90e5 100644 --- a/lib/std/crypto/x25519.zig +++ b/lib/std/crypto/x25519.zig @@ -7,8 +7,8 @@ const builtin = @import("builtin"); const fmt = std.fmt; const Endian = builtin.Endian; -const readIntSliceLittle = std.mem.readIntSliceLittle; -const writeIntSliceLittle = std.mem.writeIntSliceLittle; +const readIntLittle = std.mem.readIntLittle; +const writeIntLittle = std.mem.writeIntLittle; // Based on Supercop's ref10 implementation. pub const X25519 = struct { @@ -255,16 +255,16 @@ const Fe = struct { var t: [10]i64 = undefined; - t[0] = readIntSliceLittle(u32, s[0..4]); - t[1] = @as(u32, readIntSliceLittle(u24, s[4..7])) << 6; - t[2] = @as(u32, readIntSliceLittle(u24, s[7..10])) << 5; - t[3] = @as(u32, readIntSliceLittle(u24, s[10..13])) << 3; - t[4] = @as(u32, readIntSliceLittle(u24, s[13..16])) << 2; - t[5] = readIntSliceLittle(u32, s[16..20]); - t[6] = @as(u32, readIntSliceLittle(u24, s[20..23])) << 7; - t[7] = @as(u32, readIntSliceLittle(u24, s[23..26])) << 5; - t[8] = @as(u32, readIntSliceLittle(u24, s[26..29])) << 4; - t[9] = (@as(u32, readIntSliceLittle(u24, s[29..32])) & 0x7fffff) << 2; + t[0] = readIntLittle(u32, s[0..4]); + t[1] = @as(u32, readIntLittle(u24, s[4..7])) << 6; + t[2] = @as(u32, readIntLittle(u24, s[7..10])) << 5; + t[3] = @as(u32, readIntLittle(u24, s[10..13])) << 3; + t[4] = @as(u32, readIntLittle(u24, s[13..16])) << 2; + t[5] = readIntLittle(u32, s[16..20]); + t[6] = @as(u32, readIntLittle(u24, s[20..23])) << 7; + t[7] = @as(u32, readIntLittle(u24, s[23..26])) << 5; + t[8] = @as(u32, readIntLittle(u24, s[26..29])) << 4; + t[9] = (@as(u32, readIntLittle(u24, s[29..32])) & 0x7fffff) << 2; carry1(h, t[0..]); } @@ -544,15 +544,14 @@ const Fe = struct { ut[i] = @bitCast(u32, @intCast(i32, t[i])); } - // TODO https://github.com/ziglang/zig/issues/863 - writeIntSliceLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26)); - writeIntSliceLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19)); - writeIntSliceLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13)); - writeIntSliceLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6)); - writeIntSliceLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25)); - writeIntSliceLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19)); - writeIntSliceLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12)); - writeIntSliceLittle(u32, s[28..], (ut[8] >> 20) | (ut[9] << 6)); + writeIntLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26)); + writeIntLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19)); + writeIntLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13)); + writeIntLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6)); + writeIntLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25)); + writeIntLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19)); + writeIntLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12)); + writeIntLittle(u32, s[28..32], (ut[8] >> 20) | (ut[9] << 6)); std.mem.secureZero(i64, t[0..]); } diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 0a7a0dee7e..5600990924 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -235,9 +235,17 @@ pub fn panic(comptime format: []const u8, args: var) noreturn { panicExtra(null, first_trace_addr, format, args); } -/// TODO multithreaded awareness +/// Non-zero whenever the program triggered a panic. +/// The counter is incremented/decremented atomically. var panicking: u8 = 0; +// Locked to avoid interleaving panic messages from multiple threads. +var panic_mutex = std.Mutex.init(); + +/// Counts how many times the panic handler is invoked by this thread. +/// This is used to catch and handle panics triggered by the panic handler. +threadlocal var panic_stage: usize = 0; + pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: var) noreturn { @setCold(true); @@ -247,25 +255,50 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c resetSegfaultHandler(); } - switch (@atomicRmw(u8, &panicking, .Add, 1, .SeqCst)) { + switch (panic_stage) { 0 => { - const stderr = getStderrStream(); - noasync stderr.print(format ++ "\n", args) catch os.abort(); - if (trace) |t| { - dumpStackTrace(t.*); + panic_stage = 1; + + _ = @atomicRmw(u8, &panicking, .Add, 1, .SeqCst); + + // Make sure to release the mutex when done + { + const held = panic_mutex.acquire(); + defer held.release(); + + const stderr = getStderrStream(); + noasync stderr.print(format ++ "\n", args) catch os.abort(); + if (trace) |t| { + dumpStackTrace(t.*); + } + dumpCurrentStackTrace(first_trace_addr); + } + + if (@atomicRmw(u8, &panicking, .Sub, 1, .SeqCst) != 1) { + // Another thread is panicking, wait for the last one to finish + // and call abort() + + // Sleep forever without hammering the CPU + var event = std.ResetEvent.init(); + event.wait(); + + unreachable; } - dumpCurrentStackTrace(first_trace_addr); }, 1 => { - // TODO detect if a different thread caused the panic, because in that case - // we would want to return here instead of calling abort, so that the thread - // which first called panic can finish printing a stack trace. - warn("Panicked during a panic. Aborting.\n", .{}); + panic_stage = 2; + + // A panic happened while trying to print a previous panic message, + // we're still holding the mutex but that's fine as we're going to + // call abort() + const stderr = getStderrStream(); + noasync stderr.print("Panicked during a panic. Aborting.\n", .{}) catch os.abort(); }, else => { // Panicked while printing "Panicked during a panic." }, } + os.abort(); } diff --git a/lib/std/dwarf.zig b/lib/std/dwarf.zig index 769f349e33..d198886b11 100644 --- a/lib/std/dwarf.zig +++ b/lib/std/dwarf.zig @@ -717,8 +717,7 @@ pub const DwarfInfo = struct { const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4)); const version = try in.readInt(u16, di.endian); - // TODO support 3 and 5 - if (version != 2 and version != 4) return error.InvalidDebugInfo; + if (version < 2 or version > 4) return error.InvalidDebugInfo; const prologue_length = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian); const prog_start_offset = (try seekable.getPos()) + prologue_length; diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 592fe9bb4e..7fc9961938 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -1223,7 +1223,8 @@ test "slice" { try testFmt("slice: abc\n", "slice: {}\n", .{value}); } { - const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[0..0]; + var runtime_zero: usize = 0; + const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[runtime_zero..runtime_zero]; try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value}); } diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 80d679aed5..e4f411c928 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -81,134 +81,74 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: } } -// TODO fix enum literal not casting to error union -const PrevStatus = enum { +pub const PrevStatus = enum { stale, fresh, }; -pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus { - return updateFileMode(source_path, dest_path, null); -} +pub const CopyFileOptions = struct { + /// When this is `null` the mode is copied from the source file. + override_mode: ?File.Mode = null, +}; -/// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing. -/// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime, -/// atime, and mode of the source file so that the next call to `updateFile` will not need a copy. -/// Returns the previous status of the file before updating. -/// If any of the directories do not exist for dest_path, they are created. -/// TODO rework this to integrate with Dir -pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !PrevStatus { +/// Same as `Dir.updateFile`, except asserts that both `source_path` and `dest_path` +/// are absolute. See `Dir.updateFile` for a function that operates on both +/// absolute and relative paths. +pub fn updateFileAbsolute( + source_path: []const u8, + dest_path: []const u8, + args: CopyFileOptions, +) !PrevStatus { + assert(path.isAbsolute(source_path)); + assert(path.isAbsolute(dest_path)); const my_cwd = cwd(); - - var src_file = try my_cwd.openFile(source_path, .{}); - defer src_file.close(); - - const src_stat = try src_file.stat(); - check_dest_stat: { - const dest_stat = blk: { - var dest_file = my_cwd.openFile(dest_path, .{}) catch |err| switch (err) { - error.FileNotFound => break :check_dest_stat, - else => |e| return e, - }; - defer dest_file.close(); - - break :blk try dest_file.stat(); - }; - - if (src_stat.size == dest_stat.size and - src_stat.mtime == dest_stat.mtime and - src_stat.mode == dest_stat.mode) - { - return PrevStatus.fresh; - } - } - const actual_mode = mode orelse src_stat.mode; - - if (path.dirname(dest_path)) |dirname| { - try cwd().makePath(dirname); - } - - var atomic_file = try AtomicFile.init(dest_path, actual_mode); - defer atomic_file.deinit(); - - try atomic_file.file.writeFileAll(src_file, .{ .in_len = src_stat.size }); - try atomic_file.file.updateTimes(src_stat.atime, src_stat.mtime); - try atomic_file.finish(); - return PrevStatus.stale; + return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, args); } -/// Guaranteed to be atomic. -/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available, -/// there is a possibility of power loss or application termination leaving temporary files present -/// in the same directory as dest_path. -/// Destination file will have the same mode as the source file. -/// TODO rework this to integrate with Dir -pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void { - var in_file = try cwd().openFile(source_path, .{}); - defer in_file.close(); - - const stat = try in_file.stat(); - - var atomic_file = try AtomicFile.init(dest_path, stat.mode); - defer atomic_file.deinit(); - - try atomic_file.file.writeFileAll(in_file, .{ .in_len = stat.size }); - return atomic_file.finish(); +/// Same as `Dir.copyFile`, except asserts that both `source_path` and `dest_path` +/// are absolute. See `Dir.copyFile` for a function that operates on both +/// absolute and relative paths. +pub fn copyFileAbsolute(source_path: []const u8, dest_path: []const u8, args: CopyFileOptions) !void { + assert(path.isAbsolute(source_path)); + assert(path.isAbsolute(dest_path)); + const my_cwd = cwd(); + return Dir.copyFile(my_cwd, source_path, my_cwd, dest_path, args); } -/// Guaranteed to be atomic. -/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available, -/// there is a possibility of power loss or application termination leaving temporary files present -/// in the same directory as dest_path. -/// TODO rework this to integrate with Dir -pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void { - var in_file = try cwd().openFile(source_path, .{}); - defer in_file.close(); - - var atomic_file = try AtomicFile.init(dest_path, mode); - defer atomic_file.deinit(); - - try atomic_file.file.writeFileAll(in_file, .{}); - return atomic_file.finish(); -} - -/// TODO update this API to avoid a getrandom syscall for every operation. It -/// should accept a random interface. -/// TODO rework this to integrate with Dir +/// TODO update this API to avoid a getrandom syscall for every operation. pub const AtomicFile = struct { file: File, - tmp_path_buf: [MAX_PATH_BYTES]u8, + tmp_path_buf: [MAX_PATH_BYTES - 1:0]u8, dest_path: []const u8, - finished: bool, + file_open: bool, + file_exists: bool, + dir: Dir, const InitError = File.OpenError; - /// dest_path must remain valid for the lifetime of AtomicFile - /// call finish to atomically replace dest_path with contents - pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile { + /// TODO rename this. Callers should go through Dir API + pub fn init2(dest_path: []const u8, mode: File.Mode, dir: Dir) InitError!AtomicFile { const dirname = path.dirname(dest_path); var rand_buf: [12]u8 = undefined; const dirname_component_len = if (dirname) |d| d.len + 1 else 0; const encoded_rand_len = comptime base64.Base64Encoder.calcSize(rand_buf.len); const tmp_path_len = dirname_component_len + encoded_rand_len; - var tmp_path_buf: [MAX_PATH_BYTES]u8 = undefined; - if (tmp_path_len >= tmp_path_buf.len) return error.NameTooLong; + var tmp_path_buf: [MAX_PATH_BYTES - 1:0]u8 = undefined; + if (tmp_path_len > tmp_path_buf.len) return error.NameTooLong; - if (dirname) |dir| { - mem.copy(u8, tmp_path_buf[0..], dir); - tmp_path_buf[dir.len] = path.sep; + if (dirname) |dn| { + mem.copy(u8, tmp_path_buf[0..], dn); + tmp_path_buf[dn.len] = path.sep; } tmp_path_buf[tmp_path_len] = 0; const tmp_path_slice = tmp_path_buf[0..tmp_path_len :0]; - const my_cwd = cwd(); - while (true) { try crypto.randomBytes(rand_buf[0..]); base64_encoder.encode(tmp_path_slice[dirname_component_len..tmp_path_len], &rand_buf); - const file = my_cwd.createFileC( + const file = dir.createFileC( tmp_path_slice, .{ .mode = mode, .exclusive = true }, ) catch |err| switch (err) { @@ -220,33 +160,46 @@ pub const AtomicFile = struct { .file = file, .tmp_path_buf = tmp_path_buf, .dest_path = dest_path, - .finished = false, + .file_open = true, + .file_exists = true, + .dir = dir, }; } } + /// Deprecated. Use `Dir.atomicFile`. + pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile { + return init2(dest_path, mode, cwd()); + } + /// always call deinit, even after successful finish() pub fn deinit(self: *AtomicFile) void { - if (!self.finished) { + if (self.file_open) { self.file.close(); - cwd().deleteFileC(@ptrCast([*:0]u8, &self.tmp_path_buf)) catch {}; - self.finished = true; + self.file_open = false; } + if (self.file_exists) { + self.dir.deleteFileC(&self.tmp_path_buf) catch {}; + self.file_exists = false; + } + self.* = undefined; } pub fn finish(self: *AtomicFile) !void { - assert(!self.finished); + assert(self.file_exists); + if (self.file_open) { + self.file.close(); + self.file_open = false; + } if (std.Target.current.os.tag == .windows) { const dest_path_w = try os.windows.sliceToPrefixedFileW(self.dest_path); - const tmp_path_w = try os.windows.cStrToPrefixedFileW(@ptrCast([*:0]u8, &self.tmp_path_buf)); - self.file.close(); - self.finished = true; - return os.renameW(&tmp_path_w, &dest_path_w); + const tmp_path_w = try os.windows.cStrToPrefixedFileW(&self.tmp_path_buf); + try os.renameatW(self.dir.fd, &tmp_path_w, self.dir.fd, &dest_path_w, os.windows.TRUE); + self.file_exists = false; } else { const dest_path_c = try os.toPosixPath(self.dest_path); - self.file.close(); - self.finished = true; - return os.renameC(@ptrCast([*:0]u8, &self.tmp_path_buf), &dest_path_c); + try os.renameatZ(self.dir.fd, &self.tmp_path_buf, self.dir.fd, &dest_path_c); + self.file_exists = false; } } }; @@ -274,44 +227,21 @@ pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void { os.windows.CloseHandle(handle); } -/// Returns `error.DirNotEmpty` if the directory is not empty. -/// To delete a directory recursively, see `deleteTree`. +/// Deprecated; use `Dir.deleteDir`. pub fn deleteDir(dir_path: []const u8) !void { return os.rmdir(dir_path); } -/// Same as `deleteDir` except the parameter is a null-terminated UTF8-encoded string. +/// Deprecated; use `Dir.deleteDirC`. pub fn deleteDirC(dir_path: [*:0]const u8) !void { return os.rmdirC(dir_path); } -/// Same as `deleteDir` except the parameter is a null-terminated UTF16LE-encoded string. +/// Deprecated; use `Dir.deleteDirW`. pub fn deleteDirW(dir_path: [*:0]const u16) !void { return os.rmdirW(dir_path); } -/// Removes a symlink, file, or directory. -/// If `full_path` is relative, this is equivalent to `Dir.deleteTree` with the -/// current working directory as the open directory handle. -/// If `full_path` is absolute, this is equivalent to `Dir.deleteTree` with the -/// base directory. -pub fn deleteTree(full_path: []const u8) !void { - if (path.isAbsolute(full_path)) { - const dirname = path.dirname(full_path) orelse return error{ - /// Attempt to remove the root file system path. - /// This error is unreachable if `full_path` is relative. - CannotDeleteRootDirectory, - }.CannotDeleteRootDirectory; - - var dir = try cwd().openDirList(dirname); - defer dir.close(); - - return dir.deleteTree(path.basename(full_path)); - } else { - return cwd().deleteTree(full_path); - } -} - pub const Dir = struct { fd: os.fd_t, @@ -368,7 +298,7 @@ pub const Dir = struct { if (rc == 0) return null; if (rc < 0) { switch (os.errno(rc)) { - os.EBADF => unreachable, + os.EBADF => unreachable, // Dir is invalid or was opened without iteration ability os.EFAULT => unreachable, os.ENOTDIR => unreachable, os.EINVAL => unreachable, @@ -411,13 +341,13 @@ pub const Dir = struct { if (self.index >= self.end_index) { const rc = os.system.getdirentries( self.dir.fd, - self.buf[0..].ptr, + &self.buf, self.buf.len, &self.seek, ); switch (os.errno(rc)) { 0 => {}, - os.EBADF => unreachable, + os.EBADF => unreachable, // Dir is invalid or was opened without iteration ability os.EFAULT => unreachable, os.ENOTDIR => unreachable, os.EINVAL => unreachable, @@ -473,7 +403,7 @@ pub const Dir = struct { const rc = os.linux.getdents64(self.dir.fd, &self.buf, self.buf.len); switch (os.linux.getErrno(rc)) { 0 => {}, - os.EBADF => unreachable, + os.EBADF => unreachable, // Dir is invalid or was opened without iteration ability os.EFAULT => unreachable, os.ENOTDIR => unreachable, os.EINVAL => unreachable, @@ -547,7 +477,8 @@ pub const Dir = struct { self.end_index = io.Information; switch (rc) { .SUCCESS => {}, - .ACCESS_DENIED => return error.AccessDenied, + .ACCESS_DENIED => return error.AccessDenied, // Double-check that the Dir was opened with iteration ability + else => return w.unexpectedStatus(rc), } } @@ -625,16 +556,6 @@ pub const Dir = struct { DeviceBusy, } || os.UnexpectedError; - /// Deprecated; call `cwd().openDirList` directly. - pub fn open(dir_path: []const u8) OpenError!Dir { - return cwd().openDirList(dir_path); - } - - /// Deprecated; call `cwd().openDirListC` directly. - pub fn openC(dir_path_c: [*:0]const u8) OpenError!Dir { - return cwd().openDirListC(dir_path_c); - } - pub fn close(self: *Dir) void { if (need_async_thread) { std.event.Loop.instance.?.close(self.fd); @@ -696,7 +617,7 @@ pub const Dir = struct { var flock = mem.zeroes(os.Flock); flock.l_type = if (flags.write) os.F_WRLCK else os.F_RDLCK; flock.l_whence = os.SEEK_SET; - try os.fcntl(fd, os.F_SETLKW, &flock); + _ = try os.fcntl(fd, os.F_SETLKW, @ptrToInt(&flock)); } return File{ @@ -721,7 +642,10 @@ pub const Dir = struct { (if (flags.write) @as(os.windows.ULONG, 0) else w.FILE_SHARE_READ) else null; - return self.openFileWindows(sub_path_w, access_mask, share_access, w.FILE_OPEN); + return @as(File, .{ + .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, share_access, w.FILE_OPEN), + .io_mode = .blocking, + }); } /// Creates, opens, or overwrites a file with write access. @@ -765,7 +689,7 @@ pub const Dir = struct { var flock = mem.zeroes(os.Flock); flock.l_type = os.F_WRLCK; flock.l_whence = os.SEEK_SET; - try os.fcntl(fd, os.F_SETLKW, &flock); + _ = try os.fcntl(fd, os.F_SETLKW, @ptrToInt(&flock)); } return File{ .handle = fd, .io_mode = .blocking }; @@ -788,7 +712,10 @@ pub const Dir = struct { @as(os.windows.ULONG, w.FILE_SHARE_DELETE) else null; - return self.openFileWindows(sub_path_w, access_mask, share_access, creation); + return @as(File, .{ + .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, share_access, creation), + .io_mode = .blocking, + }); } /// Deprecated; call `openFile` directly. @@ -806,87 +733,6 @@ pub const Dir = struct { return self.openFileW(sub_path, .{}); } - pub fn openFileWindows( - self: Dir, - sub_path_w: [*:0]const u16, - access_mask: os.windows.ACCESS_MASK, - share_access_opt: ?os.windows.ULONG, - creation: os.windows.ULONG, - ) File.OpenError!File { - var delay: usize = 1; - while (true) { - const w = os.windows; - - if (sub_path_w[0] == '.' and sub_path_w[1] == 0) { - return error.IsDir; - } - if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) { - return error.IsDir; - } - - var result = File{ - .handle = undefined, - .io_mode = .blocking, - }; - - const path_len_bytes = math.cast(u16, mem.toSliceConst(u16, sub_path_w).len * 2) catch |err| switch (err) { - error.Overflow => return error.NameTooLong, - }; - var nt_name = w.UNICODE_STRING{ - .Length = path_len_bytes, - .MaximumLength = path_len_bytes, - .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)), - }; - var attr = w.OBJECT_ATTRIBUTES{ - .Length = @sizeOf(w.OBJECT_ATTRIBUTES), - .RootDirectory = if (path.isAbsoluteWindowsW(sub_path_w)) null else self.fd, - .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here. - .ObjectName = &nt_name, - .SecurityDescriptor = null, - .SecurityQualityOfService = null, - }; - var io: w.IO_STATUS_BLOCK = undefined; - const share_access = share_access_opt orelse w.FILE_SHARE_WRITE | w.FILE_SHARE_READ | w.FILE_SHARE_DELETE; - const rc = w.ntdll.NtCreateFile( - &result.handle, - access_mask, - &attr, - &io, - null, - w.FILE_ATTRIBUTE_NORMAL, - share_access, - creation, - w.FILE_NON_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT, - null, - 0, - ); - switch (rc) { - .SUCCESS => return result, - .OBJECT_NAME_INVALID => unreachable, - .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, - .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, - .NO_MEDIA_IN_DEVICE => return error.NoDevice, - .INVALID_PARAMETER => unreachable, - .SHARING_VIOLATION => { - // TODO: check if async or blocking - //return error.SharingViolation - // Sleep so we don't consume a ton of CPU waiting to get lock on file - std.time.sleep(delay); - // Increase sleep time as long as it is less than 5 seconds - if (delay < 5 * std.time.ns_per_s) { - delay *= 2; - } - continue; - }, - .ACCESS_DENIED => return error.AccessDenied, - .PIPE_BUSY => return error.PipeBusy, - .OBJECT_PATH_SYNTAX_BAD => unreachable, - .OBJECT_NAME_COLLISION => return error.PathAlreadyExists, - else => return w.unexpectedStatus(rc), - } - } - } - pub fn makeDir(self: Dir, sub_path: []const u8) !void { try os.mkdirat(self.fd, sub_path, default_new_dir_mode); } @@ -945,77 +791,61 @@ pub const Dir = struct { try os.fchdir(self.fd); } - /// Deprecated; call `openDirList` directly. - pub fn openDir(self: Dir, sub_path: []const u8) OpenError!Dir { - return self.openDirList(sub_path); - } + pub const OpenDirOptions = struct { + /// `true` means the opened directory can be used as the `Dir` parameter + /// for functions which operate based on an open directory handle. When `false`, + /// such operations are Illegal Behavior. + access_sub_paths: bool = true, - /// Deprecated; call `openDirListC` directly. - pub fn openDirC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir { - return self.openDirListC(sub_path_c); - } + /// `true` means the opened directory can be scanned for the files and sub-directories + /// of the result. It means the `iterate` function can be called. + iterate: bool = false, + }; - /// Opens a directory at the given path with the ability to access subpaths - /// of the result. Calling `iterate` on the result is illegal behavior; to - /// list the contents of a directory, open it with `openDirList`. - /// - /// Call `close` on the result when done. + /// Opens a directory at the given path. The directory is a system resource that remains + /// open until `close` is called on the result. /// /// Asserts that the path parameter has no null bytes. - pub fn openDirTraverse(self: Dir, sub_path: []const u8) OpenError!Dir { + pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir { if (builtin.os.tag == .windows) { const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); - return self.openDirTraverseW(&sub_path_w); + return self.openDirW(&sub_path_w, args); + } else { + const sub_path_c = try os.toPosixPath(sub_path); + return self.openDirC(&sub_path_c, args); } - - const sub_path_c = try os.toPosixPath(sub_path); - return self.openDirTraverseC(&sub_path_c); } - /// Opens a directory at the given path with the ability to access subpaths and list contents - /// of the result. If the ability to list contents is unneeded, `openDirTraverse` acts the - /// same and may be more efficient. - /// - /// Call `close` on the result when done. - /// - /// Asserts that the path parameter has no null bytes. - pub fn openDirList(self: Dir, sub_path: []const u8) OpenError!Dir { - if (builtin.os.tag == .windows) { - const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); - return self.openDirListW(&sub_path_w); - } - - const sub_path_c = try os.toPosixPath(sub_path); - return self.openDirListC(&sub_path_c); - } - - /// Same as `openDirTraverse` except the parameter is null-terminated. - pub fn openDirTraverseC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir { + /// Same as `openDir` except the parameter is null-terminated. + pub fn openDirC(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions) OpenError!Dir { if (builtin.os.tag == .windows) { const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); - return self.openDirTraverseW(&sub_path_w); - } else { + return self.openDirW(&sub_path_w, args); + } else if (!args.iterate) { const O_PATH = if (@hasDecl(os, "O_PATH")) os.O_PATH else 0; - return self.openDirFlagsC(sub_path_c, os.O_RDONLY | os.O_CLOEXEC | O_PATH); - } - } - - /// Same as `openDirList` except the parameter is null-terminated. - pub fn openDirListC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir { - if (builtin.os.tag == .windows) { - const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); - return self.openDirListW(&sub_path_w); + return self.openDirFlagsC(sub_path_c, os.O_DIRECTORY | os.O_RDONLY | os.O_CLOEXEC | O_PATH); } else { - return self.openDirFlagsC(sub_path_c, os.O_RDONLY | os.O_CLOEXEC); + return self.openDirFlagsC(sub_path_c, os.O_DIRECTORY | os.O_RDONLY | os.O_CLOEXEC); } } + /// Same as `openDir` except the path parameter is WTF-16 encoded, NT-prefixed. + /// This function asserts the target OS is Windows. + pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) OpenError!Dir { + const w = os.windows; + // TODO remove some of these flags if args.access_sub_paths is false + const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | + w.SYNCHRONIZE | w.FILE_TRAVERSE; + const flags: u32 = if (args.iterate) base_flags | w.FILE_LIST_DIRECTORY else base_flags; + return self.openDirAccessMaskW(sub_path_w, flags); + } + + /// `flags` must contain `os.O_DIRECTORY`. fn openDirFlagsC(self: Dir, sub_path_c: [*:0]const u8, flags: u32) OpenError!Dir { - const os_flags = flags | os.O_DIRECTORY; const result = if (need_async_thread) - std.event.Loop.instance.?.openatZ(self.fd, sub_path_c, os_flags, 0) + std.event.Loop.instance.?.openatZ(self.fd, sub_path_c, flags, 0) else - os.openatC(self.fd, sub_path_c, os_flags, 0); + os.openatC(self.fd, sub_path_c, flags, 0); const fd = result catch |err| switch (err) { error.FileTooBig => unreachable, // can't happen for directories error.IsDir => unreachable, // we're providing O_DIRECTORY @@ -1026,22 +856,6 @@ pub const Dir = struct { return Dir{ .fd = fd }; } - /// Same as `openDirTraverse` except the path parameter is UTF16LE, NT-prefixed. - /// This function is Windows-only. - pub fn openDirTraverseW(self: Dir, sub_path_w: [*:0]const u16) OpenError!Dir { - const w = os.windows; - - return self.openDirAccessMaskW(sub_path_w, w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | w.SYNCHRONIZE | w.FILE_TRAVERSE); - } - - /// Same as `openDirList` except the path parameter is UTF16LE, NT-prefixed. - /// This function is Windows-only. - pub fn openDirListW(self: Dir, sub_path_w: [*:0]const u16) OpenError!Dir { - const w = os.windows; - - return self.openDirAccessMaskW(sub_path_w, w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | w.SYNCHRONIZE | w.FILE_TRAVERSE | w.FILE_LIST_DIRECTORY); - } - fn openDirAccessMaskW(self: Dir, sub_path_w: [*:0]const u16, access_mask: u32) OpenError!Dir { const w = os.windows; @@ -1262,7 +1076,7 @@ pub const Dir = struct { error.Unexpected, => |e| return e, } - var dir = self.openDirList(sub_path) catch |err| switch (err) { + var dir = self.openDir(sub_path, .{ .iterate = true }) catch |err| switch (err) { error.NotDir => { if (got_access_denied) { return error.AccessDenied; @@ -1295,7 +1109,6 @@ pub const Dir = struct { var dir_name_buf: [MAX_PATH_BYTES]u8 = undefined; var dir_name: []const u8 = sub_path; - var parent_dir = self; // Here we must avoid recursion, in order to provide O(1) memory guarantee of this function. // Go through each entry and if it is not a directory, delete it. If it is a directory, @@ -1327,7 +1140,7 @@ pub const Dir = struct { => |e| return e, } - const new_dir = dir.openDirList(entry.name) catch |err| switch (err) { + const new_dir = dir.openDir(entry.name, .{ .iterate = true }) catch |err| switch (err) { error.NotDir => { if (got_access_denied) { return error.AccessDenied; @@ -1434,9 +1247,96 @@ pub const Dir = struct { pub fn accessW(self: Dir, sub_path_w: [*:0]const u16, flags: File.OpenFlags) AccessError!void { return os.faccessatW(self.fd, sub_path_w, 0, 0); } + + /// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing. + /// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime, + /// atime, and mode of the source file so that the next call to `updateFile` will not need a copy. + /// Returns the previous status of the file before updating. + /// If any of the directories do not exist for dest_path, they are created. + pub fn updateFile( + source_dir: Dir, + source_path: []const u8, + dest_dir: Dir, + dest_path: []const u8, + options: CopyFileOptions, + ) !PrevStatus { + var src_file = try source_dir.openFile(source_path, .{}); + defer src_file.close(); + + const src_stat = try src_file.stat(); + const actual_mode = options.override_mode orelse src_stat.mode; + check_dest_stat: { + const dest_stat = blk: { + var dest_file = dest_dir.openFile(dest_path, .{}) catch |err| switch (err) { + error.FileNotFound => break :check_dest_stat, + else => |e| return e, + }; + defer dest_file.close(); + + break :blk try dest_file.stat(); + }; + + if (src_stat.size == dest_stat.size and + src_stat.mtime == dest_stat.mtime and + actual_mode == dest_stat.mode) + { + return PrevStatus.fresh; + } + } + + if (path.dirname(dest_path)) |dirname| { + try dest_dir.makePath(dirname); + } + + var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = actual_mode }); + defer atomic_file.deinit(); + + try atomic_file.file.writeFileAll(src_file, .{ .in_len = src_stat.size }); + try atomic_file.file.updateTimes(src_stat.atime, src_stat.mtime); + try atomic_file.finish(); + return PrevStatus.stale; + } + + /// Guaranteed to be atomic. + /// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available, + /// there is a possibility of power loss or application termination leaving temporary files present + /// in the same directory as dest_path. + pub fn copyFile( + source_dir: Dir, + source_path: []const u8, + dest_dir: Dir, + dest_path: []const u8, + options: CopyFileOptions, + ) !void { + var in_file = try source_dir.openFile(source_path, .{}); + defer in_file.close(); + + var size: ?u64 = null; + const mode = options.override_mode orelse blk: { + const stat = try in_file.stat(); + size = stat.size; + break :blk stat.mode; + }; + + var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = mode }); + defer atomic_file.deinit(); + + try atomic_file.file.writeFileAll(in_file, .{ .in_len = size }); + return atomic_file.finish(); + } + + pub const AtomicFileOptions = struct { + mode: File.Mode = File.default_mode, + }; + + /// `dest_path` must remain valid for the lifetime of `AtomicFile`. + /// Call `AtomicFile.finish` to atomically replace `dest_path` with contents. + pub fn atomicFile(self: Dir, dest_path: []const u8, options: AtomicFileOptions) !AtomicFile { + return AtomicFile.init2(dest_path, options.mode, self); + } }; -/// Returns an handle to the current working directory that is open for traversal. +/// Returns an handle to the current working directory. It is not opened with iteration capability. /// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior. /// On POSIX targets, this function is comptime-callable. pub fn cwd() Dir { @@ -1514,6 +1414,25 @@ pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) DeleteFileError!void return cwd().deleteFileW(absolute_path_w); } +/// Removes a symlink, file, or directory. +/// This is equivalent to `Dir.deleteTree` with the base directory. +/// Asserts that the path is absolute. See `Dir.deleteTree` for a function that +/// operates on both absolute and relative paths. +/// Asserts that the path parameter has no null bytes. +pub fn deleteTreeAbsolute(absolute_path: []const u8) !void { + assert(path.isAbsolute(absolute_path)); + const dirname = path.dirname(absolute_path) orelse return error{ + /// Attempt to remove the root file system path. + /// This error is unreachable if `absolute_path` is relative. + CannotDeleteRootDirectory, + }.CannotDeleteRootDirectory; + + var dir = try cwd().openDir(dirname, .{}); + defer dir.close(); + + return dir.deleteTree(path.basename(absolute_path)); +} + pub const Walker = struct { stack: std.ArrayList(StackItem), name_buffer: std.Buffer, @@ -1548,7 +1467,7 @@ pub const Walker = struct { try self.name_buffer.appendByte(path.sep); try self.name_buffer.append(base.name); if (base.kind == .Directory) { - var new_dir = top.dir_it.dir.openDirList(base.name) catch |err| switch (err) { + var new_dir = top.dir_it.dir.openDir(base.name, .{ .iterate = true }) catch |err| switch (err) { error.NameTooLong => unreachable, // no path sep in base.name else => |e| return e, }; @@ -1586,7 +1505,7 @@ pub const Walker = struct { pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { assert(!mem.endsWith(u8, dir_path, path.sep_str)); - var dir = try cwd().openDirList(dir_path); + var dir = try cwd().openDir(dir_path, .{ .iterate = true }); errdefer dir.close(); var name_buffer = try std.Buffer.init(allocator, dir_path); @@ -1605,13 +1524,12 @@ pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { return walker; } -/// Read value of a symbolic link. -/// The return value is a slice of buffer, from index `0`. +/// Deprecated; use `Dir.readLink`. pub fn readLink(pathname: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { return os.readlink(pathname, buffer); } -/// Same as `readLink`, except the parameter is null-terminated. +/// Deprecated; use `Dir.readLinkC`. pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { return os.readlinkC(pathname_c, buffer); } @@ -1718,6 +1636,7 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const } /// `realpath`, except caller must free the returned memory. +/// TODO integrate with `Dir` pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 { var buf: [MAX_PATH_BYTES]u8 = undefined; return mem.dupe(allocator, u8, try os.realpath(pathname, &buf)); @@ -1726,6 +1645,9 @@ pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 { test "" { _ = makeDirAbsolute; _ = makeDirAbsoluteZ; + _ = copyFileAbsolute; + _ = updateFileAbsolute; + _ = Dir.copyFile; _ = @import("fs/path.zig"); _ = @import("fs/file.zig"); _ = @import("fs/get_app_data_dir.zig"); diff --git a/lib/std/fs/watch.zig b/lib/std/fs/watch.zig index 3180240a72..96fe1538e4 100644 --- a/lib/std/fs/watch.zig +++ b/lib/std/fs/watch.zig @@ -619,7 +619,7 @@ test "write a file, watch it, write it again" { if (true) return error.SkipZigTest; try fs.cwd().makePath(test_tmp_dir); - defer os.deleteTree(test_tmp_dir) catch {}; + defer fs.cwd().deleteTree(test_tmp_dir) catch {}; const allocator = std.heap.page_allocator; return testFsWatch(&allocator); diff --git a/lib/std/hash/auto_hash.zig b/lib/std/hash/auto_hash.zig index 2c6b37e3db..b5d6c528a5 100644 --- a/lib/std/hash/auto_hash.zig +++ b/lib/std/hash/auto_hash.zig @@ -40,7 +40,9 @@ pub fn hashPointer(hasher: var, key: var, comptime strat: HashStrategy) void { .DeepRecursive => hashArray(hasher, key, .DeepRecursive), }, - .Many, .C, => switch (strat) { + .Many, + .C, + => switch (strat) { .Shallow => hash(hasher, @ptrToInt(key), .Shallow), else => @compileError( \\ unknown-length pointers and C pointers cannot be hashed deeply. @@ -236,9 +238,11 @@ test "hash slice shallow" { defer std.testing.allocator.destroy(array1); array1.* = [_]u32{ 1, 2, 3, 4, 5, 6 }; const array2 = [_]u32{ 1, 2, 3, 4, 5, 6 }; - const a = array1[0..]; - const b = array2[0..]; - const c = array1[0..3]; + // TODO audit deep/shallow - maybe it has the wrong behavior with respect to array pointers and slices + var runtime_zero: usize = 0; + const a = array1[runtime_zero..]; + const b = array2[runtime_zero..]; + const c = array1[runtime_zero..3]; testing.expect(testHashShallow(a) == testHashShallow(a)); testing.expect(testHashShallow(a) != testHashShallow(array1)); testing.expect(testHashShallow(a) != testHashShallow(b)); diff --git a/lib/std/hash/siphash.zig b/lib/std/hash/siphash.zig index ccef47c4b2..ebafdd6855 100644 --- a/lib/std/hash/siphash.zig +++ b/lib/std/hash/siphash.zig @@ -39,8 +39,8 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round pub fn init(key: []const u8) Self { assert(key.len >= 16); - const k0 = mem.readIntSliceLittle(u64, key[0..8]); - const k1 = mem.readIntSliceLittle(u64, key[8..16]); + const k0 = mem.readIntLittle(u64, key[0..8]); + const k1 = mem.readIntLittle(u64, key[8..16]); var d = Self{ .v0 = k0 ^ 0x736f6d6570736575, @@ -111,7 +111,7 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round fn round(self: *Self, b: []const u8) void { assert(b.len == 8); - const m = mem.readIntSliceLittle(u64, b[0..]); + const m = mem.readIntLittle(u64, b[0..8]); self.v3 ^= m; // TODO this is a workaround, should be able to supply the value without a separate variable diff --git a/lib/std/hash/wyhash.zig b/lib/std/hash/wyhash.zig index 8fcbbbce4c..8b7edd246f 100644 --- a/lib/std/hash/wyhash.zig +++ b/lib/std/hash/wyhash.zig @@ -11,7 +11,7 @@ const primes = [_]u64{ fn read_bytes(comptime bytes: u8, data: []const u8) u64 { const T = std.meta.IntType(false, 8 * bytes); - return mem.readIntSliceLittle(T, data[0..bytes]); + return mem.readIntLittle(T, data[0..bytes]); } fn read_8bytes_swapped(data: []const u8) u64 { diff --git a/lib/std/io/serialization.zig b/lib/std/io/serialization.zig index 4aa462aab8..4aea4ed892 100644 --- a/lib/std/io/serialization.zig +++ b/lib/std/io/serialization.zig @@ -1,6 +1,10 @@ const std = @import("../std.zig"); const builtin = std.builtin; const io = std.io; +const assert = std.debug.assert; +const math = std.math; +const meta = std.meta; +const trait = meta.trait; pub const Packing = enum { /// Pack data to byte alignment @@ -252,7 +256,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co byte.* = if (t_bit_count < u8_bit_count) v else @truncate(u8, v); } - try self.out_stream.write(&buffer); + try self.out_stream.writeAll(&buffer); } /// Serializes the passed value into the stream diff --git a/lib/std/json.zig b/lib/std/json.zig index f5a72d86da..3dd8088785 100644 --- a/lib/std/json.zig +++ b/lib/std/json.zig @@ -2249,11 +2249,16 @@ pub const StringifyOptions = struct { // TODO: allow picking if []u8 is string or array? }; +pub const StringifyError = error{ + TooMuchData, + DifferentData, +}; + pub fn stringify( value: var, options: StringifyOptions, out_stream: var, -) !void { +) StringifyError!void { const T = @TypeOf(value); switch (@typeInfo(T)) { .Float, .ComptimeFloat => { @@ -2320,9 +2325,15 @@ pub fn stringify( return; }, .Pointer => |ptr_info| switch (ptr_info.size) { - .One => { - // TODO: avoid loops? - return try stringify(value.*, options, out_stream); + .One => switch (@typeInfo(ptr_info.child)) { + .Array => { + const Slice = []const std.meta.Elem(ptr_info.child); + return stringify(@as(Slice, value), options, out_stream); + }, + else => { + // TODO: avoid loops? + return stringify(value.*, options, out_stream); + }, }, // TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972) .Slice => { @@ -2381,9 +2392,7 @@ pub fn stringify( }, else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"), }, - .Array => |info| { - return try stringify(value[0..], options, out_stream); - }, + .Array => return stringify(&value, options, out_stream), else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"), } unreachable; diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index 95d0764f68..8a3dd43727 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -373,6 +373,7 @@ pub const Int = struct { const d = switch (ch) { '0'...'9' => ch - '0', 'a'...'f' => (ch - 'a') + 0xa, + 'A'...'F' => (ch - 'A') + 0xa, else => return error.InvalidCharForDigit, }; @@ -393,8 +394,9 @@ pub const Int = struct { /// Set self from the string representation `value`. /// - /// value must contain only digits <= `base`. Base prefixes are not allowed (e.g. 0x43 should - /// simply be 43). + /// `value` must contain only digits <= `base` and is case insensitive. Base prefixes are + /// not allowed (e.g. 0x43 should simply be 43). Underscores in the input string are + /// ignored and can be used as digit separators. /// /// Returns an error if memory could not be allocated or `value` has invalid digits for the /// requested base. @@ -415,6 +417,9 @@ pub const Int = struct { try self.set(0); for (value[i..]) |ch| { + if (ch == '_') { + continue; + } const d = try charToDigit(ch, base); const ap_d = Int.initFixed(([_]Limb{d})[0..]); @@ -520,13 +525,13 @@ pub const Int = struct { comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: var, - ) FmtError!void { + ) !void { self.assertWritable(); // TODO look at fmt and support other bases // TODO support read-only fixed integers const str = self.toString(self.allocator.?, 10) catch @panic("TODO make this non allocating"); defer self.allocator.?.free(str); - return out_stream.print(str); + return out_stream.writeAll(str); } /// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively. @@ -1582,6 +1587,22 @@ test "big.int string negative" { testing.expect((try a.to(i32)) == -1023); } +test "big.int string set number with underscores" { + var a = try Int.init(testing.allocator); + defer a.deinit(); + + try a.setString(10, "__1_2_0_3_1_7_2_4_1_2_0_____9_1__2__4_7_8_1_2_4_1_2_9_0_8_4_7_1_2_4___"); + testing.expect((try a.to(u128)) == 120317241209124781241290847124); +} + +test "big.int string set case insensitive number" { + var a = try Int.init(testing.allocator); + defer a.deinit(); + + try a.setString(16, "aB_cD_eF"); + testing.expect((try a.to(u32)) == 0xabcdef); +} + test "big.int string set bad char error" { var a = try Int.init(testing.allocator); defer a.deinit(); diff --git a/lib/std/mem.zig b/lib/std/mem.zig index c767765652..fa2794160b 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -116,7 +116,7 @@ pub const Allocator = struct { pub fn allocSentinel(self: *Allocator, comptime Elem: type, n: usize, comptime sentinel: Elem) Error![:sentinel]Elem { var ptr = try self.alloc(Elem, n + 1); ptr[n] = sentinel; - return ptr[0 .. n :sentinel]; + return ptr[0..n :sentinel]; } pub fn alignedAlloc( @@ -496,14 +496,14 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool { return true; } -/// Deprecated. Use `span`. +/// Deprecated. Use `spanZ`. pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T { - return ptr[0..len(ptr) :0]; + return ptr[0..lenZ(ptr) :0]; } -/// Deprecated. Use `span`. +/// Deprecated. Use `spanZ`. pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T { - return ptr[0..len(ptr) :0]; + return ptr[0..lenZ(ptr) :0]; } /// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and @@ -548,6 +548,9 @@ test "Span" { /// returns a slice. If there is a sentinel on the input type, there will be a /// sentinel on the output type. The constness of the output type matches /// the constness of the input type. +/// +/// When there is both a sentinel and an array length or slice length, the +/// length value is used instead of the sentinel. pub fn span(ptr: var) Span(@TypeOf(ptr)) { const Result = Span(@TypeOf(ptr)); const l = len(ptr); @@ -560,20 +563,42 @@ pub fn span(ptr: var) Span(@TypeOf(ptr)) { test "span" { var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; - const ptr = array[0..2 :3].ptr; + const ptr = @as([*:3]u16, array[0..2 :3]); testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 })); testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 })); } +/// Same as `span`, except when there is both a sentinel and an array +/// length or slice length, scans the memory for the sentinel value +/// rather than using the length. +pub fn spanZ(ptr: var) Span(@TypeOf(ptr)) { + const Result = Span(@TypeOf(ptr)); + const l = lenZ(ptr); + if (@typeInfo(Result).Pointer.sentinel) |s| { + return ptr[0..l :s]; + } else { + return ptr[0..l]; + } +} + +test "spanZ" { + var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; + const ptr = @as([*:3]u16, array[0..2 :3]); + testing.expect(eql(u16, spanZ(ptr), &[_]u16{ 1, 2 })); + testing.expect(eql(u16, spanZ(&array), &[_]u16{ 1, 2, 3, 4, 5 })); +} + /// Takes a pointer to an array, an array, a sentinel-terminated pointer, /// or a slice, and returns the length. +/// In the case of a sentinel-terminated array, it uses the array length. +/// For C pointers it assumes it is a pointer-to-many with a 0 sentinel. pub fn len(ptr: var) usize { return switch (@typeInfo(@TypeOf(ptr))) { .Array => |info| info.len, .Pointer => |info| switch (info.size) { .One => switch (@typeInfo(info.child)) { - .Array => |x| x.len, - else => @compileError("invalid type given to std.mem.length"), + .Array => ptr.len, + else => @compileError("invalid type given to std.mem.len"), }, .Many => if (info.sentinel) |sentinel| indexOfSentinel(info.child, sentinel, ptr) @@ -582,7 +607,7 @@ pub fn len(ptr: var) usize { .C => indexOfSentinel(info.child, 0, ptr), .Slice => ptr.len, }, - else => @compileError("invalid type given to std.mem.length"), + else => @compileError("invalid type given to std.mem.len"), }; } @@ -594,9 +619,67 @@ test "len" { testing.expect(len(&array) == 5); testing.expect(len(array[0..3]) == 3); array[2] = 0; - const ptr = array[0..2 :0].ptr; + const ptr = @as([*:0]u16, array[0..2 :0]); testing.expect(len(ptr) == 2); } + { + var array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 }; + testing.expect(len(&array) == 5); + array[2] = 0; + testing.expect(len(&array) == 5); + } +} + +/// Takes a pointer to an array, an array, a sentinel-terminated pointer, +/// or a slice, and returns the length. +/// In the case of a sentinel-terminated array, it scans the array +/// for a sentinel and uses that for the length, rather than using the array length. +/// For C pointers it assumes it is a pointer-to-many with a 0 sentinel. +pub fn lenZ(ptr: var) usize { + return switch (@typeInfo(@TypeOf(ptr))) { + .Array => |info| if (info.sentinel) |sentinel| + indexOfSentinel(info.child, sentinel, &ptr) + else + info.len, + .Pointer => |info| switch (info.size) { + .One => switch (@typeInfo(info.child)) { + .Array => |x| if (x.sentinel) |sentinel| + indexOfSentinel(x.child, sentinel, ptr) + else + ptr.len, + else => @compileError("invalid type given to std.mem.lenZ"), + }, + .Many => if (info.sentinel) |sentinel| + indexOfSentinel(info.child, sentinel, ptr) + else + @compileError("length of pointer with no sentinel"), + .C => indexOfSentinel(info.child, 0, ptr), + .Slice => if (info.sentinel) |sentinel| + indexOfSentinel(info.child, sentinel, ptr.ptr) + else + ptr.len, + }, + else => @compileError("invalid type given to std.mem.lenZ"), + }; +} + +test "lenZ" { + testing.expect(lenZ("aoeu") == 4); + + { + var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; + testing.expect(lenZ(&array) == 5); + testing.expect(lenZ(array[0..3]) == 3); + array[2] = 0; + const ptr = @as([*:0]u16, array[0..2 :0]); + testing.expect(lenZ(ptr) == 2); + } + { + var array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 }; + testing.expect(lenZ(&array) == 5); + array[2] = 0; + testing.expect(lenZ(&array) == 2); + } } pub fn indexOfSentinel(comptime Elem: type, comptime sentinel: Elem, ptr: [*:sentinel]const Elem) usize { @@ -810,8 +893,7 @@ pub const readIntBig = switch (builtin.endian) { pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T { const n = @divExact(T.bit_count, 8); assert(bytes.len >= n); - // TODO https://github.com/ziglang/zig/issues/863 - return readIntNative(T, @ptrCast(*const [n]u8, bytes.ptr)); + return readIntNative(T, bytes[0..n]); } /// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0 @@ -849,8 +931,7 @@ pub fn readInt(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8, en pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T { const n = @divExact(T.bit_count, 8); assert(bytes.len >= n); - // TODO https://github.com/ziglang/zig/issues/863 - return readInt(T, @ptrCast(*const [n]u8, bytes.ptr), endian); + return readInt(T, bytes[0..n], endian); } test "comptime read/write int" { @@ -1572,24 +1653,24 @@ pub fn nativeToBig(comptime T: type, x: T) T { } fn AsBytesReturnType(comptime P: type) type { - if (comptime !trait.isSingleItemPtr(P)) + if (!trait.isSingleItemPtr(P)) @compileError("expected single item pointer, passed " ++ @typeName(P)); - const size = @as(usize, @sizeOf(meta.Child(P))); - const alignment = comptime meta.alignment(P); + const size = @sizeOf(meta.Child(P)); + const alignment = meta.alignment(P); if (alignment == 0) { - if (comptime trait.isConstPtr(P)) + if (trait.isConstPtr(P)) return *const [size]u8; return *[size]u8; } - if (comptime trait.isConstPtr(P)) + if (trait.isConstPtr(P)) return *align(alignment) const [size]u8; return *align(alignment) [size]u8; } -///Given a pointer to a single item, returns a slice of the underlying bytes, preserving constness. +/// Given a pointer to a single item, returns a slice of the underlying bytes, preserving constness. pub fn asBytes(ptr: var) AsBytesReturnType(@TypeOf(ptr)) { const P = @TypeOf(ptr); return @ptrCast(AsBytesReturnType(P), ptr); @@ -1736,34 +1817,50 @@ fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type { } pub fn bytesAsSlice(comptime T: type, bytes: var) BytesAsSliceReturnType(T, @TypeOf(bytes)) { - const bytesSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(bytes))) bytes[0..] else bytes; - // let's not give an undefined pointer to @ptrCast // it may be equal to zero and fail a null check - if (bytesSlice.len == 0) { + if (bytes.len == 0) { return &[0]T{}; } - const bytesType = @TypeOf(bytesSlice); - const alignment = comptime meta.alignment(bytesType); + const Bytes = @TypeOf(bytes); + const alignment = comptime meta.alignment(Bytes); - const castTarget = if (comptime trait.isConstPtr(bytesType)) [*]align(alignment) const T else [*]align(alignment) T; + const cast_target = if (comptime trait.isConstPtr(Bytes)) [*]align(alignment) const T else [*]align(alignment) T; - return @ptrCast(castTarget, bytesSlice.ptr)[0..@divExact(bytes.len, @sizeOf(T))]; + return @ptrCast(cast_target, bytes)[0..@divExact(bytes.len, @sizeOf(T))]; } test "bytesAsSlice" { - const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; - const slice = bytesAsSlice(u16, bytes[0..]); - testing.expect(slice.len == 2); - testing.expect(bigToNative(u16, slice[0]) == 0xDEAD); - testing.expect(bigToNative(u16, slice[1]) == 0xBEEF); + { + const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; + const slice = bytesAsSlice(u16, bytes[0..]); + testing.expect(slice.len == 2); + testing.expect(bigToNative(u16, slice[0]) == 0xDEAD); + testing.expect(bigToNative(u16, slice[1]) == 0xBEEF); + } + { + const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; + var runtime_zero: usize = 0; + const slice = bytesAsSlice(u16, bytes[runtime_zero..]); + testing.expect(slice.len == 2); + testing.expect(bigToNative(u16, slice[0]) == 0xDEAD); + testing.expect(bigToNative(u16, slice[1]) == 0xBEEF); + } } test "bytesAsSlice keeps pointer alignment" { - var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 }; - const numbers = bytesAsSlice(u32, bytes[0..]); - comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32); + { + var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 }; + const numbers = bytesAsSlice(u32, bytes[0..]); + comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32); + } + { + var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 }; + var runtime_zero: usize = 0; + const numbers = bytesAsSlice(u32, bytes[runtime_zero..]); + comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32); + } } test "bytesAsSlice on a packed struct" { @@ -1799,21 +1896,19 @@ fn SliceAsBytesReturnType(comptime sliceType: type) type { } pub fn sliceAsBytes(slice: var) SliceAsBytesReturnType(@TypeOf(slice)) { - const actualSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(slice))) slice[0..] else slice; - const actualSliceTypeInfo = @typeInfo(@TypeOf(actualSlice)).Pointer; + const Slice = @TypeOf(slice); // let's not give an undefined pointer to @ptrCast // it may be equal to zero and fail a null check - if (actualSlice.len == 0 and actualSliceTypeInfo.sentinel == null) { + if (slice.len == 0 and comptime meta.sentinel(Slice) == null) { return &[0]u8{}; } - const sliceType = @TypeOf(actualSlice); - const alignment = comptime meta.alignment(sliceType); + const alignment = comptime meta.alignment(Slice); - const castTarget = if (comptime trait.isConstPtr(sliceType)) [*]align(alignment) const u8 else [*]align(alignment) u8; + const cast_target = if (comptime trait.isConstPtr(Slice)) [*]align(alignment) const u8 else [*]align(alignment) u8; - return @ptrCast(castTarget, actualSlice.ptr)[0 .. actualSlice.len * @sizeOf(comptime meta.Child(sliceType))]; + return @ptrCast(cast_target, slice)[0 .. slice.len * @sizeOf(meta.Elem(Slice))]; } test "sliceAsBytes" { @@ -1883,39 +1978,6 @@ test "sliceAsBytes and bytesAsSlice back" { testing.expect(bytes[11] == math.maxInt(u8)); } -fn SubArrayPtrReturnType(comptime T: type, comptime length: usize) type { - if (trait.isConstPtr(T)) - return *const [length]meta.Child(meta.Child(T)); - return *[length]meta.Child(meta.Child(T)); -} - -/// Given a pointer to an array, returns a pointer to a portion of that array, preserving constness. -/// TODO this will be obsoleted by https://github.com/ziglang/zig/issues/863 -pub fn subArrayPtr( - ptr: var, - comptime start: usize, - comptime length: usize, -) SubArrayPtrReturnType(@TypeOf(ptr), length) { - assert(start + length <= ptr.*.len); - - const ReturnType = SubArrayPtrReturnType(@TypeOf(ptr), length); - const T = meta.Child(meta.Child(@TypeOf(ptr))); - return @ptrCast(ReturnType, &ptr[start]); -} - -test "subArrayPtr" { - const a1: [6]u8 = "abcdef".*; - const sub1 = subArrayPtr(&a1, 2, 3); - testing.expect(eql(u8, sub1, "cde")); - - var a2: [6]u8 = "abcdef".*; - var sub2 = subArrayPtr(&a2, 2, 3); - - testing.expect(eql(u8, sub2, "cde")); - sub2[1] = 'X'; - testing.expect(eql(u8, &a2, "abcXef")); -} - /// Round an address up to the nearest aligned address /// The alignment must be a power of 2 and greater than 0. pub fn alignForward(addr: usize, alignment: usize) usize { diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 65809abb5c..7343cfc51a 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -104,7 +104,7 @@ pub fn Child(comptime T: type) type { .Array => |info| info.child, .Pointer => |info| info.child, .Optional => |info| info.child, - else => @compileError("Expected pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"), + else => @compileError("Expected pointer, optional, or array type, found '" ++ @typeName(T) ++ "'"), }; } @@ -115,30 +115,65 @@ test "std.meta.Child" { testing.expect(Child(?u8) == u8); } -/// Given a type with a sentinel e.g. `[:0]u8`, returns the sentinel -pub fn Sentinel(comptime T: type) Child(T) { - // comptime asserts that ptr has a sentinel +/// Given a "memory span" type, returns the "element type". +pub fn Elem(comptime T: type) type { switch (@typeInfo(T)) { - .Array => |arrayInfo| { - return comptime arrayInfo.sentinel.?; + .Array => |info| return info.child, + .Pointer => |info| switch (info.size) { + .One => switch (@typeInfo(info.child)) { + .Array => |array_info| return array_info.child, + else => {}, + }, + .Many, .C, .Slice => return info.child, }, - .Pointer => |ptrInfo| { - switch (ptrInfo.size) { - .Many, .Slice => { - return comptime ptrInfo.sentinel.?; + else => {}, + } + @compileError("Expected pointer, slice, or array, found '" ++ @typeName(T) ++ "'"); +} + +test "std.meta.Elem" { + testing.expect(Elem([1]u8) == u8); + testing.expect(Elem([*]u8) == u8); + testing.expect(Elem([]u8) == u8); + testing.expect(Elem(*[10]u8) == u8); +} + +/// Given a type which can have a sentinel e.g. `[:0]u8`, returns the sentinel value, +/// or `null` if there is not one. +/// Types which cannot possibly have a sentinel will be a compile error. +pub fn sentinel(comptime T: type) ?Elem(T) { + switch (@typeInfo(T)) { + .Array => |info| return info.sentinel, + .Pointer => |info| { + switch (info.size) { + .Many, .Slice => return info.sentinel, + .One => switch (@typeInfo(info.child)) { + .Array => |array_info| return array_info.sentinel, + else => {}, }, else => {}, } }, else => {}, } - @compileError("not a sentinel type, found '" ++ @typeName(T) ++ "'"); + @compileError("type '" ++ @typeName(T) ++ "' cannot possibly have a sentinel"); } -test "std.meta.Sentinel" { - testing.expectEqual(@as(u8, 0), Sentinel([:0]u8)); - testing.expectEqual(@as(u8, 0), Sentinel([*:0]u8)); - testing.expectEqual(@as(u8, 0), Sentinel([5:0]u8)); +test "std.meta.sentinel" { + testSentinel(); + comptime testSentinel(); +} + +fn testSentinel() void { + testing.expectEqual(@as(u8, 0), sentinel([:0]u8).?); + testing.expectEqual(@as(u8, 0), sentinel([*:0]u8).?); + testing.expectEqual(@as(u8, 0), sentinel([5:0]u8).?); + testing.expectEqual(@as(u8, 0), sentinel(*const [5:0]u8).?); + + testing.expect(sentinel([]u8) == null); + testing.expect(sentinel([*]u8) == null); + testing.expect(sentinel([5]u8) == null); + testing.expect(sentinel(*const [5]u8) == null); } pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout { diff --git a/lib/std/meta/trait.zig b/lib/std/meta/trait.zig index c0fb8c5025..c99e1389f4 100644 --- a/lib/std/meta/trait.zig +++ b/lib/std/meta/trait.zig @@ -230,9 +230,10 @@ pub fn isSingleItemPtr(comptime T: type) bool { test "std.meta.trait.isSingleItemPtr" { const array = [_]u8{0} ** 10; - testing.expect(isSingleItemPtr(@TypeOf(&array[0]))); - testing.expect(!isSingleItemPtr(@TypeOf(array))); - testing.expect(!isSingleItemPtr(@TypeOf(array[0..1]))); + comptime testing.expect(isSingleItemPtr(@TypeOf(&array[0]))); + comptime testing.expect(!isSingleItemPtr(@TypeOf(array))); + var runtime_zero: usize = 0; + testing.expect(!isSingleItemPtr(@TypeOf(array[runtime_zero..1]))); } pub fn isManyItemPtr(comptime T: type) bool { @@ -259,7 +260,8 @@ pub fn isSlice(comptime T: type) bool { test "std.meta.trait.isSlice" { const array = [_]u8{0} ** 10; - testing.expect(isSlice(@TypeOf(array[0..]))); + var runtime_zero: usize = 0; + testing.expect(isSlice(@TypeOf(array[runtime_zero..]))); testing.expect(!isSlice(@TypeOf(array))); testing.expect(!isSlice(@TypeOf(&array[0]))); } @@ -276,7 +278,7 @@ pub fn isIndexable(comptime T: type) bool { test "std.meta.trait.isIndexable" { const array = [_]u8{0} ** 10; - const slice = array[0..]; + const slice = @as([]const u8, &array); testing.expect(isIndexable(@TypeOf(array))); testing.expect(isIndexable(@TypeOf(&array))); diff --git a/lib/std/net.zig b/lib/std/net.zig index c2328b9bd0..0a789b0dde 100644 --- a/lib/std/net.zig +++ b/lib/std/net.zig @@ -612,8 +612,7 @@ fn linuxLookupName( } else { mem.copy(u8, &sa6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff"); mem.copy(u8, &da6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff"); - // TODO https://github.com/ziglang/zig/issues/863 - mem.writeIntNative(u32, @ptrCast(*[4]u8, da6.addr[12..].ptr), addr.addr.in.addr); + mem.writeIntNative(u32, da6.addr[12..], addr.addr.in.addr); da4.addr = addr.addr.in.addr; da = @ptrCast(*os.sockaddr, &da4); dalen = @sizeOf(os.sockaddr_in); @@ -821,7 +820,7 @@ fn linuxLookupNameFromHosts( // Skip to the delimiter in the stream, to fix parsing try stream.skipUntilDelimiterOrEof('\n'); // Use the truncated line. A truncated comment or hostname will be handled correctly. - break :blk line_buf[0..]; + break :blk &line_buf; }, else => |e| return e, }) |line| { @@ -958,7 +957,10 @@ fn linuxLookupNameFromDns( } } - var ap = [2][]u8{ apbuf[0][0..0], apbuf[1][0..0] }; + var ap = [2][]u8{ apbuf[0], apbuf[1] }; + ap[0].len = 0; + ap[1].len = 0; + try resMSendRc(qp[0..nq], ap[0..nq], apbuf[0..nq], rc); var i: usize = 0; diff --git a/lib/std/os.zig b/lib/std/os.zig index f6fdb9482f..2dec2c4c1d 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -461,13 +461,11 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void { ); switch (rc) { - .SUCCESS => {}, + .SUCCESS => return, .INVALID_HANDLE => unreachable, // Handle not open for writing .ACCESS_DENIED => return error.CannotTruncate, else => return windows.unexpectedStatus(rc), } - - return; } while (true) { @@ -852,6 +850,7 @@ pub const OpenError = error{ /// Open and possibly create a file. Keeps trying if it gets interrupted. /// See also `openC`. +/// TODO support windows pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t { const file_path_c = try toPosixPath(file_path); return openC(&file_path_c, flags, perm); @@ -859,6 +858,7 @@ pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t { /// Open and possibly create a file. Keeps trying if it gets interrupted. /// See also `open`. +/// TODO support windows pub fn openC(file_path: [*:0]const u8, flags: u32, perm: usize) OpenError!fd_t { while (true) { const rc = system.open(file_path, flags, perm); @@ -892,6 +892,7 @@ pub fn openC(file_path: [*:0]const u8, flags: u32, perm: usize) OpenError!fd_t { /// Open and possibly create a file. Keeps trying if it gets interrupted. /// `file_path` is relative to the open directory handle `dir_fd`. /// See also `openatC`. +/// TODO support windows pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) OpenError!fd_t { const file_path_c = try toPosixPath(file_path); return openatC(dir_fd, &file_path_c, flags, mode); @@ -900,6 +901,7 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope /// Open and possibly create a file. Keeps trying if it gets interrupted. /// `file_path` is relative to the open directory handle `dir_fd`. /// See also `openat`. +/// TODO support windows pub fn openatC(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t) OpenError!fd_t { while (true) { const rc = system.openat(dir_fd, file_path, flags, mode); @@ -1140,24 +1142,6 @@ pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) allocator.free(envp_buf); } -pub const FcntlError = error{ - /// The file is locked by another process - FileLocked, -} || UnexpectedError; - -/// Attempts to get lock the file, blocking if the file is locked. -pub fn fcntl(fd: fd_t, cmd: i32, flock_p: *Flock) FcntlError!void { - while (true) { - switch (errno(system.fcntl(fd, cmd, flock_p))) { - 0 => return, - EACCES => return error.FileLocked, - EAGAIN => return error.FileLocked, - EINTR => continue, - else => |err| return unexpectedErrno(err), - } - } -} - /// Get an environment variable. /// See also `getenvZ`. pub fn getenv(key: []const u8) ?[]const u8 { @@ -1545,6 +1529,9 @@ const RenameError = error{ RenameAcrossMountPoints, InvalidUtf8, BadPathName, + NoDevice, + SharingViolation, + PipeBusy, } || UnexpectedError; /// Change the name or location of a file. @@ -1598,6 +1585,113 @@ pub fn renameW(old_path: [*:0]const u16, new_path: [*:0]const u16) RenameError!v return windows.MoveFileExW(old_path, new_path, flags); } +/// Change the name or location of a file based on an open directory handle. +pub fn renameat( + old_dir_fd: fd_t, + old_path: []const u8, + new_dir_fd: fd_t, + new_path: []const u8, +) RenameError!void { + if (builtin.os.tag == .windows) { + const old_path_w = try windows.sliceToPrefixedFileW(old_path); + const new_path_w = try windows.sliceToPrefixedFileW(new_path); + return renameatW(old_dir_fd, &old_path_w, new_dir_fd, &new_path_w, windows.TRUE); + } else { + const old_path_c = try toPosixPath(old_path); + const new_path_c = try toPosixPath(new_path); + return renameatZ(old_dir_fd, &old_path_c, new_dir_fd, &new_path_c); + } +} + +/// Same as `renameat` except the parameters are null-terminated byte arrays. +pub fn renameatZ( + old_dir_fd: fd_t, + old_path: [*:0]const u8, + new_dir_fd: fd_t, + new_path: [*:0]const u8, +) RenameError!void { + if (builtin.os.tag == .windows) { + const old_path_w = try windows.cStrToPrefixedFileW(old_path); + const new_path_w = try windows.cStrToPrefixedFileW(new_path); + return renameatW(old_dir_fd, &old_path_w, new_dir_fd, &new_path_w, windows.TRUE); + } + + switch (errno(system.renameat(old_dir_fd, old_path, new_dir_fd, new_path))) { + 0 => return, + EACCES => return error.AccessDenied, + EPERM => return error.AccessDenied, + EBUSY => return error.FileBusy, + EDQUOT => return error.DiskQuota, + EFAULT => unreachable, + EINVAL => unreachable, + EISDIR => return error.IsDir, + ELOOP => return error.SymLinkLoop, + EMLINK => return error.LinkQuotaExceeded, + ENAMETOOLONG => return error.NameTooLong, + ENOENT => return error.FileNotFound, + ENOTDIR => return error.NotDir, + ENOMEM => return error.SystemResources, + ENOSPC => return error.NoSpaceLeft, + EEXIST => return error.PathAlreadyExists, + ENOTEMPTY => return error.PathAlreadyExists, + EROFS => return error.ReadOnlyFileSystem, + EXDEV => return error.RenameAcrossMountPoints, + else => |err| return unexpectedErrno(err), + } +} + +/// Same as `renameat` except the parameters are null-terminated UTF16LE encoded byte arrays. +/// Assumes target is Windows. +/// TODO these args can actually be slices when using ntdll. audit the rest of the W functions too. +pub fn renameatW( + old_dir_fd: fd_t, + old_path: [*:0]const u16, + new_dir_fd: fd_t, + new_path_w: [*:0]const u16, + ReplaceIfExists: windows.BOOLEAN, +) RenameError!void { + const access_mask = windows.SYNCHRONIZE | windows.GENERIC_WRITE | windows.DELETE; + const src_fd = try windows.OpenFileW(old_dir_fd, old_path, null, access_mask, windows.FILE_OPEN); + defer windows.CloseHandle(src_fd); + + const struct_buf_len = @sizeOf(windows.FILE_RENAME_INFORMATION) + (MAX_PATH_BYTES - 1); + var rename_info_buf: [struct_buf_len]u8 align(@alignOf(windows.FILE_RENAME_INFORMATION)) = undefined; + const new_path = mem.span(new_path_w); + const struct_len = @sizeOf(windows.FILE_RENAME_INFORMATION) - 1 + new_path.len * 2; + if (struct_len > struct_buf_len) return error.NameTooLong; + + const rename_info = @ptrCast(*windows.FILE_RENAME_INFORMATION, &rename_info_buf); + + rename_info.* = .{ + .ReplaceIfExists = ReplaceIfExists, + .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(new_path_w)) null else new_dir_fd, + .FileNameLength = @intCast(u32, new_path.len * 2), // already checked error.NameTooLong + .FileName = undefined, + }; + std.mem.copy(u16, @as([*]u16, &rename_info.FileName)[0..new_path.len], new_path); + + var io_status_block: windows.IO_STATUS_BLOCK = undefined; + + const rc = windows.ntdll.NtSetInformationFile( + src_fd, + &io_status_block, + rename_info, + @intCast(u32, struct_len), // already checked for error.NameTooLong + .FileRenameInformation, + ); + + switch (rc) { + .SUCCESS => return, + .INVALID_HANDLE => unreachable, + .INVALID_PARAMETER => unreachable, + .OBJECT_PATH_SYNTAX_BAD => unreachable, + .ACCESS_DENIED => return error.AccessDenied, + .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, + .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, + else => return windows.unexpectedStatus(rc), + } +} + pub const MakeDirError = error{ AccessDenied, DiskQuota, @@ -2090,7 +2184,7 @@ const ListenError = error{ OperationNotSupported, } || UnexpectedError; -pub fn listen(sockfd: i32, backlog: u32) ListenError!void { +pub fn listen(sockfd: fd_t, backlog: u32) ListenError!void { const rc = system.listen(sockfd, backlog); switch (errno(rc)) { 0 => return, @@ -2381,7 +2475,7 @@ pub fn connect(sockfd: fd_t, sock_addr: *const sockaddr, len: socklen_t) Connect } } -pub fn getsockoptError(sockfd: i32) ConnectError!void { +pub fn getsockoptError(sockfd: fd_t) ConnectError!void { var err_code: u32 = undefined; var size: u32 = @sizeOf(u32); const rc = system.getsockopt(sockfd, SOL_SOCKET, SO_ERROR, @ptrCast([*]u8, &err_code), &size); @@ -3069,6 +3163,31 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 { } } +pub const FcntlError = error{ + PermissionDenied, + FileBusy, + ProcessFdQuotaExceeded, + Locked, +} || UnexpectedError; + +pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) FcntlError!usize { + while (true) { + const rc = system.fcntl(fd, cmd, arg); + switch (errno(rc)) { + 0 => return @intCast(usize, rc), + EINTR => continue, + EACCES => return error.Locked, + EBADF => unreachable, + EBUSY => return error.FileBusy, + EINVAL => unreachable, // invalid parameters + EPERM => return error.PermissionDenied, + EMFILE => return error.ProcessFdQuotaExceeded, + ENOTDIR => unreachable, // invalid parameter + else => |err| return unexpectedErrno(err), + } + } +} + pub const RealPathError = error{ FileNotFound, AccessDenied, @@ -3143,6 +3262,7 @@ pub fn realpathC(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealP } /// Same as `realpath` except `pathname` is null-terminated and UTF16LE-encoded. +/// TODO use ntdll for better semantics pub fn realpathW(pathname: [*:0]const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { const h_file = try windows.CreateFileW( pathname, diff --git a/lib/std/os/bits/dragonfly.zig b/lib/std/os/bits/dragonfly.zig index 27b2733b76..4a9b51d472 100644 --- a/lib/std/os/bits/dragonfly.zig +++ b/lib/std/os/bits/dragonfly.zig @@ -283,6 +283,8 @@ pub const F_LOCK = 1; pub const F_TLOCK = 2; pub const F_TEST = 3; +pub const FD_CLOEXEC = 1; + pub const AT_FDCWD = -328243; pub const AT_SYMLINK_NOFOLLOW = 1; pub const AT_REMOVEDIR = 2; diff --git a/lib/std/os/bits/freebsd.zig b/lib/std/os/bits/freebsd.zig index f0490ee23a..1417381051 100644 --- a/lib/std/os/bits/freebsd.zig +++ b/lib/std/os/bits/freebsd.zig @@ -372,6 +372,8 @@ pub const F_GETOWN_EX = 16; pub const F_GETOWNER_UIDS = 17; +pub const FD_CLOEXEC = 1; + pub const SEEK_SET = 0; pub const SEEK_CUR = 1; pub const SEEK_END = 2; diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index 2a58c14490..89364909c9 100644 --- a/lib/std/os/bits/linux.zig +++ b/lib/std/os/bits/linux.zig @@ -136,6 +136,8 @@ pub const MAP_FIXED_NOREPLACE = 0x100000; /// For anonymous mmap, memory could be uninitialized pub const MAP_UNINITIALIZED = 0x4000000; +pub const FD_CLOEXEC = 1; + pub const F_OK = 0; pub const X_OK = 1; pub const W_OK = 2; diff --git a/lib/std/os/bits/netbsd.zig b/lib/std/os/bits/netbsd.zig index 4599baddff..d76ef8ea15 100644 --- a/lib/std/os/bits/netbsd.zig +++ b/lib/std/os/bits/netbsd.zig @@ -327,6 +327,8 @@ pub const F_RDLCK = 1; pub const F_WRLCK = 3; pub const F_UNLCK = 2; +pub const FD_CLOEXEC = 1; + pub const SEEK_SET = 0; pub const SEEK_CUR = 1; pub const SEEK_END = 2; diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index f47b0b8e3a..ae48d831cf 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -219,10 +219,6 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, of } } -pub fn fcntl(fd: fd_t, cmd: i32, arg: ?*c_void) usize { - return syscall3(SYS_fcntl, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, cmd)), @ptrToInt(arg)); -} - pub fn mprotect(address: [*]const u8, length: usize, protection: usize) usize { return syscall3(SYS_mprotect, @ptrToInt(address), length, protection); } @@ -469,17 +465,17 @@ pub fn renameat(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const return syscall4( SYS_renameat, @bitCast(usize, @as(isize, oldfd)), - @ptrToInt(old), + @ptrToInt(oldpath), @bitCast(usize, @as(isize, newfd)), - @ptrToInt(new), + @ptrToInt(newpath), ); } else { return syscall5( SYS_renameat2, @bitCast(usize, @as(isize, oldfd)), - @ptrToInt(old), + @ptrToInt(oldpath), @bitCast(usize, @as(isize, newfd)), - @ptrToInt(new), + @ptrToInt(newpath), 0, ); } @@ -592,6 +588,10 @@ pub fn waitpid(pid: pid_t, status: *u32, flags: u32) usize { return syscall4(SYS_wait4, @bitCast(usize, @as(isize, pid)), @ptrToInt(status), flags, 0); } +pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) usize { + return syscall3(SYS_fcntl, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, cmd)), arg); +} + var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime); // We must follow the C calling convention when we call into the VDSO diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index 1ef6798b50..154932d9c5 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -1,7 +1,8 @@ const std = @import("../std.zig"); const os = std.os; const testing = std.testing; -const expect = std.testing.expect; +const expect = testing.expect; +const expectEqual = testing.expectEqual; const io = std.io; const fs = std.fs; const mem = std.mem; @@ -19,8 +20,8 @@ test "makePath, put some files in it, deleteTree" { try fs.cwd().makePath("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c"); try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c" ++ fs.path.sep_str ++ "file.txt", "nonsense"); try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah"); - try fs.deleteTree("os_test_tmp"); - if (fs.cwd().openDirTraverse("os_test_tmp")) |dir| { + try fs.cwd().deleteTree("os_test_tmp"); + if (fs.cwd().openDir("os_test_tmp", .{})) |dir| { @panic("expected error"); } else |err| { expect(err == error.FileNotFound); @@ -37,7 +38,7 @@ test "access file" { try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", ""); try os.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", os.F_OK); - try fs.deleteTree("os_test_tmp"); + try fs.cwd().deleteTree("os_test_tmp"); } fn testThreadIdFn(thread_id: *Thread.Id) void { @@ -46,9 +47,9 @@ fn testThreadIdFn(thread_id: *Thread.Id) void { test "sendfile" { try fs.cwd().makePath("os_test_tmp"); - defer fs.deleteTree("os_test_tmp") catch {}; + defer fs.cwd().deleteTree("os_test_tmp") catch {}; - var dir = try fs.cwd().openDirList("os_test_tmp"); + var dir = try fs.cwd().openDir("os_test_tmp", .{}); defer dir.close(); const line1 = "line1\n"; @@ -112,14 +113,16 @@ test "fs.copyFile" { const dest_file = "tmp_test_copy_file2.txt"; const dest_file2 = "tmp_test_copy_file3.txt"; - try fs.cwd().writeFile(src_file, data); - defer fs.cwd().deleteFile(src_file) catch {}; + const cwd = fs.cwd(); - try fs.copyFile(src_file, dest_file); - defer fs.cwd().deleteFile(dest_file) catch {}; + try cwd.writeFile(src_file, data); + defer cwd.deleteFile(src_file) catch {}; - try fs.copyFileMode(src_file, dest_file2, File.default_mode); - defer fs.cwd().deleteFile(dest_file2) catch {}; + try cwd.copyFile(src_file, cwd, dest_file, .{}); + defer cwd.deleteFile(dest_file) catch {}; + + try cwd.copyFile(src_file, cwd, dest_file2, .{ .override_mode = File.default_mode }); + defer cwd.deleteFile(dest_file2) catch {}; try expectFileContents(dest_file, data); try expectFileContents(dest_file2, data); @@ -446,3 +449,32 @@ test "getenv" { expect(os.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null); } } + +test "fcntl" { + if (builtin.os.tag == .windows) + return error.SkipZigTest; + + const test_out_file = "os_tmp_test"; + + const file = try fs.cwd().createFile(test_out_file, .{}); + defer { + file.close(); + fs.cwd().deleteFile(test_out_file) catch {}; + } + + // Note: The test assumes createFile opens the file with O_CLOEXEC + { + const flags = try os.fcntl(file.handle, os.F_GETFD, 0); + expect((flags & os.FD_CLOEXEC) != 0); + } + { + _ = try os.fcntl(file.handle, os.F_SETFD, 0); + const flags = try os.fcntl(file.handle, os.F_GETFD, 0); + expect((flags & os.FD_CLOEXEC) == 0); + } + { + _ = try os.fcntl(file.handle, os.F_SETFD, os.FD_CLOEXEC); + const flags = try os.fcntl(file.handle, os.F_GETFD, 0); + expect((flags & os.FD_CLOEXEC) != 0); + } +} diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 6c9a1f24b7..813a77c275 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -88,6 +88,82 @@ pub fn CreateFileW( return result; } +pub const OpenError = error{ + IsDir, + FileNotFound, + NoDevice, + SharingViolation, + AccessDenied, + PipeBusy, + PathAlreadyExists, + Unexpected, + NameTooLong, +}; + +/// TODO rename to CreateFileW +/// TODO actually we don't need the path parameter to be null terminated +pub fn OpenFileW( + dir: ?HANDLE, + sub_path_w: [*:0]const u16, + sa: ?*SECURITY_ATTRIBUTES, + access_mask: ACCESS_MASK, + creation: ULONG, +) OpenError!HANDLE { + if (sub_path_w[0] == '.' and sub_path_w[1] == 0) { + return error.IsDir; + } + if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) { + return error.IsDir; + } + + var result: HANDLE = undefined; + + const path_len_bytes = math.cast(u16, mem.toSliceConst(u16, sub_path_w).len * 2) catch |err| switch (err) { + error.Overflow => return error.NameTooLong, + }; + var nt_name = UNICODE_STRING{ + .Length = path_len_bytes, + .MaximumLength = path_len_bytes, + .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)), + }; + var attr = OBJECT_ATTRIBUTES{ + .Length = @sizeOf(OBJECT_ATTRIBUTES), + .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w)) null else dir, + .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here. + .ObjectName = &nt_name, + .SecurityDescriptor = if (sa) |ptr| ptr.lpSecurityDescriptor else null, + .SecurityQualityOfService = null, + }; + var io: IO_STATUS_BLOCK = undefined; + const rc = ntdll.NtCreateFile( + &result, + access_mask, + &attr, + &io, + null, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, + creation, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, + null, + 0, + ); + switch (rc) { + .SUCCESS => return result, + .OBJECT_NAME_INVALID => unreachable, + .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, + .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, + .NO_MEDIA_IN_DEVICE => return error.NoDevice, + .INVALID_PARAMETER => unreachable, + .SHARING_VIOLATION => return error.SharingViolation, + .ACCESS_DENIED => return error.AccessDenied, + .PIPE_BUSY => return error.PipeBusy, + .OBJECT_PATH_SYNTAX_BAD => unreachable, + .OBJECT_NAME_COLLISION => return error.PathAlreadyExists, + else => return unexpectedStatus(rc), + } +} + pub const CreatePipeError = error{Unexpected}; pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) CreatePipeError!void { @@ -1200,7 +1276,15 @@ pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError { // 614 is the length of the longest windows error desciption var buf_u16: [614]u16 = undefined; var buf_u8: [614]u8 = undefined; - var len = kernel32.FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, null, err, MAKELANGID(LANG.NEUTRAL, SUBLANG.DEFAULT), buf_u16[0..].ptr, buf_u16.len / @sizeOf(TCHAR), null); + const len = kernel32.FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + null, + err, + MAKELANGID(LANG.NEUTRAL, SUBLANG.DEFAULT), + &buf_u16, + buf_u16.len / @sizeOf(TCHAR), + null, + ); _ = std.unicode.utf16leToUtf8(&buf_u8, buf_u16[0..len]) catch unreachable; std.debug.warn("error.Unexpected: GetLastError({}): {}\n", .{ @enumToInt(err), buf_u8[0..len] }); std.debug.dumpCurrentStackTrace(null); diff --git a/lib/std/os/windows/bits.zig b/lib/std/os/windows/bits.zig index 1e49b903cb..16cc6d7441 100644 --- a/lib/std/os/windows/bits.zig +++ b/lib/std/os/windows/bits.zig @@ -242,6 +242,13 @@ pub const FILE_NAME_INFORMATION = extern struct { FileName: [1]WCHAR, }; +pub const FILE_RENAME_INFORMATION = extern struct { + ReplaceIfExists: BOOLEAN, + RootDirectory: ?HANDLE, + FileNameLength: ULONG, + FileName: [1]WCHAR, +}; + pub const IO_STATUS_BLOCK = extern struct { // "DUMMYUNIONNAME" expands to "u" u: extern union { diff --git a/lib/std/rand.zig b/lib/std/rand.zig index 31891f5f0e..ede46e3065 100644 --- a/lib/std/rand.zig +++ b/lib/std/rand.zig @@ -5,7 +5,7 @@ // ``` // var buf: [8]u8 = undefined; // try std.crypto.randomBytes(buf[0..]); -// const seed = mem.readIntSliceLittle(u64, buf[0..8]); +// const seed = mem.readIntLittle(u64, buf[0..8]); // // var r = DefaultPrng.init(seed); // diff --git a/lib/std/special/compiler_rt/floatundisf.zig b/lib/std/special/compiler_rt/floatundisf.zig index 41ff02daee..ff242721d6 100644 --- a/lib/std/special/compiler_rt/floatundisf.zig +++ b/lib/std/special/compiler_rt/floatundisf.zig @@ -69,23 +69,23 @@ test "floatundisf" { test__floatundisf(0, 0.0); test__floatundisf(1, 1.0); test__floatundisf(2, 2.0); - test__floatundisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62F); - test__floatundisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62F); - test__floatundisf(0x8000008000000000, 0x1p+63F); - test__floatundisf(0x8000010000000000, 0x1.000002p+63F); - test__floatundisf(0x8000000000000000, 0x1p+63F); - test__floatundisf(0x8000000000000001, 0x1p+63F); - test__floatundisf(0xFFFFFFFFFFFFFFFE, 0x1p+64F); - test__floatundisf(0xFFFFFFFFFFFFFFFF, 0x1p+64F); - test__floatundisf(0x0007FB72E8000000, 0x1.FEDCBAp+50F); - test__floatundisf(0x0007FB72EA000000, 0x1.FEDCBAp+50F); - test__floatundisf(0x0007FB72EB000000, 0x1.FEDCBAp+50F); - test__floatundisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50F); - test__floatundisf(0x0007FB72EC000000, 0x1.FEDCBCp+50F); - test__floatundisf(0x0007FB72E8000001, 0x1.FEDCBAp+50F); - test__floatundisf(0x0007FB72E6000000, 0x1.FEDCBAp+50F); - test__floatundisf(0x0007FB72E7000000, 0x1.FEDCBAp+50F); - test__floatundisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50F); - test__floatundisf(0x0007FB72E4000001, 0x1.FEDCBAp+50F); - test__floatundisf(0x0007FB72E4000000, 0x1.FEDCB8p+50F); + test__floatundisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + test__floatundisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + test__floatundisf(0x8000008000000000, 0x1p+63); + test__floatundisf(0x8000010000000000, 0x1.000002p+63); + test__floatundisf(0x8000000000000000, 0x1p+63); + test__floatundisf(0x8000000000000001, 0x1p+63); + test__floatundisf(0xFFFFFFFFFFFFFFFE, 0x1p+64); + test__floatundisf(0xFFFFFFFFFFFFFFFF, 0x1p+64); + test__floatundisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + test__floatundisf(0x0007FB72EA000000, 0x1.FEDCBAp+50); + test__floatundisf(0x0007FB72EB000000, 0x1.FEDCBAp+50); + test__floatundisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); + test__floatundisf(0x0007FB72EC000000, 0x1.FEDCBCp+50); + test__floatundisf(0x0007FB72E8000001, 0x1.FEDCBAp+50); + test__floatundisf(0x0007FB72E6000000, 0x1.FEDCBAp+50); + test__floatundisf(0x0007FB72E7000000, 0x1.FEDCBAp+50); + test__floatundisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); + test__floatundisf(0x0007FB72E4000001, 0x1.FEDCBAp+50); + test__floatundisf(0x0007FB72E4000000, 0x1.FEDCB8p+50); } diff --git a/lib/std/start.zig b/lib/std/start.zig index 857af03b56..1a4997edbd 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -41,6 +41,10 @@ fn _DllMainCRTStartup( fdwReason: std.os.windows.DWORD, lpReserved: std.os.windows.LPVOID, ) callconv(.Stdcall) std.os.windows.BOOL { + if (!builtin.single_threaded) { + _ = @import("start_windows_tls.zig"); + } + if (@hasDecl(root, "DllMain")) { return root.DllMain(hinstDLL, fdwReason, lpReserved); } diff --git a/lib/std/thread.zig b/lib/std/thread.zig index b2f8a44a47..596a8f3cd9 100644 --- a/lib/std/thread.zig +++ b/lib/std/thread.zig @@ -6,6 +6,8 @@ const windows = std.os.windows; const c = std.c; const assert = std.debug.assert; +const bad_startfn_ret = "expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"; + pub const Thread = struct { data: Data, @@ -158,15 +160,34 @@ pub const Thread = struct { }; fn threadMain(raw_arg: windows.LPVOID) callconv(.C) windows.DWORD { const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*; + switch (@typeInfo(@TypeOf(startFn).ReturnType)) { - .Int => { - return startFn(arg); + .NoReturn => { + startFn(arg); }, .Void => { startFn(arg); return 0; }, - else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"), + .Int => |info| { + if (info.bits != 8) { + @compileError(bad_startfn_ret); + } + return startFn(arg); + }, + .ErrorUnion => |info| { + if (info.payload != void) { + @compileError(bad_startfn_ret); + } + startFn(arg) catch |err| { + std.debug.warn("error: {}\n", .{@errorName(err)}); + if (@errorReturnTrace()) |trace| { + std.debug.dumpStackTrace(trace.*); + } + }; + return 0; + }, + else => @compileError(bad_startfn_ret), } } }; @@ -202,14 +223,32 @@ pub const Thread = struct { const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*; switch (@typeInfo(@TypeOf(startFn).ReturnType)) { - .Int => { - return startFn(arg); + .NoReturn => { + startFn(arg); }, .Void => { startFn(arg); return 0; }, - else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"), + .Int => |info| { + if (info.bits != 8) { + @compileError(bad_startfn_ret); + } + return startFn(arg); + }, + .ErrorUnion => |info| { + if (info.payload != void) { + @compileError(bad_startfn_ret); + } + startFn(arg) catch |err| { + std.debug.warn("error: {}\n", .{@errorName(err)}); + if (@errorReturnTrace()) |trace| { + std.debug.dumpStackTrace(trace.*); + } + }; + return 0; + }, + else => @compileError(bad_startfn_ret), } } fn posixThreadMain(ctx: ?*c_void) callconv(.C) ?*c_void { diff --git a/lib/std/unicode.zig b/lib/std/unicode.zig index 8ed51fa145..a971a730e8 100644 --- a/lib/std/unicode.zig +++ b/lib/std/unicode.zig @@ -251,12 +251,12 @@ pub const Utf16LeIterator = struct { pub fn nextCodepoint(it: *Utf16LeIterator) !?u21 { assert(it.i <= it.bytes.len); if (it.i == it.bytes.len) return null; - const c0: u21 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]); + const c0: u21 = mem.readIntLittle(u16, it.bytes[it.i..][0..2]); if (c0 & ~@as(u21, 0x03ff) == 0xd800) { // surrogate pair it.i += 2; if (it.i >= it.bytes.len) return error.DanglingSurrogateHalf; - const c1: u21 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]); + const c1: u21 = mem.readIntLittle(u16, it.bytes[it.i..][0..2]); if (c1 & ~@as(u21, 0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf; it.i += 2; return 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff)); @@ -630,11 +630,11 @@ test "utf8ToUtf16LeWithNull" { } } -/// Converts a UTF-8 string literal into a UTF-16LE string literal. -pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16LeLen(utf8) :0] u16 { +/// Converts a UTF-8 string literal into a UTF-16LE string literal. +pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16LeLen(utf8):0]u16 { comptime { const len: usize = calcUtf16LeLen(utf8); - var utf16le: [len :0]u16 = [_ :0]u16{0} ** len; + var utf16le: [len:0]u16 = [_:0]u16{0} ** len; const utf16le_len = utf8ToUtf16Le(&utf16le, utf8[0..]) catch |err| @compileError(err); assert(len == utf16le_len); return &utf16le; @@ -660,8 +660,8 @@ fn calcUtf16LeLen(utf8: []const u8) usize { } test "utf8ToUtf16LeStringLiteral" { -{ - const bytes = [_:0]u16{ 0x41 }; + { + const bytes = [_:0]u16{0x41}; const utf16 = utf8ToUtf16LeStringLiteral("A"); testing.expectEqualSlices(u16, &bytes, utf16); testing.expect(utf16[1] == 0); @@ -673,19 +673,19 @@ test "utf8ToUtf16LeStringLiteral" { testing.expect(utf16[2] == 0); } { - const bytes = [_:0]u16{ 0x02FF }; + const bytes = [_:0]u16{0x02FF}; const utf16 = utf8ToUtf16LeStringLiteral("\u{02FF}"); testing.expectEqualSlices(u16, &bytes, utf16); testing.expect(utf16[1] == 0); } { - const bytes = [_:0]u16{ 0x7FF }; + const bytes = [_:0]u16{0x7FF}; const utf16 = utf8ToUtf16LeStringLiteral("\u{7FF}"); testing.expectEqualSlices(u16, &bytes, utf16); testing.expect(utf16[1] == 0); } { - const bytes = [_:0]u16{ 0x801 }; + const bytes = [_:0]u16{0x801}; const utf16 = utf8ToUtf16LeStringLiteral("\u{801}"); testing.expectEqualSlices(u16, &bytes, utf16); testing.expect(utf16[1] == 0); diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index 8ae219a998..5445d3435f 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -740,11 +740,11 @@ pub const Node = struct { var i = index; switch (self.init_arg_expr) { - InitArg.Type => |t| { + .Type => |t| { if (i < 1) return t; i -= 1; }, - InitArg.None, InitArg.Enum => {}, + .None, .Enum => {}, } if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i).*; @@ -904,12 +904,7 @@ pub const Node = struct { } switch (self.return_type) { - // TODO allow this and next prong to share bodies since the types are the same - ReturnType.Explicit => |node| { - if (i < 1) return node; - i -= 1; - }, - ReturnType.InferErrorSet => |node| { + .Explicit, .InferErrorSet => |node| { if (i < 1) return node; i -= 1; }, @@ -934,9 +929,7 @@ pub const Node = struct { pub fn lastToken(self: *const FnProto) TokenIndex { if (self.body_node) |body_node| return body_node.lastToken(); switch (self.return_type) { - // TODO allow this and next prong to share bodies since the types are the same - ReturnType.Explicit => |node| return node.lastToken(), - ReturnType.InferErrorSet => |node| return node.lastToken(), + .Explicit, .InferErrorSet => |node| return node.lastToken(), } } }; @@ -1039,6 +1032,7 @@ pub const Node = struct { pub const Defer = struct { base: Node = Node{ .id = .Defer }, defer_token: TokenIndex, + payload: ?*Node, expr: *Node, pub fn iterate(self: *Defer, index: usize) ?*Node { @@ -1512,55 +1506,55 @@ pub const Node = struct { i -= 1; switch (self.op) { - Op.Catch => |maybe_payload| { + .Catch => |maybe_payload| { if (maybe_payload) |payload| { if (i < 1) return payload; i -= 1; } }, - Op.Add, - Op.AddWrap, - Op.ArrayCat, - Op.ArrayMult, - Op.Assign, - Op.AssignBitAnd, - Op.AssignBitOr, - Op.AssignBitShiftLeft, - Op.AssignBitShiftRight, - Op.AssignBitXor, - Op.AssignDiv, - Op.AssignSub, - Op.AssignSubWrap, - Op.AssignMod, - Op.AssignAdd, - Op.AssignAddWrap, - Op.AssignMul, - Op.AssignMulWrap, - Op.BangEqual, - Op.BitAnd, - Op.BitOr, - Op.BitShiftLeft, - Op.BitShiftRight, - Op.BitXor, - Op.BoolAnd, - Op.BoolOr, - Op.Div, - Op.EqualEqual, - Op.ErrorUnion, - Op.GreaterOrEqual, - Op.GreaterThan, - Op.LessOrEqual, - Op.LessThan, - Op.MergeErrorSets, - Op.Mod, - Op.Mul, - Op.MulWrap, - Op.Period, - Op.Range, - Op.Sub, - Op.SubWrap, - Op.UnwrapOptional, + .Add, + .AddWrap, + .ArrayCat, + .ArrayMult, + .Assign, + .AssignBitAnd, + .AssignBitOr, + .AssignBitShiftLeft, + .AssignBitShiftRight, + .AssignBitXor, + .AssignDiv, + .AssignSub, + .AssignSubWrap, + .AssignMod, + .AssignAdd, + .AssignAddWrap, + .AssignMul, + .AssignMulWrap, + .BangEqual, + .BitAnd, + .BitOr, + .BitShiftLeft, + .BitShiftRight, + .BitXor, + .BoolAnd, + .BoolOr, + .Div, + .EqualEqual, + .ErrorUnion, + .GreaterOrEqual, + .GreaterThan, + .LessOrEqual, + .LessThan, + .MergeErrorSets, + .Mod, + .Mul, + .MulWrap, + .Period, + .Range, + .Sub, + .SubWrap, + .UnwrapOptional, => {}, } @@ -1591,7 +1585,6 @@ pub const Node = struct { Await, BitNot, BoolNot, - Cancel, OptionalType, Negation, NegationWrap, @@ -1628,8 +1621,7 @@ pub const Node = struct { var i = index; switch (self.op) { - // TODO https://github.com/ziglang/zig/issues/1107 - Op.SliceType => |addr_of_info| { + .PtrType, .SliceType => |addr_of_info| { if (addr_of_info.sentinel) |sentinel| { if (i < 1) return sentinel; i -= 1; @@ -1641,14 +1633,7 @@ pub const Node = struct { } }, - Op.PtrType => |addr_of_info| { - if (addr_of_info.align_info) |align_info| { - if (i < 1) return align_info.node; - i -= 1; - } - }, - - Op.ArrayType => |array_info| { + .ArrayType => |array_info| { if (i < 1) return array_info.len_expr; i -= 1; if (array_info.sentinel) |sentinel| { @@ -1657,16 +1642,15 @@ pub const Node = struct { } }, - Op.AddressOf, - Op.Await, - Op.BitNot, - Op.BoolNot, - Op.Cancel, - Op.OptionalType, - Op.Negation, - Op.NegationWrap, - Op.Try, - Op.Resume, + .AddressOf, + .Await, + .BitNot, + .BoolNot, + .OptionalType, + .Negation, + .NegationWrap, + .Try, + .Resume, => {}, } @@ -1850,19 +1834,13 @@ pub const Node = struct { var i = index; switch (self.kind) { - Kind.Break => |maybe_label| { + .Break, .Continue => |maybe_label| { if (maybe_label) |label| { if (i < 1) return label; i -= 1; } }, - Kind.Continue => |maybe_label| { - if (maybe_label) |label| { - if (i < 1) return label; - i -= 1; - } - }, - Kind.Return => {}, + .Return => {}, } if (self.rhs) |rhs| { @@ -1883,17 +1861,12 @@ pub const Node = struct { } switch (self.kind) { - Kind.Break => |maybe_label| { + .Break, .Continue => |maybe_label| { if (maybe_label) |label| { return label.lastToken(); } }, - Kind.Continue => |maybe_label| { - if (maybe_label) |label| { - return label.lastToken(); - } - }, - Kind.Return => return self.ltoken, + .Return => return self.ltoken, } return self.ltoken; @@ -2134,11 +2107,11 @@ pub const Node = struct { i -= 1; switch (self.kind) { - Kind.Variable => |variable_name| { + .Variable => |variable_name| { if (i < 1) return &variable_name.base; i -= 1; }, - Kind.Return => |return_type| { + .Return => |return_type| { if (i < 1) return return_type; i -= 1; }, diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index 9a574c6231..2fcaaaab2d 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -23,7 +23,7 @@ pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree { var arena = std.heap.ArenaAllocator.init(allocator); errdefer arena.deinit(); const tree = try arena.allocator.create(ast.Tree); - tree.* = ast.Tree{ + tree.* = .{ .source = source, .root_node = undefined, .arena_allocator = arena, @@ -66,10 +66,10 @@ pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree { /// Root <- skip ContainerMembers eof fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!*Node.Root { const node = try arena.create(Node.Root); - node.* = Node.Root{ + node.* = .{ .decls = try parseContainerMembers(arena, it, tree), .eof_token = eatToken(it, .Eof) orelse { - try tree.errors.push(AstError{ + try tree.errors.push(.{ .ExpectedContainerMembers = .{ .token = it.index }, }); return error.ParseError; @@ -139,8 +139,8 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No } if (visib_token != null) { - try tree.errors.push(AstError{ - .ExpectedPubItem = AstError.ExpectedPubItem{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedPubItem = .{ .token = it.index }, }); return error.ParseError; } @@ -157,8 +157,8 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No // Dangling doc comment if (doc_comments != null) { - try tree.errors.push(AstError{ - .UnattachedDocComment = AstError.UnattachedDocComment{ .token = doc_comments.?.firstToken() }, + try tree.errors.push(.{ + .UnattachedDocComment = .{ .token = doc_comments.?.firstToken() }, }); } break; @@ -177,7 +177,7 @@ fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree) if (lines.len == 0) return null; const node = try arena.create(Node.DocComment); - node.* = Node.DocComment{ + node.* = .{ .lines = lines, }; return &node.base; @@ -186,15 +186,15 @@ fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree) /// TestDecl <- KEYWORD_test STRINGLITERALSINGLE Block fn parseTestDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const test_token = eatToken(it, .Keyword_test) orelse return null; - const name_node = try expectNode(arena, it, tree, parseStringLiteralSingle, AstError{ - .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index }, + const name_node = try expectNode(arena, it, tree, parseStringLiteralSingle, .{ + .ExpectedStringLiteral = .{ .token = it.index }, }); - const block_node = try expectNode(arena, it, tree, parseBlock, AstError{ - .ExpectedLBrace = AstError.ExpectedLBrace{ .token = it.index }, + const block_node = try expectNode(arena, it, tree, parseBlock, .{ + .ExpectedLBrace = .{ .token = it.index }, }); const test_node = try arena.create(Node.TestDecl); - test_node.* = Node.TestDecl{ + test_node.* = .{ .doc_comments = null, .test_token = test_token, .name = name_node, @@ -211,12 +211,12 @@ fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?* return null; }; putBackToken(it, lbrace); - const block_node = try expectNode(arena, it, tree, parseBlockExpr, AstError{ - .ExpectedLabelOrLBrace = AstError.ExpectedLabelOrLBrace{ .token = it.index }, + const block_node = try expectNode(arena, it, tree, parseBlockExpr, .{ + .ExpectedLabelOrLBrace = .{ .token = it.index }, }); const comptime_node = try arena.create(Node.Comptime); - comptime_node.* = Node.Comptime{ + comptime_node.* = .{ .doc_comments = null, .comptime_token = tok, .expr = block_node, @@ -250,8 +250,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node fn_node.body_node = body_node; return node; } - try tree.errors.push(AstError{ - .ExpectedSemiOrLBrace = AstError.ExpectedSemiOrLBrace{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedSemiOrLBrace = .{ .token = it.index }, }); return null; } @@ -277,8 +277,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } if (thread_local_token != null) { - try tree.errors.push(AstError{ - .ExpectedVarDecl = AstError.ExpectedVarDecl{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedVarDecl = .{ .token = it.index }, }); return error.ParseError; } @@ -291,8 +291,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } const use_node = (try parseUse(arena, it, tree)) orelse return null; - const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const semicolon_token = try expectToken(it, tree, .Semicolon); const use_node_raw = use_node.cast(Node.Use).?; @@ -310,7 +310,7 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { if (fnCC == .Extern) { putBackToken(it, fnCC.Extern); // 'extern' is also used in ContainerDecl } else { - try tree.errors.push(AstError{ + try tree.errors.push(.{ .ExpectedToken = .{ .token = it.index, .expected_id = .Keyword_fn }, }); return error.ParseError; @@ -328,16 +328,16 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const exclamation_token = eatToken(it, .Bang); const return_type_expr = (try parseVarType(arena, it, tree)) orelse - try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedReturnType = AstError.ExpectedReturnType{ .token = it.index }, + try expectNode(arena, it, tree, parseTypeExpr, .{ + .ExpectedReturnType = .{ .token = it.index }, }); - const return_type = if (exclamation_token != null) - Node.FnProto.ReturnType{ + const return_type: Node.FnProto.ReturnType = if (exclamation_token != null) + .{ .InferErrorSet = return_type_expr, } else - Node.FnProto.ReturnType{ + .{ .Explicit = return_type_expr, }; @@ -347,7 +347,7 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { null; const fn_proto_node = try arena.create(Node.FnProto); - fn_proto_node.* = Node.FnProto{ + fn_proto_node.* = .{ .doc_comments = null, .visib_token = null, .fn_token = fn_token, @@ -382,8 +382,8 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const name_token = try expectToken(it, tree, .Identifier); const type_node = if (eatToken(it, .Colon) != null) - try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, + try expectNode(arena, it, tree, parseTypeExpr, .{ + .ExpectedTypeExpr = .{ .token = it.index }, }) else null; @@ -391,14 +391,14 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const section_node = try parseLinkSection(arena, it, tree); const eq_token = eatToken(it, .Equal); const init_node = if (eq_token != null) blk: { - break :blk try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + break :blk try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); } else null; const semicolon_token = try expectToken(it, tree, .Semicolon); const node = try arena.create(Node.VarDecl); - node.* = Node.VarDecl{ + node.* = .{ .doc_comments = null, .visib_token = null, .thread_local_token = null, @@ -433,22 +433,22 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No node.* = .{ .token = var_tok }; type_expr = &node.base; } else { - type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, + type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ + .ExpectedTypeExpr = .{ .token = it.index }, }); align_expr = try parseByteAlign(arena, it, tree); } } const value_expr = if (eatToken(it, .Equal)) |_| - try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }) else null; const node = try arena.create(Node.ContainerField); - node.* = Node.ContainerField{ + node.* = .{ .doc_comments = null, .comptime_token = comptime_token, .name_token = name_token, @@ -465,7 +465,7 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No /// / KEYWORD_noasync BlockExprStatement /// / KEYWORD_suspend (SEMICOLON / BlockExprStatement) /// / KEYWORD_defer BlockExprStatement -/// / KEYWORD_errdefer BlockExprStatement +/// / KEYWORD_errdefer Payload? BlockExprStatement /// / IfStatement /// / LabeledStatement /// / SwitchExpr @@ -481,12 +481,12 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No } if (comptime_token) |token| { - const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, AstError{ - .ExpectedBlockOrAssignment = AstError.ExpectedBlockOrAssignment{ .token = it.index }, + const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, .{ + .ExpectedBlockOrAssignment = .{ .token = it.index }, }); const node = try arena.create(Node.Comptime); - node.* = Node.Comptime{ + node.* = .{ .doc_comments = null, .comptime_token = token, .expr = block_expr, @@ -511,13 +511,13 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No const semicolon = eatToken(it, .Semicolon); const body_node = if (semicolon == null) blk: { - break :blk try expectNode(arena, it, tree, parseBlockExprStatement, AstError{ - .ExpectedBlockOrExpression = AstError.ExpectedBlockOrExpression{ .token = it.index }, + break :blk try expectNode(arena, it, tree, parseBlockExprStatement, .{ + .ExpectedBlockOrExpression = .{ .token = it.index }, }); } else null; const node = try arena.create(Node.Suspend); - node.* = Node.Suspend{ + node.* = .{ .suspend_token = suspend_token, .body = body_node, }; @@ -526,13 +526,18 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No const defer_token = eatToken(it, .Keyword_defer) orelse eatToken(it, .Keyword_errdefer); if (defer_token) |token| { - const expr_node = try expectNode(arena, it, tree, parseBlockExprStatement, AstError{ - .ExpectedBlockOrExpression = AstError.ExpectedBlockOrExpression{ .token = it.index }, + const payload = if (tree.tokens.at(token).id == .Keyword_errdefer) + try parsePayload(arena, it, tree) + else + null; + const expr_node = try expectNode(arena, it, tree, parseBlockExprStatement, .{ + .ExpectedBlockOrExpression = .{ .token = it.index }, }); const node = try arena.create(Node.Defer); - node.* = Node.Defer{ + node.* = .{ .defer_token = token, .expr = expr_node, + .payload = payload, }; return &node.base; } @@ -561,8 +566,8 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } else null; if (block_expr == null and assign_expr == null) { - try tree.errors.push(AstError{ - .ExpectedBlockOrAssignment = AstError.ExpectedBlockOrAssignment{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedBlockOrAssignment = .{ .token = it.index }, }); return error.ParseError; } @@ -572,12 +577,12 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const else_node = if (semicolon == null) blk: { const else_token = eatToken(it, .Keyword_else) orelse break :blk null; const payload = try parsePayload(arena, it, tree); - const else_body = try expectNode(arena, it, tree, parseStatement, AstError{ - .InvalidToken = AstError.InvalidToken{ .token = it.index }, + const else_body = try expectNode(arena, it, tree, parseStatement, .{ + .InvalidToken = .{ .token = it.index }, }); const node = try arena.create(Node.Else); - node.* = Node.Else{ + node.* = .{ .else_token = else_token, .payload = payload, .body = else_body, @@ -599,8 +604,8 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node if_prefix.@"else" = else_node; return if_node; } - try tree.errors.push(AstError{ - .ExpectedSemiOrElse = AstError.ExpectedSemiOrElse{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedSemiOrElse = .{ .token = it.index }, }); return error.ParseError; } @@ -628,8 +633,8 @@ fn parseLabeledStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?* } if (label_token != null) { - try tree.errors.push(AstError{ - .ExpectedLabelable = AstError.ExpectedLabelable{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedLabelable = .{ .token = it.index }, }); return error.ParseError; } @@ -665,12 +670,12 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node for_prefix.body = block_expr_node; if (eatToken(it, .Keyword_else)) |else_token| { - const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{ - .InvalidToken = AstError.InvalidToken{ .token = it.index }, + const statement_node = try expectNode(arena, it, tree, parseStatement, .{ + .InvalidToken = .{ .token = it.index }, }); const else_node = try arena.create(Node.Else); - else_node.* = Node.Else{ + else_node.* = .{ .else_token = else_token, .payload = null, .body = statement_node, @@ -689,12 +694,12 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node if (eatToken(it, .Semicolon) != null) return node; if (eatToken(it, .Keyword_else)) |else_token| { - const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{ - .ExpectedStatement = AstError.ExpectedStatement{ .token = it.index }, + const statement_node = try expectNode(arena, it, tree, parseStatement, .{ + .ExpectedStatement = .{ .token = it.index }, }); const else_node = try arena.create(Node.Else); - else_node.* = Node.Else{ + else_node.* = .{ .else_token = else_token, .payload = null, .body = statement_node, @@ -703,8 +708,8 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node return node; } - try tree.errors.push(AstError{ - .ExpectedSemiOrElse = AstError.ExpectedSemiOrElse{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedSemiOrElse = .{ .token = it.index }, }); return null; } @@ -725,12 +730,12 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No if (eatToken(it, .Keyword_else)) |else_token| { const payload = try parsePayload(arena, it, tree); - const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{ - .InvalidToken = AstError.InvalidToken{ .token = it.index }, + const statement_node = try expectNode(arena, it, tree, parseStatement, .{ + .InvalidToken = .{ .token = it.index }, }); const else_node = try arena.create(Node.Else); - else_node.* = Node.Else{ + else_node.* = .{ .else_token = else_token, .payload = payload, .body = statement_node, @@ -751,12 +756,12 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No if (eatToken(it, .Keyword_else)) |else_token| { const payload = try parsePayload(arena, it, tree); - const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{ - .ExpectedStatement = AstError.ExpectedStatement{ .token = it.index }, + const statement_node = try expectNode(arena, it, tree, parseStatement, .{ + .ExpectedStatement = .{ .token = it.index }, }); const else_node = try arena.create(Node.Else); - else_node.* = Node.Else{ + else_node.* = .{ .else_token = else_token, .payload = payload, .body = statement_node, @@ -765,8 +770,8 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No return node; } - try tree.errors.push(AstError{ - .ExpectedSemiOrElse = AstError.ExpectedSemiOrElse{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedSemiOrElse = .{ .token = it.index }, }); return null; } @@ -894,8 +899,8 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } if (eatToken(it, .Keyword_comptime)) |token| { - const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const node = try arena.create(Node.Comptime); node.* = .{ @@ -907,8 +912,8 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } if (eatToken(it, .Keyword_noasync)) |token| { - const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const node = try arena.create(Node.Noasync); node.* = .{ @@ -930,13 +935,13 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } if (eatToken(it, .Keyword_resume)) |token| { - const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const node = try arena.create(Node.PrefixOp); node.* = .{ .op_token = token, - .op = Node.PrefixOp.Op.Resume, + .op = .Resume, .rhs = expr_node, }; return &node.base; @@ -992,7 +997,7 @@ fn parseBlock(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const rbrace = try expectToken(it, tree, .RBrace); const block_node = try arena.create(Node.Block); - block_node.* = Node.Block{ + block_node.* = .{ .label = null, .lbrace = lbrace, .statements = statements, @@ -1019,8 +1024,8 @@ fn parseLoopExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { if (inline_token == null) return null; // If we've seen "inline", there should have been a "for" or "while" - try tree.errors.push(AstError{ - .ExpectedInlinable = AstError.ExpectedInlinable{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedInlinable = .{ .token = it.index }, }); return error.ParseError; } @@ -1030,18 +1035,18 @@ fn parseForExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = (try parseForPrefix(arena, it, tree)) orelse return null; const for_prefix = node.cast(Node.For).?; - const body_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const body_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); for_prefix.body = body_node; if (eatToken(it, .Keyword_else)) |else_token| { - const body = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const body = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const else_node = try arena.create(Node.Else); - else_node.* = Node.Else{ + else_node.* = .{ .else_token = else_token, .payload = null, .body = body, @@ -1058,19 +1063,19 @@ fn parseWhileExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = (try parseWhilePrefix(arena, it, tree)) orelse return null; const while_prefix = node.cast(Node.While).?; - const body_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const body_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); while_prefix.body = body_node; if (eatToken(it, .Keyword_else)) |else_token| { const payload = try parsePayload(arena, it, tree); - const body = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const body = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const else_node = try arena.create(Node.Else); - else_node.* = Node.Else{ + else_node.* = .{ .else_token = else_token, .payload = payload, .body = body, @@ -1098,14 +1103,14 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf const lbrace = eatToken(it, .LBrace) orelse return null; var init_list = Node.SuffixOp.Op.InitList.init(arena); - const op = blk: { + const op: Node.SuffixOp.Op = blk: { if (try parseFieldInit(arena, it, tree)) |field_init| { try init_list.push(field_init); while (eatToken(it, .Comma)) |_| { const next = (try parseFieldInit(arena, it, tree)) orelse break; try init_list.push(next); } - break :blk Node.SuffixOp.Op{ .StructInitializer = init_list }; + break :blk .{ .StructInitializer = init_list }; } if (try parseExpr(arena, it, tree)) |expr| { @@ -1114,14 +1119,14 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf const next = (try parseExpr(arena, it, tree)) orelse break; try init_list.push(next); } - break :blk Node.SuffixOp.Op{ .ArrayInitializer = init_list }; + break :blk .{ .ArrayInitializer = init_list }; } - break :blk Node.SuffixOp.Op{ .StructInitializer = init_list }; + break :blk .{ .StructInitializer = init_list }; }; const node = try arena.create(Node.SuffixOp); - node.* = Node.SuffixOp{ + node.* = .{ .lhs = .{ .node = undefined }, // set by caller .op = op, .rtoken = try expectToken(it, tree, .RBrace), @@ -1140,8 +1145,8 @@ fn parseErrorUnionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No if (try SimpleBinOpParseFn(.Bang, Node.InfixOp.Op.ErrorUnion)(arena, it, tree)) |node| { const error_union = node.cast(Node.InfixOp).?; - const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, + const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ + .ExpectedTypeExpr = .{ .token = it.index }, }); error_union.lhs = suffix_expr; error_union.rhs = type_expr; @@ -1168,8 +1173,8 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { return parsePrimaryTypeExpr(arena, it, tree); } // TODO: Implement hack for parsing `async fn ...` in ast_parse_suffix_expr - var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, AstError{ - .ExpectedPrimaryTypeExpr = AstError.ExpectedPrimaryTypeExpr{ .token = it.index }, + var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, .{ + .ExpectedPrimaryTypeExpr = .{ .token = it.index }, }); while (try parseSuffixOp(arena, it, tree)) |node| { @@ -1182,16 +1187,16 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { } const params = (try parseFnCallArguments(arena, it, tree)) orelse { - try tree.errors.push(AstError{ - .ExpectedParamList = AstError.ExpectedParamList{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedParamList = .{ .token = it.index }, }); return null; }; const node = try arena.create(Node.SuffixOp); - node.* = Node.SuffixOp{ + node.* = .{ .lhs = .{ .node = res }, - .op = Node.SuffixOp.Op{ - .Call = Node.SuffixOp.Op.Call{ + .op = .{ + .Call = .{ .params = params.list, .async_token = async_token, }, @@ -1215,10 +1220,10 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { } if (try parseFnCallArguments(arena, it, tree)) |params| { const call = try arena.create(Node.SuffixOp); - call.* = Node.SuffixOp{ + call.* = .{ .lhs = .{ .node = res }, - .op = Node.SuffixOp.Op{ - .Call = Node.SuffixOp.Op.Call{ + .op = .{ + .Call = .{ .params = params.list, .async_token = null, }, @@ -1264,7 +1269,7 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N if (try parseBuiltinCall(arena, it, tree)) |node| return node; if (eatToken(it, .CharLiteral)) |token| { const node = try arena.create(Node.CharLiteral); - node.* = Node.CharLiteral{ + node.* = .{ .token = token, }; return &node.base; @@ -1300,15 +1305,15 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N } if (eatToken(it, .Keyword_error)) |token| { const period = try expectToken(it, tree, .Period); - const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{ - .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, + const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ + .ExpectedIdentifier = .{ .token = it.index }, }); const global_error_set = try createLiteral(arena, Node.ErrorType, token); const node = try arena.create(Node.InfixOp); node.* = .{ .op_token = period, .lhs = global_error_set, - .op = Node.InfixOp.Op.Period, + .op = .Period, .rhs = identifier, }; return &node.base; @@ -1358,7 +1363,7 @@ fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const rbrace = try expectToken(it, tree, .RBrace); const node = try arena.create(Node.ErrorSetDecl); - node.* = Node.ErrorSetDecl{ + node.* = .{ .error_token = error_token, .decls = decls, .rbrace_token = rbrace, @@ -1369,13 +1374,13 @@ fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node /// GroupedExpr <- LPAREN Expr RPAREN fn parseGroupedExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const lparen = eatToken(it, .LParen) orelse return null; - const expr = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const rparen = try expectToken(it, tree, .RParen); const node = try arena.create(Node.GroupedExpression); - node.* = Node.GroupedExpression{ + node.* = .{ .lparen = lparen, .expr = expr, .rparen = rparen, @@ -1435,8 +1440,8 @@ fn parseLoopTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node if (inline_token == null) return null; // If we've seen "inline", there should have been a "for" or "while" - try tree.errors.push(AstError{ - .ExpectedInlinable = AstError.ExpectedInlinable{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedInlinable = .{ .token = it.index }, }); return error.ParseError; } @@ -1446,18 +1451,18 @@ fn parseForTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const node = (try parseForPrefix(arena, it, tree)) orelse return null; const for_prefix = node.cast(Node.For).?; - const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, + const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ + .ExpectedTypeExpr = .{ .token = it.index }, }); for_prefix.body = type_expr; if (eatToken(it, .Keyword_else)) |else_token| { - const else_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, + const else_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ + .ExpectedTypeExpr = .{ .token = it.index }, }); const else_node = try arena.create(Node.Else); - else_node.* = Node.Else{ + else_node.* = .{ .else_token = else_token, .payload = null, .body = else_expr, @@ -1474,20 +1479,20 @@ fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod const node = (try parseWhilePrefix(arena, it, tree)) orelse return null; const while_prefix = node.cast(Node.While).?; - const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, + const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ + .ExpectedTypeExpr = .{ .token = it.index }, }); while_prefix.body = type_expr; if (eatToken(it, .Keyword_else)) |else_token| { const payload = try parsePayload(arena, it, tree); - const else_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, + const else_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ + .ExpectedTypeExpr = .{ .token = it.index }, }); const else_node = try arena.create(Node.Else); - else_node.* = Node.Else{ + else_node.* = .{ .else_token = else_token, .payload = null, .body = else_expr, @@ -1503,8 +1508,8 @@ fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const switch_token = eatToken(it, .Keyword_switch) orelse return null; _ = try expectToken(it, tree, .LParen); - const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); _ = try expectToken(it, tree, .LBrace); @@ -1512,7 +1517,7 @@ fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const rbrace = try expectToken(it, tree, .RBrace); const node = try arena.create(Node.Switch); - node.* = Node.Switch{ + node.* = .{ .switch_token = switch_token, .expr = expr_node, .cases = cases, @@ -1526,12 +1531,12 @@ fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const asm_token = eatToken(it, .Keyword_asm) orelse return null; const volatile_token = eatToken(it, .Keyword_volatile); _ = try expectToken(it, tree, .LParen); - const template = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const template = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const node = try arena.create(Node.Asm); - node.* = Node.Asm{ + node.* = .{ .asm_token = asm_token, .volatile_token = volatile_token, .template = template, @@ -1553,7 +1558,7 @@ fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node // anon enum literal if (eatToken(it, .Identifier)) |name| { const node = try arena.create(Node.EnumLiteral); - node.* = Node.EnumLiteral{ + node.* = .{ .dot = dot, .name = name, }; @@ -1580,32 +1585,32 @@ fn parseAsmOutput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: /// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN fn parseAsmOutputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmOutput { const lbracket = eatToken(it, .LBracket) orelse return null; - const name = try expectNode(arena, it, tree, parseIdentifier, AstError{ - .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, + const name = try expectNode(arena, it, tree, parseIdentifier, .{ + .ExpectedIdentifier = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RBracket); - const constraint = try expectNode(arena, it, tree, parseStringLiteral, AstError{ - .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index }, + const constraint = try expectNode(arena, it, tree, parseStringLiteral, .{ + .ExpectedStringLiteral = .{ .token = it.index }, }); _ = try expectToken(it, tree, .LParen); - const kind = blk: { + const kind: Node.AsmOutput.Kind = blk: { if (eatToken(it, .Arrow) != null) { - const return_ident = try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, + const return_ident = try expectNode(arena, it, tree, parseTypeExpr, .{ + .ExpectedTypeExpr = .{ .token = it.index }, }); - break :blk Node.AsmOutput.Kind{ .Return = return_ident }; + break :blk .{ .Return = return_ident }; } - const variable = try expectNode(arena, it, tree, parseIdentifier, AstError{ - .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, + const variable = try expectNode(arena, it, tree, parseIdentifier, .{ + .ExpectedIdentifier = .{ .token = it.index }, }); - break :blk Node.AsmOutput.Kind{ .Variable = variable.cast(Node.Identifier).? }; + break :blk .{ .Variable = variable.cast(Node.Identifier).? }; }; const rparen = try expectToken(it, tree, .RParen); const node = try arena.create(Node.AsmOutput); - node.* = Node.AsmOutput{ + node.* = .{ .lbracket = lbracket, .symbolic_name = name, .constraint = constraint, @@ -1625,23 +1630,23 @@ fn parseAsmInput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: * /// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN fn parseAsmInputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmInput { const lbracket = eatToken(it, .LBracket) orelse return null; - const name = try expectNode(arena, it, tree, parseIdentifier, AstError{ - .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, + const name = try expectNode(arena, it, tree, parseIdentifier, .{ + .ExpectedIdentifier = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RBracket); - const constraint = try expectNode(arena, it, tree, parseStringLiteral, AstError{ - .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index }, + const constraint = try expectNode(arena, it, tree, parseStringLiteral, .{ + .ExpectedStringLiteral = .{ .token = it.index }, }); _ = try expectToken(it, tree, .LParen); - const expr = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const rparen = try expectToken(it, tree, .RParen); const node = try arena.create(Node.AsmInput); - node.* = Node.AsmInput{ + node.* = .{ .lbracket = lbracket, .symbolic_name = name, .constraint = constraint, @@ -1664,8 +1669,8 @@ fn parseAsmClobbers(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node /// BreakLabel <- COLON IDENTIFIER fn parseBreakLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { _ = eatToken(it, .Colon) orelse return null; - return try expectNode(arena, it, tree, parseIdentifier, AstError{ - .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, + return try expectNode(arena, it, tree, parseIdentifier, .{ + .ExpectedIdentifier = .{ .token = it.index }, }); } @@ -1694,12 +1699,12 @@ fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { putBackToken(it, period_token); return null; }; - const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const node = try arena.create(Node.FieldInitializer); - node.* = Node.FieldInitializer{ + node.* = .{ .period_token = period_token, .name_token = name_token, .expr = expr_node, @@ -1711,8 +1716,8 @@ fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { fn parseWhileContinueExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { _ = eatToken(it, .Colon) orelse return null; _ = try expectToken(it, tree, .LParen); - const node = try expectNode(arena, it, tree, parseAssignExpr, AstError{ - .ExpectedExprOrAssignment = AstError.ExpectedExprOrAssignment{ .token = it.index }, + const node = try expectNode(arena, it, tree, parseAssignExpr, .{ + .ExpectedExprOrAssignment = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); return node; @@ -1722,8 +1727,8 @@ fn parseWhileContinueExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { _ = eatToken(it, .Keyword_linksection) orelse return null; _ = try expectToken(it, tree, .LParen); - const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); return expr_node; @@ -1733,8 +1738,8 @@ fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node fn parseCallconv(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { _ = eatToken(it, .Keyword_callconv) orelse return null; _ = try expectToken(it, tree, .LParen); - const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); return expr_node; @@ -1775,14 +1780,14 @@ fn parseParamDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { comptime_token == null and name_token == null and doc_comments == null) return null; - try tree.errors.push(AstError{ - .ExpectedParamType = AstError.ExpectedParamType{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedParamType = .{ .token = it.index }, }); return error.ParseError; }; const param_decl = try arena.create(Node.ParamDecl); - param_decl.* = Node.ParamDecl{ + param_decl.* = .{ .doc_comments = doc_comments, .comptime_token = comptime_token, .noalias_token = noalias_token, @@ -1821,14 +1826,14 @@ const ParamType = union(enum) { fn parseIfPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const if_token = eatToken(it, .Keyword_if) orelse return null; _ = try expectToken(it, tree, .LParen); - const condition = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const condition = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); const payload = try parsePtrPayload(arena, it, tree); const node = try arena.create(Node.If); - node.* = Node.If{ + node.* = .{ .if_token = if_token, .condition = condition, .payload = payload, @@ -1843,8 +1848,8 @@ fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const while_token = eatToken(it, .Keyword_while) orelse return null; _ = try expectToken(it, tree, .LParen); - const condition = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const condition = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); @@ -1852,7 +1857,7 @@ fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const continue_expr = try parseWhileContinueExpr(arena, it, tree); const node = try arena.create(Node.While); - node.* = Node.While{ + node.* = .{ .label = null, .inline_token = null, .while_token = while_token, @@ -1870,17 +1875,17 @@ fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const for_token = eatToken(it, .Keyword_for) orelse return null; _ = try expectToken(it, tree, .LParen); - const array_expr = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const array_expr = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); - const payload = try expectNode(arena, it, tree, parsePtrIndexPayload, AstError{ - .ExpectedPayload = AstError.ExpectedPayload{ .token = it.index }, + const payload = try expectNode(arena, it, tree, parsePtrIndexPayload, .{ + .ExpectedPayload = .{ .token = it.index }, }); const node = try arena.create(Node.For); - node.* = Node.For{ + node.* = .{ .label = null, .inline_token = null, .for_token = for_token, @@ -1895,13 +1900,13 @@ fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// Payload <- PIPE IDENTIFIER PIPE fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const lpipe = eatToken(it, .Pipe) orelse return null; - const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{ - .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, + const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ + .ExpectedIdentifier = .{ .token = it.index }, }); const rpipe = try expectToken(it, tree, .Pipe); const node = try arena.create(Node.Payload); - node.* = Node.Payload{ + node.* = .{ .lpipe = lpipe, .error_symbol = identifier, .rpipe = rpipe, @@ -1913,13 +1918,13 @@ fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const lpipe = eatToken(it, .Pipe) orelse return null; const asterisk = eatToken(it, .Asterisk); - const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{ - .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, + const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ + .ExpectedIdentifier = .{ .token = it.index }, }); const rpipe = try expectToken(it, tree, .Pipe); const node = try arena.create(Node.PointerPayload); - node.* = Node.PointerPayload{ + node.* = .{ .lpipe = lpipe, .ptr_token = asterisk, .value_symbol = identifier, @@ -1932,21 +1937,21 @@ fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { fn parsePtrIndexPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const lpipe = eatToken(it, .Pipe) orelse return null; const asterisk = eatToken(it, .Asterisk); - const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{ - .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, + const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ + .ExpectedIdentifier = .{ .token = it.index }, }); const index = if (eatToken(it, .Comma) == null) null else - try expectNode(arena, it, tree, parseIdentifier, AstError{ - .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, + try expectNode(arena, it, tree, parseIdentifier, .{ + .ExpectedIdentifier = .{ .token = it.index }, }); const rpipe = try expectToken(it, tree, .Pipe); const node = try arena.create(Node.PointerIndexPayload); - node.* = Node.PointerIndexPayload{ + node.* = .{ .lpipe = lpipe, .ptr_token = asterisk, .value_symbol = identifier, @@ -1961,8 +1966,8 @@ fn parseSwitchProng(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const node = (try parseSwitchCase(arena, it, tree)) orelse return null; const arrow = try expectToken(it, tree, .EqualAngleBracketRight); const payload = try parsePtrPayload(arena, it, tree); - const expr = try expectNode(arena, it, tree, parseAssignExpr, AstError{ - .ExpectedExprOrAssignment = AstError.ExpectedExprOrAssignment{ .token = it.index }, + const expr = try expectNode(arena, it, tree, parseAssignExpr, .{ + .ExpectedExprOrAssignment = .{ .token = it.index }, }); const switch_case = node.cast(Node.SwitchCase).?; @@ -1987,14 +1992,14 @@ fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { } } else if (eatToken(it, .Keyword_else)) |else_token| { const else_node = try arena.create(Node.SwitchElse); - else_node.* = Node.SwitchElse{ + else_node.* = .{ .token = else_token, }; try list.push(&else_node.base); } else return null; const node = try arena.create(Node.SwitchCase); - node.* = Node.SwitchCase{ + node.* = .{ .items = list, .arrow_token = undefined, // set by caller .payload = null, @@ -2007,15 +2012,15 @@ fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const expr = (try parseExpr(arena, it, tree)) orelse return null; if (eatToken(it, .Ellipsis3)) |token| { - const range_end = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const range_end = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const node = try arena.create(Node.InfixOp); - node.* = Node.InfixOp{ + node.* = .{ .op_token = token, .lhs = expr, - .op = Node.InfixOp.Op{ .Range = {} }, + .op = .Range, .rhs = range_end, }; return &node.base; @@ -2039,24 +2044,22 @@ fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// / MINUSPERCENTEQUAL /// / EQUAL fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const Op = Node.InfixOp.Op; - const token = nextToken(it); - const op = switch (token.ptr.id) { - .AsteriskEqual => Op{ .AssignMul = {} }, - .SlashEqual => Op{ .AssignDiv = {} }, - .PercentEqual => Op{ .AssignMod = {} }, - .PlusEqual => Op{ .AssignAdd = {} }, - .MinusEqual => Op{ .AssignSub = {} }, - .AngleBracketAngleBracketLeftEqual => Op{ .AssignBitShiftLeft = {} }, - .AngleBracketAngleBracketRightEqual => Op{ .AssignBitShiftRight = {} }, - .AmpersandEqual => Op{ .AssignBitAnd = {} }, - .CaretEqual => Op{ .AssignBitXor = {} }, - .PipeEqual => Op{ .AssignBitOr = {} }, - .AsteriskPercentEqual => Op{ .AssignMulWrap = {} }, - .PlusPercentEqual => Op{ .AssignAddWrap = {} }, - .MinusPercentEqual => Op{ .AssignSubWrap = {} }, - .Equal => Op{ .Assign = {} }, + const op: Node.InfixOp.Op = switch (token.ptr.id) { + .AsteriskEqual => .AssignMul, + .SlashEqual => .AssignDiv, + .PercentEqual => .AssignMod, + .PlusEqual => .AssignAdd, + .MinusEqual => .AssignSub, + .AngleBracketAngleBracketLeftEqual => .AssignBitShiftLeft, + .AngleBracketAngleBracketRightEqual => .AssignBitShiftRight, + .AmpersandEqual => .AssignBitAnd, + .CaretEqual => .AssignBitXor, + .PipeEqual => .AssignBitOr, + .AsteriskPercentEqual => .AssignMulWrap, + .PlusPercentEqual => .AssignAddWrap, + .MinusPercentEqual => .AssignSubWrap, + .Equal => .Assign, else => { putBackToken(it, token.index); return null; @@ -2064,7 +2067,7 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { }; const node = try arena.create(Node.InfixOp); - node.* = Node.InfixOp{ + node.* = .{ .op_token = token.index, .lhs = undefined, // set by caller .op = op, @@ -2081,16 +2084,14 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// / LARROWEQUAL /// / RARROWEQUAL fn parseCompareOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const ops = Node.InfixOp.Op; - const token = nextToken(it); - const op = switch (token.ptr.id) { - .EqualEqual => ops{ .EqualEqual = {} }, - .BangEqual => ops{ .BangEqual = {} }, - .AngleBracketLeft => ops{ .LessThan = {} }, - .AngleBracketRight => ops{ .GreaterThan = {} }, - .AngleBracketLeftEqual => ops{ .LessOrEqual = {} }, - .AngleBracketRightEqual => ops{ .GreaterOrEqual = {} }, + const op: Node.InfixOp.Op = switch (token.ptr.id) { + .EqualEqual => .EqualEqual, + .BangEqual => .BangEqual, + .AngleBracketLeft => .LessThan, + .AngleBracketRight => .GreaterThan, + .AngleBracketLeftEqual => .LessOrEqual, + .AngleBracketRightEqual => .GreaterOrEqual, else => { putBackToken(it, token.index); return null; @@ -2107,15 +2108,13 @@ fn parseCompareOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// / KEYWORD_orelse /// / KEYWORD_catch Payload? fn parseBitwiseOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const ops = Node.InfixOp.Op; - const token = nextToken(it); - const op = switch (token.ptr.id) { - .Ampersand => ops{ .BitAnd = {} }, - .Caret => ops{ .BitXor = {} }, - .Pipe => ops{ .BitOr = {} }, - .Keyword_orelse => ops{ .UnwrapOptional = {} }, - .Keyword_catch => ops{ .Catch = try parsePayload(arena, it, tree) }, + const op: Node.InfixOp.Op = switch (token.ptr.id) { + .Ampersand => .BitAnd, + .Caret => .BitXor, + .Pipe => .BitOr, + .Keyword_orelse => .UnwrapOptional, + .Keyword_catch => .{ .Catch = try parsePayload(arena, it, tree) }, else => { putBackToken(it, token.index); return null; @@ -2129,12 +2128,10 @@ fn parseBitwiseOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// <- LARROW2 /// / RARROW2 fn parseBitShiftOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const ops = Node.InfixOp.Op; - const token = nextToken(it); - const op = switch (token.ptr.id) { - .AngleBracketAngleBracketLeft => ops{ .BitShiftLeft = {} }, - .AngleBracketAngleBracketRight => ops{ .BitShiftRight = {} }, + const op: Node.InfixOp.Op = switch (token.ptr.id) { + .AngleBracketAngleBracketLeft => .BitShiftLeft, + .AngleBracketAngleBracketRight => .BitShiftRight, else => { putBackToken(it, token.index); return null; @@ -2151,15 +2148,13 @@ fn parseBitShiftOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// / PLUSPERCENT /// / MINUSPERCENT fn parseAdditionOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const ops = Node.InfixOp.Op; - const token = nextToken(it); - const op = switch (token.ptr.id) { - .Plus => ops{ .Add = {} }, - .Minus => ops{ .Sub = {} }, - .PlusPlus => ops{ .ArrayCat = {} }, - .PlusPercent => ops{ .AddWrap = {} }, - .MinusPercent => ops{ .SubWrap = {} }, + const op: Node.InfixOp.Op = switch (token.ptr.id) { + .Plus => .Add, + .Minus => .Sub, + .PlusPlus => .ArrayCat, + .PlusPercent => .AddWrap, + .MinusPercent => .SubWrap, else => { putBackToken(it, token.index); return null; @@ -2177,16 +2172,14 @@ fn parseAdditionOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// / ASTERISK2 /// / ASTERISKPERCENT fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const ops = Node.InfixOp.Op; - const token = nextToken(it); - const op = switch (token.ptr.id) { - .PipePipe => ops{ .BoolOr = {} }, - .Asterisk => ops{ .Mul = {} }, - .Slash => ops{ .Div = {} }, - .Percent => ops{ .Mod = {} }, - .AsteriskAsterisk => ops{ .ArrayMult = {} }, - .AsteriskPercent => ops{ .MulWrap = {} }, + const op: Node.InfixOp.Op = switch (token.ptr.id) { + .PipePipe => .MergeErrorSets, + .Asterisk => .Mul, + .Slash => .Div, + .Percent => .Mod, + .AsteriskAsterisk => .ArrayMult, + .AsteriskPercent => .MulWrap, else => { putBackToken(it, token.index); return null; @@ -2205,17 +2198,15 @@ fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// / KEYWORD_try /// / KEYWORD_await fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const ops = Node.PrefixOp.Op; - const token = nextToken(it); - const op = switch (token.ptr.id) { - .Bang => ops{ .BoolNot = {} }, - .Minus => ops{ .Negation = {} }, - .Tilde => ops{ .BitNot = {} }, - .MinusPercent => ops{ .NegationWrap = {} }, - .Ampersand => ops{ .AddressOf = {} }, - .Keyword_try => ops{ .Try = {} }, - .Keyword_await => ops{ .Await = .{} }, + const op: Node.PrefixOp.Op = switch (token.ptr.id) { + .Bang => .BoolNot, + .Minus => .Negation, + .Tilde => .BitNot, + .MinusPercent => .NegationWrap, + .Ampersand => .AddressOf, + .Keyword_try => .Try, + .Keyword_await => .Await, else => { putBackToken(it, token.index); return null; @@ -2223,7 +2214,7 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { }; const node = try arena.create(Node.PrefixOp); - node.* = Node.PrefixOp{ + node.* = .{ .op_token = token.index, .op = op, .rhs = undefined, // set by caller @@ -2246,9 +2237,9 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { if (eatToken(it, .QuestionMark)) |token| { const node = try arena.create(Node.PrefixOp); - node.* = Node.PrefixOp{ + node.* = .{ .op_token = token, - .op = Node.PrefixOp.Op.OptionalType, + .op = .OptionalType, .rhs = undefined, // set by caller }; return &node.base; @@ -2264,7 +2255,7 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node return null; }; const node = try arena.create(Node.AnyFrameType); - node.* = Node.AnyFrameType{ + node.* = .{ .anyframe_token = token, .result = Node.AnyFrameType.Result{ .arrow_token = arrow, @@ -2286,18 +2277,18 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node while (true) { if (eatToken(it, .Keyword_align)) |align_token| { const lparen = try expectToken(it, tree, .LParen); - const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); // Optional bit range const bit_range = if (eatToken(it, .Colon)) |_| bit_range_value: { - const range_start = try expectNode(arena, it, tree, parseIntegerLiteral, AstError{ - .ExpectedIntegerLiteral = AstError.ExpectedIntegerLiteral{ .token = it.index }, + const range_start = try expectNode(arena, it, tree, parseIntegerLiteral, .{ + .ExpectedIntegerLiteral = .{ .token = it.index }, }); _ = try expectToken(it, tree, .Colon); - const range_end = try expectNode(arena, it, tree, parseIntegerLiteral, AstError{ - .ExpectedIntegerLiteral = AstError.ExpectedIntegerLiteral{ .token = it.index }, + const range_end = try expectNode(arena, it, tree, parseIntegerLiteral, .{ + .ExpectedIntegerLiteral = .{ .token = it.index }, }); break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{ @@ -2340,8 +2331,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node while (true) { if (try parseByteAlign(arena, it, tree)) |align_expr| { if (slice_type.align_info != null) { - try tree.errors.push(AstError{ - .ExtraAlignQualifier = AstError.ExtraAlignQualifier{ .token = it.index }, + try tree.errors.push(.{ + .ExtraAlignQualifier = .{ .token = it.index }, }); return error.ParseError; } @@ -2353,8 +2344,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } if (eatToken(it, .Keyword_const)) |const_token| { if (slice_type.const_token != null) { - try tree.errors.push(AstError{ - .ExtraConstQualifier = AstError.ExtraConstQualifier{ .token = it.index }, + try tree.errors.push(.{ + .ExtraConstQualifier = .{ .token = it.index }, }); return error.ParseError; } @@ -2363,8 +2354,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } if (eatToken(it, .Keyword_volatile)) |volatile_token| { if (slice_type.volatile_token != null) { - try tree.errors.push(AstError{ - .ExtraVolatileQualifier = AstError.ExtraVolatileQualifier{ .token = it.index }, + try tree.errors.push(.{ + .ExtraVolatileQualifier = .{ .token = it.index }, }); return error.ParseError; } @@ -2373,8 +2364,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } if (eatToken(it, .Keyword_allowzero)) |allowzero_token| { if (slice_type.allowzero_token != null) { - try tree.errors.push(AstError{ - .ExtraAllowZeroQualifier = AstError.ExtraAllowZeroQualifier{ .token = it.index }, + try tree.errors.push(.{ + .ExtraAllowZeroQualifier = .{ .token = it.index }, }); return error.ParseError; } @@ -2398,15 +2389,14 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node /// / DOTASTERISK /// / DOTQUESTIONMARK fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const Op = Node.SuffixOp.Op; const OpAndToken = struct { op: Node.SuffixOp.Op, token: TokenIndex, }; - const op_and_token = blk: { + const op_and_token: OpAndToken = blk: { if (eatToken(it, .LBracket)) |_| { - const index_expr = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const index_expr = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); if (eatToken(it, .Ellipsis2) != null) { @@ -2415,9 +2405,9 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { try parseExpr(arena, it, tree) else null; - break :blk OpAndToken{ - .op = Op{ - .Slice = Op.Slice{ + break :blk .{ + .op = .{ + .Slice = .{ .start = index_expr, .end = end_expr, .sentinel = sentinel, @@ -2427,14 +2417,14 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { }; } - break :blk OpAndToken{ - .op = Op{ .ArrayAccess = index_expr }, + break :blk .{ + .op = .{ .ArrayAccess = index_expr }, .token = try expectToken(it, tree, .RBracket), }; } if (eatToken(it, .PeriodAsterisk)) |period_asterisk| { - break :blk OpAndToken{ .op = Op{ .Deref = {} }, .token = period_asterisk }; + break :blk .{ .op = .Deref, .token = period_asterisk }; } if (eatToken(it, .Period)) |period| { @@ -2443,19 +2433,19 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { // Should there be an ast.Node.SuffixOp.FieldAccess variant? Or should // this grammar rule be altered? const node = try arena.create(Node.InfixOp); - node.* = Node.InfixOp{ + node.* = .{ .op_token = period, .lhs = undefined, // set by caller - .op = Node.InfixOp.Op.Period, + .op = .Period, .rhs = identifier, }; return &node.base; } if (eatToken(it, .QuestionMark)) |question_mark| { - break :blk OpAndToken{ .op = Op{ .UnwrapOptional = {} }, .token = question_mark }; + break :blk .{ .op = .UnwrapOptional, .token = question_mark }; } - try tree.errors.push(AstError{ - .ExpectedSuffixOp = AstError.ExpectedSuffixOp{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedSuffixOp = .{ .token = it.index }, }); return null; } @@ -2464,7 +2454,7 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { }; const node = try arena.create(Node.SuffixOp); - node.* = Node.SuffixOp{ + node.* = .{ .lhs = undefined, // set by caller .op = op_and_token.op, .rtoken = op_and_token.token, @@ -2491,22 +2481,22 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No const lbracket = eatToken(it, .LBracket) orelse return null; const expr = try parseExpr(arena, it, tree); const sentinel = if (eatToken(it, .Colon)) |_| - try expectNode(arena, it, tree, parseExpr, AstError{ + try expectNode(arena, it, tree, parseExpr, .{ .ExpectedExpr = .{ .token = it.index }, }) else null; const rbracket = try expectToken(it, tree, .RBracket); - const op = if (expr) |len_expr| - Node.PrefixOp.Op{ + const op: Node.PrefixOp.Op = if (expr) |len_expr| + .{ .ArrayType = .{ .len_expr = len_expr, .sentinel = sentinel, }, } else - Node.PrefixOp.Op{ + .{ .SliceType = Node.PrefixOp.PtrInfo{ .allowzero_token = null, .align_info = null, @@ -2517,7 +2507,7 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No }; const node = try arena.create(Node.PrefixOp); - node.* = Node.PrefixOp{ + node.* = .{ .op_token = lbracket, .op = op, .rhs = undefined, // set by caller @@ -2533,7 +2523,7 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { if (eatToken(it, .Asterisk)) |asterisk| { const sentinel = if (eatToken(it, .Colon)) |_| - try expectNode(arena, it, tree, parseExpr, AstError{ + try expectNode(arena, it, tree, parseExpr, .{ .ExpectedExpr = .{ .token = it.index }, }) else @@ -2549,17 +2539,17 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node if (eatToken(it, .AsteriskAsterisk)) |double_asterisk| { const node = try arena.create(Node.PrefixOp); - node.* = Node.PrefixOp{ + node.* = .{ .op_token = double_asterisk, - .op = Node.PrefixOp.Op{ .PtrType = .{} }, + .op = .{ .PtrType = .{} }, .rhs = undefined, // set by caller }; // Special case for **, which is its own token const child = try arena.create(Node.PrefixOp); - child.* = Node.PrefixOp{ + child.* = .{ .op_token = double_asterisk, - .op = Node.PrefixOp.Op{ .PtrType = .{} }, + .op = .{ .PtrType = .{} }, .rhs = undefined, // set by caller }; node.rhs = &child.base; @@ -2586,7 +2576,7 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } } const sentinel = if (eatToken(it, .Colon)) |_| - try expectNode(arena, it, tree, parseExpr, AstError{ + try expectNode(arena, it, tree, parseExpr, .{ .ExpectedExpr = .{ .token = it.index }, }) else @@ -2629,8 +2619,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? .Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} }, .Keyword_enum => blk: { if (eatToken(it, .LParen) != null) { - const expr = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); break :blk Node.ContainerDecl.InitArg{ .Type = expr }; @@ -2641,8 +2631,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? if (eatToken(it, .LParen) != null) { if (eatToken(it, .Keyword_enum) != null) { if (eatToken(it, .LParen) != null) { - const expr = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); _ = try expectToken(it, tree, .RParen); @@ -2651,8 +2641,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? _ = try expectToken(it, tree, .RParen); break :blk Node.ContainerDecl.InitArg{ .Enum = null }; } - const expr = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); break :blk Node.ContainerDecl.InitArg{ .Type = expr }; @@ -2666,7 +2656,7 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? }; const node = try arena.create(Node.ContainerDecl); - node.* = Node.ContainerDecl{ + node.* = .{ .layout_token = null, .kind_token = kind_token.index, .init_arg_expr = init_arg_expr, @@ -2681,8 +2671,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? fn parseByteAlign(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { _ = eatToken(it, .Keyword_align) orelse return null; _ = try expectToken(it, tree, .LParen); - const expr = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); return expr; @@ -2738,7 +2728,7 @@ fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) No pub fn parse(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node { const op_token = eatToken(it, token) orelse return null; const node = try arena.create(Node.InfixOp); - node.* = Node.InfixOp{ + node.* = .{ .op_token = op_token, .lhs = undefined, // set by caller .op = op, @@ -2754,13 +2744,13 @@ fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) No fn parseBuiltinCall(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .Builtin) orelse return null; const params = (try parseFnCallArguments(arena, it, tree)) orelse { - try tree.errors.push(AstError{ - .ExpectedParamList = AstError.ExpectedParamList{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedParamList = .{ .token = it.index }, }); return error.ParseError; }; const node = try arena.create(Node.BuiltinCall); - node.* = Node.BuiltinCall{ + node.* = .{ .builtin_token = token, .params = params.list, .rparen_token = params.rparen, @@ -2773,7 +2763,7 @@ fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .Identifier) orelse return null; const node = try arena.create(Node.ErrorTag); - node.* = Node.ErrorTag{ + node.* = .{ .doc_comments = doc_comments, .name_token = token, }; @@ -2783,7 +2773,7 @@ fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .Identifier) orelse return null; const node = try arena.create(Node.Identifier); - node.* = Node.Identifier{ + node.* = .{ .token = token, }; return &node.base; @@ -2792,7 +2782,7 @@ fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { fn parseVarType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .Keyword_var) orelse return null; const node = try arena.create(Node.VarType); - node.* = Node.VarType{ + node.* = .{ .token = token, }; return &node.base; @@ -2810,7 +2800,7 @@ fn createLiteral(arena: *Allocator, comptime T: type, token: TokenIndex) !*Node fn parseStringLiteralSingle(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { if (eatToken(it, .StringLiteral)) |token| { const node = try arena.create(Node.StringLiteral); - node.* = Node.StringLiteral{ + node.* = .{ .token = token, }; return &node.base; @@ -2824,7 +2814,7 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod if (eatToken(it, .MultilineStringLiteralLine)) |first_line| { const node = try arena.create(Node.MultilineStringLiteral); - node.* = Node.MultilineStringLiteral{ + node.* = .{ .lines = Node.MultilineStringLiteral.LineList.init(arena), }; try node.lines.push(first_line); @@ -2840,7 +2830,7 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .IntegerLiteral) orelse return null; const node = try arena.create(Node.IntegerLiteral); - node.* = Node.IntegerLiteral{ + node.* = .{ .token = token, }; return &node.base; @@ -2849,7 +2839,7 @@ fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .FloatLiteral) orelse return null; const node = try arena.create(Node.FloatLiteral); - node.* = Node.FloatLiteral{ + node.* = .{ .token = token, }; return &node.base; @@ -2858,9 +2848,9 @@ fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .Keyword_try) orelse return null; const node = try arena.create(Node.PrefixOp); - node.* = Node.PrefixOp{ + node.* = .{ .op_token = token, - .op = Node.PrefixOp.Op.Try, + .op = .Try, .rhs = undefined, // set by caller }; return &node.base; @@ -2869,7 +2859,7 @@ fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .Keyword_usingnamespace) orelse return null; const node = try arena.create(Node.Use); - node.* = Node.Use{ + node.* = .{ .doc_comments = null, .visib_token = null, .use_token = token, @@ -2884,17 +2874,17 @@ fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: Node const node = (try parseIfPrefix(arena, it, tree)) orelse return null; const if_prefix = node.cast(Node.If).?; - if_prefix.body = try expectNode(arena, it, tree, bodyParseFn, AstError{ - .InvalidToken = AstError.InvalidToken{ .token = it.index }, + if_prefix.body = try expectNode(arena, it, tree, bodyParseFn, .{ + .InvalidToken = .{ .token = it.index }, }); const else_token = eatToken(it, .Keyword_else) orelse return node; const payload = try parsePayload(arena, it, tree); - const else_expr = try expectNode(arena, it, tree, bodyParseFn, AstError{ - .InvalidToken = AstError.InvalidToken{ .token = it.index }, + const else_expr = try expectNode(arena, it, tree, bodyParseFn, .{ + .InvalidToken = .{ .token = it.index }, }); const else_node = try arena.create(Node.Else); - else_node.* = Node.Else{ + else_node.* = .{ .else_token = else_token, .payload = payload, .body = else_expr, @@ -2914,7 +2904,7 @@ fn parseDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.D if (lines.len == 0) return null; const node = try arena.create(Node.DocComment); - node.* = Node.DocComment{ + node.* = .{ .lines = lines, }; return node; @@ -2925,7 +2915,7 @@ fn parseAppendedDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree, a const comment_token = eatToken(it, .DocComment) orelse return null; if (tree.tokensOnSameLine(after_token, comment_token)) { const node = try arena.create(Node.DocComment); - node.* = Node.DocComment{ + node.* = .{ .lines = Node.DocComment.LineList.init(arena), }; try node.lines.push(comment_token); @@ -2974,14 +2964,14 @@ fn parsePrefixOpExpr( switch (rightmost_op.id) { .PrefixOp => { const prefix_op = rightmost_op.cast(Node.PrefixOp).?; - prefix_op.rhs = try expectNode(arena, it, tree, childParseFn, AstError{ - .InvalidToken = AstError.InvalidToken{ .token = it.index }, + prefix_op.rhs = try expectNode(arena, it, tree, childParseFn, .{ + .InvalidToken = .{ .token = it.index }, }); }, .AnyFrameType => { const prom = rightmost_op.cast(Node.AnyFrameType).?; - prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, AstError{ - .InvalidToken = AstError.InvalidToken{ .token = it.index }, + prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, .{ + .InvalidToken = .{ .token = it.index }, }); }, else => unreachable, @@ -3010,8 +3000,8 @@ fn parseBinOpExpr( var res = (try childParseFn(arena, it, tree)) orelse return null; while (try opParseFn(arena, it, tree)) |node| { - const right = try expectNode(arena, it, tree, childParseFn, AstError{ - .InvalidToken = AstError.InvalidToken{ .token = it.index }, + const right = try expectNode(arena, it, tree, childParseFn, .{ + .InvalidToken = .{ .token = it.index }, }); const left = res; res = node; @@ -3031,7 +3021,7 @@ fn parseBinOpExpr( fn createInfixOp(arena: *Allocator, index: TokenIndex, op: Node.InfixOp.Op) !*Node { const node = try arena.create(Node.InfixOp); - node.* = Node.InfixOp{ + node.* = .{ .op_token = index, .lhs = undefined, // set by caller .op = op, @@ -3051,8 +3041,8 @@ fn eatAnnotatedToken(it: *TokenIterator, id: Token.Id) ?AnnotatedToken { fn expectToken(it: *TokenIterator, tree: *Tree, id: Token.Id) Error!TokenIndex { const token = nextToken(it); if (token.ptr.id != id) { - try tree.errors.push(AstError{ - .ExpectedToken = AstError.ExpectedToken{ .token = token.index, .expected_id = id }, + try tree.errors.push(.{ + .ExpectedToken = .{ .token = token.index, .expected_id = id }, }); return error.ParseError; } diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index d00568e49f..daeb197913 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -1,3 +1,16 @@ +test "zig fmt: errdefer with payload" { + try testCanonical( + \\pub fn main() anyerror!void { + \\ errdefer |a| x += 1; + \\ errdefer |a| {} + \\ errdefer |a| { + \\ x += 1; + \\ } + \\} + \\ + ); +} + test "zig fmt: noasync block" { try testCanonical( \\pub fn main() anyerror!void { @@ -1509,6 +1522,8 @@ test "zig fmt: error set declaration" { \\const Error = error{OutOfMemory}; \\const Error = error{}; \\ + \\const Error = error{ OutOfMemory, OutOfTime }; + \\ ); } @@ -2800,6 +2815,75 @@ test "zig fmt: extern without container keyword returns error" { ); } +test "zig fmt: integer literals with underscore separators" { + try testTransform( + \\const + \\ x = + \\ 1_234_567 + \\ +(0b0_1-0o7_0+0xff_FF ) + 0_0; + , + \\const x = 1_234_567 + (0b0_1 - 0o7_0 + 0xff_FF) + 0_0; + \\ + ); +} + +test "zig fmt: hex literals with underscore separators" { + try testTransform( + \\pub fn orMask(a: [ 1_000 ]u64, b: [ 1_000] u64) [1_000]u64 { + \\ var c: [1_000]u64 = [1]u64{ 0xFFFF_FFFF_FFFF_FFFF}**1_000; + \\ for (c [ 0_0 .. ]) |_, i| { + \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA; + \\ } + \\ return c; + \\} + \\ + \\ + , + \\pub fn orMask(a: [1_000]u64, b: [1_000]u64) [1_000]u64 { + \\ var c: [1_000]u64 = [1]u64{0xFFFF_FFFF_FFFF_FFFF} ** 1_000; + \\ for (c[0_0..]) |_, i| { + \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA; + \\ } + \\ return c; + \\} + \\ + ); +} + +test "zig fmt: decimal float literals with underscore separators" { + try testTransform( + \\pub fn main() void { + \\ const a:f64=(10.0e-0+(10.e+0))+10_00.00_00e-2+00_00.00_10e+4; + \\ const b:f64=010.0--0_10.+0_1_0.0_0+1e2; + \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); + \\} + , + \\pub fn main() void { + \\ const a: f64 = (10.0e-0 + (10.e+0)) + 10_00.00_00e-2 + 00_00.00_10e+4; + \\ const b: f64 = 010.0 - -0_10. + 0_1_0.0_0 + 1e2; + \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); + \\} + \\ + ); +} + +test "zig fmt: hexadeciaml float literals with underscore separators" { + try testTransform( + \\pub fn main() void { + \\ const a: f64 = (0x10.0p-0+(0x10.p+0))+0x10_00.00_00p-8+0x00_00.00_10p+16; + \\ const b: f64 = 0x0010.0--0x00_10.+0x10.00+0x1p4; + \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); + \\} + , + \\pub fn main() void { + \\ const a: f64 = (0x10.0p-0 + (0x10.p+0)) + 0x10_00.00_00p-8 + 0x00_00.00_10p+16; + \\ const b: f64 = 0x0010.0 - -0x00_10. + 0x10.00 + 0x1p4; + \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); + \\} + \\ + ); +} + const std = @import("std"); const mem = std.mem; const warn = std.debug.warn; diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 1a221bd5b3..37d058bebf 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -376,6 +376,9 @@ fn renderExpression( const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base); try renderToken(tree, stream, defer_node.defer_token, indent, start_col, Space.Space); + if (defer_node.payload) |payload| { + try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space); + } return renderExpression(allocator, stream, tree, indent, start_col, defer_node.expr, space); }, .Comptime => { @@ -583,7 +586,6 @@ fn renderExpression( }, .Try, - .Cancel, .Resume, => { try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space); @@ -1269,25 +1271,51 @@ fn renderExpression( } try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None); // error - try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // { - const new_indent = indent + indent_delta; - var it = err_set_decl.decls.iterator(0); - while (it.next()) |node| { - try stream.writeByteNTimes(' ', new_indent); + const src_has_trailing_comma = blk: { + const maybe_comma = tree.prevToken(err_set_decl.rbrace_token); + break :blk tree.tokens.at(maybe_comma).id == .Comma; + }; - if (it.peek()) |next_node| { - try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.None); - try renderToken(tree, stream, tree.nextToken(node.*.lastToken()), new_indent, start_col, Space.Newline); // , + if (src_has_trailing_comma) { + try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // { + const new_indent = indent + indent_delta; - try renderExtraNewline(tree, stream, start_col, next_node.*); - } else { - try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.Comma); + var it = err_set_decl.decls.iterator(0); + while (it.next()) |node| { + try stream.writeByteNTimes(' ', new_indent); + + if (it.peek()) |next_node| { + try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.None); + try renderToken(tree, stream, tree.nextToken(node.*.lastToken()), new_indent, start_col, Space.Newline); // , + + try renderExtraNewline(tree, stream, start_col, next_node.*); + } else { + try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.Comma); + } } - } - try stream.writeByteNTimes(' ', indent); - return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // } + try stream.writeByteNTimes(' ', indent); + return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // } + } else { + try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); // { + + var it = err_set_decl.decls.iterator(0); + while (it.next()) |node| { + if (it.peek()) |next_node| { + try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None); + + const comma_token = tree.nextToken(node.*.lastToken()); + assert(tree.tokens.at(comma_token).id == .Comma); + try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // , + try renderExtraNewline(tree, stream, start_col, next_node.*); + } else { + try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Space); + } + } + + return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // } + } }, .ErrorTag => { @@ -1590,8 +1618,7 @@ fn renderExpression( } } else { var it = switch_case.items.iterator(0); - while (true) { - const node = it.next().?; + while (it.next()) |node| { if (it.peek()) |next_node| { try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None); @@ -1602,7 +1629,6 @@ fn renderExpression( } else { try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Comma); try stream.writeByteNTimes(' ', indent); - break; } } } diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index 88b3022bb2..1714437add 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -468,6 +468,9 @@ pub const NativeTargetInfo = struct { error.InvalidUtf8 => unreachable, error.BadPathName => unreachable, error.PipeBusy => unreachable, + error.PermissionDenied => unreachable, + error.FileBusy => unreachable, + error.Locked => unreachable, error.IsDir, error.NotDir, @@ -754,7 +757,7 @@ pub const NativeTargetInfo = struct { const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr)); var it = mem.tokenize(rpath_list, ":"); while (it.next()) |rpath| { - var dir = fs.cwd().openDirList(rpath) catch |err| switch (err) { + var dir = fs.cwd().openDir(rpath, .{}) catch |err| switch (err) { error.NameTooLong => unreachable, error.InvalidUtf8 => unreachable, error.BadPathName => unreachable, diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig index f6c71479e7..6cb66595a7 100644 --- a/lib/std/zig/tokenizer.zig +++ b/lib/std/zig/tokenizer.zig @@ -387,17 +387,23 @@ pub const Tokenizer = struct { DocComment, ContainerDocComment, Zero, - IntegerLiteral, - IntegerLiteralWithRadix, - IntegerLiteralWithRadixHex, - NumberDot, + IntegerLiteralDec, + IntegerLiteralDecNoUnderscore, + IntegerLiteralBin, + IntegerLiteralBinNoUnderscore, + IntegerLiteralOct, + IntegerLiteralOctNoUnderscore, + IntegerLiteralHex, + IntegerLiteralHexNoUnderscore, + NumberDotDec, NumberDotHex, - FloatFraction, + FloatFractionDec, + FloatFractionDecNoUnderscore, FloatFractionHex, + FloatFractionHexNoUnderscore, FloatExponentUnsigned, - FloatExponentUnsignedHex, FloatExponentNumber, - FloatExponentNumberHex, + FloatExponentNumberNoUnderscore, Ampersand, Caret, Percent, @@ -412,6 +418,10 @@ pub const Tokenizer = struct { SawAtSign, }; + fn isIdentifierChar(char: u8) bool { + return std.ascii.isAlNum(char) or char == '_'; + } + pub fn next(self: *Tokenizer) Token { if (self.pending_invalid_token) |token| { self.pending_invalid_token = null; @@ -550,7 +560,7 @@ pub const Tokenizer = struct { result.id = Token.Id.IntegerLiteral; }, '1'...'9' => { - state = State.IntegerLiteral; + state = State.IntegerLiteralDec; result.id = Token.Id.IntegerLiteral; }, else => { @@ -1048,55 +1058,145 @@ pub const Tokenizer = struct { else => self.checkLiteralCharacter(), }, State.Zero => switch (c) { - 'b', 'o' => { - state = State.IntegerLiteralWithRadix; + 'b' => { + state = State.IntegerLiteralBinNoUnderscore; + }, + 'o' => { + state = State.IntegerLiteralOctNoUnderscore; }, 'x' => { - state = State.IntegerLiteralWithRadixHex; + state = State.IntegerLiteralHexNoUnderscore; + }, + '0'...'9', '_', '.', 'e', 'E' => { + // reinterpret as a decimal number + self.index -= 1; + state = State.IntegerLiteralDec; }, else => { - // reinterpret as a normal number - self.index -= 1; - state = State.IntegerLiteral; + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; }, }, - State.IntegerLiteral => switch (c) { - '.' => { - state = State.NumberDot; + State.IntegerLiteralBinNoUnderscore => switch (c) { + '0'...'1' => { + state = State.IntegerLiteralBin; }, - 'p', 'P', 'e', 'E' => { + else => { + result.id = Token.Id.Invalid; + break; + }, + }, + State.IntegerLiteralBin => switch (c) { + '_' => { + state = State.IntegerLiteralBinNoUnderscore; + }, + '0'...'1' => {}, + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; + }, + }, + State.IntegerLiteralOctNoUnderscore => switch (c) { + '0'...'7' => { + state = State.IntegerLiteralOct; + }, + else => { + result.id = Token.Id.Invalid; + break; + }, + }, + State.IntegerLiteralOct => switch (c) { + '_' => { + state = State.IntegerLiteralOctNoUnderscore; + }, + '0'...'7' => {}, + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; + }, + }, + State.IntegerLiteralDecNoUnderscore => switch (c) { + '0'...'9' => { + state = State.IntegerLiteralDec; + }, + else => { + result.id = Token.Id.Invalid; + break; + }, + }, + State.IntegerLiteralDec => switch (c) { + '_' => { + state = State.IntegerLiteralDecNoUnderscore; + }, + '.' => { + state = State.NumberDotDec; + result.id = Token.Id.FloatLiteral; + }, + 'e', 'E' => { state = State.FloatExponentUnsigned; + result.id = Token.Id.FloatLiteral; }, '0'...'9' => {}, - else => break, - }, - State.IntegerLiteralWithRadix => switch (c) { - '.' => { - state = State.NumberDot; + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; }, - '0'...'9' => {}, - else => break, }, - State.IntegerLiteralWithRadixHex => switch (c) { + State.IntegerLiteralHexNoUnderscore => switch (c) { + '0'...'9', 'a'...'f', 'A'...'F' => { + state = State.IntegerLiteralHex; + }, + else => { + result.id = Token.Id.Invalid; + break; + }, + }, + State.IntegerLiteralHex => switch (c) { + '_' => { + state = State.IntegerLiteralHexNoUnderscore; + }, '.' => { state = State.NumberDotHex; + result.id = Token.Id.FloatLiteral; }, 'p', 'P' => { - state = State.FloatExponentUnsignedHex; + state = State.FloatExponentUnsigned; + result.id = Token.Id.FloatLiteral; }, '0'...'9', 'a'...'f', 'A'...'F' => {}, - else => break, + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; + }, }, - State.NumberDot => switch (c) { + State.NumberDotDec => switch (c) { '.' => { self.index -= 1; state = State.Start; break; }, - else => { - self.index -= 1; + 'e', 'E' => { + state = State.FloatExponentUnsigned; + }, + '0'...'9' => { result.id = Token.Id.FloatLiteral; - state = State.FloatFraction; + state = State.FloatFractionDec; + }, + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; }, }, State.NumberDotHex => switch (c) { @@ -1105,65 +1205,112 @@ pub const Tokenizer = struct { state = State.Start; break; }, - else => { - self.index -= 1; + 'p', 'P' => { + state = State.FloatExponentUnsigned; + }, + '0'...'9', 'a'...'f', 'A'...'F' => { result.id = Token.Id.FloatLiteral; state = State.FloatFractionHex; }, + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; + }, }, - State.FloatFraction => switch (c) { + State.FloatFractionDecNoUnderscore => switch (c) { + '0'...'9' => { + state = State.FloatFractionDec; + }, + else => { + result.id = Token.Id.Invalid; + break; + }, + }, + State.FloatFractionDec => switch (c) { + '_' => { + state = State.FloatFractionDecNoUnderscore; + }, 'e', 'E' => { state = State.FloatExponentUnsigned; }, '0'...'9' => {}, - else => break, + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; + }, + }, + State.FloatFractionHexNoUnderscore => switch (c) { + '0'...'9', 'a'...'f', 'A'...'F' => { + state = State.FloatFractionHex; + }, + else => { + result.id = Token.Id.Invalid; + break; + }, }, State.FloatFractionHex => switch (c) { + '_' => { + state = State.FloatFractionHexNoUnderscore; + }, 'p', 'P' => { - state = State.FloatExponentUnsignedHex; + state = State.FloatExponentUnsigned; }, '0'...'9', 'a'...'f', 'A'...'F' => {}, - else => break, + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; + }, }, State.FloatExponentUnsigned => switch (c) { '+', '-' => { - state = State.FloatExponentNumber; + state = State.FloatExponentNumberNoUnderscore; }, else => { // reinterpret as a normal exponent number self.index -= 1; - state = State.FloatExponentNumber; + state = State.FloatExponentNumberNoUnderscore; }, }, - State.FloatExponentUnsignedHex => switch (c) { - '+', '-' => { - state = State.FloatExponentNumberHex; + State.FloatExponentNumberNoUnderscore => switch (c) { + '0'...'9' => { + state = State.FloatExponentNumber; }, else => { - // reinterpret as a normal exponent number - self.index -= 1; - state = State.FloatExponentNumberHex; + result.id = Token.Id.Invalid; + break; }, }, State.FloatExponentNumber => switch (c) { + '_' => { + state = State.FloatExponentNumberNoUnderscore; + }, '0'...'9' => {}, - else => break, - }, - State.FloatExponentNumberHex => switch (c) { - '0'...'9', 'a'...'f', 'A'...'F' => {}, - else => break, + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; + }, }, } } else if (self.index == self.buffer.len) { switch (state) { State.Start, - State.IntegerLiteral, - State.IntegerLiteralWithRadix, - State.IntegerLiteralWithRadixHex, - State.FloatFraction, + State.IntegerLiteralDec, + State.IntegerLiteralBin, + State.IntegerLiteralOct, + State.IntegerLiteralHex, + State.NumberDotDec, + State.NumberDotHex, + State.FloatFractionDec, State.FloatFractionHex, State.FloatExponentNumber, - State.FloatExponentNumberHex, State.StringLiteral, // find this error later State.MultilineStringLiteralLine, State.Builtin, @@ -1184,10 +1331,14 @@ pub const Tokenizer = struct { result.id = Token.Id.ContainerDocComment; }, - State.NumberDot, - State.NumberDotHex, + State.IntegerLiteralDecNoUnderscore, + State.IntegerLiteralBinNoUnderscore, + State.IntegerLiteralOctNoUnderscore, + State.IntegerLiteralHexNoUnderscore, + State.FloatFractionDecNoUnderscore, + State.FloatFractionHexNoUnderscore, + State.FloatExponentNumberNoUnderscore, State.FloatExponentUnsigned, - State.FloatExponentUnsignedHex, State.SawAtSign, State.Backslash, State.CharLiteral, @@ -1585,6 +1736,236 @@ test "correctly parse pointer assignment" { }); } +test "tokenizer - number literals decimal" { + testTokenize("0", &[_]Token.Id{.IntegerLiteral}); + testTokenize("1", &[_]Token.Id{.IntegerLiteral}); + testTokenize("2", &[_]Token.Id{.IntegerLiteral}); + testTokenize("3", &[_]Token.Id{.IntegerLiteral}); + testTokenize("4", &[_]Token.Id{.IntegerLiteral}); + testTokenize("5", &[_]Token.Id{.IntegerLiteral}); + testTokenize("6", &[_]Token.Id{.IntegerLiteral}); + testTokenize("7", &[_]Token.Id{.IntegerLiteral}); + testTokenize("8", &[_]Token.Id{.IntegerLiteral}); + testTokenize("9", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0a", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("9b", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1z", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1z_1", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("9z3", &[_]Token.Id{ .Invalid, .Identifier }); + + testTokenize("0_0", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0001", &[_]Token.Id{.IntegerLiteral}); + testTokenize("01234567890", &[_]Token.Id{.IntegerLiteral}); + testTokenize("012_345_6789_0", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0_1_2_3_4_5_6_7_8_9_0", &[_]Token.Id{.IntegerLiteral}); + + testTokenize("00_", &[_]Token.Id{.Invalid}); + testTokenize("0_0_", &[_]Token.Id{.Invalid}); + testTokenize("0__0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0_0f", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0_0_f", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0_0_f_00", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1_,", &[_]Token.Id{ .Invalid, .Comma }); + + testTokenize("1.", &[_]Token.Id{.FloatLiteral}); + testTokenize("0.0", &[_]Token.Id{.FloatLiteral}); + testTokenize("1.0", &[_]Token.Id{.FloatLiteral}); + testTokenize("10.0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0e0", &[_]Token.Id{.FloatLiteral}); + testTokenize("1e0", &[_]Token.Id{.FloatLiteral}); + testTokenize("1e100", &[_]Token.Id{.FloatLiteral}); + testTokenize("1.e100", &[_]Token.Id{.FloatLiteral}); + testTokenize("1.0e100", &[_]Token.Id{.FloatLiteral}); + testTokenize("1.0e+100", &[_]Token.Id{.FloatLiteral}); + testTokenize("1.0e-100", &[_]Token.Id{.FloatLiteral}); + testTokenize("1_0_0_0.0_0_0_0_0_1e1_0_0_0", &[_]Token.Id{.FloatLiteral}); + testTokenize("1.+", &[_]Token.Id{ .FloatLiteral, .Plus }); + + testTokenize("1e", &[_]Token.Id{.Invalid}); + testTokenize("1.0e1f0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1.0p100", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1.0p-100", &[_]Token.Id{ .Invalid, .Identifier, .Minus, .IntegerLiteral }); + testTokenize("1.0p1f0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1.0_,", &[_]Token.Id{ .Invalid, .Comma }); + testTokenize("1_.0", &[_]Token.Id{ .Invalid, .Period, .IntegerLiteral }); + testTokenize("1._", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1.a", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1.z", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1._0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1._+", &[_]Token.Id{ .Invalid, .Identifier, .Plus }); + testTokenize("1._e", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1.0e", &[_]Token.Id{.Invalid}); + testTokenize("1.0e,", &[_]Token.Id{ .Invalid, .Comma }); + testTokenize("1.0e_", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1.0e+_", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1.0e-_", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1.0e0_+", &[_]Token.Id{ .Invalid, .Plus }); +} + +test "tokenizer - number literals binary" { + testTokenize("0b0", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0b1", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0b2", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0b3", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0b4", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0b5", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0b6", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0b7", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0b8", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0b9", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0ba", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0bb", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0bc", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0bd", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0be", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0bf", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0bz", &[_]Token.Id{ .Invalid, .Identifier }); + + testTokenize("0b0000_0000", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0b1111_1111", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0b10_10_10_10", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0b0_1_0_1_0_1_0_1", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0b1.", &[_]Token.Id{ .IntegerLiteral, .Period }); + testTokenize("0b1.0", &[_]Token.Id{ .IntegerLiteral, .Period, .IntegerLiteral }); + + testTokenize("0B0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0b_", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0b_0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0b1_", &[_]Token.Id{.Invalid}); + testTokenize("0b0__1", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0b0_1_", &[_]Token.Id{.Invalid}); + testTokenize("0b1e", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0b1p", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0b1e0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0b1p0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0b1_,", &[_]Token.Id{ .Invalid, .Comma }); +} + +test "tokenizer - number literals octal" { + testTokenize("0o0", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o1", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o2", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o3", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o4", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o5", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o6", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o7", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o8", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0o9", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0oa", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0ob", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0oc", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0od", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0oe", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0of", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0oz", &[_]Token.Id{ .Invalid, .Identifier }); + + testTokenize("0o01234567", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o0123_4567", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o01_23_45_67", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o0_1_2_3_4_5_6_7", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o7.", &[_]Token.Id{ .IntegerLiteral, .Period }); + testTokenize("0o7.0", &[_]Token.Id{ .IntegerLiteral, .Period, .IntegerLiteral }); + + testTokenize("0O0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0o_", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0o_0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0o1_", &[_]Token.Id{.Invalid}); + testTokenize("0o0__1", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0o0_1_", &[_]Token.Id{.Invalid}); + testTokenize("0o1e", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0o1p", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0o1e0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0o1p0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0o_,", &[_]Token.Id{ .Invalid, .Identifier, .Comma }); +} + +test "tokenizer - number literals hexadeciaml" { + testTokenize("0x0", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x1", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x2", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x3", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x4", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x5", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x6", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x7", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x8", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x9", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xa", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xb", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xc", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xd", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xe", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xf", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xA", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xB", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xC", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xD", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xE", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xF", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x0z", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0xz", &[_]Token.Id{ .Invalid, .Identifier }); + + testTokenize("0x0123456789ABCDEF", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x0123_4567_89AB_CDEF", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x01_23_45_67_89AB_CDE_F", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F", &[_]Token.Id{.IntegerLiteral}); + + testTokenize("0X0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x_", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x_1", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x1_", &[_]Token.Id{.Invalid}); + testTokenize("0x0__1", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0_1_", &[_]Token.Id{.Invalid}); + testTokenize("0x_,", &[_]Token.Id{ .Invalid, .Identifier, .Comma }); + + testTokenize("0x1.", &[_]Token.Id{.FloatLiteral}); + testTokenize("0x1.0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xF.", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xF.0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xF.F", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xF.Fp0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xF.FP0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0x1p0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xfp0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0x1.+0xF.", &[_]Token.Id{ .FloatLiteral, .Plus, .FloatLiteral }); + + testTokenize("0x0123456.789ABCDEF", &[_]Token.Id{.FloatLiteral}); + testTokenize("0x0_123_456.789_ABC_DEF", &[_]Token.Id{.FloatLiteral}); + testTokenize("0x0_1_2_3_4_5_6.7_8_9_A_B_C_D_E_F", &[_]Token.Id{.FloatLiteral}); + testTokenize("0x0p0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0x0.0p0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xff.ffp10", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xff.ffP10", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xff.p10", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xffp10", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xff_ff.ff_ffp1_0_0_0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xf_f_f_f.f_f_f_fp+1_000", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xf_f_f_f.f_f_f_fp-1_00_0", &[_]Token.Id{.FloatLiteral}); + + testTokenize("0x1e", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x1e0", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x1p", &[_]Token.Id{.Invalid}); + testTokenize("0xfp0z1", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0xff.ffpff", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0.p", &[_]Token.Id{.Invalid}); + testTokenize("0x0.z", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0._", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0_.0", &[_]Token.Id{ .Invalid, .Period, .IntegerLiteral }); + testTokenize("0x0_.0.0", &[_]Token.Id{ .Invalid, .Period, .FloatLiteral }); + testTokenize("0x0._0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0.0_", &[_]Token.Id{.Invalid}); + testTokenize("0x0_p0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0_.p0", &[_]Token.Id{ .Invalid, .Period, .Identifier }); + testTokenize("0x0._p0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0.0_p0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0._0p0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0.0p_0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0.0p+_0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0.0p-_0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0.0p0_", &[_]Token.Id{ .Invalid, .Eof }); +} + fn testTokenize(source: []const u8, expected_tokens: []const Token.Id) void { var tokenizer = Tokenizer.init(source); for (expected_tokens) |expected_token_id| { diff --git a/src-self-hosted/c_int.zig b/src-self-hosted/c_int.zig index 1ee27c7596..e61a5bf657 100644 --- a/src-self-hosted/c_int.zig +++ b/src-self-hosted/c_int.zig @@ -69,9 +69,9 @@ pub const CInt = struct { }; pub fn sizeInBits(cint: CInt, self: Target) u32 { - const arch = self.getArch(); + const arch = self.cpu.arch; switch (self.os.tag) { - .freestanding, .other => switch (self.getArch()) { + .freestanding, .other => switch (self.cpu.arch) { .msp430 => switch (cint.id) { .Short, .UShort, @@ -94,7 +94,7 @@ pub const CInt = struct { => return 32, .Long, .ULong, - => return self.getArchPtrBitWidth(), + => return self.cpu.arch.ptrBitWidth(), .LongLong, .ULongLong, => return 64, @@ -114,7 +114,7 @@ pub const CInt = struct { => return 32, .Long, .ULong, - => return self.getArchPtrBitWidth(), + => return self.cpu.arch.ptrBitWidth(), .LongLong, .ULongLong, => return 64, diff --git a/src-self-hosted/clang_options.zig b/src-self-hosted/clang_options.zig new file mode 100644 index 0000000000..70525655de --- /dev/null +++ b/src-self-hosted/clang_options.zig @@ -0,0 +1,126 @@ +const std = @import("std"); +const mem = std.mem; + +pub const list = @import("clang_options_data.zig").data; + +pub const CliArg = struct { + name: []const u8, + syntax: Syntax, + + /// TODO we're going to want to change this when we start shipping self-hosted because this causes + /// all the functions in stage2.zig to get exported. + zig_equivalent: @import("stage2.zig").ClangArgIterator.ZigEquivalent, + + /// Prefixed by "-" + pd1: bool = false, + + /// Prefixed by "--" + pd2: bool = false, + + /// Prefixed by "/" + psl: bool = false, + + pub const Syntax = union(enum) { + /// A flag with no values. + flag, + + /// An option which prefixes its (single) value. + joined, + + /// An option which is followed by its value. + separate, + + /// An option which is either joined to its (non-empty) value, or followed by its value. + joined_or_separate, + + /// An option which is both joined to its (first) value, and followed by its (second) value. + joined_and_separate, + + /// An option followed by its values, which are separated by commas. + comma_joined, + + /// An option which consumes an optional joined argument and any other remaining arguments. + remaining_args_joined, + + /// An option which is which takes multiple (separate) arguments. + multi_arg: u8, + }; + + pub fn matchEql(self: CliArg, arg: []const u8) u2 { + if (self.pd1 and arg.len >= self.name.len + 1 and + mem.startsWith(u8, arg, "-") and mem.eql(u8, arg[1..], self.name)) + { + return 1; + } + if (self.pd2 and arg.len >= self.name.len + 2 and + mem.startsWith(u8, arg, "--") and mem.eql(u8, arg[2..], self.name)) + { + return 2; + } + if (self.psl and arg.len >= self.name.len + 1 and + mem.startsWith(u8, arg, "/") and mem.eql(u8, arg[1..], self.name)) + { + return 1; + } + return 0; + } + + pub fn matchStartsWith(self: CliArg, arg: []const u8) usize { + if (self.pd1 and arg.len >= self.name.len + 1 and + mem.startsWith(u8, arg, "-") and mem.startsWith(u8, arg[1..], self.name)) + { + return self.name.len + 1; + } + if (self.pd2 and arg.len >= self.name.len + 2 and + mem.startsWith(u8, arg, "--") and mem.startsWith(u8, arg[2..], self.name)) + { + return self.name.len + 2; + } + if (self.psl and arg.len >= self.name.len + 1 and + mem.startsWith(u8, arg, "/") and mem.startsWith(u8, arg[1..], self.name)) + { + return self.name.len + 1; + } + return 0; + } +}; + +/// Shortcut function for initializing a `CliArg` +pub fn flagpd1(name: []const u8) CliArg { + return .{ + .name = name, + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + }; +} + +/// Shortcut function for initializing a `CliArg` +pub fn joinpd1(name: []const u8) CliArg { + return .{ + .name = name, + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + }; +} + +/// Shortcut function for initializing a `CliArg` +pub fn jspd1(name: []const u8) CliArg { + return .{ + .name = name, + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + }; +} + +/// Shortcut function for initializing a `CliArg` +pub fn sepd1(name: []const u8) CliArg { + return .{ + .name = name, + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = true, + }; +} diff --git a/src-self-hosted/clang_options_data.zig b/src-self-hosted/clang_options_data.zig new file mode 100644 index 0000000000..1e472f80a5 --- /dev/null +++ b/src-self-hosted/clang_options_data.zig @@ -0,0 +1,5702 @@ +// This file is generated by tools/update_clang_options.zig. +// zig fmt: off +usingnamespace @import("clang_options.zig"); +pub const data = blk: { @setEvalBranchQuota(6000); break :blk &[_]CliArg{ +flagpd1("C"), +flagpd1("CC"), +.{ + .name = "E", + .syntax = .flag, + .zig_equivalent = .preprocess, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("EB"), +flagpd1("EL"), +flagpd1("Eonly"), +flagpd1("H"), +.{ + .name = "", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = false, + .psl = false, +}, +flagpd1("I-"), +flagpd1("M"), +flagpd1("MD"), +flagpd1("MG"), +flagpd1("MM"), +flagpd1("MMD"), +flagpd1("MP"), +flagpd1("MV"), +flagpd1("Mach"), +flagpd1("O0"), +flagpd1("O4"), +.{ + .name = "O", + .syntax = .flag, + .zig_equivalent = .optimize, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("ObjC"), +flagpd1("ObjC++"), +flagpd1("P"), +flagpd1("Q"), +flagpd1("Qn"), +flagpd1("Qunused-arguments"), +flagpd1("Qy"), +.{ + .name = "S", + .syntax = .flag, + .zig_equivalent = .driver_punt, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = false, + .psl = false, +}, +flagpd1("WCL4"), +flagpd1("Wall"), +flagpd1("Wdeprecated"), +flagpd1("Wlarge-by-value-copy"), +flagpd1("Wno-deprecated"), +flagpd1("Wno-rewrite-macros"), +flagpd1("Wno-write-strings"), +flagpd1("Wwrite-strings"), +flagpd1("X"), +sepd1("Xanalyzer"), +sepd1("Xassembler"), +sepd1("Xclang"), +sepd1("Xcuda-fatbinary"), +sepd1("Xcuda-ptxas"), +sepd1("Xlinker"), +sepd1("Xopenmp-target"), +sepd1("Xpreprocessor"), +flagpd1("Z"), +flagpd1("Z-Xlinker-no-demangle"), +flagpd1("Z-reserved-lib-cckext"), +flagpd1("Z-reserved-lib-stdc++"), +sepd1("Zlinker-input"), +.{ + .name = "CLASSPATH", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +flagpd1("###"), +.{ + .name = "Brepro", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Brepro-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Bt", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Bt+", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "C", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "E", + .syntax = .flag, + .zig_equivalent = .preprocess, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "EP", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "FA", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "FC", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "FS", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fx", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "G1", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "G2", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GA", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GF", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GF-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GH", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GL", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GL-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GR", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GR-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GS", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GS-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GT", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GX", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GX-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GZ", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gd", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Ge", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gh", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gm", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gm-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gr", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gregcall", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gv", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gw", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gw-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gy", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gy-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gz", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "H", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "HELP", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "J", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "JMC", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "LD", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "LDd", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "LN", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "MD", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "MDd", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "MT", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "MTd", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "P", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "QIfist", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "?", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Qfast_transcendentals", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Qimprecise_fwaits", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Qpar", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Qsafe_fp_loads", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Qspectre", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Qvec", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Qvec-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "TC", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "TP", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "V", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "W0", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "W1", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "W2", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "W3", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "W4", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "WL", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "WX", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "WX-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Wall", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Wp64", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "X", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Y-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Yd", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Z7", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "ZH:MD5", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "ZH:SHA1", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "ZH:SHA_256", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "ZI", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Za", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:__cplusplus", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:alignedNew", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:alignedNew-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:auto", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:char8_t", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:char8_t-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:dllexportInlines", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:dllexportInlines-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:forScope", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:inline", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:rvalueCast", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:sizedDealloc", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:sizedDealloc-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:strictStrings", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:ternary", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:threadSafeInit", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:threadSafeInit-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:trigraphs", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:trigraphs-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:twoPhase", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:twoPhase-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:wchar_t", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zd", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Ze", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zg", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zi", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zl", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zo", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zo-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zp", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zs", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "analyze-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "await", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "bigobj", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "c", + .syntax = .flag, + .zig_equivalent = .c, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "d1PP", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "d1reportAllClassLayout", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "d2FastFail", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "d2Zi+", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "diagnostics:caret", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "diagnostics:classic", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "diagnostics:column", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "fallback", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "fp:except", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "fp:except-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "fp:fast", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "fp:precise", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "fp:strict", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "help", + .syntax = .flag, + .zig_equivalent = .driver_punt, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "homeparams", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "hotpatch", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "kernel", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "kernel-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "nologo", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "openmp", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "openmp-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "openmp:experimental", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "permissive-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "sdl", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "sdl-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "showFilenames", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "showFilenames-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "showIncludes", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "u", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "utf-8", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "validate-charset", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "validate-charset-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "vmb", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "vmg", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "vmm", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "vms", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "vmv", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "volatile:iso", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "volatile:ms", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "w", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "wd4005", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "wd4018", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "wd4100", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "wd4910", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "wd4996", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "all-warnings", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "analyze", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "analyzer-no-default-checks", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "assemble", + .syntax = .flag, + .zig_equivalent = .driver_punt, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "assert", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "bootclasspath", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "classpath", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "comments", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "comments-in-macros", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "compile", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "constant-cfstrings", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "debug", + .syntax = .flag, + .zig_equivalent = .debug, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "define-macro", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "dependencies", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "dyld-prefix", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "encoding", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "entry", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "extdirs", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "extra-warnings", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "for-linker", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "force-link", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "help-hidden", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-barrier", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-directory", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-directory-after", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-prefix", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-with-prefix", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-with-prefix-after", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-with-prefix-before", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "language", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "library-directory", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "mhwdiv", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "migrate", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-line-commands", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-standard-includes", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-standard-libraries", + .syntax = .flag, + .zig_equivalent = .nostdlib, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-undefined", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-warnings", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "optimize", + .syntax = .flag, + .zig_equivalent = .optimize, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "output", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "output-class-directory", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "param", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "precompile", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "prefix", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "preprocess", + .syntax = .flag, + .zig_equivalent = .preprocess, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-diagnostic-categories", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-file-name", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-missing-file-dependencies", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-prog-name", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "profile", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "profile-blocks", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "resource", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "rtlib", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "serialize-diagnostics", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "signed-char", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "std", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "stdlib", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "sysroot", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "target-help", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "trace-includes", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "undefine-macro", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "unsigned-char", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "user-dependencies", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "verbose", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "version", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "write-dependencies", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "write-user-dependencies", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +sepd1("add-plugin"), +flagpd1("faggressive-function-elimination"), +flagpd1("fno-aggressive-function-elimination"), +flagpd1("falign-commons"), +flagpd1("fno-align-commons"), +flagpd1("falign-jumps"), +flagpd1("fno-align-jumps"), +flagpd1("falign-labels"), +flagpd1("fno-align-labels"), +flagpd1("falign-loops"), +flagpd1("fno-align-loops"), +flagpd1("faligned-alloc-unavailable"), +flagpd1("all_load"), +flagpd1("fall-intrinsics"), +flagpd1("fno-all-intrinsics"), +sepd1("allowable_client"), +flagpd1("cfg-add-implicit-dtors"), +flagpd1("unoptimized-cfg"), +flagpd1("analyze"), +sepd1("analyze-function"), +sepd1("analyzer-checker"), +flagpd1("analyzer-checker-help"), +flagpd1("analyzer-checker-help-alpha"), +flagpd1("analyzer-checker-help-developer"), +flagpd1("analyzer-checker-option-help"), +flagpd1("analyzer-checker-option-help-alpha"), +flagpd1("analyzer-checker-option-help-developer"), +sepd1("analyzer-config"), +sepd1("analyzer-config-compatibility-mode"), +flagpd1("analyzer-config-help"), +sepd1("analyzer-constraints"), +flagpd1("analyzer-disable-all-checks"), +sepd1("analyzer-disable-checker"), +flagpd1("analyzer-disable-retry-exhausted"), +flagpd1("analyzer-display-progress"), +sepd1("analyzer-dump-egraph"), +sepd1("analyzer-inline-max-stack-depth"), +sepd1("analyzer-inlining-mode"), +flagpd1("analyzer-list-enabled-checkers"), +sepd1("analyzer-max-loop"), +flagpd1("analyzer-opt-analyze-headers"), +flagpd1("analyzer-opt-analyze-nested-blocks"), +sepd1("analyzer-output"), +sepd1("analyzer-purge"), +flagpd1("analyzer-stats"), +sepd1("analyzer-store"), +flagpd1("analyzer-viz-egraph-graphviz"), +flagpd1("analyzer-werror"), +flagpd1("fslp-vectorize-aggressive"), +flagpd1("fno-slp-vectorize-aggressive"), +flagpd1("fexpensive-optimizations"), +flagpd1("fno-expensive-optimizations"), +flagpd1("fdefer-pop"), +flagpd1("fno-defer-pop"), +flagpd1("fextended-identifiers"), +flagpd1("fno-extended-identifiers"), +flagpd1("fhonor-infinites"), +flagpd1("fno-honor-infinites"), +flagpd1("findirect-virtual-calls"), +sepd1("fnew-alignment"), +flagpd1("faligned-new"), +flagpd1("fno-aligned-new"), +flagpd1("fsched-interblock"), +flagpd1("ftree-vectorize"), +flagpd1("fno-tree-vectorize"), +flagpd1("ftree-slp-vectorize"), +flagpd1("fno-tree-slp-vectorize"), +flagpd1("fterminated-vtables"), +flagpd1("grecord-gcc-switches"), +flagpd1("gno-record-gcc-switches"), +flagpd1("fident"), +flagpd1("nocudalib"), +.{ + .name = "system-header-prefix", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-system-header-prefix", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +flagpd1("integrated-as"), +flagpd1("no-integrated-as"), +flagpd1("fkeep-inline-functions"), +flagpd1("fno-keep-inline-functions"), +flagpd1("fno-semantic-interposition"), +.{ + .name = "Gs", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "O1", + .syntax = .flag, + .zig_equivalent = .optimize, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "O2", + .syntax = .flag, + .zig_equivalent = .optimize, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +flagpd1("fno-ident"), +.{ + .name = "Ob0", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Ob1", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Ob2", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Od", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Og", + .syntax = .flag, + .zig_equivalent = .optimize, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Oi", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Oi-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Os", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Ot", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Ox", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +flagpd1("fcuda-rdc"), +.{ + .name = "Oy", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Oy-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +flagpd1("fno-cuda-rdc"), +flagpd1("shared-libasan"), +flagpd1("frecord-gcc-switches"), +flagpd1("fno-record-gcc-switches"), +.{ + .name = "ansi", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +sepd1("arch"), +flagpd1("arch_errors_fatal"), +sepd1("arch_only"), +flagpd1("arcmt-check"), +flagpd1("arcmt-migrate"), +flagpd1("arcmt-migrate-emit-errors"), +sepd1("arcmt-migrate-report-output"), +flagpd1("arcmt-modify"), +flagpd1("ast-dump"), +flagpd1("ast-dump-all"), +sepd1("ast-dump-filter"), +flagpd1("ast-dump-lookups"), +flagpd1("ast-list"), +sepd1("ast-merge"), +flagpd1("ast-print"), +flagpd1("ast-view"), +flagpd1("fautomatic"), +flagpd1("fno-automatic"), +sepd1("aux-triple"), +flagpd1("fbackslash"), +flagpd1("fno-backslash"), +flagpd1("fbacktrace"), +flagpd1("fno-backtrace"), +flagpd1("bind_at_load"), +flagpd1("fbounds-check"), +flagpd1("fno-bounds-check"), +flagpd1("fbranch-count-reg"), +flagpd1("fno-branch-count-reg"), +flagpd1("building-pch-with-obj"), +flagpd1("bundle"), +sepd1("bundle_loader"), +.{ + .name = "c", + .syntax = .flag, + .zig_equivalent = .c, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("fcaller-saves"), +flagpd1("fno-caller-saves"), +flagpd1("cc1"), +flagpd1("cc1as"), +flagpd1("ccc-arcmt-check"), +sepd1("ccc-arcmt-migrate"), +flagpd1("ccc-arcmt-modify"), +sepd1("ccc-gcc-name"), +sepd1("ccc-install-dir"), +sepd1("ccc-objcmt-migrate"), +flagpd1("ccc-print-bindings"), +flagpd1("ccc-print-phases"), +flagpd1("cfguard"), +flagpd1("cfguard-no-checks"), +sepd1("chain-include"), +flagpd1("fcheck-array-temporaries"), +flagpd1("fno-check-array-temporaries"), +flagpd1("cl-denorms-are-zero"), +flagpd1("cl-fast-relaxed-math"), +flagpd1("cl-finite-math-only"), +flagpd1("cl-fp32-correctly-rounded-divide-sqrt"), +flagpd1("cl-kernel-arg-info"), +flagpd1("cl-mad-enable"), +flagpd1("cl-no-signed-zeros"), +flagpd1("cl-opt-disable"), +flagpd1("cl-single-precision-constant"), +flagpd1("cl-strict-aliasing"), +flagpd1("cl-uniform-work-group-size"), +flagpd1("cl-unsafe-math-optimizations"), +sepd1("code-completion-at"), +flagpd1("code-completion-brief-comments"), +flagpd1("code-completion-macros"), +flagpd1("code-completion-patterns"), +flagpd1("code-completion-with-fixits"), +.{ + .name = "combine", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("compiler-options-dump"), +.{ + .name = "compress-debug-sections", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "config", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "coverage", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("coverage-cfg-checksum"), +sepd1("coverage-data-file"), +flagpd1("coverage-exit-block-before-body"), +flagpd1("coverage-no-function-names-in-data"), +sepd1("coverage-notes-file"), +flagpd1("cpp"), +flagpd1("cpp-precomp"), +flagpd1("fcray-pointer"), +flagpd1("fno-cray-pointer"), +.{ + .name = "cuda-compile-host-device", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cuda-device-only", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cuda-host-only", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cuda-noopt-device-debug", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cuda-path-ignore-env", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +flagpd1("dA"), +flagpd1("dD"), +flagpd1("dI"), +flagpd1("dM"), +flagpd1("d"), +flagpd1("fd-lines-as-code"), +flagpd1("fno-d-lines-as-code"), +flagpd1("fd-lines-as-comments"), +flagpd1("fno-d-lines-as-comments"), +flagpd1("dead_strip"), +flagpd1("debug-forward-template-params"), +flagpd1("debug-info-macro"), +flagpd1("fdefault-double-8"), +flagpd1("fno-default-double-8"), +sepd1("default-function-attr"), +flagpd1("fdefault-inline"), +flagpd1("fno-default-inline"), +flagpd1("fdefault-integer-8"), +flagpd1("fno-default-integer-8"), +flagpd1("fdefault-real-8"), +flagpd1("fno-default-real-8"), +sepd1("defsym"), +sepd1("dependency-dot"), +sepd1("dependency-file"), +flagpd1("detailed-preprocessing-record"), +flagpd1("fdevirtualize"), +flagpd1("fno-devirtualize"), +flagpd1("fdevirtualize-speculatively"), +flagpd1("fno-devirtualize-speculatively"), +sepd1("diagnostic-log-file"), +sepd1("serialize-diagnostic-file"), +flagpd1("disable-O0-optnone"), +flagpd1("disable-free"), +flagpd1("disable-lifetime-markers"), +flagpd1("disable-llvm-optzns"), +flagpd1("disable-llvm-passes"), +flagpd1("disable-llvm-verifier"), +flagpd1("disable-objc-default-synthesize-properties"), +flagpd1("disable-pragma-debug-crash"), +flagpd1("disable-red-zone"), +flagpd1("discard-value-names"), +flagpd1("fdollar-ok"), +flagpd1("fno-dollar-ok"), +flagpd1("dump-coverage-mapping"), +flagpd1("dump-deserialized-decls"), +flagpd1("fdump-fortran-optimized"), +flagpd1("fno-dump-fortran-optimized"), +flagpd1("fdump-fortran-original"), +flagpd1("fno-dump-fortran-original"), +flagpd1("fdump-parse-tree"), +flagpd1("fno-dump-parse-tree"), +flagpd1("dump-raw-tokens"), +flagpd1("dump-tokens"), +flagpd1("dumpmachine"), +flagpd1("dumpspecs"), +flagpd1("dumpversion"), +flagpd1("dwarf-column-info"), +sepd1("dwarf-debug-flags"), +sepd1("dwarf-debug-producer"), +flagpd1("dwarf-explicit-import"), +flagpd1("dwarf-ext-refs"), +sepd1("dylib_file"), +flagpd1("dylinker"), +flagpd1("dynamic"), +flagpd1("dynamiclib"), +flagpd1("feliminate-unused-debug-types"), +flagpd1("fno-eliminate-unused-debug-types"), +flagpd1("emit-ast"), +flagpd1("emit-codegen-only"), +flagpd1("emit-header-module"), +flagpd1("emit-html"), +flagpd1("emit-interface-stubs"), +flagpd1("emit-llvm"), +flagpd1("emit-llvm-bc"), +flagpd1("emit-llvm-only"), +flagpd1("emit-llvm-uselists"), +flagpd1("emit-merged-ifs"), +flagpd1("emit-module"), +flagpd1("emit-module-interface"), +flagpd1("emit-obj"), +flagpd1("emit-pch"), +flagpd1("enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang"), +sepd1("error-on-deserialized-decl"), +sepd1("exported_symbols_list"), +flagpd1("fexternal-blas"), +flagpd1("fno-external-blas"), +flagpd1("ff2c"), +flagpd1("fno-f2c"), +.{ + .name = "fPIC", + .syntax = .flag, + .zig_equivalent = .pic, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("fPIE"), +flagpd1("faccess-control"), +flagpd1("faddrsig"), +flagpd1("falign-functions"), +flagpd1("faligned-allocation"), +flagpd1("fallow-editor-placeholders"), +flagpd1("fallow-half-arguments-and-returns"), +flagpd1("fallow-pch-with-compiler-errors"), +flagpd1("fallow-unsupported"), +flagpd1("faltivec"), +flagpd1("fansi-escape-codes"), +flagpd1("fapple-kext"), +flagpd1("fapple-link-rtlib"), +flagpd1("fapple-pragma-pack"), +flagpd1("fapplication-extension"), +flagpd1("fapply-global-visibility-to-externs"), +flagpd1("fasm"), +flagpd1("fasm-blocks"), +flagpd1("fassociative-math"), +flagpd1("fassume-sane-operator-new"), +flagpd1("fast"), +flagpd1("fastcp"), +flagpd1("fastf"), +flagpd1("fasynchronous-unwind-tables"), +flagpd1("ffat-lto-objects"), +flagpd1("fno-fat-lto-objects"), +flagpd1("fauto-profile"), +flagpd1("fauto-profile-accurate"), +flagpd1("fautolink"), +flagpd1("fblocks"), +flagpd1("fblocks-runtime-optional"), +flagpd1("fborland-extensions"), +sepd1("fbracket-depth"), +flagpd1("fbuiltin"), +flagpd1("fbuiltin-module-map"), +flagpd1("fcall-saved-x10"), +flagpd1("fcall-saved-x11"), +flagpd1("fcall-saved-x12"), +flagpd1("fcall-saved-x13"), +flagpd1("fcall-saved-x14"), +flagpd1("fcall-saved-x15"), +flagpd1("fcall-saved-x18"), +flagpd1("fcall-saved-x8"), +flagpd1("fcall-saved-x9"), +flagpd1("fcaret-diagnostics"), +sepd1("fcaret-diagnostics-max-lines"), +flagpd1("fcf-protection"), +flagpd1("fchar8_t"), +flagpd1("fcheck-new"), +flagpd1("fno-check-new"), +flagpd1("fcolor-diagnostics"), +flagpd1("fcommon"), +flagpd1("fcomplete-member-pointers"), +flagpd1("fconcepts-ts"), +flagpd1("fconst-strings"), +flagpd1("fconstant-cfstrings"), +sepd1("fconstant-string-class"), +sepd1("fconstexpr-backtrace-limit"), +sepd1("fconstexpr-depth"), +sepd1("fconstexpr-steps"), +flagpd1("fconvergent-functions"), +flagpd1("fcoroutines-ts"), +flagpd1("fcoverage-mapping"), +flagpd1("fcreate-profile"), +flagpd1("fcs-profile-generate"), +flagpd1("fcuda-allow-variadic-functions"), +flagpd1("fcuda-approx-transcendentals"), +flagpd1("fcuda-flush-denormals-to-zero"), +sepd1("fcuda-include-gpubinary"), +flagpd1("fcuda-is-device"), +flagpd1("fcuda-short-ptr"), +flagpd1("fcxx-exceptions"), +flagpd1("fcxx-modules"), +flagpd1("fc++-static-destructors"), +flagpd1("fdata-sections"), +sepd1("fdebug-compilation-dir"), +flagpd1("fdebug-info-for-profiling"), +flagpd1("fdebug-macro"), +flagpd1("fdebug-pass-arguments"), +flagpd1("fdebug-pass-manager"), +flagpd1("fdebug-pass-structure"), +flagpd1("fdebug-ranges-base-address"), +flagpd1("fdebug-types-section"), +flagpd1("fdebugger-cast-result-to-id"), +flagpd1("fdebugger-objc-literal"), +flagpd1("fdebugger-support"), +flagpd1("fdeclare-opencl-builtins"), +flagpd1("fdeclspec"), +flagpd1("fdelayed-template-parsing"), +flagpd1("fdelete-null-pointer-checks"), +flagpd1("fdeprecated-macro"), +flagpd1("fdiagnostics-absolute-paths"), +flagpd1("fdiagnostics-color"), +flagpd1("fdiagnostics-fixit-info"), +sepd1("fdiagnostics-format"), +flagpd1("fdiagnostics-parseable-fixits"), +flagpd1("fdiagnostics-print-source-range-info"), +sepd1("fdiagnostics-show-category"), +flagpd1("fdiagnostics-show-hotness"), +flagpd1("fdiagnostics-show-note-include-stack"), +flagpd1("fdiagnostics-show-option"), +flagpd1("fdiagnostics-show-template-tree"), +flagpd1("fdigraphs"), +flagpd1("fdisable-module-hash"), +flagpd1("fdiscard-value-names"), +flagpd1("fdollars-in-identifiers"), +flagpd1("fdouble-square-bracket-attributes"), +flagpd1("fdump-record-layouts"), +flagpd1("fdump-record-layouts-simple"), +flagpd1("fdump-vtable-layouts"), +flagpd1("fdwarf2-cfi-asm"), +flagpd1("fdwarf-directory-asm"), +flagpd1("fdwarf-exceptions"), +flagpd1("felide-constructors"), +flagpd1("feliminate-unused-debug-symbols"), +flagpd1("fembed-bitcode"), +flagpd1("fembed-bitcode-marker"), +flagpd1("femit-all-decls"), +flagpd1("femit-coverage-data"), +flagpd1("femit-coverage-notes"), +flagpd1("femit-debug-entry-values"), +flagpd1("femulated-tls"), +flagpd1("fencode-extended-block-signature"), +sepd1("ferror-limit"), +flagpd1("fescaping-block-tail-calls"), +flagpd1("fexceptions"), +flagpd1("fexperimental-isel"), +flagpd1("fexperimental-new-constant-interpreter"), +flagpd1("fexperimental-new-pass-manager"), +flagpd1("fexternc-nounwind"), +flagpd1("ffake-address-space-map"), +flagpd1("ffast-math"), +flagpd1("ffine-grained-bitfield-accesses"), +flagpd1("ffinite-math-only"), +flagpd1("ffixed-point"), +flagpd1("ffixed-r19"), +flagpd1("ffixed-r9"), +flagpd1("ffixed-x1"), +flagpd1("ffixed-x10"), +flagpd1("ffixed-x11"), +flagpd1("ffixed-x12"), +flagpd1("ffixed-x13"), +flagpd1("ffixed-x14"), +flagpd1("ffixed-x15"), +flagpd1("ffixed-x16"), +flagpd1("ffixed-x17"), +flagpd1("ffixed-x18"), +flagpd1("ffixed-x19"), +flagpd1("ffixed-x2"), +flagpd1("ffixed-x20"), +flagpd1("ffixed-x21"), +flagpd1("ffixed-x22"), +flagpd1("ffixed-x23"), +flagpd1("ffixed-x24"), +flagpd1("ffixed-x25"), +flagpd1("ffixed-x26"), +flagpd1("ffixed-x27"), +flagpd1("ffixed-x28"), +flagpd1("ffixed-x29"), +flagpd1("ffixed-x3"), +flagpd1("ffixed-x30"), +flagpd1("ffixed-x31"), +flagpd1("ffixed-x4"), +flagpd1("ffixed-x5"), +flagpd1("ffixed-x6"), +flagpd1("ffixed-x7"), +flagpd1("ffixed-x8"), +flagpd1("ffixed-x9"), +flagpd1("ffor-scope"), +flagpd1("fforbid-guard-variables"), +flagpd1("fforce-dwarf-frame"), +flagpd1("fforce-emit-vtables"), +flagpd1("fforce-enable-int128"), +flagpd1("ffreestanding"), +flagpd1("ffunction-sections"), +flagpd1("fgnu89-inline"), +flagpd1("fgnu-inline-asm"), +flagpd1("fgnu-keywords"), +flagpd1("fgnu-runtime"), +flagpd1("fgpu-allow-device-init"), +flagpd1("fgpu-rdc"), +flagpd1("fheinous-gnu-extensions"), +flagpd1("fhip-dump-offload-linker-script"), +flagpd1("fhip-new-launch-api"), +flagpd1("fhonor-infinities"), +flagpd1("fhonor-nans"), +flagpd1("fhosted"), +sepd1("filelist"), +sepd1("filetype"), +flagpd1("fimplicit-module-maps"), +flagpd1("fimplicit-modules"), +flagpd1("finclude-default-header"), +flagpd1("finline"), +flagpd1("finline-functions"), +flagpd1("finline-hint-functions"), +flagpd1("finline-limit"), +flagpd1("fno-inline-limit"), +flagpd1("finstrument-function-entry-bare"), +flagpd1("finstrument-functions"), +flagpd1("finstrument-functions-after-inlining"), +flagpd1("fintegrated-as"), +flagpd1("fintegrated-cc1"), +flagpd1("fix-only-warnings"), +flagpd1("fix-what-you-can"), +flagpd1("ffixed-form"), +flagpd1("fno-fixed-form"), +flagpd1("fixit"), +flagpd1("fixit-recompile"), +flagpd1("fixit-to-temporary"), +flagpd1("fjump-tables"), +flagpd1("fkeep-static-consts"), +flagpd1("flat_namespace"), +flagpd1("flax-vector-conversions"), +flagpd1("flimit-debug-info"), +flagpd1("ffloat-store"), +flagpd1("fno-float-store"), +flagpd1("flto"), +flagpd1("flto-unit"), +flagpd1("flto-visibility-public-std"), +sepd1("fmacro-backtrace-limit"), +flagpd1("fmath-errno"), +flagpd1("fmerge-all-constants"), +flagpd1("fmerge-functions"), +sepd1("fmessage-length"), +sepd1("fmodule-feature"), +flagpd1("fmodule-file-deps"), +sepd1("fmodule-implementation-of"), +flagpd1("fmodule-map-file-home-is-cwd"), +flagpd1("fmodule-maps"), +sepd1("fmodule-name"), +flagpd1("fmodules"), +flagpd1("fmodules-codegen"), +flagpd1("fmodules-debuginfo"), +flagpd1("fmodules-decluse"), +flagpd1("fmodules-disable-diagnostic-validation"), +flagpd1("fmodules-hash-content"), +flagpd1("fmodules-local-submodule-visibility"), +flagpd1("fmodules-search-all"), +flagpd1("fmodules-strict-context-hash"), +flagpd1("fmodules-strict-decluse"), +flagpd1("fmodules-ts"), +sepd1("fmodules-user-build-path"), +flagpd1("fmodules-validate-input-files-content"), +flagpd1("fmodules-validate-once-per-build-session"), +flagpd1("fmodules-validate-system-headers"), +flagpd1("fms-compatibility"), +flagpd1("fms-extensions"), +flagpd1("fms-volatile"), +flagpd1("fmudflap"), +flagpd1("fmudflapth"), +flagpd1("fnative-half-arguments-and-returns"), +flagpd1("fnative-half-type"), +flagpd1("fnested-functions"), +flagpd1("fnext-runtime"), +.{ + .name = "fno-PIC", + .syntax = .flag, + .zig_equivalent = .no_pic, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("fno-PIE"), +flagpd1("fno-access-control"), +flagpd1("fno-addrsig"), +flagpd1("fno-align-functions"), +flagpd1("fno-aligned-allocation"), +flagpd1("fno-allow-editor-placeholders"), +flagpd1("fno-altivec"), +flagpd1("fno-apple-pragma-pack"), +flagpd1("fno-application-extension"), +flagpd1("fno-asm"), +flagpd1("fno-asm-blocks"), +flagpd1("fno-associative-math"), +flagpd1("fno-assume-sane-operator-new"), +flagpd1("fno-asynchronous-unwind-tables"), +flagpd1("fno-auto-profile"), +flagpd1("fno-auto-profile-accurate"), +flagpd1("fno-autolink"), +flagpd1("fno-bitfield-type-align"), +flagpd1("fno-blocks"), +flagpd1("fno-borland-extensions"), +flagpd1("fno-builtin"), +flagpd1("fno-caret-diagnostics"), +flagpd1("fno-char8_t"), +flagpd1("fno-color-diagnostics"), +flagpd1("fno-common"), +flagpd1("fno-complete-member-pointers"), +flagpd1("fno-concept-satisfaction-caching"), +flagpd1("fno-const-strings"), +flagpd1("fno-constant-cfstrings"), +flagpd1("fno-coroutines-ts"), +flagpd1("fno-coverage-mapping"), +flagpd1("fno-crash-diagnostics"), +flagpd1("fno-cuda-approx-transcendentals"), +flagpd1("fno-cuda-flush-denormals-to-zero"), +flagpd1("fno-cuda-host-device-constexpr"), +flagpd1("fno-cuda-short-ptr"), +flagpd1("fno-cxx-exceptions"), +flagpd1("fno-cxx-modules"), +flagpd1("fno-c++-static-destructors"), +flagpd1("fno-data-sections"), +flagpd1("fno-debug-info-for-profiling"), +flagpd1("fno-debug-macro"), +flagpd1("fno-debug-pass-manager"), +flagpd1("fno-debug-ranges-base-address"), +flagpd1("fno-debug-types-section"), +flagpd1("fno-declspec"), +flagpd1("fno-delayed-template-parsing"), +flagpd1("fno-delete-null-pointer-checks"), +flagpd1("fno-deprecated-macro"), +flagpd1("fno-diagnostics-color"), +flagpd1("fno-diagnostics-fixit-info"), +flagpd1("fno-diagnostics-show-hotness"), +flagpd1("fno-diagnostics-show-note-include-stack"), +flagpd1("fno-diagnostics-show-option"), +flagpd1("fno-diagnostics-use-presumed-location"), +flagpd1("fno-digraphs"), +flagpd1("fno-discard-value-names"), +flagpd1("fno-dllexport-inlines"), +flagpd1("fno-dollars-in-identifiers"), +flagpd1("fno-double-square-bracket-attributes"), +flagpd1("fno-dwarf2-cfi-asm"), +flagpd1("fno-dwarf-directory-asm"), +flagpd1("fno-elide-constructors"), +flagpd1("fno-elide-type"), +flagpd1("fno-eliminate-unused-debug-symbols"), +flagpd1("fno-emulated-tls"), +flagpd1("fno-escaping-block-tail-calls"), +flagpd1("fno-exceptions"), +flagpd1("fno-experimental-isel"), +flagpd1("fno-experimental-new-pass-manager"), +flagpd1("fno-fast-math"), +flagpd1("fno-fine-grained-bitfield-accesses"), +flagpd1("fno-finite-math-only"), +flagpd1("fno-fixed-point"), +flagpd1("fno-for-scope"), +flagpd1("fno-force-dwarf-frame"), +flagpd1("fno-force-emit-vtables"), +flagpd1("fno-force-enable-int128"), +flagpd1("fno-function-sections"), +flagpd1("fno-gnu89-inline"), +flagpd1("fno-gnu-inline-asm"), +flagpd1("fno-gnu-keywords"), +flagpd1("fno-gpu-allow-device-init"), +flagpd1("fno-gpu-rdc"), +flagpd1("fno-hip-new-launch-api"), +flagpd1("fno-honor-infinities"), +flagpd1("fno-honor-nans"), +flagpd1("fno-implicit-module-maps"), +flagpd1("fno-implicit-modules"), +flagpd1("fno-inline"), +flagpd1("fno-inline-functions"), +flagpd1("fno-integrated-as"), +flagpd1("fno-integrated-cc1"), +flagpd1("fno-jump-tables"), +flagpd1("fno-lax-vector-conversions"), +flagpd1("fno-limit-debug-info"), +flagpd1("fno-lto"), +flagpd1("fno-lto-unit"), +flagpd1("fno-math-builtin"), +flagpd1("fno-math-errno"), +flagpd1("fno-max-type-align"), +flagpd1("fno-merge-all-constants"), +flagpd1("fno-module-file-deps"), +flagpd1("fno-module-maps"), +flagpd1("fno-modules"), +flagpd1("fno-modules-decluse"), +flagpd1("fno-modules-error-recovery"), +flagpd1("fno-modules-global-index"), +flagpd1("fno-modules-search-all"), +flagpd1("fno-strict-modules-decluse"), +flagpd1("fno_modules-validate-input-files-content"), +flagpd1("fno-modules-validate-system-headers"), +flagpd1("fno-ms-compatibility"), +flagpd1("fno-ms-extensions"), +flagpd1("fno-objc-arc"), +flagpd1("fno-objc-arc-exceptions"), +flagpd1("fno-objc-convert-messages-to-runtime-calls"), +flagpd1("fno-objc-exceptions"), +flagpd1("fno-objc-infer-related-result-type"), +flagpd1("fno-objc-legacy-dispatch"), +flagpd1("fno-objc-nonfragile-abi"), +flagpd1("fno-objc-weak"), +flagpd1("fno-omit-frame-pointer"), +flagpd1("fno-openmp"), +flagpd1("fno-openmp-cuda-force-full-runtime"), +flagpd1("fno-openmp-cuda-mode"), +flagpd1("fno-openmp-optimistic-collapse"), +flagpd1("fno-openmp-simd"), +flagpd1("fno-operator-names"), +flagpd1("fno-optimize-sibling-calls"), +flagpd1("fno-pack-struct"), +flagpd1("fno-padding-on-unsigned-fixed-point"), +flagpd1("fno-pascal-strings"), +flagpd1("fno-pch-timestamp"), +flagpd1("fno_pch-validate-input-files-content"), +flagpd1("fno-pic"), +flagpd1("fno-pie"), +flagpd1("fno-plt"), +flagpd1("fno-preserve-as-comments"), +flagpd1("fno-profile-arcs"), +flagpd1("fno-profile-generate"), +flagpd1("fno-profile-instr-generate"), +flagpd1("fno-profile-instr-use"), +flagpd1("fno-profile-sample-accurate"), +flagpd1("fno-profile-sample-use"), +flagpd1("fno-profile-use"), +flagpd1("fno-reciprocal-math"), +flagpd1("fno-record-command-line"), +flagpd1("fno-register-global-dtors-with-atexit"), +flagpd1("fno-relaxed-template-template-args"), +flagpd1("fno-reroll-loops"), +flagpd1("fno-rewrite-imports"), +flagpd1("fno-rewrite-includes"), +flagpd1("fno-ropi"), +flagpd1("fno-rounding-math"), +flagpd1("fno-rtlib-add-rpath"), +flagpd1("fno-rtti"), +flagpd1("fno-rtti-data"), +flagpd1("fno-rwpi"), +flagpd1("fno-sanitize-address-poison-custom-array-cookie"), +flagpd1("fno-sanitize-address-use-after-scope"), +flagpd1("fno-sanitize-address-use-odr-indicator"), +flagpd1("fno-sanitize-blacklist"), +flagpd1("fno-sanitize-cfi-canonical-jump-tables"), +flagpd1("fno-sanitize-cfi-cross-dso"), +flagpd1("fno-sanitize-link-c++-runtime"), +flagpd1("fno-sanitize-link-runtime"), +flagpd1("fno-sanitize-memory-track-origins"), +flagpd1("fno-sanitize-memory-use-after-dtor"), +flagpd1("fno-sanitize-minimal-runtime"), +flagpd1("fno-sanitize-recover"), +flagpd1("fno-sanitize-stats"), +flagpd1("fno-sanitize-thread-atomics"), +flagpd1("fno-sanitize-thread-func-entry-exit"), +flagpd1("fno-sanitize-thread-memory-access"), +flagpd1("fno-sanitize-undefined-trap-on-error"), +flagpd1("fno-save-optimization-record"), +flagpd1("fno-short-enums"), +flagpd1("fno-short-wchar"), +flagpd1("fno-show-column"), +flagpd1("fno-show-source-location"), +flagpd1("fno-signaling-math"), +flagpd1("fno-signed-char"), +flagpd1("fno-signed-wchar"), +flagpd1("fno-signed-zeros"), +flagpd1("fno-sized-deallocation"), +flagpd1("fno-slp-vectorize"), +flagpd1("fno-spell-checking"), +flagpd1("fno-split-dwarf-inlining"), +flagpd1("fno-split-lto-unit"), +flagpd1("fno-stack-protector"), +flagpd1("fno-stack-size-section"), +flagpd1("fno-standalone-debug"), +flagpd1("fno-strict-aliasing"), +flagpd1("fno-strict-enums"), +flagpd1("fno-strict-float-cast-overflow"), +flagpd1("fno-strict-overflow"), +flagpd1("fno-strict-return"), +flagpd1("fno-strict-vtable-pointers"), +flagpd1("fno-struct-path-tbaa"), +flagpd1("fno-temp-file"), +flagpd1("fno-threadsafe-statics"), +flagpd1("fno-trapping-math"), +flagpd1("fno-trigraphs"), +flagpd1("fno-unique-section-names"), +flagpd1("fno-unit-at-a-time"), +flagpd1("fno-unroll-loops"), +flagpd1("fno-unsafe-math-optimizations"), +flagpd1("fno-unsigned-char"), +flagpd1("fno-unwind-tables"), +flagpd1("fno-use-cxa-atexit"), +flagpd1("fno-use-init-array"), +flagpd1("fno-use-line-directives"), +flagpd1("fno-validate-pch"), +flagpd1("fno-var-tracking"), +flagpd1("fno-vectorize"), +flagpd1("fno-verbose-asm"), +flagpd1("fno-virtual-function_elimination"), +flagpd1("fno-wchar"), +flagpd1("fno-whole-program-vtables"), +flagpd1("fno-working-directory"), +flagpd1("fno-wrapv"), +flagpd1("fno-zero-initialized-in-bss"), +flagpd1("fno-zvector"), +flagpd1("fnoopenmp-relocatable-target"), +flagpd1("fnoopenmp-use-tls"), +flagpd1("fno-xray-always-emit-customevents"), +flagpd1("fno-xray-always-emit-typedevents"), +flagpd1("fno-xray-instrument"), +flagpd1("fnoxray-link-deps"), +flagpd1("fobjc-arc"), +flagpd1("fobjc-arc-exceptions"), +flagpd1("fobjc-atdefs"), +flagpd1("fobjc-call-cxx-cdtors"), +flagpd1("fobjc-convert-messages-to-runtime-calls"), +flagpd1("fobjc-exceptions"), +flagpd1("fobjc-gc"), +flagpd1("fobjc-gc-only"), +flagpd1("fobjc-infer-related-result-type"), +flagpd1("fobjc-legacy-dispatch"), +flagpd1("fobjc-link-runtime"), +flagpd1("fobjc-new-property"), +flagpd1("fobjc-nonfragile-abi"), +flagpd1("fobjc-runtime-has-weak"), +flagpd1("fobjc-sender-dependent-dispatch"), +flagpd1("fobjc-subscripting-legacy-runtime"), +flagpd1("fobjc-weak"), +flagpd1("fomit-frame-pointer"), +flagpd1("fopenmp"), +flagpd1("fopenmp-cuda-force-full-runtime"), +flagpd1("fopenmp-cuda-mode"), +flagpd1("fopenmp-enable-irbuilder"), +sepd1("fopenmp-host-ir-file-path"), +flagpd1("fopenmp-is-device"), +flagpd1("fopenmp-optimistic-collapse"), +flagpd1("fopenmp-relocatable-target"), +flagpd1("fopenmp-simd"), +flagpd1("fopenmp-use-tls"), +sepd1("foperator-arrow-depth"), +flagpd1("foptimize-sibling-calls"), +flagpd1("force_cpusubtype_ALL"), +flagpd1("force_flat_namespace"), +sepd1("force_load"), +flagpd1("forder-file-instrumentation"), +flagpd1("fpack-struct"), +flagpd1("fpadding-on-unsigned-fixed-point"), +flagpd1("fparse-all-comments"), +flagpd1("fpascal-strings"), +flagpd1("fpcc-struct-return"), +flagpd1("fpch-preprocess"), +flagpd1("fpch-validate-input-files-content"), +flagpd1("fpic"), +flagpd1("fpie"), +flagpd1("fplt"), +flagpd1("fpreserve-as-comments"), +flagpd1("fpreserve-vec3-type"), +flagpd1("fprofile-arcs"), +flagpd1("fprofile-generate"), +flagpd1("fprofile-instr-generate"), +flagpd1("fprofile-instr-use"), +sepd1("fprofile-remapping-file"), +flagpd1("fprofile-sample-accurate"), +flagpd1("fprofile-sample-use"), +flagpd1("fprofile-use"), +sepd1("framework"), +flagpd1("freciprocal-math"), +flagpd1("frecord-command-line"), +flagpd1("ffree-form"), +flagpd1("fno-free-form"), +flagpd1("freg-struct-return"), +flagpd1("fregister-global-dtors-with-atexit"), +flagpd1("frelaxed-template-template-args"), +flagpd1("freroll-loops"), +flagpd1("fretain-comments-from-system-headers"), +flagpd1("frewrite-imports"), +flagpd1("frewrite-includes"), +sepd1("frewrite-map-file"), +flagpd1("ffriend-injection"), +flagpd1("fno-friend-injection"), +flagpd1("ffrontend-optimize"), +flagpd1("fno-frontend-optimize"), +flagpd1("fropi"), +flagpd1("frounding-math"), +flagpd1("frtlib-add-rpath"), +flagpd1("frtti"), +flagpd1("frwpi"), +flagpd1("fsanitize-address-globals-dead-stripping"), +flagpd1("fsanitize-address-poison-custom-array-cookie"), +flagpd1("fsanitize-address-use-after-scope"), +flagpd1("fsanitize-address-use-odr-indicator"), +flagpd1("fsanitize-cfi-canonical-jump-tables"), +flagpd1("fsanitize-cfi-cross-dso"), +flagpd1("fsanitize-cfi-icall-generalize-pointers"), +flagpd1("fsanitize-coverage-8bit-counters"), +flagpd1("fsanitize-coverage-indirect-calls"), +flagpd1("fsanitize-coverage-inline-8bit-counters"), +flagpd1("fsanitize-coverage-no-prune"), +flagpd1("fsanitize-coverage-pc-table"), +flagpd1("fsanitize-coverage-stack-depth"), +flagpd1("fsanitize-coverage-trace-bb"), +flagpd1("fsanitize-coverage-trace-cmp"), +flagpd1("fsanitize-coverage-trace-div"), +flagpd1("fsanitize-coverage-trace-gep"), +flagpd1("fsanitize-coverage-trace-pc"), +flagpd1("fsanitize-coverage-trace-pc-guard"), +flagpd1("fsanitize-link-c++-runtime"), +flagpd1("fsanitize-link-runtime"), +flagpd1("fsanitize-memory-track-origins"), +flagpd1("fsanitize-memory-use-after-dtor"), +flagpd1("fsanitize-minimal-runtime"), +flagpd1("fsanitize-recover"), +flagpd1("fsanitize-stats"), +flagpd1("fsanitize-thread-atomics"), +flagpd1("fsanitize-thread-func-entry-exit"), +flagpd1("fsanitize-thread-memory-access"), +flagpd1("fsanitize-undefined-trap-on-error"), +flagpd1("fsave-optimization-record"), +flagpd1("fseh-exceptions"), +flagpd1("fshort-enums"), +flagpd1("fshort-wchar"), +flagpd1("fshow-column"), +flagpd1("fshow-source-location"), +flagpd1("fsignaling-math"), +flagpd1("fsigned-bitfields"), +flagpd1("fsigned-char"), +flagpd1("fsigned-wchar"), +flagpd1("fsigned-zeros"), +flagpd1("fsized-deallocation"), +flagpd1("fsjlj-exceptions"), +flagpd1("fslp-vectorize"), +flagpd1("fspell-checking"), +sepd1("fspell-checking-limit"), +flagpd1("fsplit-dwarf-inlining"), +flagpd1("fsplit-lto-unit"), +flagpd1("fsplit-stack"), +flagpd1("fstack-protector"), +flagpd1("fstack-protector-all"), +flagpd1("fstack-protector-strong"), +flagpd1("fstack-size-section"), +flagpd1("fstandalone-debug"), +flagpd1("fstrict-aliasing"), +flagpd1("fstrict-enums"), +flagpd1("fstrict-float-cast-overflow"), +flagpd1("fstrict-overflow"), +flagpd1("fstrict-return"), +flagpd1("fstrict-vtable-pointers"), +flagpd1("fstruct-path-tbaa"), +flagpd1("fsycl-is-device"), +flagpd1("fsyntax-only"), +sepd1("ftabstop"), +sepd1("ftemplate-backtrace-limit"), +sepd1("ftemplate-depth"), +flagpd1("ftest-coverage"), +flagpd1("fthreadsafe-statics"), +flagpd1("ftime-report"), +flagpd1("ftime-trace"), +flagpd1("ftrapping-math"), +flagpd1("ftrapv"), +sepd1("ftrapv-handler"), +flagpd1("ftrigraphs"), +sepd1("ftype-visibility"), +sepd1("function-alignment"), +flagpd1("ffunction-attribute-list"), +flagpd1("fno-function-attribute-list"), +flagpd1("funique-section-names"), +flagpd1("funit-at-a-time"), +flagpd1("funknown-anytype"), +flagpd1("funroll-loops"), +flagpd1("funsafe-math-optimizations"), +flagpd1("funsigned-bitfields"), +flagpd1("funsigned-char"), +flagpd1("funwind-tables"), +flagpd1("fuse-cxa-atexit"), +flagpd1("fuse-init-array"), +flagpd1("fuse-line-directives"), +flagpd1("fuse-register-sized-bitfield-access"), +flagpd1("fvalidate-ast-input-files-content"), +flagpd1("fvectorize"), +flagpd1("fverbose-asm"), +flagpd1("fvirtual-function-elimination"), +sepd1("fvisibility"), +flagpd1("fvisibility-global-new-delete-hidden"), +flagpd1("fvisibility-inlines-hidden"), +flagpd1("fvisibility-ms-compat"), +flagpd1("fwasm-exceptions"), +flagpd1("fwhole-program-vtables"), +flagpd1("fwrapv"), +flagpd1("fwritable-strings"), +flagpd1("fxray-always-emit-customevents"), +flagpd1("fxray-always-emit-typedevents"), +flagpd1("fxray-instrument"), +flagpd1("fxray-link-deps"), +flagpd1("fzero-initialized-in-bss"), +flagpd1("fzvector"), +flagpd1("g0"), +flagpd1("g1"), +flagpd1("g2"), +flagpd1("g3"), +.{ + .name = "g", + .syntax = .flag, + .zig_equivalent = .debug, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +sepd1("gcc-toolchain"), +flagpd1("gcodeview"), +flagpd1("gcodeview-ghash"), +flagpd1("gcolumn-info"), +flagpd1("fgcse-after-reload"), +flagpd1("fno-gcse-after-reload"), +flagpd1("fgcse"), +flagpd1("fno-gcse"), +flagpd1("fgcse-las"), +flagpd1("fno-gcse-las"), +flagpd1("fgcse-sm"), +flagpd1("fno-gcse-sm"), +flagpd1("gdwarf"), +flagpd1("gdwarf-2"), +flagpd1("gdwarf-3"), +flagpd1("gdwarf-4"), +flagpd1("gdwarf-5"), +flagpd1("gdwarf-aranges"), +flagpd1("gembed-source"), +sepd1("gen-cdb-fragment-path"), +flagpd1("gen-reproducer"), +flagpd1("gfull"), +flagpd1("ggdb"), +flagpd1("ggdb0"), +flagpd1("ggdb1"), +flagpd1("ggdb2"), +flagpd1("ggdb3"), +flagpd1("ggnu-pubnames"), +flagpd1("ginline-line-tables"), +flagpd1("gline-directives-only"), +flagpd1("gline-tables-only"), +flagpd1("glldb"), +flagpd1("gmlt"), +flagpd1("gmodules"), +flagpd1("gno-codeview-ghash"), +flagpd1("gno-column-info"), +flagpd1("gno-embed-source"), +flagpd1("gno-gnu-pubnames"), +flagpd1("gno-inline-line-tables"), +flagpd1("gno-pubnames"), +flagpd1("gno-record-command-line"), +flagpd1("gno-strict-dwarf"), +flagpd1("fgnu"), +flagpd1("fno-gnu"), +flagpd1("gpubnames"), +flagpd1("grecord-command-line"), +flagpd1("gsce"), +flagpd1("gsplit-dwarf"), +flagpd1("gstrict-dwarf"), +flagpd1("gtoggle"), +flagpd1("gused"), +flagpd1("gz"), +sepd1("header-include-file"), +.{ + .name = "help", + .syntax = .flag, + .zig_equivalent = .driver_punt, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "hip-link", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +sepd1("image_base"), +flagpd1("fimplement-inlines"), +flagpd1("fno-implement-inlines"), +flagpd1("fimplicit-none"), +flagpd1("fno-implicit-none"), +flagpd1("fimplicit-templates"), +flagpd1("fno-implicit-templates"), +sepd1("imultilib"), +sepd1("include-pch"), +flagpd1("index-header-map"), +sepd1("init"), +flagpd1("finit-local-zero"), +flagpd1("fno-init-local-zero"), +flagpd1("init-only"), +flagpd1("finline-functions-called-once"), +flagpd1("fno-inline-functions-called-once"), +flagpd1("finline-small-functions"), +flagpd1("fno-inline-small-functions"), +sepd1("install_name"), +flagpd1("finteger-4-integer-8"), +flagpd1("fno-integer-4-integer-8"), +flagpd1("fintrinsic-modules-path"), +flagpd1("fno-intrinsic-modules-path"), +flagpd1("fipa-cp"), +flagpd1("fno-ipa-cp"), +flagpd1("fivopts"), +flagpd1("fno-ivopts"), +flagpd1("keep_private_externs"), +sepd1("lazy_framework"), +sepd1("lazy_library"), +sepd1("load"), +flagpd1("m16"), +flagpd1("m32"), +flagpd1("m3dnow"), +flagpd1("m3dnowa"), +flagpd1("m64"), +flagpd1("m80387"), +flagpd1("mabi=ieeelongdouble"), +flagpd1("mabicalls"), +flagpd1("madx"), +flagpd1("maes"), +sepd1("main-file-name"), +flagpd1("malign-double"), +flagpd1("maltivec"), +flagpd1("marm"), +flagpd1("masm-verbose"), +flagpd1("massembler-fatal-warnings"), +flagpd1("massembler-no-warn"), +flagpd1("matomics"), +flagpd1("mavx"), +flagpd1("mavx2"), +flagpd1("mavx512bf16"), +flagpd1("mavx512bitalg"), +flagpd1("mavx512bw"), +flagpd1("mavx512cd"), +flagpd1("mavx512dq"), +flagpd1("mavx512er"), +flagpd1("mavx512f"), +flagpd1("mavx512ifma"), +flagpd1("mavx512pf"), +flagpd1("mavx512vbmi"), +flagpd1("mavx512vbmi2"), +flagpd1("mavx512vl"), +flagpd1("mavx512vnni"), +flagpd1("mavx512vp2intersect"), +flagpd1("mavx512vpopcntdq"), +flagpd1("fmax-identifier-length"), +flagpd1("fno-max-identifier-length"), +flagpd1("mbackchain"), +flagpd1("mbig-endian"), +flagpd1("mbmi"), +flagpd1("mbmi2"), +flagpd1("mbranch-likely"), +flagpd1("mbranch-target-enforce"), +flagpd1("mbranches-within-32B-boundaries"), +flagpd1("mbulk-memory"), +flagpd1("mcheck-zero-division"), +flagpd1("mcldemote"), +flagpd1("mclflushopt"), +flagpd1("mclwb"), +flagpd1("mclzero"), +flagpd1("mcmodel=medany"), +flagpd1("mcmodel=medlow"), +flagpd1("mcmpb"), +flagpd1("mcmse"), +sepd1("mcode-model"), +flagpd1("mcode-object-v3"), +flagpd1("mconstant-cfstrings"), +flagpd1("mconstructor-aliases"), +flagpd1("mcpu=?"), +flagpd1("mcrbits"), +flagpd1("mcrc"), +flagpd1("mcumode"), +flagpd1("mcx16"), +sepd1("mdebug-pass"), +flagpd1("mdirect-move"), +flagpd1("mdisable-tail-calls"), +flagpd1("mdouble-float"), +flagpd1("mdsp"), +flagpd1("mdspr2"), +sepd1("meabi"), +flagpd1("membedded-data"), +flagpd1("menable-no-infs"), +flagpd1("menable-no-nans"), +flagpd1("menable-unsafe-fp-math"), +flagpd1("menqcmd"), +flagpd1("fmerge-constants"), +flagpd1("fno-merge-constants"), +flagpd1("mexception-handling"), +flagpd1("mexecute-only"), +flagpd1("mextern-sdata"), +flagpd1("mf16c"), +flagpd1("mfancy-math-387"), +flagpd1("mfentry"), +flagpd1("mfix-and-continue"), +flagpd1("mfix-cortex-a53-835769"), +flagpd1("mfloat128"), +sepd1("mfloat-abi"), +flagpd1("mfma"), +flagpd1("mfma4"), +flagpd1("mfp32"), +flagpd1("mfp64"), +sepd1("mfpmath"), +flagpd1("mfprnd"), +flagpd1("mfpxx"), +flagpd1("mfsgsbase"), +flagpd1("mfxsr"), +flagpd1("mgeneral-regs-only"), +flagpd1("mgfni"), +flagpd1("mginv"), +flagpd1("mglibc"), +flagpd1("mglobal-merge"), +flagpd1("mgpopt"), +flagpd1("mhard-float"), +flagpd1("mhvx"), +flagpd1("mhtm"), +flagpd1("miamcu"), +flagpd1("mieee-fp"), +flagpd1("mieee-rnd-near"), +flagpd1("migrate"), +flagpd1("no-finalize-removal"), +flagpd1("no-ns-alloc-error"), +flagpd1("mimplicit-float"), +flagpd1("mincremental-linker-compatible"), +flagpd1("minline-all-stringops"), +flagpd1("minvariant-function-descriptors"), +flagpd1("minvpcid"), +flagpd1("mips1"), +flagpd1("mips16"), +flagpd1("mips2"), +flagpd1("mips3"), +flagpd1("mips32"), +flagpd1("mips32r2"), +flagpd1("mips32r3"), +flagpd1("mips32r5"), +flagpd1("mips32r6"), +flagpd1("mips4"), +flagpd1("mips5"), +flagpd1("mips64"), +flagpd1("mips64r2"), +flagpd1("mips64r3"), +flagpd1("mips64r5"), +flagpd1("mips64r6"), +flagpd1("misel"), +flagpd1("mkernel"), +flagpd1("mldc1-sdc1"), +sepd1("mlimit-float-precision"), +sepd1("mlink-bitcode-file"), +sepd1("mlink-builtin-bitcode"), +sepd1("mlink-cuda-bitcode"), +flagpd1("mlittle-endian"), +sepd1("mllvm"), +flagpd1("mlocal-sdata"), +flagpd1("mlong-calls"), +flagpd1("mlong-double-128"), +flagpd1("mlong-double-64"), +flagpd1("mlong-double-80"), +flagpd1("mlongcall"), +flagpd1("mlwp"), +flagpd1("mlzcnt"), +flagpd1("mmadd4"), +flagpd1("mmemops"), +flagpd1("mmfcrf"), +flagpd1("mmfocrf"), +flagpd1("mmicromips"), +flagpd1("mmmx"), +flagpd1("mmovbe"), +flagpd1("mmovdir64b"), +flagpd1("mmovdiri"), +flagpd1("mmpx"), +flagpd1("mms-bitfields"), +flagpd1("mmsa"), +flagpd1("mmt"), +flagpd1("mmultivalue"), +flagpd1("mmutable-globals"), +flagpd1("mmwaitx"), +flagpd1("mno-3dnow"), +flagpd1("mno-3dnowa"), +flagpd1("mno-80387"), +flagpd1("mno-abicalls"), +flagpd1("mno-adx"), +flagpd1("mno-aes"), +flagpd1("mno-altivec"), +flagpd1("mno-atomics"), +flagpd1("mno-avx"), +flagpd1("mno-avx2"), +flagpd1("mno-avx512bf16"), +flagpd1("mno-avx512bitalg"), +flagpd1("mno-avx512bw"), +flagpd1("mno-avx512cd"), +flagpd1("mno-avx512dq"), +flagpd1("mno-avx512er"), +flagpd1("mno-avx512f"), +flagpd1("mno-avx512ifma"), +flagpd1("mno-avx512pf"), +flagpd1("mno-avx512vbmi"), +flagpd1("mno-avx512vbmi2"), +flagpd1("mno-avx512vl"), +flagpd1("mno-avx512vnni"), +flagpd1("mno-avx512vp2intersect"), +flagpd1("mno-avx512vpopcntdq"), +flagpd1("mno-backchain"), +flagpd1("mno-bmi"), +flagpd1("mno-bmi2"), +flagpd1("mno-branch-likely"), +flagpd1("mno-bulk-memory"), +flagpd1("mno-check-zero-division"), +flagpd1("mno-cldemote"), +flagpd1("mno-clflushopt"), +flagpd1("mno-clwb"), +flagpd1("mno-clzero"), +flagpd1("mno-cmpb"), +flagpd1("mno-code-object-v3"), +flagpd1("mno-constant-cfstrings"), +flagpd1("mno-crbits"), +flagpd1("mno-crc"), +flagpd1("mno-cumode"), +flagpd1("mno-cx16"), +flagpd1("mno-dsp"), +flagpd1("mno-dspr2"), +flagpd1("mno-embedded-data"), +flagpd1("mno-enqcmd"), +flagpd1("mno-exception-handling"), +flagpd1("mnoexecstack"), +flagpd1("mno-execute-only"), +flagpd1("mno-extern-sdata"), +flagpd1("mno-f16c"), +flagpd1("mno-fix-cortex-a53-835769"), +flagpd1("mno-float128"), +flagpd1("mno-fma"), +flagpd1("mno-fma4"), +flagpd1("mno-fprnd"), +flagpd1("mno-fsgsbase"), +flagpd1("mno-fxsr"), +flagpd1("mno-gfni"), +flagpd1("mno-ginv"), +flagpd1("mno-global-merge"), +flagpd1("mno-gpopt"), +flagpd1("mno-hvx"), +flagpd1("mno-htm"), +flagpd1("mno-iamcu"), +flagpd1("mno-implicit-float"), +flagpd1("mno-incremental-linker-compatible"), +flagpd1("mno-inline-all-stringops"), +flagpd1("mno-invariant-function-descriptors"), +flagpd1("mno-invpcid"), +flagpd1("mno-isel"), +flagpd1("mno-ldc1-sdc1"), +flagpd1("mno-local-sdata"), +flagpd1("mno-long-calls"), +flagpd1("mno-longcall"), +flagpd1("mno-lwp"), +flagpd1("mno-lzcnt"), +flagpd1("mno-madd4"), +flagpd1("mno-memops"), +flagpd1("mno-mfcrf"), +flagpd1("mno-mfocrf"), +flagpd1("mno-micromips"), +flagpd1("mno-mips16"), +flagpd1("mno-mmx"), +flagpd1("mno-movbe"), +flagpd1("mno-movdir64b"), +flagpd1("mno-movdiri"), +flagpd1("mno-movt"), +flagpd1("mno-mpx"), +flagpd1("mno-ms-bitfields"), +flagpd1("mno-msa"), +flagpd1("mno-mt"), +flagpd1("mno-multivalue"), +flagpd1("mno-mutable-globals"), +flagpd1("mno-mwaitx"), +flagpd1("mno-neg-immediates"), +flagpd1("mno-nontrapping-fptoint"), +flagpd1("mno-nvj"), +flagpd1("mno-nvs"), +flagpd1("mno-odd-spreg"), +flagpd1("mno-omit-leaf-frame-pointer"), +flagpd1("mno-outline"), +flagpd1("mno-packed-stack"), +flagpd1("mno-packets"), +flagpd1("mno-pascal-strings"), +flagpd1("mno-pclmul"), +flagpd1("mno-pconfig"), +flagpd1("mno-pie-copy-relocations"), +flagpd1("mno-pku"), +flagpd1("mno-popcnt"), +flagpd1("mno-popcntd"), +flagpd1("mno-power8-vector"), +flagpd1("mno-power9-vector"), +flagpd1("mno-prefetchwt1"), +flagpd1("mno-prfchw"), +flagpd1("mno-ptwrite"), +flagpd1("mno-pure-code"), +flagpd1("mno-qpx"), +flagpd1("mno-rdpid"), +flagpd1("mno-rdrnd"), +flagpd1("mno-rdseed"), +flagpd1("mno-red-zone"), +flagpd1("mno-reference-types"), +flagpd1("mno-relax"), +flagpd1("mno-relax-all"), +flagpd1("mno-relax-pic-calls"), +flagpd1("mno-restrict-it"), +flagpd1("mno-retpoline"), +flagpd1("mno-retpoline-external-thunk"), +flagpd1("mno-rtd"), +flagpd1("mno-rtm"), +flagpd1("mno-sahf"), +flagpd1("mno-save-restore"), +flagpd1("mno-sgx"), +flagpd1("mno-sha"), +flagpd1("mno-shstk"), +flagpd1("mno-sign-ext"), +flagpd1("mno-simd128"), +flagpd1("mno-soft-float"), +flagpd1("mno-spe"), +flagpd1("mno-speculative-load-hardening"), +flagpd1("mno-sram-ecc"), +flagpd1("mno-sse"), +flagpd1("mno-sse2"), +flagpd1("mno-sse3"), +flagpd1("mno-sse4"), +flagpd1("mno-sse4.1"), +flagpd1("mno-sse4.2"), +flagpd1("mno-sse4a"), +flagpd1("mno-ssse3"), +flagpd1("mno-stack-arg-probe"), +flagpd1("mno-stackrealign"), +flagpd1("mno-tail-call"), +flagpd1("mno-tbm"), +flagpd1("mno-thumb"), +flagpd1("mno-tls-direct-seg-refs"), +flagpd1("mno-unaligned-access"), +flagpd1("mno-unimplemented-simd128"), +flagpd1("mno-vaes"), +flagpd1("mno-virt"), +flagpd1("mno-vpclmulqdq"), +flagpd1("mno-vsx"), +flagpd1("mno-vx"), +flagpd1("mno-vzeroupper"), +flagpd1("mno-waitpkg"), +flagpd1("mno-warn-nonportable-cfstrings"), +flagpd1("mno-wavefrontsize64"), +flagpd1("mno-wbnoinvd"), +flagpd1("mno-x87"), +flagpd1("mno-xgot"), +flagpd1("mno-xnack"), +flagpd1("mno-xop"), +flagpd1("mno-xsave"), +flagpd1("mno-xsavec"), +flagpd1("mno-xsaveopt"), +flagpd1("mno-xsaves"), +flagpd1("mno-zero-initialized-in-bss"), +flagpd1("mno-zvector"), +flagpd1("mnocrc"), +flagpd1("mno-direct-move"), +flagpd1("mnontrapping-fptoint"), +flagpd1("mnop-mcount"), +flagpd1("mno-crypto"), +flagpd1("mnvj"), +flagpd1("mnvs"), +flagpd1("modd-spreg"), +sepd1("module-dependency-dir"), +flagpd1("module-file-deps"), +flagpd1("module-file-info"), +flagpd1("fmodule-private"), +flagpd1("fno-module-private"), +flagpd1("fmodulo-sched-allow-regmoves"), +flagpd1("fno-modulo-sched-allow-regmoves"), +flagpd1("fmodulo-sched"), +flagpd1("fno-modulo-sched"), +flagpd1("momit-leaf-frame-pointer"), +flagpd1("moutline"), +flagpd1("mpacked-stack"), +flagpd1("mpackets"), +flagpd1("mpascal-strings"), +flagpd1("mpclmul"), +flagpd1("mpconfig"), +flagpd1("mpie-copy-relocations"), +flagpd1("mpku"), +flagpd1("mpopcnt"), +flagpd1("mpopcntd"), +flagpd1("mcrypto"), +flagpd1("mpower8-vector"), +flagpd1("mpower9-vector"), +flagpd1("mprefetchwt1"), +flagpd1("mprfchw"), +flagpd1("mptwrite"), +flagpd1("mpure-code"), +flagpd1("mqdsp6-compat"), +flagpd1("mqpx"), +flagpd1("mrdpid"), +flagpd1("mrdrnd"), +flagpd1("mrdseed"), +flagpd1("mreassociate"), +flagpd1("mrecip"), +flagpd1("mrecord-mcount"), +flagpd1("mred-zone"), +flagpd1("mreference-types"), +sepd1("mregparm"), +flagpd1("mrelax"), +flagpd1("mrelax-all"), +flagpd1("mrelax-pic-calls"), +.{ + .name = "mrelax-relocations", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +sepd1("mrelocation-model"), +flagpd1("mrestrict-it"), +flagpd1("mretpoline"), +flagpd1("mretpoline-external-thunk"), +flagpd1("mrtd"), +flagpd1("mrtm"), +flagpd1("msahf"), +flagpd1("msave-restore"), +flagpd1("msave-temp-labels"), +flagpd1("msecure-plt"), +flagpd1("msgx"), +flagpd1("msha"), +flagpd1("mshstk"), +flagpd1("msign-ext"), +flagpd1("msimd128"), +flagpd1("msingle-float"), +flagpd1("msoft-float"), +flagpd1("mspe"), +flagpd1("mspeculative-load-hardening"), +flagpd1("msram-ecc"), +flagpd1("msse"), +flagpd1("msse2"), +flagpd1("msse3"), +flagpd1("msse4"), +flagpd1("msse4.1"), +flagpd1("msse4.2"), +flagpd1("msse4a"), +flagpd1("mssse3"), +flagpd1("mstack-arg-probe"), +flagpd1("mstackrealign"), +flagpd1("mstrict-align"), +sepd1("mt-migrate-directory"), +flagpd1("mtail-call"), +flagpd1("mtbm"), +sepd1("mthread-model"), +flagpd1("mthumb"), +flagpd1("mtls-direct-seg-refs"), +sepd1("mtp"), +flagpd1("mtune=?"), +flagpd1("muclibc"), +flagpd1("multi_module"), +sepd1("multiply_defined"), +sepd1("multiply_defined_unused"), +flagpd1("munaligned-access"), +flagpd1("munimplemented-simd128"), +flagpd1("munwind-tables"), +flagpd1("mv5"), +flagpd1("mv55"), +flagpd1("mv60"), +flagpd1("mv62"), +flagpd1("mv65"), +flagpd1("mv66"), +flagpd1("mvaes"), +flagpd1("mvirt"), +flagpd1("mvpclmulqdq"), +flagpd1("mvsx"), +flagpd1("mvx"), +flagpd1("mvzeroupper"), +flagpd1("mwaitpkg"), +flagpd1("mwarn-nonportable-cfstrings"), +flagpd1("mwavefrontsize64"), +flagpd1("mwbnoinvd"), +flagpd1("mx32"), +flagpd1("mx87"), +flagpd1("mxgot"), +flagpd1("mxnack"), +flagpd1("mxop"), +flagpd1("mxsave"), +flagpd1("mxsavec"), +flagpd1("mxsaveopt"), +flagpd1("mxsaves"), +flagpd1("mzvector"), +flagpd1("n"), +flagpd1("new-struct-path-tbaa"), +flagpd1("no_dead_strip_inits_and_terms"), +flagpd1("no-canonical-prefixes"), +flagpd1("no-code-completion-globals"), +flagpd1("no-code-completion-ns-level-decls"), +flagpd1("no-cpp-precomp"), +.{ + .name = "no-cuda-noopt-device-debug", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-cuda-version-check", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +flagpd1("no-emit-llvm-uselists"), +flagpd1("no-implicit-float"), +.{ + .name = "no-integrated-cpp", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-pedantic", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("no-pie"), +flagpd1("no-pthread"), +flagpd1("no-struct-path-tbaa"), +flagpd1("nobuiltininc"), +flagpd1("nocpp"), +flagpd1("nocudainc"), +flagpd1("nodefaultlibs"), +flagpd1("nofixprebinding"), +flagpd1("nogpulib"), +flagpd1("nolibc"), +flagpd1("nomultidefs"), +flagpd1("fnon-call-exceptions"), +flagpd1("fno-non-call-exceptions"), +flagpd1("nopie"), +flagpd1("noprebind"), +flagpd1("noprofilelib"), +flagpd1("noseglinkedit"), +flagpd1("nostartfiles"), +flagpd1("nostdinc"), +flagpd1("nostdinc++"), +.{ + .name = "nostdlib", + .syntax = .flag, + .zig_equivalent = .nostdlib, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("nostdlibinc"), +flagpd1("nostdlib++"), +flagpd1("nostdsysteminc"), +flagpd1("objcmt-atomic-property"), +flagpd1("objcmt-migrate-all"), +flagpd1("objcmt-migrate-annotation"), +flagpd1("objcmt-migrate-designated-init"), +flagpd1("objcmt-migrate-instancetype"), +flagpd1("objcmt-migrate-literals"), +flagpd1("objcmt-migrate-ns-macros"), +flagpd1("objcmt-migrate-property"), +flagpd1("objcmt-migrate-property-dot-syntax"), +flagpd1("objcmt-migrate-protocol-conformance"), +flagpd1("objcmt-migrate-readonly-property"), +flagpd1("objcmt-migrate-readwrite-property"), +flagpd1("objcmt-migrate-subscripting"), +flagpd1("objcmt-ns-nonatomic-iosonly"), +flagpd1("objcmt-returns-innerpointer-property"), +flagpd1("object"), +sepd1("opt-record-file"), +sepd1("opt-record-format"), +sepd1("opt-record-passes"), +sepd1("output-asm-variant"), +flagpd1("p"), +flagpd1("fpack-derived"), +flagpd1("fno-pack-derived"), +.{ + .name = "pass-exit-codes", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("pch-through-hdrstop-create"), +flagpd1("pch-through-hdrstop-use"), +.{ + .name = "pedantic", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "pedantic-errors", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("fpeel-loops"), +flagpd1("fno-peel-loops"), +flagpd1("fpermissive"), +flagpd1("fno-permissive"), +flagpd1("pg"), +flagpd1("pic-is-pie"), +sepd1("pic-level"), +flagpd1("pie"), +.{ + .name = "pipe", + .syntax = .flag, + .zig_equivalent = .ignore, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +sepd1("plugin"), +flagpd1("prebind"), +flagpd1("prebind_all_twolevel_modules"), +flagpd1("fprefetch-loop-arrays"), +flagpd1("fno-prefetch-loop-arrays"), +flagpd1("preload"), +flagpd1("print-dependency-directives-minimized-source"), +.{ + .name = "print-effective-triple", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("print-ivar-layout"), +.{ + .name = "print-libgcc-file-name", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-multi-directory", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-multi-lib", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-multi-os-directory", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("print-preamble"), +.{ + .name = "print-resource-dir", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-search-dirs", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("print-stats"), +.{ + .name = "print-supported-cpus", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-target-triple", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("fprintf"), +flagpd1("fno-printf"), +flagpd1("private_bundle"), +flagpd1("fprofile-correction"), +flagpd1("fno-profile-correction"), +flagpd1("fprofile"), +flagpd1("fno-profile"), +flagpd1("fprofile-generate-sampling"), +flagpd1("fno-profile-generate-sampling"), +flagpd1("fprofile-reusedist"), +flagpd1("fno-profile-reusedist"), +flagpd1("fprofile-values"), +flagpd1("fno-profile-values"), +flagpd1("fprotect-parens"), +flagpd1("fno-protect-parens"), +flagpd1("pthread"), +flagpd1("pthreads"), +flagpd1("r"), +flagpd1("frange-check"), +flagpd1("fno-range-check"), +.{ + .name = "rdynamic", + .syntax = .flag, + .zig_equivalent = .rdynamic, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +sepd1("read_only_relocs"), +flagpd1("freal-4-real-10"), +flagpd1("fno-real-4-real-10"), +flagpd1("freal-4-real-16"), +flagpd1("fno-real-4-real-16"), +flagpd1("freal-4-real-8"), +flagpd1("fno-real-4-real-8"), +flagpd1("freal-8-real-10"), +flagpd1("fno-real-8-real-10"), +flagpd1("freal-8-real-16"), +flagpd1("fno-real-8-real-16"), +flagpd1("freal-8-real-4"), +flagpd1("fno-real-8-real-4"), +flagpd1("frealloc-lhs"), +flagpd1("fno-realloc-lhs"), +sepd1("record-command-line"), +flagpd1("frecursive"), +flagpd1("fno-recursive"), +flagpd1("fregs-graph"), +flagpd1("fno-regs-graph"), +flagpd1("relaxed-aliasing"), +.{ + .name = "relocatable-pch", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("remap"), +sepd1("remap-file"), +flagpd1("frename-registers"), +flagpd1("fno-rename-registers"), +flagpd1("freorder-blocks"), +flagpd1("fno-reorder-blocks"), +flagpd1("frepack-arrays"), +flagpd1("fno-repack-arrays"), +sepd1("resource-dir"), +flagpd1("rewrite-legacy-objc"), +flagpd1("rewrite-macros"), +flagpd1("rewrite-objc"), +flagpd1("rewrite-test"), +flagpd1("fripa"), +flagpd1("fno-ripa"), +sepd1("rpath"), +flagpd1("s"), +.{ + .name = "save-stats", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "save-temps", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("fschedule-insns2"), +flagpd1("fno-schedule-insns2"), +flagpd1("fschedule-insns"), +flagpd1("fno-schedule-insns"), +flagpd1("fsecond-underscore"), +flagpd1("fno-second-underscore"), +.{ + .name = "sectalign", + .syntax = .{.multi_arg=3}, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "sectcreate", + .syntax = .{.multi_arg=3}, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "sectobjectsymbols", + .syntax = .{.multi_arg=2}, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "sectorder", + .syntax = .{.multi_arg=3}, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("fsee"), +flagpd1("fno-see"), +sepd1("seg_addr_table"), +sepd1("seg_addr_table_filename"), +.{ + .name = "segaddr", + .syntax = .{.multi_arg=2}, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "segcreate", + .syntax = .{.multi_arg=3}, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("seglinkedit"), +.{ + .name = "segprot", + .syntax = .{.multi_arg=3}, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +sepd1("segs_read_only_addr"), +sepd1("segs_read_write_addr"), +flagpd1("setup-static-analyzer"), +.{ + .name = "shared", + .syntax = .flag, + .zig_equivalent = .shared, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("shared-libgcc"), +flagpd1("shared-libsan"), +flagpd1("show-encoding"), +.{ + .name = "show-includes", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +flagpd1("show-inst"), +flagpd1("fsign-zero"), +flagpd1("fno-sign-zero"), +flagpd1("fsignaling-nans"), +flagpd1("fno-signaling-nans"), +flagpd1("single_module"), +flagpd1("fsingle-precision-constant"), +flagpd1("fno-single-precision-constant"), +flagpd1("fspec-constr-count"), +flagpd1("fno-spec-constr-count"), +.{ + .name = "specs", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +sepd1("split-dwarf-file"), +sepd1("split-dwarf-output"), +flagpd1("split-stacks"), +flagpd1("fstack-arrays"), +flagpd1("fno-stack-arrays"), +flagpd1("fstack-check"), +flagpd1("fno-stack-check"), +sepd1("stack-protector"), +sepd1("stack-protector-buffer-size"), +.{ + .name = "static", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("static-define"), +flagpd1("static-libgcc"), +flagpd1("static-libgfortran"), +flagpd1("static-libsan"), +flagpd1("static-libstdc++"), +flagpd1("static-openmp"), +flagpd1("static-pie"), +flagpd1("fstrength-reduce"), +flagpd1("fno-strength-reduce"), +flagpd1("sys-header-deps"), +flagpd1("t"), +sepd1("target-abi"), +sepd1("target-cpu"), +sepd1("target-feature"), +.{ + .name = "target", + .syntax = .separate, + .zig_equivalent = .target, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +sepd1("target-linker-version"), +flagpd1("templight-dump"), +flagpd1("test-coverage"), +flagpd1("time"), +flagpd1("ftls-model"), +flagpd1("fno-tls-model"), +flagpd1("ftracer"), +flagpd1("fno-tracer"), +.{ + .name = "traditional", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "traditional-cpp", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("ftree-dce"), +flagpd1("fno-tree-dce"), +flagpd1("ftree_loop_im"), +flagpd1("fno-tree_loop_im"), +flagpd1("ftree_loop_ivcanon"), +flagpd1("fno-tree_loop_ivcanon"), +flagpd1("ftree_loop_linear"), +flagpd1("fno-tree_loop_linear"), +flagpd1("ftree-salias"), +flagpd1("fno-tree-salias"), +flagpd1("ftree-ter"), +flagpd1("fno-tree-ter"), +flagpd1("ftree-vectorizer-verbose"), +flagpd1("fno-tree-vectorizer-verbose"), +flagpd1("ftree-vrp"), +flagpd1("fno-tree-vrp"), +.{ + .name = "trigraphs", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("trim-egraph"), +sepd1("triple"), +flagpd1("twolevel_namespace"), +flagpd1("twolevel_namespace_hints"), +sepd1("umbrella"), +flagpd1("undef"), +flagpd1("funderscoring"), +flagpd1("fno-underscoring"), +sepd1("unexported_symbols_list"), +flagpd1("funroll-all-loops"), +flagpd1("fno-unroll-all-loops"), +flagpd1("funsafe-loop-optimizations"), +flagpd1("fno-unsafe-loop-optimizations"), +flagpd1("funswitch-loops"), +flagpd1("fno-unswitch-loops"), +flagpd1("fuse-linker-plugin"), +flagpd1("fno-use-linker-plugin"), +flagpd1("v"), +flagpd1("fvariable-expansion-in-unroller"), +flagpd1("fno-variable-expansion-in-unroller"), +flagpd1("fvect-cost-model"), +flagpd1("fno-vect-cost-model"), +flagpd1("vectorize-loops"), +flagpd1("vectorize-slp"), +flagpd1("verify"), +.{ + .name = "verify-debug-info", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +flagpd1("verify-ignore-unexpected"), +flagpd1("verify-pch"), +flagpd1("version"), +.{ + .name = "via-file-asm", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("w"), +sepd1("weak_framework"), +sepd1("weak_library"), +sepd1("weak_reference_mismatches"), +flagpd1("fweb"), +flagpd1("fno-web"), +flagpd1("whatsloaded"), +flagpd1("fwhole-file"), +flagpd1("fno-whole-file"), +flagpd1("fwhole-program"), +flagpd1("fno-whole-program"), +flagpd1("whyload"), +sepd1("z"), +joinpd1("fsanitize-undefined-strip-path-components="), +joinpd1("fopenmp-cuda-teams-reduction-recs-num="), +joinpd1("analyzer-config-compatibility-mode="), +joinpd1("fpatchable-function-entry-offset="), +joinpd1("analyzer-inline-max-stack-depth="), +joinpd1("fsanitize-address-field-padding="), +joinpd1("fdiagnostics-hotness-threshold="), +joinpd1("fsanitize-memory-track-origins="), +joinpd1("mwatchos-simulator-version-min="), +joinpd1("mappletvsimulator-version-min="), +joinpd1("fobjc-nonfragile-abi-version="), +joinpd1("fprofile-instrument-use-path="), +jspd1("fxray-instrumentation-bundle="), +joinpd1("miphonesimulator-version-min="), +joinpd1("faddress-space-map-mangling="), +joinpd1("foptimization-record-passes="), +joinpd1("ftest-module-file-extension="), +jspd1("fxray-instruction-threshold="), +joinpd1("mno-default-build-attributes"), +joinpd1("mtvos-simulator-version-min="), +joinpd1("mwatchsimulator-version-min="), +.{ + .name = "include-with-prefix-before=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("objcmt-white-list-dir-path="), +joinpd1("error-on-deserialized-decl="), +joinpd1("fconstexpr-backtrace-limit="), +joinpd1("fdiagnostics-show-category="), +joinpd1("fdiagnostics-show-location="), +joinpd1("fopenmp-cuda-blocks-per-sm="), +joinpd1("fsanitize-system-blacklist="), +jspd1("fxray-instruction-threshold"), +joinpd1("headerpad_max_install_names"), +joinpd1("mios-simulator-version-min="), +.{ + .name = "include-with-prefix-after=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("fms-compatibility-version="), +joinpd1("fopenmp-cuda-number-of-sm="), +joinpd1("foptimization-record-file="), +joinpd1("fpatchable-function-entry="), +joinpd1("fsave-optimization-record="), +joinpd1("ftemplate-backtrace-limit="), +.{ + .name = "gpu-max-threads-per-block=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("malign-branch-prefix-size="), +joinpd1("objcmt-whitelist-dir-path="), +joinpd1("Wno-nonportable-cfstrings"), +joinpd1("analyzer-disable-checker="), +joinpd1("fbuild-session-timestamp="), +joinpd1("fprofile-instrument-path="), +joinpd1("mdefault-build-attributes"), +joinpd1("msign-return-address-key="), +.{ + .name = "verify-ignore-unexpected=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "include-directory-after=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "compress-debug-sections=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "fcomment-block-commands=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("flax-vector-conversions="), +joinpd1("fmodules-embed-all-files"), +joinpd1("fmodules-prune-interval="), +joinpd1("foverride-record-layout="), +joinpd1("fprofile-instr-generate="), +joinpd1("fprofile-remapping-file="), +joinpd1("fsanitize-coverage-type="), +joinpd1("fsanitize-hwaddress-abi="), +joinpd1("ftime-trace-granularity="), +jspd1("fxray-always-instrument="), +jspd1("internal-externc-isystem"), +.{ + .name = "libomptarget-nvptx-path=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-system-header-prefix=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "output-class-directory=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("analyzer-inlining-mode="), +joinpd1("fconstant-string-class="), +joinpd1("fcrash-diagnostics-dir="), +joinpd1("fdebug-compilation-dir="), +joinpd1("fdebug-default-version="), +joinpd1("ffp-exception-behavior="), +joinpd1("fmacro-backtrace-limit="), +joinpd1("fmax-array-constructor="), +joinpd1("fprofile-exclude-files="), +joinpd1("ftrivial-auto-var-init="), +jspd1("fxray-never-instrument="), +jspd1("interface-stub-version="), +joinpd1("malign-branch-boundary="), +joinpd1("mappletvos-version-min="), +joinpd1("Wnonportable-cfstrings"), +joinpd1("fdefault-calling-conv="), +joinpd1("fmax-subrecord-length="), +joinpd1("fmodules-ignore-macro="), +.{ + .name = "fno-sanitize-coverage=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("fobjc-dispatch-method="), +joinpd1("foperator-arrow-depth="), +joinpd1("fprebuilt-module-path="), +joinpd1("fprofile-filter-files="), +joinpd1("fspell-checking-limit="), +joinpd1("miphoneos-version-min="), +joinpd1("msmall-data-threshold="), +joinpd1("Wlarge-by-value-copy="), +joinpd1("analyzer-constraints="), +joinpd1("analyzer-dump-egraph="), +jspd1("compatibility_version"), +jspd1("dylinker_install_name"), +joinpd1("fcs-profile-generate="), +joinpd1("fmodules-prune-after="), +.{ + .name = "fno-sanitize-recover=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +jspd1("iframeworkwithsysroot"), +joinpd1("mamdgpu-debugger-abi="), +joinpd1("mprefer-vector-width="), +joinpd1("msign-return-address="), +joinpd1("mwatchos-version-min="), +.{ + .name = "system-header-prefix=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-with-prefix=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("coverage-notes-file="), +joinpd1("fbuild-session-file="), +joinpd1("fdiagnostics-format="), +joinpd1("fmax-stack-var-size="), +joinpd1("fmodules-cache-path="), +joinpd1("fmodules-embed-file="), +joinpd1("fprofile-instrument="), +joinpd1("fprofile-sample-use="), +joinpd1("fsanitize-blacklist="), +.{ + .name = "hip-device-lib-path=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("mmacosx-version-min="), +.{ + .name = "no-cuda-include-ptx=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("Wframe-larger-than="), +joinpd1("code-completion-at="), +joinpd1("coverage-data-file="), +joinpd1("fblas-matmul-limit="), +joinpd1("fdiagnostics-color="), +joinpd1("ffixed-line-length-"), +joinpd1("flimited-precision="), +joinpd1("fprofile-instr-use="), +.{ + .name = "fsanitize-coverage=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("fthin-link-bitcode="), +joinpd1("mbranch-protection="), +joinpd1("mmacos-version-min="), +joinpd1("pch-through-header="), +joinpd1("target-sdk-version="), +.{ + .name = "execution-charset:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "include-directory=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "library-directory=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "config-system-dir=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("fclang-abi-compat="), +joinpd1("fcompile-resource="), +joinpd1("fdebug-prefix-map="), +joinpd1("fdenormal-fp-math="), +joinpd1("fexcess-precision="), +joinpd1("ffree-line-length-"), +joinpd1("fmacro-prefix-map="), +.{ + .name = "fno-sanitize-trap=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("fobjc-abi-version="), +joinpd1("foutput-class-dir="), +joinpd1("fprofile-generate="), +joinpd1("frewrite-map-file="), +.{ + .name = "fsanitize-recover=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("fsymbol-partition="), +joinpd1("mcompact-branches="), +joinpd1("mstack-probe-size="), +joinpd1("mtvos-version-min="), +joinpd1("working-directory="), +joinpd1("analyze-function="), +joinpd1("analyzer-checker="), +joinpd1("coverage-version="), +.{ + .name = "cuda-include-ptx=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("falign-functions="), +joinpd1("fconstexpr-depth="), +joinpd1("fconstexpr-steps="), +joinpd1("ffile-prefix-map="), +joinpd1("fmodule-map-file="), +joinpd1("fobjc-arc-cxxlib="), +jspd1("iwithprefixbefore"), +joinpd1("malign-functions="), +joinpd1("mios-version-min="), +joinpd1("mstack-alignment="), +.{ + .name = "no-cuda-gpu-arch=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +jspd1("working-directory"), +joinpd1("analyzer-output="), +.{ + .name = "config-user-dir=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("debug-info-kind="), +joinpd1("debugger-tuning="), +joinpd1("fcf-runtime-abi="), +joinpd1("finit-character="), +joinpd1("fmax-type-align="), +joinpd1("fmessage-length="), +.{ + .name = "fopenmp-targets=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("fopenmp-version="), +joinpd1("fshow-overloads="), +joinpd1("ftemplate-depth-"), +joinpd1("ftemplate-depth="), +jspd1("fxray-attr-list="), +jspd1("internal-isystem"), +joinpd1("mlinker-version="), +.{ + .name = "print-file-name=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-prog-name=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +jspd1("stdlib++-isystem"), +joinpd1("Rpass-analysis="), +.{ + .name = "Xopenmp-target=", + .syntax = .joined_and_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "source-charset:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "analyzer-output", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-prefix=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "undefine-macro=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("analyzer-purge="), +joinpd1("analyzer-store="), +jspd1("current_version"), +joinpd1("fbootclasspath="), +joinpd1("fbracket-depth="), +joinpd1("fcf-protection="), +joinpd1("fdepfile-entry="), +joinpd1("fembed-bitcode="), +joinpd1("finput-charset="), +joinpd1("fmodule-format="), +joinpd1("fms-memptr-rep="), +joinpd1("fnew-alignment="), +joinpd1("frecord-marker="), +.{ + .name = "fsanitize-trap=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("fthinlto-index="), +joinpd1("ftrap-function="), +joinpd1("ftrapv-handler="), +.{ + .name = "hip-device-lib=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("mdynamic-no-pic"), +joinpd1("mframe-pointer="), +joinpd1("mindirect-jump="), +joinpd1("preamble-bytes="), +.{ + .name = "bootclasspath=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cuda-gpu-arch=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "dependent-lib=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("dwarf-version="), +joinpd1("falign-labels="), +joinpd1("fauto-profile="), +joinpd1("fexec-charset="), +joinpd1("fgnuc-version="), +joinpd1("finit-integer="), +joinpd1("finit-logical="), +joinpd1("finline-limit="), +joinpd1("fobjc-runtime="), +.{ + .name = "gcc-toolchain=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "linker-option=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "malign-branch=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +jspd1("objcxx-isystem"), +joinpd1("vtordisp-mode="), +joinpd1("Rpass-missed="), +joinpd1("Wlarger-than-"), +joinpd1("Wlarger-than="), +.{ + .name = "define-macro=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("ast-dump-all="), +.{ + .name = "autocomplete=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("falign-jumps="), +joinpd1("falign-loops="), +joinpd1("faligned-new="), +joinpd1("ferror-limit="), +joinpd1("ffp-contract="), +joinpd1("fmodule-file="), +joinpd1("fmodule-name="), +joinpd1("fmsc-version="), +.{ + .name = "fno-sanitize=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("fpack-struct="), +joinpd1("fpass-plugin="), +joinpd1("fprofile-dir="), +joinpd1("fprofile-use="), +joinpd1("frandom-seed="), +joinpd1("gsplit-dwarf="), +jspd1("isystem-after"), +joinpd1("malign-jumps="), +joinpd1("malign-loops="), +joinpd1("mimplicit-it="), +jspd1("pagezero_size"), +joinpd1("resource-dir="), +.{ + .name = "dyld-prefix=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "driver-mode=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("fmax-errors="), +joinpd1("fno-builtin-"), +joinpd1("fvisibility="), +joinpd1("fwchar-type="), +jspd1("fxray-modes="), +jspd1("iwithsysroot"), +joinpd1("mhvx-length="), +jspd1("objc-isystem"), +.{ + .name = "rsp-quoting=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("std-default="), +jspd1("sub_umbrella"), +.{ + .name = "Qpar-report", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Qvec-report", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "errorReport", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "for-linker=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "force-link=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +jspd1("client_name"), +jspd1("cxx-isystem"), +joinpd1("fclasspath="), +joinpd1("finit-real="), +joinpd1("fforce-addr"), +joinpd1("ftls-model="), +jspd1("ivfsoverlay"), +jspd1("iwithprefix"), +joinpd1("mfloat-abi="), +.{ + .name = "plugin-arg-", + .syntax = .joined_and_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "ptxas-path=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "save-stats=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "save-temps=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +joinpd1("stats-file="), +jspd1("sub_library"), +.{ + .name = "CLASSPATH=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "constexpr:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "classpath=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cuda-path=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("fencoding="), +joinpd1("ffp-model="), +joinpd1("ffpe-trap="), +joinpd1("flto-jobs="), +.{ + .name = "fsanitize=", + .syntax = .comma_joined, + .zig_equivalent = .sanitize, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +jspd1("iframework"), +joinpd1("mtls-size="), +joinpd1("segs_read_"), +.{ + .name = "unwindlib=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cgthreads", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "encoding=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "language=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "optimize=", + .syntax = .joined, + .zig_equivalent = .optimize, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "resource=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("ast-dump="), +jspd1("c-isystem"), +joinpd1("fcoarray="), +joinpd1("fconvert="), +joinpd1("fextdirs="), +joinpd1("ftabstop="), +jspd1("idirafter"), +joinpd1("mregparm="), +jspd1("undefined"), +.{ + .name = "extdirs=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "imacros=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "sysroot=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("fopenmp="), +joinpd1("fplugin="), +joinpd1("fuse-ld="), +joinpd1("fveclib="), +jspd1("isysroot"), +joinpd1("mcmodel="), +joinpd1("mconsole"), +joinpd1("mfpmath="), +joinpd1("mhwmult="), +joinpd1("mthreads"), +joinpd1("municode"), +joinpd1("mwindows"), +jspd1("seg1addr"), +.{ + .name = "assert=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "mhwdiv=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "output=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "prefix=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cl-ext=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("cl-std="), +joinpd1("fcheck="), +.{ + .name = "imacros", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +jspd1("iprefix"), +jspd1("isystem"), +joinpd1("mhwdiv="), +joinpd1("moslib="), +.{ + .name = "mrecip=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "stdlib=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "target=", + .syntax = .joined, + .zig_equivalent = .target, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("triple="), +.{ + .name = "verify=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("Rpass="), +.{ + .name = "Xarch_", + .syntax = .joined_and_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "clang:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "guard:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "debug=", + .syntax = .joined, + .zig_equivalent = .debug, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "param=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "warn-=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("fixit="), +joinpd1("gstabs"), +joinpd1("gxcoff"), +jspd1("iquote"), +joinpd1("march="), +joinpd1("mtune="), +.{ + .name = "rtlib=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "specs=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +joinpd1("weak-l"), +.{ + .name = "Ofast", + .syntax = .joined, + .zig_equivalent = .optimize, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +jspd1("Tdata"), +jspd1("Ttext"), +.{ + .name = "arch:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "favor", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "imsvc", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "warn-", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("flto="), +joinpd1("gcoff"), +joinpd1("mabi="), +joinpd1("mabs="), +joinpd1("masm="), +joinpd1("mcpu="), +joinpd1("mfpu="), +joinpd1("mhvx="), +joinpd1("mmcu="), +joinpd1("mnan="), +jspd1("Tbss"), +.{ + .name = "link", + .syntax = .remaining_args_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "std:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +joinpd1("ccc-"), +joinpd1("gvms"), +joinpd1("mdll"), +joinpd1("mtp="), +.{ + .name = "std=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "Wa,", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "Wl,", + .syntax = .comma_joined, + .zig_equivalent = .wl, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "Wp,", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "RTC", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "clr", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "doc", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +joinpd1("gz="), +joinpd1("A-"), +joinpd1("G="), +jspd1("MF"), +jspd1("MJ"), +jspd1("MQ"), +jspd1("MT"), +.{ + .name = "AI", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "EH", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "FA", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "FI", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "FR", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "FU", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fa", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fd", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fe", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fi", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fm", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fo", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fp", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fr", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gs", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "MP", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Tc", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Tp", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Yc", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Yl", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Yu", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "ZW", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zm", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zp", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "d2", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "vd", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +jspd1("A"), +jspd1("B"), +jspd1("D"), +jspd1("F"), +jspd1("G"), +jspd1("I"), +jspd1("J"), +jspd1("L"), +.{ + .name = "O", + .syntax = .joined, + .zig_equivalent = .optimize, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("R"), +jspd1("T"), +jspd1("U"), +jspd1("V"), +joinpd1("W"), +joinpd1("X"), +joinpd1("Z"), +.{ + .name = "D", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "F", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "I", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "O", + .syntax = .joined, + .zig_equivalent = .optimize, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "U", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "o", + .syntax = .joined_or_separate, + .zig_equivalent = .o, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "w", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +joinpd1("a"), +jspd1("b"), +joinpd1("d"), +jspd1("e"), +.{ + .name = "l", + .syntax = .joined_or_separate, + .zig_equivalent = .l, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "o", + .syntax = .joined_or_separate, + .zig_equivalent = .o, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +jspd1("u"), +jspd1("x"), +joinpd1("y"), +};}; diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index 7a45bb3c37..03e71c102d 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -95,7 +95,7 @@ pub const ZigCompiler = struct { pub fn getNativeLibC(self: *ZigCompiler) !*LibCInstallation { if (self.native_libc.start()) |ptr| return ptr; - try self.native_libc.data.findNative(self.allocator); + self.native_libc.data = try LibCInstallation.findNative(.{ .allocator = self.allocator }); self.native_libc.resolve(); return &self.native_libc.data; } @@ -126,7 +126,7 @@ pub const Compilation = struct { name: Buffer, llvm_triple: Buffer, root_src_path: ?[]const u8, - target: Target, + target: std.Target, llvm_target: *llvm.Target, build_mode: builtin.Mode, zig_lib_dir: []const u8, @@ -338,7 +338,7 @@ pub const Compilation = struct { zig_compiler: *ZigCompiler, name: []const u8, root_src_path: ?[]const u8, - target: Target, + target: std.zig.CrossTarget, kind: Kind, build_mode: builtin.Mode, is_static: bool, @@ -370,13 +370,18 @@ pub const Compilation = struct { zig_compiler: *ZigCompiler, name: []const u8, root_src_path: ?[]const u8, - target: Target, + cross_target: std.zig.CrossTarget, kind: Kind, build_mode: builtin.Mode, is_static: bool, zig_lib_dir: []const u8, ) !void { const allocator = zig_compiler.allocator; + + // TODO merge this line with stage2.zig crossTargetToTarget + const target_info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator, cross_target); + const target = target_info.target; + var comp = Compilation{ .arena_allocator = std.heap.ArenaAllocator.init(allocator), .zig_compiler = zig_compiler, @@ -419,7 +424,7 @@ pub const Compilation = struct { .target_machine = undefined, .target_data_ref = undefined, .target_layout_str = undefined, - .target_ptr_bits = target.getArchPtrBitWidth(), + .target_ptr_bits = target.cpu.arch.ptrBitWidth(), .root_package = undefined, .std_package = undefined, @@ -440,7 +445,7 @@ pub const Compilation = struct { } comp.name = try Buffer.init(comp.arena(), name); - comp.llvm_triple = try util.getTriple(comp.arena(), target); + comp.llvm_triple = try util.getLLVMTriple(comp.arena(), target); comp.llvm_target = try util.llvmTargetFromTriple(comp.llvm_triple); comp.zig_std_dir = try fs.path.join(comp.arena(), &[_][]const u8{ zig_lib_dir, "std" }); @@ -451,17 +456,12 @@ pub const Compilation = struct { const reloc_mode = if (is_static) llvm.RelocStatic else llvm.RelocPIC; - // LLVM creates invalid binaries on Windows sometimes. - // See https://github.com/ziglang/zig/issues/508 - // As a workaround we do not use target native features on Windows. var target_specific_cpu_args: ?[*:0]u8 = null; var target_specific_cpu_features: ?[*:0]u8 = null; defer llvm.DisposeMessage(target_specific_cpu_args); defer llvm.DisposeMessage(target_specific_cpu_features); - if (target == Target.Native and !target.isWindows()) { - target_specific_cpu_args = llvm.GetHostCPUName() orelse return error.OutOfMemory; - target_specific_cpu_features = llvm.GetNativeFeatures() orelse return error.OutOfMemory; - } + + // TODO detect native CPU & features here comp.target_machine = llvm.CreateTargetMachine( comp.llvm_target, @@ -520,8 +520,7 @@ pub const Compilation = struct { if (comp.tmp_dir.getOrNull()) |tmp_dir_result| if (tmp_dir_result.*) |tmp_dir| { - // TODO evented I/O? - fs.deleteTree(tmp_dir) catch {}; + fs.cwd().deleteTree(tmp_dir) catch {}; } else |_| {}; } @@ -1125,7 +1124,9 @@ pub const Compilation = struct { self.libc_link_lib = link_lib; // get a head start on looking for the native libc - if (self.target == Target.Native and self.override_libc == null) { + // TODO this is missing a bunch of logic related to whether the target is native + // and whether we can build libc + if (self.override_libc == null) { try self.deinit_group.call(startFindingNativeLibC, .{self}); } } diff --git a/src-self-hosted/errmsg.zig b/src-self-hosted/errmsg.zig index c1ebf0058e..606c8c4b3a 100644 --- a/src-self-hosted/errmsg.zig +++ b/src-self-hosted/errmsg.zig @@ -164,8 +164,7 @@ pub const Msg = struct { const realpath_copy = try mem.dupe(comp.gpa(), u8, tree_scope.root().realpath); errdefer comp.gpa().free(realpath_copy); - var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; - try parse_error.render(&tree_scope.tree.tokens, out_stream); + try parse_error.render(&tree_scope.tree.tokens, text_buf.outStream()); const msg = try comp.gpa().create(Msg); msg.* = Msg{ @@ -204,8 +203,7 @@ pub const Msg = struct { const realpath_copy = try mem.dupe(allocator, u8, realpath); errdefer allocator.free(realpath_copy); - var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; - try parse_error.render(&tree.tokens, out_stream); + try parse_error.render(&tree.tokens, text_buf.outStream()); const msg = try allocator.create(Msg); msg.* = Msg{ @@ -272,7 +270,7 @@ pub const Msg = struct { }); try stream.writeByteNTimes(' ', start_loc.column); try stream.writeByteNTimes('~', last_token.end - first_token.start); - try stream.write("\n"); + try stream.writeAll("\n"); } pub fn printToFile(msg: *const Msg, file: fs.File, color: Color) !void { @@ -281,7 +279,6 @@ pub const Msg = struct { .On => true, .Off => false, }; - var stream = &file.outStream().stream; - return msg.printToStream(stream, color_on); + return msg.printToStream(file.outStream(), color_on); } }; diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index 2e65962d41..7ad9e0ccc4 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -1099,7 +1099,6 @@ pub const Builder = struct { .Await => return error.Unimplemented, .BitNot => return error.Unimplemented, .BoolNot => return error.Unimplemented, - .Cancel => return error.Unimplemented, .OptionalType => return error.Unimplemented, .Negation => return error.Unimplemented, .NegationWrap => return error.Unimplemented, @@ -1188,6 +1187,7 @@ pub const Builder = struct { .ParamDecl => return error.Unimplemented, .FieldInitializer => return error.Unimplemented, .EnumLiteral => return error.Unimplemented, + .Noasync => return error.Unimplemented, } } @@ -1311,13 +1311,16 @@ pub const Builder = struct { var base: u8 = undefined; var rest: []const u8 = undefined; if (int_token.len >= 3 and int_token[0] == '0') { - base = switch (int_token[1]) { - 'b' => 2, - 'o' => 8, - 'x' => 16, - else => unreachable, - }; rest = int_token[2..]; + switch (int_token[1]) { + 'b' => base = 2, + 'o' => base = 8, + 'x' => base = 16, + else => { + base = 10; + rest = int_token; + }, + } } else { base = 10; rest = int_token; diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig index c07ef03b51..996f705060 100644 --- a/src-self-hosted/libc_installation.zig +++ b/src-self-hosted/libc_installation.zig @@ -280,7 +280,7 @@ pub const LibCInstallation = struct { // search in reverse order const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1); const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " "); - var search_dir = fs.cwd().openDirList(search_path) catch |err| switch (err) { + var search_dir = fs.cwd().openDir(search_path, .{}) catch |err| switch (err) { error.FileNotFound, error.NotDir, error.NoDevice, @@ -335,7 +335,7 @@ pub const LibCInstallation = struct { const stream = result_buf.outStream(); try stream.print("{}\\Include\\{}\\ucrt", .{ search.path, search.version }); - var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) { + var dir = fs.cwd().openDir(result_buf.toSliceConst(), .{}) catch |err| switch (err) { error.FileNotFound, error.NotDir, error.NoDevice, @@ -382,7 +382,7 @@ pub const LibCInstallation = struct { const stream = result_buf.outStream(); try stream.print("{}\\Lib\\{}\\ucrt\\{}", .{ search.path, search.version, arch_sub_dir }); - var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) { + var dir = fs.cwd().openDir(result_buf.toSliceConst(), .{}) catch |err| switch (err) { error.FileNotFound, error.NotDir, error.NoDevice, @@ -437,7 +437,7 @@ pub const LibCInstallation = struct { const stream = result_buf.outStream(); try stream.print("{}\\Lib\\{}\\um\\{}", .{ search.path, search.version, arch_sub_dir }); - var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) { + var dir = fs.cwd().openDir(result_buf.toSliceConst(), .{}) catch |err| switch (err) { error.FileNotFound, error.NotDir, error.NoDevice, @@ -475,7 +475,7 @@ pub const LibCInstallation = struct { try result_buf.append("\\include"); - var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) { + var dir = fs.cwd().openDir(result_buf.toSliceConst(), .{}) catch |err| switch (err) { error.FileNotFound, error.NotDir, error.NoDevice, diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index 1efa15574a..e67b307097 100644 --- a/src-self-hosted/link.zig +++ b/src-self-hosted/link.zig @@ -56,12 +56,13 @@ pub fn link(comp: *Compilation) !void { if (comp.haveLibC()) { // TODO https://github.com/ziglang/zig/issues/3190 var libc = ctx.comp.override_libc orelse blk: { - switch (comp.target) { - Target.Native => { - break :blk comp.zig_compiler.getNativeLibC() catch return error.LibCRequiredButNotProvidedOrFound; - }, - else => return error.LibCRequiredButNotProvidedOrFound, - } + @panic("this code has bitrotted"); + //switch (comp.target) { + // Target.Native => { + // break :blk comp.zig_compiler.getNativeLibC() catch return error.LibCRequiredButNotProvidedOrFound; + // }, + // else => return error.LibCRequiredButNotProvidedOrFound, + //} }; ctx.libc = libc; } @@ -155,11 +156,11 @@ fn constructLinkerArgsElf(ctx: *Context) !void { //bool shared = !g->is_static && is_lib; //Buf *soname = nullptr; if (ctx.comp.is_static) { - if (util.isArmOrThumb(ctx.comp.target)) { - try ctx.args.append("-Bstatic"); - } else { - try ctx.args.append("-static"); - } + //if (util.isArmOrThumb(ctx.comp.target)) { + // try ctx.args.append("-Bstatic"); + //} else { + // try ctx.args.append("-static"); + //} } //} else if (shared) { // lj->args.append("-shared"); @@ -176,29 +177,24 @@ fn constructLinkerArgsElf(ctx: *Context) !void { if (ctx.link_in_crt) { const crt1o = if (ctx.comp.is_static) "crt1.o" else "Scrt1.o"; - const crtbegino = if (ctx.comp.is_static) "crtbeginT.o" else "crtbegin.o"; - try addPathJoin(ctx, ctx.libc.lib_dir.?, crt1o); - try addPathJoin(ctx, ctx.libc.lib_dir.?, "crti.o"); - try addPathJoin(ctx, ctx.libc.static_lib_dir.?, crtbegino); + try addPathJoin(ctx, ctx.libc.crt_dir.?, crt1o); + try addPathJoin(ctx, ctx.libc.crt_dir.?, "crti.o"); } if (ctx.comp.haveLibC()) { try ctx.args.append("-L"); // TODO addNullByte should probably return [:0]u8 - try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.lib_dir.?)).ptr)); + try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.crt_dir.?)).ptr)); - try ctx.args.append("-L"); - try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.static_lib_dir.?)).ptr)); - - if (!ctx.comp.is_static) { - const dl = blk: { - if (ctx.libc.dynamic_linker_path) |dl| break :blk dl; - if (util.getDynamicLinkerPath(ctx.comp.target)) |dl| break :blk dl; - return error.LibCMissingDynamicLinker; - }; - try ctx.args.append("-dynamic-linker"); - try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr)); - } + //if (!ctx.comp.is_static) { + // const dl = blk: { + // //if (ctx.libc.dynamic_linker_path) |dl| break :blk dl; + // //if (util.getDynamicLinkerPath(ctx.comp.target)) |dl| break :blk dl; + // return error.LibCMissingDynamicLinker; + // }; + // try ctx.args.append("-dynamic-linker"); + // try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr)); + //} } //if (shared) { @@ -265,13 +261,12 @@ fn constructLinkerArgsElf(ctx: *Context) !void { // crt end if (ctx.link_in_crt) { - try addPathJoin(ctx, ctx.libc.static_lib_dir.?, "crtend.o"); - try addPathJoin(ctx, ctx.libc.lib_dir.?, "crtn.o"); + try addPathJoin(ctx, ctx.libc.crt_dir.?, "crtn.o"); } - if (ctx.comp.target != Target.Native) { - try ctx.args.append("--allow-shlib-undefined"); - } + //if (ctx.comp.target != Target.Native) { + // try ctx.args.append("--allow-shlib-undefined"); + //} } fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void { @@ -287,7 +282,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { try ctx.args.append("-DEBUG"); } - switch (ctx.comp.target.getArch()) { + switch (ctx.comp.target.cpu.arch) { .i386 => try ctx.args.append("-MACHINE:X86"), .x86_64 => try ctx.args.append("-MACHINE:X64"), .aarch64 => try ctx.args.append("-MACHINE:ARM"), @@ -302,7 +297,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { if (ctx.comp.haveLibC()) { try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.msvc_lib_dir.?})).ptr)); try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.kernel32_lib_dir.?})).ptr)); - try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.lib_dir.?})).ptr)); + try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.crt_dir.?})).ptr)); } if (ctx.link_in_crt) { @@ -417,7 +412,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { } }, .IPhoneOS => { - if (ctx.comp.target.getArch() == .aarch64) { + if (ctx.comp.target.cpu.arch == .aarch64) { // iOS does not need any crt1 files for arm64 } else if (platform.versionLessThan(3, 1)) { try ctx.args.append("-lcrt1.o"); @@ -435,28 +430,29 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { } try addFnObjects(ctx); - if (ctx.comp.target == Target.Native) { - for (ctx.comp.link_libs_list.toSliceConst()) |lib| { - if (mem.eql(u8, lib.name, "c")) { - // on Darwin, libSystem has libc in it, but also you have to use it - // to make syscalls because the syscall numbers are not documented - // and change between versions. - // so we always link against libSystem - try ctx.args.append("-lSystem"); - } else { - if (mem.indexOfScalar(u8, lib.name, '/') == null) { - const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", .{lib.name}); - try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); - } else { - const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name); - try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); - } - } - } - } else { - try ctx.args.append("-undefined"); - try ctx.args.append("dynamic_lookup"); - } + // TODO + //if (ctx.comp.target == Target.Native) { + // for (ctx.comp.link_libs_list.toSliceConst()) |lib| { + // if (mem.eql(u8, lib.name, "c")) { + // // on Darwin, libSystem has libc in it, but also you have to use it + // // to make syscalls because the syscall numbers are not documented + // // and change between versions. + // // so we always link against libSystem + // try ctx.args.append("-lSystem"); + // } else { + // if (mem.indexOfScalar(u8, lib.name, '/') == null) { + // const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", .{lib.name}); + // try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); + // } else { + // const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name); + // try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); + // } + // } + // } + //} else { + // try ctx.args.append("-undefined"); + // try ctx.args.append("dynamic_lookup"); + //} if (platform.kind == .MacOS) { if (platform.versionLessThan(10, 5)) { diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index 20e39bd2a1..f5faa26615 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -18,10 +18,6 @@ const Target = std.Target; const errmsg = @import("errmsg.zig"); const LibCInstallation = @import("libc_installation.zig").LibCInstallation; -var stderr_file: fs.File = undefined; -var stderr: *io.OutStream(fs.File.WriteError) = undefined; -var stdout: *io.OutStream(fs.File.WriteError) = undefined; - pub const io_mode = .evented; pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB @@ -51,17 +47,14 @@ const Command = struct { pub fn main() !void { const allocator = std.heap.c_allocator; - stdout = &std.io.getStdOut().outStream().stream; - - stderr_file = std.io.getStdErr(); - stderr = &stderr_file.outStream().stream; + const stderr = io.getStdErr().outStream(); const args = try process.argsAlloc(allocator); defer process.argsFree(allocator, args); if (args.len <= 1) { - try stderr.write("expected command argument\n\n"); - try stderr.write(usage); + try stderr.writeAll("expected command argument\n\n"); + try stderr.writeAll(usage); process.exit(1); } @@ -78,8 +71,8 @@ pub fn main() !void { } else if (mem.eql(u8, cmd, "libc")) { return cmdLibC(allocator, cmd_args); } else if (mem.eql(u8, cmd, "targets")) { - const info = try std.zig.system.NativeTargetInfo.detect(allocator); - defer info.deinit(allocator); + const info = try std.zig.system.NativeTargetInfo.detect(allocator, .{}); + const stdout = io.getStdOut().outStream(); return @import("print_targets.zig").cmdTargets(allocator, cmd_args, stdout, info.target); } else if (mem.eql(u8, cmd, "version")) { return cmdVersion(allocator, cmd_args); @@ -91,7 +84,7 @@ pub fn main() !void { return cmdInternal(allocator, cmd_args); } else { try stderr.print("unknown command: {}\n\n", .{args[1]}); - try stderr.write(usage); + try stderr.writeAll(usage); process.exit(1); } } @@ -156,6 +149,8 @@ const usage_build_generic = ; fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Compilation.Kind) !void { + const stderr = io.getStdErr().outStream(); + var color: errmsg.Color = .Auto; var build_mode: std.builtin.Mode = .Debug; var emit_bin = true; @@ -208,11 +203,11 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co const arg = args[i]; if (mem.startsWith(u8, arg, "-")) { if (mem.eql(u8, arg, "--help")) { - try stdout.write(usage_build_generic); + try io.getStdOut().writeAll(usage_build_generic); process.exit(0); } else if (mem.eql(u8, arg, "--color")) { if (i + 1 >= args.len) { - try stderr.write("expected [auto|on|off] after --color\n"); + try stderr.writeAll("expected [auto|on|off] after --color\n"); process.exit(1); } i += 1; @@ -229,7 +224,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co } } else if (mem.eql(u8, arg, "--mode")) { if (i + 1 >= args.len) { - try stderr.write("expected [Debug|ReleaseSafe|ReleaseFast|ReleaseSmall] after --mode\n"); + try stderr.writeAll("expected [Debug|ReleaseSafe|ReleaseFast|ReleaseSmall] after --mode\n"); process.exit(1); } i += 1; @@ -248,49 +243,49 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co } } else if (mem.eql(u8, arg, "--name")) { if (i + 1 >= args.len) { - try stderr.write("expected parameter after --name\n"); + try stderr.writeAll("expected parameter after --name\n"); process.exit(1); } i += 1; provided_name = args[i]; } else if (mem.eql(u8, arg, "--ver-major")) { if (i + 1 >= args.len) { - try stderr.write("expected parameter after --ver-major\n"); + try stderr.writeAll("expected parameter after --ver-major\n"); process.exit(1); } i += 1; version.major = try std.fmt.parseInt(u32, args[i], 10); } else if (mem.eql(u8, arg, "--ver-minor")) { if (i + 1 >= args.len) { - try stderr.write("expected parameter after --ver-minor\n"); + try stderr.writeAll("expected parameter after --ver-minor\n"); process.exit(1); } i += 1; version.minor = try std.fmt.parseInt(u32, args[i], 10); } else if (mem.eql(u8, arg, "--ver-patch")) { if (i + 1 >= args.len) { - try stderr.write("expected parameter after --ver-patch\n"); + try stderr.writeAll("expected parameter after --ver-patch\n"); process.exit(1); } i += 1; version.patch = try std.fmt.parseInt(u32, args[i], 10); } else if (mem.eql(u8, arg, "--linker-script")) { if (i + 1 >= args.len) { - try stderr.write("expected parameter after --linker-script\n"); + try stderr.writeAll("expected parameter after --linker-script\n"); process.exit(1); } i += 1; linker_script = args[i]; } else if (mem.eql(u8, arg, "--libc")) { if (i + 1 >= args.len) { - try stderr.write("expected parameter after --libc\n"); + try stderr.writeAll("expected parameter after --libc\n"); process.exit(1); } i += 1; libc_arg = args[i]; } else if (mem.eql(u8, arg, "-mllvm")) { if (i + 1 >= args.len) { - try stderr.write("expected parameter after -mllvm\n"); + try stderr.writeAll("expected parameter after -mllvm\n"); process.exit(1); } i += 1; @@ -300,14 +295,14 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co try mllvm_flags.append(args[i]); } else if (mem.eql(u8, arg, "-mmacosx-version-min")) { if (i + 1 >= args.len) { - try stderr.write("expected parameter after -mmacosx-version-min\n"); + try stderr.writeAll("expected parameter after -mmacosx-version-min\n"); process.exit(1); } i += 1; macosx_version_min = args[i]; } else if (mem.eql(u8, arg, "-mios-version-min")) { if (i + 1 >= args.len) { - try stderr.write("expected parameter after -mios-version-min\n"); + try stderr.writeAll("expected parameter after -mios-version-min\n"); process.exit(1); } i += 1; @@ -348,7 +343,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co linker_rdynamic = true; } else if (mem.eql(u8, arg, "--pkg-begin")) { if (i + 2 >= args.len) { - try stderr.write("expected [name] [path] after --pkg-begin\n"); + try stderr.writeAll("expected [name] [path] after --pkg-begin\n"); process.exit(1); } i += 1; @@ -363,7 +358,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co if (cur_pkg.parent) |parent| { cur_pkg = parent; } else { - try stderr.write("encountered --pkg-end with no matching --pkg-begin\n"); + try stderr.writeAll("encountered --pkg-end with no matching --pkg-begin\n"); process.exit(1); } } else if (mem.startsWith(u8, arg, "-l")) { @@ -411,18 +406,18 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co var it = mem.separate(basename, "."); break :blk it.next() orelse basename; } else { - try stderr.write("--name [name] not provided and unable to infer\n"); + try stderr.writeAll("--name [name] not provided and unable to infer\n"); process.exit(1); } }; if (root_src_file == null and link_objects.len == 0 and assembly_files.len == 0) { - try stderr.write("Expected source file argument or at least one --object or --assembly argument\n"); + try stderr.writeAll("Expected source file argument or at least one --object or --assembly argument\n"); process.exit(1); } if (out_type == Compilation.Kind.Obj and link_objects.len != 0) { - try stderr.write("When building an object file, --object arguments are invalid\n"); + try stderr.writeAll("When building an object file, --object arguments are invalid\n"); process.exit(1); } @@ -440,7 +435,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co &zig_compiler, root_name, root_src_file, - Target.Native, + .{}, out_type, build_mode, !is_dynamic, @@ -478,7 +473,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co comp.linker_rdynamic = linker_rdynamic; if (macosx_version_min != null and ios_version_min != null) { - try stderr.write("-mmacosx-version-min and -mios-version-min options not allowed together\n"); + try stderr.writeAll("-mmacosx-version-min and -mios-version-min options not allowed together\n"); process.exit(1); } @@ -501,6 +496,8 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co } fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void { + const stderr_file = io.getStdErr(); + const stderr = stderr_file.outStream(); var count: usize = 0; while (!comp.cancelled) { const build_event = comp.events.get(); @@ -551,7 +548,8 @@ const Fmt = struct { }; fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_file: []const u8) void { - libc.parse(allocator, libc_paths_file, stderr) catch |err| { + const stderr = io.getStdErr().outStream(); + libc.* = LibCInstallation.parse(allocator, libc_paths_file, stderr) catch |err| { stderr.print("Unable to parse libc path file '{}': {}.\n" ++ "Try running `zig libc` to see an example for the native target.\n", .{ libc_paths_file, @@ -562,6 +560,7 @@ fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_fil } fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void { + const stderr = io.getStdErr().outStream(); switch (args.len) { 0 => {}, 1 => { @@ -582,10 +581,12 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void { stderr.print("unable to find libc: {}\n", .{@errorName(err)}) catch {}; process.exit(1); }; - libc.render(stdout) catch process.exit(1); + libc.render(io.getStdOut().outStream()) catch process.exit(1); } fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { + const stderr_file = io.getStdErr(); + const stderr = stderr_file.outStream(); var color: errmsg.Color = .Auto; var stdin_flag: bool = false; var check_flag: bool = false; @@ -597,11 +598,12 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { const arg = args[i]; if (mem.startsWith(u8, arg, "-")) { if (mem.eql(u8, arg, "--help")) { - try stdout.write(usage_fmt); + const stdout = io.getStdOut().outStream(); + try stdout.writeAll(usage_fmt); process.exit(0); } else if (mem.eql(u8, arg, "--color")) { if (i + 1 >= args.len) { - try stderr.write("expected [auto|on|off] after --color\n"); + try stderr.writeAll("expected [auto|on|off] after --color\n"); process.exit(1); } i += 1; @@ -632,14 +634,13 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { if (stdin_flag) { if (input_files.len != 0) { - try stderr.write("cannot use --stdin with positional arguments\n"); + try stderr.writeAll("cannot use --stdin with positional arguments\n"); process.exit(1); } - var stdin_file = io.getStdIn(); - var stdin = stdin_file.inStream(); + const stdin = io.getStdIn().inStream(); - const source_code = try stdin.stream.readAllAlloc(allocator, max_src_size); + const source_code = try stdin.readAllAlloc(allocator, max_src_size); defer allocator.free(source_code); const tree = std.zig.parse(allocator, source_code) catch |err| { @@ -653,7 +654,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, tree, ""); defer msg.destroy(); - try msg.printToFile(stderr_file, color); + try msg.printToFile(io.getStdErr(), color); } if (tree.errors.len != 0) { process.exit(1); @@ -664,12 +665,13 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { process.exit(code); } + const stdout = io.getStdOut().outStream(); _ = try std.zig.render(allocator, stdout, tree); return; } if (input_files.len == 0) { - try stderr.write("expected at least one source file argument\n"); + try stderr.writeAll("expected at least one source file argument\n"); process.exit(1); } @@ -713,6 +715,9 @@ const FmtError = error{ } || fs.File.OpenError; async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void { + const stderr_file = io.getStdErr(); + const stderr = stderr_file.outStream(); + const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref); defer fmt.allocator.free(file_path); @@ -729,7 +734,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro max_src_size, ) catch |err| switch (err) { error.IsDir, error.AccessDenied => { - var dir = try fs.cwd().openDirList(file_path); + var dir = try fs.cwd().openDir(file_path, .{ .iterate = true }); defer dir.close(); var group = event.Group(FmtError!void).init(fmt.allocator); @@ -791,11 +796,13 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro } fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void { + const stdout = io.getStdOut().outStream(); try stdout.print("{}\n", .{c.ZIG_VERSION_STRING}); } fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void { - try stdout.write(usage); + const stdout = io.getStdOut(); + try stdout.writeAll(usage); } pub const info_zen = @@ -816,7 +823,7 @@ pub const info_zen = ; fn cmdZen(allocator: *Allocator, args: []const []const u8) !void { - try stdout.write(info_zen); + try io.getStdOut().writeAll(info_zen); } const usage_internal = @@ -829,8 +836,9 @@ const usage_internal = ; fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void { + const stderr = io.getStdErr().outStream(); if (args.len == 0) { - try stderr.write(usage_internal); + try stderr.writeAll(usage_internal); process.exit(1); } @@ -849,10 +857,11 @@ fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void { } try stderr.print("unknown sub command: {}\n\n", .{args[0]}); - try stderr.write(usage_internal); + try stderr.writeAll(usage_internal); } fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void { + const stdout = io.getStdOut().outStream(); try stdout.print( \\ZIG_CMAKE_BINARY_DIR {} \\ZIG_CXX_COMPILER {} diff --git a/src-self-hosted/print_targets.zig b/src-self-hosted/print_targets.zig index ad506425d2..997cfcfddc 100644 --- a/src-self-hosted/print_targets.zig +++ b/src-self-hosted/print_targets.zig @@ -72,7 +72,7 @@ pub fn cmdTargets( }; defer allocator.free(zig_lib_dir); - var dir = try std.fs.cwd().openDirList(zig_lib_dir); + var dir = try std.fs.cwd().openDir(zig_lib_dir, .{}); defer dir.close(); const vers_txt = try dir.readFileAlloc(allocator, "libc/glibc/vers.txt", 10 * 1024); diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index 38dfbaf072..9b710b822c 100644 --- a/src-self-hosted/stage2.zig +++ b/src-self-hosted/stage2.zig @@ -113,6 +113,10 @@ const Error = extern enum { TargetHasNoDynamicLinker, InvalidAbiVersion, InvalidOperatingSystemVersion, + UnknownClangOption, + PermissionDenied, + FileBusy, + Locked, }; const FILE = std.c.FILE; @@ -128,7 +132,7 @@ export fn stage2_translate_c( args_end: [*]?[*]const u8, resources_path: [*:0]const u8, ) Error { - var errors = @as([*]translate_c.ClangErrMsg, undefined)[0..0]; + var errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{}; out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) { error.SemanticAnalyzeFail => { out_errors_ptr.* = errors.ptr; @@ -319,7 +323,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) { error.IsDir, error.AccessDenied => { // TODO make event based (and dir.next()) - var dir = try fs.cwd().openDirList(file_path); + var dir = try fs.cwd().openDir(file_path, .{ .iterate = true }); defer dir.close(); var dir_it = dir.iterate(); @@ -843,6 +847,9 @@ export fn stage2_libc_parse(stage1_libc: *Stage2LibCInstallation, libc_file_z: [ error.NoDevice => return .NoDevice, error.NotDir => return .NotDir, error.DeviceBusy => return .DeviceBusy, + error.PermissionDenied => return .PermissionDenied, + error.FileBusy => return .FileBusy, + error.Locked => return .Locked, }; stage1_libc.initFromStage2(libc); return .None; @@ -909,6 +916,7 @@ const Stage2Target = extern struct { os_builtin_str: ?[*:0]const u8, dynamic_linker: ?[*:0]const u8, + standard_dynamic_linker_path: ?[*:0]const u8, fn fromTarget(self: *Stage2Target, cross_target: CrossTarget) !void { const allocator = std.heap.c_allocator; @@ -1119,6 +1127,12 @@ const Stage2Target = extern struct { } }; + const std_dl = target.standardDynamicLinkerPath(); + const std_dl_z = if (std_dl.get()) |dl| + (try mem.dupeZ(std.heap.c_allocator, u8, dl)).ptr + else + null; + const cache_hash_slice = cache_hash.toOwnedSlice(); self.* = .{ .arch = @enumToInt(target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch @@ -1134,6 +1148,7 @@ const Stage2Target = extern struct { .is_native = cross_target.isNative(), .glibc_or_darwin_version = glibc_or_darwin_version, .dynamic_linker = dynamic_linker, + .standard_dynamic_linker_path = std_dl_z, }; } }; @@ -1207,3 +1222,173 @@ fn convertSlice(slice: [][:0]u8, ptr: *[*][*:0]u8, len: *usize) !void { } ptr.* = new_slice.ptr; } + +const clang_args = @import("clang_options.zig").list; + +// ABI warning +pub const ClangArgIterator = extern struct { + has_next: bool, + zig_equivalent: ZigEquivalent, + only_arg: [*:0]const u8, + second_arg: [*:0]const u8, + other_args_ptr: [*]const [*:0]const u8, + other_args_len: usize, + argv_ptr: [*]const [*:0]const u8, + argv_len: usize, + next_index: usize, + + // ABI warning + pub const ZigEquivalent = extern enum { + target, + o, + c, + other, + positional, + l, + ignore, + driver_punt, + pic, + no_pic, + nostdlib, + shared, + rdynamic, + wl, + preprocess, + optimize, + debug, + sanitize, + }; + + fn init(argv: []const [*:0]const u8) ClangArgIterator { + return .{ + .next_index = 2, // `zig cc foo` this points to `foo` + .has_next = argv.len > 2, + .zig_equivalent = undefined, + .only_arg = undefined, + .second_arg = undefined, + .other_args_ptr = undefined, + .other_args_len = undefined, + .argv_ptr = argv.ptr, + .argv_len = argv.len, + }; + } + + fn next(self: *ClangArgIterator) !void { + assert(self.has_next); + assert(self.next_index < self.argv_len); + // In this state we know that the parameter we are looking at is a root parameter + // rather than an argument to a parameter. + self.other_args_ptr = self.argv_ptr + self.next_index; + self.other_args_len = 1; // We adjust this value below when necessary. + const arg = mem.span(self.argv_ptr[self.next_index]); + self.next_index += 1; + defer { + if (self.next_index >= self.argv_len) self.has_next = false; + } + + if (!mem.startsWith(u8, arg, "-")) { + self.zig_equivalent = .positional; + self.only_arg = arg.ptr; + return; + } + + find_clang_arg: for (clang_args) |clang_arg| switch (clang_arg.syntax) { + .flag => { + const prefix_len = clang_arg.matchEql(arg); + if (prefix_len > 0) { + self.zig_equivalent = clang_arg.zig_equivalent; + self.only_arg = arg.ptr + prefix_len; + + break :find_clang_arg; + } + }, + .joined, .comma_joined => { + // joined example: --target=foo + // comma_joined example: -Wl,-soname,libsoundio.so.2 + const prefix_len = clang_arg.matchStartsWith(arg); + if (prefix_len != 0) { + self.zig_equivalent = clang_arg.zig_equivalent; + self.only_arg = arg.ptr + prefix_len; // This will skip over the "--target=" part. + + break :find_clang_arg; + } + }, + .joined_or_separate => { + // Examples: `-lfoo`, `-l foo` + const prefix_len = clang_arg.matchStartsWith(arg); + if (prefix_len == arg.len) { + if (self.next_index >= self.argv_len) { + std.debug.warn("Expected parameter after '{}'\n", .{arg}); + process.exit(1); + } + self.only_arg = self.argv_ptr[self.next_index]; + self.next_index += 1; + self.other_args_len += 1; + self.zig_equivalent = clang_arg.zig_equivalent; + + break :find_clang_arg; + } else if (prefix_len != 0) { + self.zig_equivalent = clang_arg.zig_equivalent; + self.only_arg = arg.ptr + prefix_len; + + break :find_clang_arg; + } + }, + .joined_and_separate => { + // Example: `-Xopenmp-target=riscv64-linux-unknown foo` + const prefix_len = clang_arg.matchStartsWith(arg); + if (prefix_len != 0) { + self.only_arg = arg.ptr + prefix_len; + if (self.next_index >= self.argv_len) { + std.debug.warn("Expected parameter after '{}'\n", .{arg}); + process.exit(1); + } + self.second_arg = self.argv_ptr[self.next_index]; + self.next_index += 1; + self.other_args_len += 1; + self.zig_equivalent = clang_arg.zig_equivalent; + break :find_clang_arg; + } + }, + .separate => if (clang_arg.matchEql(arg) > 0) { + if (self.next_index >= self.argv_len) { + std.debug.warn("Expected parameter after '{}'\n", .{arg}); + process.exit(1); + } + self.only_arg = self.argv_ptr[self.next_index]; + self.next_index += 1; + self.other_args_len += 1; + self.zig_equivalent = clang_arg.zig_equivalent; + break :find_clang_arg; + }, + .remaining_args_joined => { + const prefix_len = clang_arg.matchStartsWith(arg); + if (prefix_len != 0) { + @panic("TODO"); + } + }, + .multi_arg => if (clang_arg.matchEql(arg) > 0) { + @panic("TODO"); + }, + } + else { + std.debug.warn("Unknown Clang option: '{}'\n", .{arg}); + process.exit(1); + } + } +}; + +export fn stage2_clang_arg_iterator( + result: *ClangArgIterator, + argc: usize, + argv: [*]const [*:0]const u8, +) void { + result.* = ClangArgIterator.init(argv[0..argc]); +} + +export fn stage2_clang_arg_next(it: *ClangArgIterator) Error { + it.next() catch |err| switch (err) { + error.UnknownClangOption => return .UnknownClangOption, + }; + return .None; +} diff --git a/src-self-hosted/test.zig b/src-self-hosted/test.zig index e87164c9fb..b146d6607a 100644 --- a/src-self-hosted/test.zig +++ b/src-self-hosted/test.zig @@ -57,11 +57,11 @@ pub const TestContext = struct { errdefer allocator.free(self.zig_lib_dir); try std.fs.cwd().makePath(tmp_dir_name); - errdefer std.fs.deleteTree(tmp_dir_name) catch {}; + errdefer std.fs.cwd().deleteTree(tmp_dir_name) catch {}; } fn deinit(self: *TestContext) void { - std.fs.deleteTree(tmp_dir_name) catch {}; + std.fs.cwd().deleteTree(tmp_dir_name) catch {}; allocator.free(self.zig_lib_dir); self.zig_compiler.deinit(); } diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 84416ac980..e6cf8fb149 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -1744,20 +1744,18 @@ fn writeEscapedString(buf: []u8, s: []const u8) void { // Returns either a string literal or a slice of `buf`. fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 { return switch (c) { - '\"' => "\\\""[0..], - '\'' => "\\'"[0..], - '\\' => "\\\\"[0..], - '\n' => "\\n"[0..], - '\r' => "\\r"[0..], - '\t' => "\\t"[0..], - else => { - // Handle the remaining escapes Zig doesn't support by turning them - // into their respective hex representation - if (std.ascii.isCntrl(c)) - return std.fmt.bufPrint(char_buf[0..], "\\x{x:0<2}", .{c}) catch unreachable - else - return std.fmt.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable; - }, + '\"' => "\\\"", + '\'' => "\\'", + '\\' => "\\\\", + '\n' => "\\n", + '\r' => "\\r", + '\t' => "\\t", + // Handle the remaining escapes Zig doesn't support by turning them + // into their respective hex representation + else => if (std.ascii.isCntrl(c)) + std.fmt.bufPrint(char_buf, "\\x{x:0<2}", .{c}) catch unreachable + else + std.fmt.bufPrint(char_buf, "{c}", .{c}) catch unreachable, }; } diff --git a/src-self-hosted/util.zig b/src-self-hosted/util.zig index 2a7bf4d9cc..ec68823ebd 100644 --- a/src-self-hosted/util.zig +++ b/src-self-hosted/util.zig @@ -3,8 +3,7 @@ const Target = std.Target; const llvm = @import("llvm.zig"); pub fn getDarwinArchString(self: Target) [:0]const u8 { - const arch = self.getArch(); - switch (arch) { + switch (self.cpu.arch) { .aarch64 => return "arm64", .thumb, .arm, @@ -34,3 +33,15 @@ pub fn initializeAllTargets() void { llvm.InitializeAllAsmPrinters(); llvm.InitializeAllAsmParsers(); } + +pub fn getLLVMTriple(allocator: *std.mem.Allocator, target: std.Target) !std.Buffer { + var result = try std.Buffer.initSize(allocator, 0); + errdefer result.deinit(); + + try result.outStream().print( + "{}-unknown-{}-{}", + .{ @tagName(target.cpu.arch), @tagName(target.os.tag), @tagName(target.abi) }, + ); + + return result; +} diff --git a/src/all_types.hpp b/src/all_types.hpp index 53aae9e236..aed03d4781 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -231,6 +231,7 @@ enum ConstPtrSpecial { // The pointer is a reference to a single object. ConstPtrSpecialRef, // The pointer points to an element in an underlying array. + // Not to be confused with ConstPtrSpecialSubArray. ConstPtrSpecialBaseArray, // The pointer points to a field in an underlying struct. ConstPtrSpecialBaseStruct, @@ -257,6 +258,10 @@ enum ConstPtrSpecial { // types to be the same, so all optionals of pointer types use x_ptr // instead of x_optional. ConstPtrSpecialNull, + // The pointer points to a sub-array (not an individual element). + // Not to be confused with ConstPtrSpecialBaseArray. However, it uses the same + // union payload struct (base_array). + ConstPtrSpecialSubArray, }; enum ConstPtrMut { @@ -739,6 +744,7 @@ struct AstNodeReturnExpr { struct AstNodeDefer { ReturnKind kind; + AstNode *err_payload; AstNode *expr; // temporary data used in IR generation @@ -1997,6 +2003,7 @@ enum WantCSanitize { struct CFile { ZigList args; const char *source_path; + const char *preprocessor_only_basename; }; // When adding fields, check if they should be added to the hash computation in build_with_cache @@ -2141,6 +2148,7 @@ struct CodeGen { // As an input parameter, mutually exclusive with enable_cache. But it gets // populated in codegen_build_and_link. Buf *output_dir; + Buf *c_artifact_dir; const char **libc_include_dir_list; size_t libc_include_dir_len; @@ -2262,6 +2270,7 @@ struct CodeGen { Buf *zig_lib_dir; Buf *zig_std_dir; Buf *version_script_path; + Buf *override_soname; const char **llvm_argv; size_t llvm_argv_len; @@ -3706,6 +3715,7 @@ struct IrInstGenSlice { IrInstGen *start; IrInstGen *end; IrInstGen *result_loc; + ZigValue *sentinel; bool safety_check_on; }; diff --git a/src/analyze.cpp b/src/analyze.cpp index 33d28269b9..77d3f33331 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -780,6 +780,8 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa } ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ZigValue *sentinel) { + Error err; + TypeId type_id = {}; type_id.id = ZigTypeIdArray; type_id.data.array.codegen = g; @@ -791,7 +793,11 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi return existing_entry->value; } - assert(type_is_resolved(child_type, ResolveStatusSizeKnown)); + size_t full_array_size = array_size + ((sentinel != nullptr) ? 1 : 0); + + if (full_array_size != 0 && (err = type_resolve(g, child_type, ResolveStatusSizeKnown))) { + codegen_report_errors_and_exit(g); + } ZigType *entry = new_type_table_entry(ZigTypeIdArray); @@ -803,15 +809,8 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi } buf_appendf(&entry->name, "]%s", buf_ptr(&child_type->name)); - size_t full_array_size; - if (array_size == 0) { - full_array_size = 0; - } else { - full_array_size = array_size + ((sentinel != nullptr) ? 1 : 0); - } - entry->size_in_bits = child_type->size_in_bits * full_array_size; - entry->abi_align = child_type->abi_align; + entry->abi_align = (full_array_size == 0) ? 0 : child_type->abi_align; entry->abi_size = child_type->abi_size * full_array_size; entry->data.array.child_type = child_type; @@ -1197,7 +1196,8 @@ Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent LazyValueArrayType *lazy_array_type = reinterpret_cast(type_val->data.x_lazy); - if (lazy_array_type->length < 1) { + // The sentinel counts as an extra element + if (lazy_array_type->length == 0 && lazy_array_type->sentinel == nullptr) { *is_zero_bits = true; return ErrorNone; } @@ -1452,7 +1452,7 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, ZigV case LazyValueIdArrayType: { LazyValueArrayType *lazy_array_type = reinterpret_cast(type_val->data.x_lazy); - if (lazy_array_type->length < 1) + if (lazy_array_type->length == 0) return OnePossibleValueYes; return type_val_resolve_has_one_possible_value(g, lazy_array_type->elem_type->value); } @@ -4488,7 +4488,14 @@ static uint32_t get_async_frame_align_bytes(CodeGen *g) { } uint32_t get_ptr_align(CodeGen *g, ZigType *type) { - ZigType *ptr_type = get_src_ptr_type(type); + ZigType *ptr_type; + if (type->id == ZigTypeIdStruct) { + assert(type->data.structure.special == StructSpecialSlice); + TypeStructField *ptr_field = type->data.structure.fields[slice_ptr_index]; + ptr_type = resolve_struct_field_type(g, ptr_field); + } else { + ptr_type = get_src_ptr_type(type); + } if (ptr_type->id == ZigTypeIdPointer) { return (ptr_type->data.pointer.explicit_alignment == 0) ? get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment; @@ -4505,8 +4512,15 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) { } } -bool get_ptr_const(ZigType *type) { - ZigType *ptr_type = get_src_ptr_type(type); +bool get_ptr_const(CodeGen *g, ZigType *type) { + ZigType *ptr_type; + if (type->id == ZigTypeIdStruct) { + assert(type->data.structure.special == StructSpecialSlice); + TypeStructField *ptr_field = type->data.structure.fields[slice_ptr_index]; + ptr_type = resolve_struct_field_type(g, ptr_field); + } else { + ptr_type = get_src_ptr_type(type); + } if (ptr_type->id == ZigTypeIdPointer) { return ptr_type->data.pointer.is_const; } else if (ptr_type->id == ZigTypeIdFn) { @@ -5282,6 +5296,11 @@ static uint32_t hash_const_val_ptr(ZigValue *const_val) { hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val); hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index); return hash_val; + case ConstPtrSpecialSubArray: + hash_val += (uint32_t)2643358777; + hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val); + hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index); + return hash_val; case ConstPtrSpecialBaseStruct: hash_val += (uint32_t)3518317043; hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val); @@ -5811,18 +5830,13 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) { // The elements array cannot be left unpopulated ZigType *array_type = result->type; ZigType *elem_type = array_type->data.array.child_type; - ZigValue *sentinel_value = array_type->data.array.sentinel; - const size_t elem_count = array_type->data.array.len + (sentinel_value != nullptr); + const size_t elem_count = array_type->data.array.len; result->data.x_array.data.s_none.elements = g->pass1_arena->allocate(elem_count); for (size_t i = 0; i < elem_count; i += 1) { ZigValue *elem_val = &result->data.x_array.data.s_none.elements[i]; copy_const_val(g, elem_val, get_the_one_possible_value(g, elem_type)); } - if (sentinel_value != nullptr) { - ZigValue *last_elem_val = &result->data.x_array.data.s_none.elements[elem_count - 1]; - copy_const_val(g, last_elem_val, sentinel_value); - } } else if (result->type->id == ZigTypeIdPointer) { result->data.x_ptr.special = ConstPtrSpecialRef; result->data.x_ptr.data.ref.pointee = get_the_one_possible_value(g, result->type->data.pointer.child_type); @@ -6753,6 +6767,7 @@ bool const_values_equal_ptr(ZigValue *a, ZigValue *b) { return false; return true; case ConstPtrSpecialBaseArray: + case ConstPtrSpecialSubArray: if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val) { return false; } @@ -7010,6 +7025,7 @@ static void render_const_val_ptr(CodeGen *g, Buf *buf, ZigValue *const_val, ZigT render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); return; case ConstPtrSpecialBaseArray: + case ConstPtrSpecialSubArray: buf_appendf(buf, "*"); // TODO we need a source node for const_ptr_pointee because it can generate compile errors render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); diff --git a/src/analyze.hpp b/src/analyze.hpp index c7cbab4b8c..b6404b1882 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -76,7 +76,7 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool all ZigType *get_src_ptr_type(ZigType *type); uint32_t get_ptr_align(CodeGen *g, ZigType *type); -bool get_ptr_const(ZigType *type); +bool get_ptr_const(CodeGen *g, ZigType *type); ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry); ZigType *container_ref_type(ZigType *type_entry); bool type_is_complete(ZigType *type_entry); diff --git a/src/codegen.cpp b/src/codegen.cpp index aba8a49032..a0fd984740 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5418,12 +5418,16 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI ZigType *array_type = array_ptr_type->data.pointer.child_type; LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); - LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); - bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); - ZigType *res_slice_ptr_type = instruction->base.value->type->data.structure.fields[slice_ptr_index]->type_entry; - ZigValue *sentinel = res_slice_ptr_type->data.pointer.sentinel; + ZigType *result_type = instruction->base.value->type; + if (!type_has_bits(g, result_type)) { + return nullptr; + } + + // This is not whether the result type has a sentinel, but whether there should be a sentinel check, + // e.g. if they used [a..b :s] syntax. + ZigValue *sentinel = instruction->sentinel; if (array_type->id == ZigTypeIdArray || (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) @@ -5458,6 +5462,8 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI } } if (!type_has_bits(g, array_type)) { + LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); // TODO if runtime safety is on, store 0xaaaaaaa in ptr field @@ -5466,20 +5472,26 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI return tmp_struct_ptr; } - - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, ""); LLVMValueRef indices[] = { LLVMConstNull(g->builtin_types.entry_usize->llvm_type), start_val, }; LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); - gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); + if (result_type->id == ZigTypeIdPointer) { + ir_assert(instruction->result_loc == nullptr, &instruction->base); + LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); + return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); + } else { + LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); + LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, ""); + gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); - LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); - LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); - gen_store_untyped(g, len_value, len_field_ptr, 0, false); + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); + LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); + gen_store_untyped(g, len_value, len_field_ptr, 0, false); - return tmp_struct_ptr; + return tmp_struct_ptr; + } } else if (array_type->id == ZigTypeIdPointer) { assert(array_type->data.pointer.ptr_len != PtrLenSingle); LLVMValueRef start_val = ir_llvm_value(g, instruction->start); @@ -5493,24 +5505,39 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI } } - if (type_has_bits(g, array_type)) { - size_t gen_ptr_index = instruction->base.value->type->data.structure.fields[slice_ptr_index]->gen_index; - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, ""); - LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, ""); - gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); + if (!type_has_bits(g, array_type)) { + LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); + size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index; + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, ""); + LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); + gen_store_untyped(g, len_value, len_field_ptr, 0, false); + return tmp_struct_ptr; } - size_t gen_len_index = instruction->base.value->type->data.structure.fields[slice_len_index]->gen_index; + LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, ""); + if (result_type->id == ZigTypeIdPointer) { + ir_assert(instruction->result_loc == nullptr, &instruction->base); + LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); + return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); + } + + LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); + + size_t gen_ptr_index = result_type->data.structure.fields[slice_ptr_index]->gen_index; + LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, ""); + gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); + + size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index; LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, ""); LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); gen_store_untyped(g, len_value, len_field_ptr, 0, false); return tmp_struct_ptr; + } else if (array_type->id == ZigTypeIdStruct) { assert(array_type->data.structure.special == StructSpecialSlice); assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); - assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(tmp_struct_ptr))) == LLVMStructTypeKind); size_t ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index; assert(ptr_index != SIZE_MAX); @@ -5547,15 +5574,22 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI } } - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)ptr_index, ""); LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, ""); - gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); + if (result_type->id == ZigTypeIdPointer) { + ir_assert(instruction->result_loc == nullptr, &instruction->base); + LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); + return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); + } else { + LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); + LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)ptr_index, ""); + gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); - LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)len_index, ""); - LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); - gen_store_untyped(g, len_value, len_field_ptr, 0, false); + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)len_index, ""); + LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); + gen_store_untyped(g, len_value, len_field_ptr, 0, false); - return tmp_struct_ptr; + return tmp_struct_ptr; + } } else { zig_unreachable(); } @@ -6640,7 +6674,6 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ZigValue *array_co }; return LLVMConstInBoundsGEP(base_ptr, indices, 2); } else { - assert(parent->id == ConstParentIdScalar); return base_ptr; } } @@ -6790,6 +6823,22 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Zig used_bits += packed_bits_size; } } + + if (type_entry->data.array.sentinel != nullptr) { + ZigValue *elem_val = type_entry->data.array.sentinel; + LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, elem_val); + + if (is_big_endian) { + LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, packed_bits_size, false); + val = LLVMConstShl(val, shift_amt); + val = LLVMConstOr(val, child_val); + } else { + LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false); + LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt); + val = LLVMConstOr(val, child_val_shifted); + used_bits += packed_bits_size; + } + } return val; } case ZigTypeIdVector: @@ -6852,24 +6901,16 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ZigValue *const_val, const cha return const_val->llvm_value; } case ConstPtrSpecialBaseArray: + case ConstPtrSpecialSubArray: { ZigValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val; assert(array_const_val->type->id == ZigTypeIdArray); if (!type_has_bits(g, array_const_val->type)) { - if (array_const_val->type->data.array.sentinel != nullptr) { - ZigValue *pointee = array_const_val->type->data.array.sentinel; - render_const_val(g, pointee, ""); - render_const_val_global(g, pointee, ""); - const_val->llvm_value = LLVMConstBitCast(pointee->llvm_global, - get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } else { - // make this a null pointer - ZigType *usize = g->builtin_types.entry_usize; - const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), - get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } + // make this a null pointer + ZigType *usize = g->builtin_types.entry_usize; + const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), + get_llvm_type(g, const_val->type)); + return const_val->llvm_value; } size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, elem_index); @@ -9228,6 +9269,7 @@ void add_cc_args(CodeGen *g, ZigList &args, const char *out_dep_pa case BuildModeDebug: // windows c runtime requires -D_DEBUG if using debug libraries args.append("-D_DEBUG"); + args.append("-Og"); if (g->libc_link_lib != nullptr) { args.append("-fstack-protector-strong"); @@ -9650,6 +9692,21 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose return ErrorNone; } +static bool need_llvm_module(CodeGen *g) { + return buf_len(&g->main_pkg->root_src_path) != 0; +} + +// before gen_c_objects +static bool main_output_dir_is_just_one_c_object_pre(CodeGen *g) { + return g->enable_cache && g->c_source_files.length == 1 && !need_llvm_module(g) && + g->out_type == OutTypeObj && g->link_objects.length == 0; +} + +// after gen_c_objects +static bool main_output_dir_is_just_one_c_object_post(CodeGen *g) { + return g->enable_cache && g->link_objects.length == 1 && !need_llvm_module(g) && g->out_type == OutTypeObj; +} + // returns true if it was a cache miss static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { Error err; @@ -9667,8 +9724,17 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { buf_len(c_source_basename), 0); Buf *final_o_basename = buf_alloc(); - os_path_extname(c_source_basename, final_o_basename, nullptr); - buf_append_str(final_o_basename, target_o_file_ext(g->zig_target)); + if (c_file->preprocessor_only_basename == nullptr) { + // We special case when doing build-obj for just one C file + if (main_output_dir_is_just_one_c_object_pre(g)) { + buf_init_from_buf(final_o_basename, g->root_out_name); + } else { + os_path_extname(c_source_basename, final_o_basename, nullptr); + } + buf_append_str(final_o_basename, target_o_file_ext(g->zig_target)); + } else { + buf_init_from_str(final_o_basename, c_file->preprocessor_only_basename); + } CacheHash *cache_hash; if ((err = create_c_object_cache(g, &cache_hash, true))) { @@ -9717,7 +9783,13 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { Termination term; ZigList args = {}; args.append(buf_ptr(self_exe_path)); - args.append("cc"); + args.append("clang"); + + if (c_file->preprocessor_only_basename != nullptr) { + args.append("-E"); + } else { + args.append("-c"); + } Buf *out_dep_path = buf_sprintf("%s.d", buf_ptr(out_obj_path)); add_cc_args(g, args, buf_ptr(out_dep_path), false); @@ -9725,7 +9797,6 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { args.append("-o"); args.append(buf_ptr(out_obj_path)); - args.append("-c"); args.append(buf_ptr(c_source_file)); for (size_t arg_i = 0; arg_i < c_file->args.length; arg_i += 1) { @@ -9780,6 +9851,7 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { os_path_join(artifact_dir, final_o_basename, o_final_path); } + g->c_artifact_dir = artifact_dir; g->link_objects.append(o_final_path); g->caches_to_release.append(cache_hash); @@ -10449,6 +10521,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_str(ch, g->libc->kernel32_lib_dir); } cache_buf_opt(ch, g->version_script_path); + cache_buf_opt(ch, g->override_soname); // gen_c_objects appends objects to g->link_objects which we want to include in the hash gen_c_objects(g); @@ -10467,10 +10540,6 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { return ErrorNone; } -static bool need_llvm_module(CodeGen *g) { - return buf_len(&g->main_pkg->root_src_path) != 0; -} - static void resolve_out_paths(CodeGen *g) { assert(g->output_dir != nullptr); assert(g->root_out_name != nullptr); @@ -10482,10 +10551,6 @@ static void resolve_out_paths(CodeGen *g) { case OutTypeUnknown: zig_unreachable(); case OutTypeObj: - if (g->enable_cache && g->link_objects.length == 1 && !need_llvm_module(g)) { - buf_init_from_buf(&g->bin_file_output_path, g->link_objects.at(0)); - return; - } if (need_llvm_module(g) && g->link_objects.length != 0 && !g->enable_cache && buf_eql_buf(o_basename, out_basename)) { @@ -10580,6 +10645,16 @@ static void output_type_information(CodeGen *g) { } } +static void init_output_dir(CodeGen *g, Buf *digest) { + if (main_output_dir_is_just_one_c_object_post(g)) { + g->output_dir = buf_alloc(); + os_path_dirname(g->link_objects.at(0), g->output_dir); + } else { + g->output_dir = buf_sprintf("%s" OS_SEP CACHE_OUT_SUBDIR OS_SEP "%s", + buf_ptr(g->cache_dir), buf_ptr(digest)); + } +} + void codegen_build_and_link(CodeGen *g) { Error err; assert(g->out_type != OutTypeUnknown); @@ -10622,8 +10697,7 @@ void codegen_build_and_link(CodeGen *g) { } if (g->enable_cache && buf_len(&digest) != 0) { - g->output_dir = buf_sprintf("%s" OS_SEP CACHE_OUT_SUBDIR OS_SEP "%s", - buf_ptr(g->cache_dir), buf_ptr(&digest)); + init_output_dir(g, &digest); resolve_out_paths(g); } else { if (need_llvm_module(g)) { @@ -10644,8 +10718,7 @@ void codegen_build_and_link(CodeGen *g) { exit(1); } } - g->output_dir = buf_sprintf("%s" OS_SEP CACHE_OUT_SUBDIR OS_SEP "%s", - buf_ptr(g->cache_dir), buf_ptr(&digest)); + init_output_dir(g, &digest); if ((err = os_make_path(g->output_dir))) { fprintf(stderr, "Unable to create output directory: %s\n", err_str(err)); diff --git a/src/error.cpp b/src/error.cpp index 2e92a98217..bd7e62f9bc 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -83,6 +83,10 @@ const char *err_str(Error err) { case ErrorTargetHasNoDynamicLinker: return "target has no dynamic linker"; case ErrorInvalidAbiVersion: return "invalid C ABI version"; case ErrorInvalidOperatingSystemVersion: return "invalid operating system version"; + case ErrorUnknownClangOption: return "unknown Clang option"; + case ErrorPermissionDenied: return "permission is denied"; + case ErrorFileBusy: return "file is busy"; + case ErrorLocked: return "file is locked by another process"; } return "(invalid error)"; } diff --git a/src/glibc.cpp b/src/glibc.cpp index da5c1d5290..75b77ec122 100644 --- a/src/glibc.cpp +++ b/src/glibc.cpp @@ -16,6 +16,7 @@ static const ZigGLibCLib glibc_libs[] = { {"pthread", 0}, {"dl", 2}, {"rt", 1}, + {"ld", 2}, }; Error glibc_load_metadata(ZigGLibCAbi **out_result, Buf *zig_lib_dir, bool verbose) { @@ -330,6 +331,8 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con return err; } + bool is_ld = (strcmp(lib->name, "ld") == 0); + CodeGen *child_gen = create_child_codegen(g, zig_file_path, OutTypeLib, nullptr, lib->name, progress_node); codegen_set_lib_version(child_gen, lib->sover, 0, 0); child_gen->is_dynamic = true; @@ -337,6 +340,13 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con child_gen->version_script_path = map_file_path; child_gen->enable_cache = false; child_gen->output_dir = dummy_dir; + if (is_ld) { + assert(g->zig_target->standard_dynamic_linker_path != nullptr); + Buf *ld_basename = buf_alloc(); + os_path_split(buf_create_from_str(g->zig_target->standard_dynamic_linker_path), + nullptr, ld_basename); + child_gen->override_soname = ld_basename; + } codegen_build_and_link(child_gen); } diff --git a/src/ir.cpp b/src/ir.cpp index b9875a7efe..f0f0930762 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -272,6 +272,15 @@ static ResultLoc *no_result_loc(void); static IrInstGen *ir_analyze_test_non_null(IrAnalyze *ira, IrInst *source_inst, IrInstGen *value); static IrInstGen *ir_error_dependency_loop(IrAnalyze *ira, IrInst *source_instr); static IrInstGen *ir_const_undef(IrAnalyze *ira, IrInst *source_instruction, ZigType *ty); +static ZigVar *ir_create_var(IrBuilderSrc *irb, AstNode *node, Scope *scope, Buf *name, + bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstSrc *is_comptime); +static void build_decl_var_and_init(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, ZigVar *var, + IrInstSrc *init, const char *name_hint, IrInstSrc *is_comptime); +static IrInstGen *ir_analyze_union_init(IrAnalyze *ira, IrInst* source_instruction, + AstNode *field_source_node, ZigType *union_type, Buf *field_name, IrInstGen *field_result_loc, + IrInstGen *result_loc); +static IrInstGen *ir_analyze_struct_value_field_value(IrAnalyze *ira, IrInst* source_instr, + IrInstGen *struct_operand, TypeStructField *field); static void destroy_instruction_src(IrInstSrc *inst) { switch (inst->id) { @@ -784,14 +793,32 @@ static ZigValue *const_ptr_pointee_unchecked_no_isf(CodeGen *g, ZigValue *const_ break; case ConstPtrSpecialBaseArray: { ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val; - if (const_val->data.x_ptr.data.base_array.elem_index == array_val->type->data.array.len) { + size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; + if (elem_index == array_val->type->data.array.len) { result = array_val->type->data.array.sentinel; } else { expand_undef_array(g, array_val); - result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index]; + result = &array_val->data.x_array.data.s_none.elements[elem_index]; } break; } + case ConstPtrSpecialSubArray: { + ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val; + size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; + + // TODO handle sentinel terminated arrays + expand_undef_array(g, array_val); + result = g->pass1_arena->create(); + result->special = array_val->special; + result->type = get_array_type(g, array_val->type->data.array.child_type, + array_val->type->data.array.len - elem_index, nullptr); + result->data.x_array.special = ConstArraySpecialNone; + result->data.x_array.data.s_none.elements = &array_val->data.x_array.data.s_none.elements[elem_index]; + result->parent.id = ConstParentIdArray; + result->parent.data.p_array.array_val = array_val; + result->parent.data.p_array.elem_index = elem_index; + break; + } case ConstPtrSpecialBaseStruct: { ZigValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val; expand_undef_struct(g, struct_val); @@ -849,11 +876,6 @@ static bool is_slice(ZigType *type) { return type->id == ZigTypeIdStruct && type->data.structure.special == StructSpecialSlice; } -static bool slice_is_const(ZigType *type) { - assert(is_slice(type)); - return type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const; -} - // This function returns true when you can change the type of a ZigValue and the // value remains meaningful. static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expected, ZigType *actual) { @@ -3719,7 +3741,8 @@ static IrInstSrc *ir_build_slice_src(IrBuilderSrc *irb, Scope *scope, AstNode *s } static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *slice_type, - IrInstGen *ptr, IrInstGen *start, IrInstGen *end, bool safety_check_on, IrInstGen *result_loc) + IrInstGen *ptr, IrInstGen *start, IrInstGen *end, bool safety_check_on, IrInstGen *result_loc, + ZigValue *sentinel) { IrInstGenSlice *instruction = ir_build_inst_gen( &ira->new_irb, source_instruction->scope, source_instruction->source_node); @@ -3729,11 +3752,12 @@ static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction, instruction->end = end; instruction->safety_check_on = safety_check_on; instruction->result_loc = result_loc; + instruction->sentinel = sentinel; ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block); ir_ref_inst_gen(start, ira->new_irb.current_basic_block); - if (end) ir_ref_inst_gen(end, ira->new_irb.current_basic_block); - ir_ref_inst_gen(result_loc, ira->new_irb.current_basic_block); + if (end != nullptr) ir_ref_inst_gen(end, ira->new_irb.current_basic_block); + if (result_loc != nullptr) ir_ref_inst_gen(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -4996,39 +5020,73 @@ static IrInstSrc *ir_mark_gen(IrInstSrc *instruction) { return instruction; } -static bool ir_gen_defers_for_block(IrBuilderSrc *irb, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers) { +static bool ir_gen_defers_for_block(IrBuilderSrc *irb, Scope *inner_scope, Scope *outer_scope, bool *is_noreturn, IrInstSrc *err_value) { Scope *scope = inner_scope; - bool is_noreturn = false; + if (is_noreturn != nullptr) *is_noreturn = false; while (scope != outer_scope) { if (!scope) - return is_noreturn; + return true; switch (scope->id) { case ScopeIdDefer: { AstNode *defer_node = scope->source_node; assert(defer_node->type == NodeTypeDefer); ReturnKind defer_kind = defer_node->data.defer.kind; - if (defer_kind == ReturnKindUnconditional || - (gen_error_defers && defer_kind == ReturnKindError)) - { - AstNode *defer_expr_node = defer_node->data.defer.expr; - Scope *defer_expr_scope = defer_node->data.defer.expr_scope; - IrInstSrc *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope); - if (defer_expr_value != irb->codegen->invalid_inst_src) { - if (defer_expr_value->is_noreturn) { - is_noreturn = true; - } else { - ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, - defer_expr_value)); - } + AstNode *defer_expr_node = defer_node->data.defer.expr; + AstNode *defer_var_node = defer_node->data.defer.err_payload; + + if (defer_kind == ReturnKindError && err_value == nullptr) { + // This is an `errdefer` but we're generating code for a + // `return` that doesn't return an error, skip it + scope = scope->parent; + continue; + } + + Scope *defer_expr_scope = defer_node->data.defer.expr_scope; + if (defer_var_node != nullptr) { + assert(defer_kind == ReturnKindError); + assert(defer_var_node->type == NodeTypeSymbol); + Buf *var_name = defer_var_node->data.symbol_expr.symbol; + + if (defer_expr_node->type == NodeTypeUnreachable) { + add_node_error(irb->codegen, defer_var_node, + buf_sprintf("unused variable: '%s'", buf_ptr(var_name))); + return false; } + + IrInstSrc *is_comptime; + if (ir_should_inline(irb->exec, defer_expr_scope)) { + is_comptime = ir_build_const_bool(irb, defer_expr_scope, + defer_expr_node, true); + } else { + is_comptime = ir_build_test_comptime(irb, defer_expr_scope, + defer_expr_node, err_value); + } + + ZigVar *err_var = ir_create_var(irb, defer_var_node, defer_expr_scope, + var_name, true, true, false, is_comptime); + build_decl_var_and_init(irb, defer_expr_scope, defer_var_node, err_var, err_value, + buf_ptr(var_name), is_comptime); + + defer_expr_scope = err_var->child_scope; + } + + IrInstSrc *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope); + if (defer_expr_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + if (defer_expr_value->is_noreturn) { + if (is_noreturn != nullptr) *is_noreturn = true; + } else { + ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, + defer_expr_value)); } scope = scope->parent; continue; } case ScopeIdDecls: case ScopeIdFnDef: - return is_noreturn; + return true; case ScopeIdBlock: case ScopeIdVarDecl: case ScopeIdLoop: @@ -5045,7 +5103,7 @@ static bool ir_gen_defers_for_block(IrBuilderSrc *irb, Scope *inner_scope, Scope zig_unreachable(); } } - return is_noreturn; + return true; } static void ir_set_cursor_at_end_gen(IrBuilderGen *irb, IrBasicBlockGen *basic_block) { @@ -5131,7 +5189,8 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node, bool have_err_defers = defer_counts[ReturnKindError] > 0; if (!have_err_defers && !irb->codegen->have_err_ret_tracing) { // only generate unconditional defers - ir_gen_defers_for_block(irb, scope, outer_scope, false); + if (!ir_gen_defers_for_block(irb, scope, outer_scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; IrInstSrc *result = ir_build_return_src(irb, scope, node, nullptr); result_loc_ret->base.source_instruction = result; return result; @@ -5154,14 +5213,16 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node, IrBasicBlockSrc *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt"); ir_set_cursor_at_end_and_append_block(irb, err_block); - ir_gen_defers_for_block(irb, scope, outer_scope, true); + if (!ir_gen_defers_for_block(irb, scope, outer_scope, nullptr, return_value)) + return irb->codegen->invalid_inst_src; if (irb->codegen->have_err_ret_tracing && !should_inline) { ir_build_save_err_ret_addr_src(irb, scope, node); } ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); ir_set_cursor_at_end_and_append_block(irb, ok_block); - ir_gen_defers_for_block(irb, scope, outer_scope, false); + if (!ir_gen_defers_for_block(irb, scope, outer_scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block); @@ -5198,7 +5259,12 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node, result_loc_ret->base.id = ResultLocIdReturn; ir_build_reset_result(irb, scope, node, &result_loc_ret->base); ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base); - if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) { + + bool is_noreturn = false; + if (!ir_gen_defers_for_block(irb, scope, outer_scope, &is_noreturn, err_val)) { + return irb->codegen->invalid_inst_src; + } + if (!is_noreturn) { if (irb->codegen->have_err_ret_tracing && !should_inline) { ir_build_save_err_ret_addr_src(irb, scope, node); } @@ -5400,7 +5466,8 @@ static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode * bool is_return_from_fn = block_node == irb->main_block_node; if (!is_return_from_fn) { - ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); + if (!ir_gen_defers_for_block(irb, child_scope, outer_block_scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; } IrInstSrc *result; @@ -5425,7 +5492,8 @@ static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode * result_loc_ret->base.id = ResultLocIdReturn; ir_build_reset_result(irb, parent_scope, block_node, &result_loc_ret->base); ir_mark_gen(ir_build_end_expr(irb, parent_scope, block_node, result, &result_loc_ret->base)); - ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); + if (!ir_gen_defers_for_block(irb, child_scope, outer_block_scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; return ir_mark_gen(ir_build_return_src(irb, child_scope, result->base.source_node, result)); } @@ -9225,7 +9293,8 @@ static IrInstSrc *ir_gen_return_from_block(IrBuilderSrc *irb, Scope *break_scope } IrBasicBlockSrc *dest_block = block_scope->end_block; - ir_gen_defers_for_block(irb, break_scope, dest_block->scope, false); + if (!ir_gen_defers_for_block(irb, break_scope, dest_block->scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; block_scope->incoming_blocks->append(irb->current_basic_block); block_scope->incoming_values->append(result_value); @@ -9299,7 +9368,8 @@ static IrInstSrc *ir_gen_break(IrBuilderSrc *irb, Scope *break_scope, AstNode *n } IrBasicBlockSrc *dest_block = loop_scope->break_block; - ir_gen_defers_for_block(irb, break_scope, dest_block->scope, false); + if (!ir_gen_defers_for_block(irb, break_scope, dest_block->scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; loop_scope->incoming_blocks->append(irb->current_basic_block); loop_scope->incoming_values->append(result_value); @@ -9358,7 +9428,8 @@ static IrInstSrc *ir_gen_continue(IrBuilderSrc *irb, Scope *continue_scope, AstN } IrBasicBlockSrc *dest_block = loop_scope->continue_block; - ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, false); + if (!ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; return ir_mark_gen(ir_build_br(irb, continue_scope, node, dest_block, is_comptime)); } @@ -12335,11 +12406,22 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT prev_type->data.pointer.child_type->id == ZigTypeIdArray && prev_type->data.pointer.ptr_len == PtrLenSingle && ((cur_type->id == ZigTypeIdErrorUnion && is_slice(cur_type->data.error_union.payload_type)) || - is_slice(cur_type))) + (cur_type->id == ZigTypeIdOptional && is_slice(cur_type->data.maybe.child_type)) || + is_slice(cur_type))) { ZigType *array_type = prev_type->data.pointer.child_type; - ZigType *slice_type = (cur_type->id == ZigTypeIdErrorUnion) ? - cur_type->data.error_union.payload_type : cur_type; + ZigType *slice_type; + switch (cur_type->id) { + case ZigTypeIdErrorUnion: + slice_type = cur_type->data.error_union.payload_type; + break; + case ZigTypeIdOptional: + slice_type = cur_type->data.maybe.child_type; + break; + default: + slice_type = cur_type; + break; + } ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 || !prev_type->data.pointer.is_const) && @@ -12677,41 +12759,80 @@ static IrInstGen *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInst* sourc Error err; assert(array_ptr->value->type->id == ZigTypeIdPointer); + assert(array_ptr->value->type->data.pointer.child_type->id == ZigTypeIdArray); + + ZigType *array_type = array_ptr->value->type->data.pointer.child_type; + size_t array_len = array_type->data.array.len; + + // A zero-sized array can be casted regardless of the destination alignment, or + // whether the pointer is undefined, and the result is always comptime known. + // TODO However, this is exposing a result location bug that I failed to solve on the first try. + // If you want to try to fix the bug, uncomment this block and get the tests passing. + //if (array_len == 0 && array_type->data.array.sentinel == nullptr) { + // ZigValue *undef_array = ira->codegen->pass1_arena->create(); + // undef_array->special = ConstValSpecialUndef; + // undef_array->type = array_type; + + // IrInstGen *result = ir_const(ira, source_instr, wanted_type); + // init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false); + // result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst; + // result->value->type = wanted_type; + // return result; + //} if ((err = type_resolve(ira->codegen, array_ptr->value->type, ResolveStatusAlignmentKnown))) { return ira->codegen->invalid_inst_gen; } - assert(array_ptr->value->type->data.pointer.child_type->id == ZigTypeIdArray); - - const size_t array_len = array_ptr->value->type->data.pointer.child_type->data.array.len; - - // A zero-sized array can always be casted irregardless of the destination - // alignment if (array_len != 0) { wanted_type = adjust_slice_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, array_ptr->value->type)); } if (instr_is_comptime(array_ptr)) { - ZigValue *array_ptr_val = ir_resolve_const(ira, array_ptr, UndefBad); + UndefAllowed undef_allowed = (array_len == 0) ? UndefOk : UndefBad; + ZigValue *array_ptr_val = ir_resolve_const(ira, array_ptr, undef_allowed); if (array_ptr_val == nullptr) return ira->codegen->invalid_inst_gen; - ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, array_ptr_val, source_instr->source_node); - if (pointee == nullptr) - return ira->codegen->invalid_inst_gen; - if (pointee->special != ConstValSpecialRuntime) { - assert(array_ptr_val->type->id == ZigTypeIdPointer); - ZigType *array_type = array_ptr_val->type->data.pointer.child_type; - assert(is_slice(wanted_type)); - bool is_const = wanted_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const; + ir_assert(is_slice(wanted_type), source_instr); + if (array_ptr_val->special == ConstValSpecialUndef) { + ZigValue *undef_array = ira->codegen->pass1_arena->create(); + undef_array->special = ConstValSpecialUndef; + undef_array->type = array_type; IrInstGen *result = ir_const(ira, source_instr, wanted_type); - init_const_slice(ira->codegen, result->value, pointee, 0, array_type->data.array.len, is_const); - result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut; + init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false); + result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst; result->value->type = wanted_type; return result; } + bool wanted_const = wanted_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const; + // Optimization to avoid creating unnecessary ZigValue in const_ptr_pointee + if (array_ptr_val->data.x_ptr.special == ConstPtrSpecialSubArray) { + ZigValue *array_val = array_ptr_val->data.x_ptr.data.base_array.array_val; + if (array_val->special != ConstValSpecialRuntime) { + IrInstGen *result = ir_const(ira, source_instr, wanted_type); + init_const_slice(ira->codegen, result->value, array_val, + array_ptr_val->data.x_ptr.data.base_array.elem_index, + array_type->data.array.len, wanted_const); + result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut; + result->value->type = wanted_type; + return result; + } + } else if (array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { + ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, array_ptr_val, source_instr->source_node); + if (pointee == nullptr) + return ira->codegen->invalid_inst_gen; + if (pointee->special != ConstValSpecialRuntime) { + assert(array_ptr_val->type->id == ZigTypeIdPointer); + + IrInstGen *result = ir_const(ira, source_instr, wanted_type); + init_const_slice(ira->codegen, result->value, pointee, 0, array_type->data.array.len, wanted_const); + result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut; + result->value->type = wanted_type; + return result; + } + } } if (result_loc == nullptr) result_loc = no_result_loc(); @@ -14329,10 +14450,71 @@ static IrInstGen *ir_analyze_struct_literal_to_struct(IrAnalyze *ira, IrInst* so } static IrInstGen *ir_analyze_struct_literal_to_union(IrAnalyze *ira, IrInst* source_instr, - IrInstGen *value, ZigType *wanted_type) + IrInstGen *value, ZigType *union_type) { - ir_add_error(ira, source_instr, buf_sprintf("TODO: type coercion of anon struct literal to union")); - return ira->codegen->invalid_inst_gen; + Error err; + ZigType *struct_type = value->value->type; + + assert(struct_type->id == ZigTypeIdStruct); + assert(union_type->id == ZigTypeIdUnion); + assert(struct_type->data.structure.src_field_count == 1); + + TypeStructField *only_field = struct_type->data.structure.fields[0]; + + if ((err = type_resolve(ira->codegen, union_type, ResolveStatusZeroBitsKnown))) + return ira->codegen->invalid_inst_gen; + + TypeUnionField *union_field = find_union_type_field(union_type, only_field->name); + if (union_field == nullptr) { + ir_add_error_node(ira, only_field->decl_node, + buf_sprintf("no member named '%s' in union '%s'", + buf_ptr(only_field->name), buf_ptr(&union_type->name))); + return ira->codegen->invalid_inst_gen; + } + + ZigType *payload_type = resolve_union_field_type(ira->codegen, union_field); + if (payload_type == nullptr) + return ira->codegen->invalid_inst_gen; + + IrInstGen *field_value = ir_analyze_struct_value_field_value(ira, source_instr, value, only_field); + if (type_is_invalid(field_value->value->type)) + return ira->codegen->invalid_inst_gen; + + IrInstGen *casted_value = ir_implicit_cast(ira, field_value, payload_type); + if (type_is_invalid(casted_value->value->type)) + return ira->codegen->invalid_inst_gen; + + if (instr_is_comptime(casted_value)) { + ZigValue *val = ir_resolve_const(ira, casted_value, UndefBad); + if (val == nullptr) + return ira->codegen->invalid_inst_gen; + + IrInstGen *result = ir_const(ira, source_instr, union_type); + bigint_init_bigint(&result->value->data.x_union.tag, &union_field->enum_field->value); + result->value->data.x_union.payload = val; + + val->parent.id = ConstParentIdUnion; + val->parent.data.p_union.union_val = result->value; + + return result; + } + + IrInstGen *result_loc_inst = ir_resolve_result(ira, source_instr, no_result_loc(), + union_type, nullptr, true, true); + if (type_is_invalid(result_loc_inst->value->type) || result_loc_inst->value->type->id == ZigTypeIdUnreachable) { + return ira->codegen->invalid_inst_gen; + } + + IrInstGen *payload_ptr = ir_analyze_container_field_ptr(ira, only_field->name, source_instr, + result_loc_inst, source_instr, union_type, true); + if (type_is_invalid(payload_ptr->value->type)) + return ira->codegen->invalid_inst_gen; + + IrInstGen *store_ptr_inst = ir_analyze_store_ptr(ira, source_instr, payload_ptr, casted_value, false); + if (type_is_invalid(store_ptr_inst->value->type)) + return ira->codegen->invalid_inst_gen; + + return ir_get_deref(ira, source_instr, result_loc_inst, nullptr); } // Add a compile error and return ErrorSemanticAnalyzeFail if the pointer alignment does not work, @@ -14581,7 +14763,7 @@ static IrInstGen *ir_analyze_cast(IrAnalyze *ira, IrInst *source_instr, return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); } - // *[N]T to ?[]const T + // *[N]T to ?[]T if (wanted_type->id == ZigTypeIdOptional && is_slice(wanted_type->data.maybe.child_type) && actual_type->id == ZigTypeIdPointer && @@ -16170,6 +16352,15 @@ static IrInstGen *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstSrcBinOp *bin_op_i IrInstGen *union_val = op1->value->type->id == ZigTypeIdUnion ? op1 : op2; IrInstGen *enum_val = op1->value->type->id == ZigTypeIdUnion ? op2 : op1; + if (!is_tagged_union(union_val->value->type)) { + ErrorMsg *msg = ir_add_error_node(ira, source_node, + buf_sprintf("comparison of union and enum literal is only valid for tagged union types")); + add_error_note(ira->codegen, msg, union_val->value->type->data.unionation.decl_node, + buf_sprintf("type %s is not a tagged union", + buf_ptr(&union_val->value->type->name))); + return ira->codegen->invalid_inst_gen; + } + ZigType *tag_type = union_val->value->type->data.unionation.tag_type; assert(tag_type != nullptr); @@ -19917,6 +20108,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf), pointee); if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) return err; + buf_deinit(&buf); return ErrorNone; } @@ -19936,6 +20128,31 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source dst_size, buf_ptr(&pointee->type->name), src_size)); return ErrorSemanticAnalyzeFail; } + case ConstPtrSpecialSubArray: { + ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val; + assert(array_val->type->id == ZigTypeIdArray); + if (array_val->data.x_array.special != ConstArraySpecialNone) + zig_panic("TODO"); + if (dst_size > src_size) { + size_t elem_index = ptr_val->data.x_ptr.data.base_array.elem_index; + opt_ir_add_error_node(ira, codegen, source_node, + buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from %s at index %" ZIG_PRI_usize " which is %" ZIG_PRI_usize " bytes", + dst_size, buf_ptr(&array_val->type->name), elem_index, src_size)); + return ErrorSemanticAnalyzeFail; + } + size_t elem_size = src_size; + size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1); + Buf buf = BUF_INIT; + buf_resize(&buf, elem_count * elem_size); + for (size_t i = 0; i < elem_count; i += 1) { + ZigValue *elem_val = &array_val->data.x_array.data.s_none.elements[i]; + buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); + } + if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) + return err; + buf_deinit(&buf); + return ErrorNone; + } case ConstPtrSpecialBaseArray: { ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val; assert(array_val->type->id == ZigTypeIdArray); @@ -19959,6 +20176,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source } if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) return err; + buf_deinit(&buf); return ErrorNone; } case ConstPtrSpecialBaseStruct: @@ -20538,6 +20756,44 @@ static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_ allow_zero); } +static Error compute_elem_align(IrAnalyze *ira, ZigType *elem_type, uint32_t base_ptr_align, + uint64_t elem_index, uint32_t *result) +{ + Error err; + + if (base_ptr_align == 0) { + *result = 0; + return ErrorNone; + } + + // figure out the largest alignment possible + if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) + return err; + + uint64_t elem_size = type_size(ira->codegen, elem_type); + uint64_t abi_align = get_abi_alignment(ira->codegen, elem_type); + uint64_t ptr_align = base_ptr_align; + + uint64_t chosen_align = abi_align; + if (ptr_align >= abi_align) { + while (ptr_align > abi_align) { + if ((elem_index * elem_size) % ptr_align == 0) { + chosen_align = ptr_align; + break; + } + ptr_align >>= 1; + } + } else if (elem_size >= ptr_align && elem_size % ptr_align == 0) { + chosen_align = ptr_align; + } else { + // can't get here because guaranteed elem_size >= abi_align + zig_unreachable(); + } + + *result = chosen_align; + return ErrorNone; +} + static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemPtr *elem_ptr_instruction) { Error err; IrInstGen *array_ptr = elem_ptr_instruction->array_ptr->child; @@ -20578,11 +20834,6 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP } if (array_type->id == ZigTypeIdArray) { - if (array_type->data.array.len == 0) { - ir_add_error_node(ira, elem_ptr_instruction->base.base.source_node, - buf_sprintf("index 0 outside array of size 0")); - return ira->codegen->invalid_inst_gen; - } ZigType *child_type = array_type->data.array.child_type; if (ptr_type->data.pointer.host_int_bytes == 0) { return_type = get_pointer_to_type_extra(ira->codegen, child_type, @@ -20681,29 +20932,11 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index, nullptr, nullptr); } else if (return_type->data.pointer.explicit_alignment != 0) { - // figure out the largest alignment possible - - if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown))) + uint32_t chosen_align; + if ((err = compute_elem_align(ira, return_type->data.pointer.child_type, + return_type->data.pointer.explicit_alignment, index, &chosen_align))) + { return ira->codegen->invalid_inst_gen; - - uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type); - uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type); - uint64_t ptr_align = get_ptr_align(ira->codegen, return_type); - - uint64_t chosen_align = abi_align; - if (ptr_align >= abi_align) { - while (ptr_align > abi_align) { - if ((index * elem_size) % ptr_align == 0) { - chosen_align = ptr_align; - break; - } - ptr_align >>= 1; - } - } else if (elem_size >= ptr_align && elem_size % ptr_align == 0) { - chosen_align = ptr_align; - } else { - // can't get here because guaranteed elem_size >= abi_align - zig_unreachable(); } return_type = adjust_ptr_align(ira->codegen, return_type, chosen_align); } @@ -20824,6 +21057,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP } break; case ConstPtrSpecialBaseArray: + case ConstPtrSpecialSubArray: { size_t offset = array_ptr_val->data.x_ptr.data.base_array.elem_index; new_index = offset + index; @@ -20894,6 +21128,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP out_val->data.x_ptr.special = ConstPtrSpecialRef; out_val->data.x_ptr.data.ref.pointee = ptr_field->data.x_ptr.data.ref.pointee; break; + case ConstPtrSpecialSubArray: case ConstPtrSpecialBaseArray: { size_t offset = ptr_field->data.x_ptr.data.base_array.elem_index; @@ -22881,7 +23116,7 @@ static IrInstGen *ir_analyze_union_init(IrAnalyze *ira, IrInst* source_instructi Error err; assert(union_type->id == ZigTypeIdUnion); - if ((err = type_resolve(ira->codegen, union_type, ResolveStatusSizeKnown))) + if ((err = type_resolve(ira->codegen, union_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_inst_gen; TypeUnionField *type_field = find_union_type_field(union_type, field_name); @@ -25445,11 +25680,22 @@ static IrInstGen *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstSrcE static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { Error err; - ZigType *ptr_type = get_src_ptr_type(ty); + ZigType *ptr_type; + if (is_slice(ty)) { + TypeStructField *ptr_field = ty->data.structure.fields[slice_ptr_index]; + ptr_type = resolve_struct_field_type(ira->codegen, ptr_field); + } else { + ptr_type = get_src_ptr_type(ty); + } assert(ptr_type != nullptr); if (ptr_type->id == ZigTypeIdPointer) { if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) return err; + } else if (is_slice(ptr_type)) { + TypeStructField *ptr_field = ptr_type->data.structure.fields[slice_ptr_index]; + ZigType *slice_ptr_type = resolve_struct_field_type(ira->codegen, ptr_field); + if ((err = type_resolve(ira->codegen, slice_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) + return err; } *result_align = get_ptr_align(ira->codegen, ty); @@ -25904,6 +26150,7 @@ static IrInstGen *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstSrcMemset start = 0; bound_end = 1; break; + case ConstPtrSpecialSubArray: case ConstPtrSpecialBaseArray: { ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; @@ -26037,6 +26284,7 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy dest_start = 0; dest_end = 1; break; + case ConstPtrSpecialSubArray: case ConstPtrSpecialBaseArray: { ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; @@ -26080,6 +26328,7 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy src_start = 0; src_end = 1; break; + case ConstPtrSpecialSubArray: case ConstPtrSpecialBaseArray: { ZigValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val; @@ -26123,7 +26372,19 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy return ir_build_memcpy_gen(ira, &instruction->base.base, casted_dest_ptr, casted_src_ptr, casted_count); } +static ZigType *get_result_loc_type(IrAnalyze *ira, ResultLoc *result_loc) { + if (result_loc == nullptr) return nullptr; + + if (result_loc->id == ResultLocIdCast) { + return ir_resolve_type(ira, result_loc->source_instruction->child); + } + + return nullptr; +} + static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *instruction) { + Error err; + IrInstGen *ptr_ptr = instruction->ptr->child; if (type_is_invalid(ptr_ptr->value->type)) return ira->codegen->invalid_inst_gen; @@ -26153,6 +26414,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i end = nullptr; } + ZigValue *slice_sentinel_val = nullptr; ZigType *non_sentinel_slice_ptr_type; ZigType *elem_type; @@ -26203,6 +26465,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i } } else if (is_slice(array_type)) { ZigType *maybe_sentineled_slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; + slice_sentinel_val = maybe_sentineled_slice_ptr_type->data.pointer.sentinel; non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr); elem_type = non_sentinel_slice_ptr_type->data.pointer.child_type; } else { @@ -26211,7 +26474,6 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i return ira->codegen->invalid_inst_gen; } - ZigType *return_type; ZigValue *sentinel_val = nullptr; if (instruction->sentinel) { IrInstGen *uncasted_sentinel = instruction->sentinel->child; @@ -26223,11 +26485,76 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); if (sentinel_val == nullptr) return ira->codegen->invalid_inst_gen; - ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, sentinel_val); + } + + ZigType *child_array_type = (array_type->id == ZigTypeIdPointer && + array_type->data.pointer.ptr_len == PtrLenSingle) ? array_type->data.pointer.child_type : array_type; + + ZigType *return_type; + + // If start index and end index are both comptime known, then the result type is a pointer to array + // not a slice. However, if the start or end index is a lazy value, and the result location is a slice, + // then the pointer-to-array would be casted to a slice anyway. So, we preserve the laziness of these + // values by making the return type a slice. + ZigType *res_loc_type = get_result_loc_type(ira, instruction->result_loc); + bool result_loc_is_slice = (res_loc_type != nullptr && is_slice(res_loc_type)); + bool end_is_known = !result_loc_is_slice && + ((end != nullptr && value_is_comptime(end->value)) || + (end == nullptr && child_array_type->id == ZigTypeIdArray)); + + ZigValue *array_sentinel = sentinel_val; + if (end_is_known) { + uint64_t end_scalar; + if (end != nullptr) { + ZigValue *end_val = ir_resolve_const(ira, end, UndefBad); + if (!end_val) + return ira->codegen->invalid_inst_gen; + end_scalar = bigint_as_u64(&end_val->data.x_bigint); + } else { + end_scalar = child_array_type->data.array.len; + } + array_sentinel = (child_array_type->id == ZigTypeIdArray && end_scalar == child_array_type->data.array.len) + ? child_array_type->data.array.sentinel : sentinel_val; + + if (value_is_comptime(casted_start->value)) { + ZigValue *start_val = ir_resolve_const(ira, casted_start, UndefBad); + if (!start_val) + return ira->codegen->invalid_inst_gen; + + uint64_t start_scalar = bigint_as_u64(&start_val->data.x_bigint); + + if (start_scalar > end_scalar) { + ir_add_error(ira, &instruction->base.base, buf_sprintf("out of bounds slice")); + return ira->codegen->invalid_inst_gen; + } + + uint32_t base_ptr_align = non_sentinel_slice_ptr_type->data.pointer.explicit_alignment; + uint32_t ptr_byte_alignment = 0; + if (end_scalar > start_scalar) { + if ((err = compute_elem_align(ira, elem_type, base_ptr_align, start_scalar, &ptr_byte_alignment))) + return ira->codegen->invalid_inst_gen; + } + + ZigType *return_array_type = get_array_type(ira->codegen, elem_type, end_scalar - start_scalar, + array_sentinel); + return_type = get_pointer_to_type_extra(ira->codegen, return_array_type, + non_sentinel_slice_ptr_type->data.pointer.is_const, + non_sentinel_slice_ptr_type->data.pointer.is_volatile, + PtrLenSingle, ptr_byte_alignment, 0, 0, false); + goto done_with_return_type; + } + } else if (array_sentinel == nullptr && end == nullptr) { + array_sentinel = slice_sentinel_val; + } + if (array_sentinel != nullptr) { + // TODO deal with non-abi-alignment here + ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, array_sentinel); return_type = get_slice_type(ira->codegen, slice_ptr_type); } else { + // TODO deal with non-abi-alignment here return_type = get_slice_type(ira->codegen, non_sentinel_slice_ptr_type); } +done_with_return_type: if (instr_is_comptime(ptr_ptr) && value_is_comptime(casted_start->value) && @@ -26238,12 +26565,8 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i size_t abs_offset; size_t rel_end; bool ptr_is_undef = false; - if (array_type->id == ZigTypeIdArray || - (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) - { + if (child_array_type->id == ZigTypeIdArray) { if (array_type->id == ZigTypeIdPointer) { - ZigType *child_array_type = array_type->data.pointer.child_type; - assert(child_array_type->id == ZigTypeIdArray); parent_ptr = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.base.source_node); if (parent_ptr == nullptr) return ira->codegen->invalid_inst_gen; @@ -26254,6 +26577,10 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i abs_offset = 0; rel_end = SIZE_MAX; ptr_is_undef = true; + } else if (parent_ptr->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { + array_val = nullptr; + abs_offset = 0; + rel_end = SIZE_MAX; } else { array_val = const_ptr_pointee(ira, ira->codegen, parent_ptr, instruction->base.base.source_node); if (array_val == nullptr) @@ -26296,6 +26623,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i rel_end = 1; } break; + case ConstPtrSpecialSubArray: case ConstPtrSpecialBaseArray: array_val = parent_ptr->data.x_ptr.data.base_array.array_val; abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index; @@ -26346,6 +26674,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i abs_offset = SIZE_MAX; rel_end = 1; break; + case ConstPtrSpecialSubArray: case ConstPtrSpecialBaseArray: array_val = parent_ptr->data.x_ptr.data.base_array.array_val; abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index; @@ -26406,15 +26735,28 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i } IrInstGen *result = ir_const(ira, &instruction->base.base, return_type); - ZigValue *out_val = result->value; - out_val->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, 2); - ZigValue *ptr_val = out_val->data.x_struct.fields[slice_ptr_index]; + ZigValue *ptr_val; + if (return_type->id == ZigTypeIdPointer) { + // pointer to array + ptr_val = result->value; + } else { + // slice + result->value->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, 2); + ptr_val = result->value->data.x_struct.fields[slice_ptr_index]; + + ZigValue *len_val = result->value->data.x_struct.fields[slice_len_index]; + init_const_usize(ira->codegen, len_val, end_scalar - start_scalar); + } + + bool return_type_is_const = non_sentinel_slice_ptr_type->data.pointer.is_const; if (array_val) { size_t index = abs_offset + start_scalar; - bool is_const = slice_is_const(return_type); - init_const_ptr_array(ira->codegen, ptr_val, array_val, index, is_const, PtrLenUnknown); + init_const_ptr_array(ira->codegen, ptr_val, array_val, index, return_type_is_const, PtrLenUnknown); + if (return_type->id == ZigTypeIdPointer) { + ptr_val->data.x_ptr.special = ConstPtrSpecialSubArray; + } if (array_type->id == ZigTypeIdArray) { ptr_val->data.x_ptr.mut = ptr_ptr->value->data.x_ptr.mut; } else if (is_slice(array_type)) { @@ -26424,16 +26766,17 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i } } else if (ptr_is_undef) { ptr_val->type = get_pointer_to_type(ira->codegen, parent_ptr->type->data.pointer.child_type, - slice_is_const(return_type)); + return_type_is_const); ptr_val->special = ConstValSpecialUndef; } else switch (parent_ptr->data.x_ptr.special) { case ConstPtrSpecialInvalid: case ConstPtrSpecialDiscard: zig_unreachable(); case ConstPtrSpecialRef: - init_const_ptr_ref(ira->codegen, ptr_val, - parent_ptr->data.x_ptr.data.ref.pointee, slice_is_const(return_type)); + init_const_ptr_ref(ira->codegen, ptr_val, parent_ptr->data.x_ptr.data.ref.pointee, + return_type_is_const); break; + case ConstPtrSpecialSubArray: case ConstPtrSpecialBaseArray: zig_unreachable(); case ConstPtrSpecialBaseStruct: @@ -26448,7 +26791,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i init_const_ptr_hard_coded_addr(ira->codegen, ptr_val, parent_ptr->type->data.pointer.child_type, parent_ptr->data.x_ptr.data.hard_coded_addr.addr + start_scalar, - slice_is_const(return_type)); + return_type_is_const); break; case ConstPtrSpecialFunction: zig_panic("TODO"); @@ -26456,26 +26799,11 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i zig_panic("TODO"); } - ZigValue *len_val = out_val->data.x_struct.fields[slice_len_index]; - init_const_usize(ira->codegen, len_val, end_scalar - start_scalar); - + // In the case of pointer-to-array, we must restore this because above it overwrites ptr_val->type + result->value->type = return_type; return result; } - IrInstGen *result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc, - return_type, nullptr, true, true); - if (result_loc != nullptr) { - if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { - return result_loc; - } - IrInstGen *dummy_value = ir_const(ira, &instruction->base.base, return_type); - dummy_value->value->special = ConstValSpecialRuntime; - IrInstGen *dummy_result = ir_implicit_cast2(ira, &instruction->base.base, - dummy_value, result_loc->value->type->data.pointer.child_type); - if (type_is_invalid(dummy_result->value->type)) - return ira->codegen->invalid_inst_gen; - } - if (generate_non_null_assert) { IrInstGen *ptr_val = ir_get_deref(ira, &instruction->base.base, ptr_ptr, nullptr); @@ -26485,8 +26813,26 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i ir_build_assert_non_null(ira, &instruction->base.base, ptr_val); } + IrInstGen *result_loc = nullptr; + + if (return_type->id != ZigTypeIdPointer) { + result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc, + return_type, nullptr, true, true); + if (result_loc != nullptr) { + if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { + return result_loc; + } + IrInstGen *dummy_value = ir_const(ira, &instruction->base.base, return_type); + dummy_value->value->special = ConstValSpecialRuntime; + IrInstGen *dummy_result = ir_implicit_cast2(ira, &instruction->base.base, + dummy_value, result_loc->value->type->data.pointer.child_type); + if (type_is_invalid(dummy_result->value->type)) + return ira->codegen->invalid_inst_gen; + } + } + return ir_build_slice_gen(ira, &instruction->base.base, return_type, ptr_ptr, - casted_start, end, instruction->safety_check_on, result_loc); + casted_start, end, instruction->safety_check_on, result_loc, sentinel_val); } static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasField *instruction) { @@ -27512,10 +27858,18 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn // We have a check for zero bits later so we use get_src_ptr_type to // validate src_type and dest_type. - ZigType *src_ptr_type = get_src_ptr_type(src_type); - if (src_ptr_type == nullptr) { - ir_add_error(ira, ptr_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); - return ira->codegen->invalid_inst_gen; + ZigType *if_slice_ptr_type; + if (is_slice(src_type)) { + TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index]; + if_slice_ptr_type = resolve_struct_field_type(ira->codegen, ptr_field); + } else { + if_slice_ptr_type = src_type; + + ZigType *src_ptr_type = get_src_ptr_type(src_type); + if (src_ptr_type == nullptr) { + ir_add_error(ira, ptr_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); + return ira->codegen->invalid_inst_gen; + } } ZigType *dest_ptr_type = get_src_ptr_type(dest_type); @@ -27525,7 +27879,7 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn return ira->codegen->invalid_inst_gen; } - if (get_ptr_const(src_type) && !get_ptr_const(dest_type)) { + if (get_ptr_const(ira->codegen, src_type) && !get_ptr_const(ira->codegen, dest_type)) { ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier")); return ira->codegen->invalid_inst_gen; } @@ -27543,7 +27897,10 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_inst_gen; - if (type_has_bits(ira->codegen, dest_type) && !type_has_bits(ira->codegen, src_type) && safety_check_on) { + if (safety_check_on && + type_has_bits(ira->codegen, dest_type) && + !type_has_bits(ira->codegen, if_slice_ptr_type)) + { ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("'%s' and '%s' do not have the same in-memory representation", buf_ptr(&src_type->name), buf_ptr(&dest_type->name))); @@ -27554,6 +27911,14 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn return ira->codegen->invalid_inst_gen; } + // For slices, follow the `ptr` field. + if (is_slice(src_type)) { + TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index]; + IrInstGen *ptr_ref = ir_get_ref(ira, source_instr, ptr, true, false); + IrInstGen *ptr_ptr = ir_analyze_struct_field_ptr(ira, source_instr, ptr_field, ptr_ref, src_type, false); + ptr = ir_get_deref(ira, source_instr, ptr_ptr, nullptr); + } + if (instr_is_comptime(ptr)) { bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type); UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad; @@ -27657,6 +28022,9 @@ static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ZigValue buf_write_value_bytes(codegen, &buf[buf_i], elem); buf_i += type_size(codegen, elem->type); } + if (val->type->id == ZigTypeIdArray && val->type->data.array.sentinel != nullptr) { + buf_write_value_bytes(codegen, &buf[buf_i], val->type->data.array.sentinel); + } } static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ZigValue *val) { diff --git a/src/link.cpp b/src/link.cpp index 5b6d3a4fdb..b340206b14 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -566,6 +566,7 @@ static const char *build_libc_object(CodeGen *parent_gen, const char *name, CFil Stage2ProgressNode *progress_node) { CodeGen *child_gen = create_child_codegen(parent_gen, nullptr, OutTypeObj, nullptr, name, progress_node); + child_gen->root_out_name = buf_create_from_str(name); ZigList c_source_files = {0}; c_source_files.append(c_file); child_gen->c_source_files = c_source_files; @@ -1650,7 +1651,6 @@ static void construct_linker_job_elf(LinkJob *lj) { bool is_lib = g->out_type == OutTypeLib; bool is_dyn_lib = g->is_dynamic && is_lib; - Buf *soname = nullptr; if (!g->have_dynamic_link) { if (g->zig_target->arch == ZigLLVM_arm || g->zig_target->arch == ZigLLVM_armeb || g->zig_target->arch == ZigLLVM_thumb || g->zig_target->arch == ZigLLVM_thumbeb) @@ -1661,15 +1661,13 @@ static void construct_linker_job_elf(LinkJob *lj) { } } else if (is_dyn_lib) { lj->args.append("-shared"); - - assert(buf_len(&g->bin_file_output_path) != 0); - soname = buf_sprintf("lib%s.so.%" ZIG_PRI_usize, buf_ptr(g->root_out_name), g->version_major); } if (target_requires_pie(g->zig_target) && g->out_type == OutTypeExe) { lj->args.append("-pie"); } + assert(buf_len(&g->bin_file_output_path) != 0); lj->args.append("-o"); lj->args.append(buf_ptr(&g->bin_file_output_path)); @@ -1739,6 +1737,9 @@ static void construct_linker_job_elf(LinkJob *lj) { } if (is_dyn_lib) { + Buf *soname = (g->override_soname == nullptr) ? + buf_sprintf("lib%s.so.%" ZIG_PRI_usize, buf_ptr(g->root_out_name), g->version_major) : + g->override_soname; lj->args.append("-soname"); lj->args.append(buf_ptr(soname)); @@ -2007,7 +2008,7 @@ static const char *get_def_lib(CodeGen *parent, const char *name, Buf *def_in_fi ZigList args = {}; args.append(buf_ptr(self_exe_path)); - args.append("cc"); + args.append("clang"); args.append("-x"); args.append("c"); args.append(buf_ptr(def_in_file)); diff --git a/src/main.cpp b/src/main.cpp index 66138dd049..33ba54c7f3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,7 +36,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " build-lib [source] create library from source or object files\n" " build-obj [source] create object from source or assembly\n" " builtin show the source code of @import(\"builtin\")\n" - " cc C compiler\n" + " cc use Zig as a drop-in C compiler\n" " fmt parse files and render in canonical zig format\n" " id print the base64-encoded compiler id\n" " init-exe initialize a `zig build` application in the cwd\n" @@ -54,7 +54,6 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " --cache-dir [path] override the local cache directory\n" " --cache [auto|off|on] build in cache, print output path to stdout\n" " --color [auto|off|on] enable or disable colored error messages\n" - " --disable-gen-h do not generate a C header file (.h)\n" " --disable-valgrind omit valgrind client requests in debug builds\n" " --eh-frame-hdr enable C++ exception handling by passing --eh-frame-hdr to linker\n" " --enable-valgrind include valgrind client requests release builds\n" @@ -77,6 +76,8 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " -fno-emit-asm (default) do not output .s (assembly code)\n" " -femit-llvm-ir produce a .ll file with LLVM IR\n" " -fno-emit-llvm-ir (default) do not produce a .ll file with LLVM IR\n" + " -femit-h generate a C header file (.h)\n" + " -fno-emit-h (default) do not generate a C header file (.h)\n" " --libc [file] Provide a file which specifies libc paths\n" " --name [name] override output name\n" " --output-dir [dir] override output directory (defaults to cwd)\n" @@ -270,7 +271,7 @@ static int main0(int argc, char **argv) { return 0; } - if (argc >= 2 && (strcmp(argv[1], "cc") == 0 || + if (argc >= 2 && (strcmp(argv[1], "clang") == 0 || strcmp(argv[1], "-cc1") == 0 || strcmp(argv[1], "-cc1as") == 0)) { return ZigClang_main(argc, argv); @@ -429,8 +430,10 @@ static int main0(int argc, char **argv) { bool enable_dump_analysis = false; bool enable_doc_generation = false; bool emit_bin = true; + const char *emit_bin_override_path = nullptr; bool emit_asm = false; bool emit_llvm_ir = false; + bool emit_h = false; const char *cache_dir = nullptr; CliPkg *cur_pkg = heap::c_allocator.create(); BuildMode build_mode = BuildModeDebug; @@ -439,7 +442,6 @@ static int main0(int argc, char **argv) { bool system_linker_hack = false; TargetSubsystem subsystem = TargetSubsystemAuto; bool want_single_threaded = false; - bool disable_gen_h = false; bool bundle_compiler_rt = false; Buf *override_lib_dir = nullptr; Buf *main_pkg_path = nullptr; @@ -450,6 +452,8 @@ static int main0(int argc, char **argv) { bool function_sections = false; const char *mcpu = nullptr; CodeModel code_model = CodeModelDefault; + const char *override_soname = nullptr; + bool only_preprocess = false; ZigList llvm_argv = {0}; llvm_argv.append("zig (LLVM option parsing)"); @@ -574,9 +578,240 @@ static int main0(int argc, char **argv) { return (term.how == TerminationIdClean) ? term.code : -1; } else if (argc >= 2 && strcmp(argv[1], "fmt") == 0) { return stage2_fmt(argc, argv); - } + } else if (argc >= 2 && strcmp(argv[1], "cc") == 0) { + emit_h = false; + strip = true; - for (int i = 1; i < argc; i += 1) { + bool c_arg = false; + Stage2ClangArgIterator it; + stage2_clang_arg_iterator(&it, argc, argv); + bool nostdlib = false; + bool is_shared_lib = false; + ZigList linker_args = {}; + while (it.has_next) { + if ((err = stage2_clang_arg_next(&it))) { + fprintf(stderr, "unable to parse command line parameters: %s\n", err_str(err)); + return EXIT_FAILURE; + } + switch (it.kind) { + case Stage2ClangArgTarget: // example: -target riscv64-linux-unknown + target_string = it.only_arg; + break; + case Stage2ClangArgO: // -o + emit_bin_override_path = it.only_arg; + enable_cache = CacheOptOn; + break; + case Stage2ClangArgC: // -c + c_arg = true; + break; + case Stage2ClangArgOther: + for (size_t i = 0; i < it.other_args_len; i += 1) { + clang_argv.append(it.other_args_ptr[i]); + } + break; + case Stage2ClangArgPositional: { + Buf *arg_buf = buf_create_from_str(it.only_arg); + if (buf_ends_with_str(arg_buf, ".c") || + buf_ends_with_str(arg_buf, ".C") || + buf_ends_with_str(arg_buf, ".cc") || + buf_ends_with_str(arg_buf, ".cpp") || + buf_ends_with_str(arg_buf, ".cxx") || + buf_ends_with_str(arg_buf, ".s") || + buf_ends_with_str(arg_buf, ".S")) + { + CFile *c_file = heap::c_allocator.create(); + c_file->source_path = it.only_arg; + c_source_files.append(c_file); + } else { + objects.append(it.only_arg); + } + break; + } + case Stage2ClangArgL: // -l + if (strcmp(it.only_arg, "c") == 0) + have_libc = true; + link_libs.append(it.only_arg); + break; + case Stage2ClangArgIgnore: + break; + case Stage2ClangArgDriverPunt: + // Never mind what we're doing, just pass the args directly. For example --help. + return ZigClang_main(argc, argv); + case Stage2ClangArgPIC: + want_pic = WantPICEnabled; + break; + case Stage2ClangArgNoPIC: + want_pic = WantPICDisabled; + break; + case Stage2ClangArgNoStdLib: + nostdlib = true; + break; + case Stage2ClangArgShared: + is_dynamic = true; + is_shared_lib = true; + break; + case Stage2ClangArgRDynamic: + rdynamic = true; + break; + case Stage2ClangArgWL: { + const char *arg = it.only_arg; + for (;;) { + size_t pos = 0; + while (arg[pos] != ',' && arg[pos] != 0) pos += 1; + linker_args.append(buf_create_from_mem(arg, pos)); + if (arg[pos] == 0) break; + arg += pos + 1; + } + break; + } + case Stage2ClangArgPreprocess: + only_preprocess = true; + break; + case Stage2ClangArgOptimize: + // alright what release mode do they want? + if (strcmp(it.only_arg, "Os") == 0) { + build_mode = BuildModeSmallRelease; + } else if (strcmp(it.only_arg, "O2") == 0 || + strcmp(it.only_arg, "O3") == 0 || + strcmp(it.only_arg, "O4") == 0) + { + build_mode = BuildModeFastRelease; + } else if (strcmp(it.only_arg, "Og") == 0) { + build_mode = BuildModeDebug; + } else { + for (size_t i = 0; i < it.other_args_len; i += 1) { + clang_argv.append(it.other_args_ptr[i]); + } + } + break; + case Stage2ClangArgDebug: + strip = false; + if (strcmp(it.only_arg, "-g") == 0) { + // we handled with strip = false above + } else { + for (size_t i = 0; i < it.other_args_len; i += 1) { + clang_argv.append(it.other_args_ptr[i]); + } + } + break; + case Stage2ClangArgSanitize: + if (strcmp(it.only_arg, "undefined") == 0) { + want_sanitize_c = WantCSanitizeEnabled; + } else { + for (size_t i = 0; i < it.other_args_len; i += 1) { + clang_argv.append(it.other_args_ptr[i]); + } + } + break; + } + } + // Parse linker args + for (size_t i = 0; i < linker_args.length; i += 1) { + Buf *arg = linker_args.at(i); + if (buf_eql_str(arg, "-soname")) { + i += 1; + if (i >= linker_args.length) { + fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg)); + return EXIT_FAILURE; + } + Buf *soname_buf = linker_args.at(i); + override_soname = buf_ptr(soname_buf); + // use it as --name + // example: libsoundio.so.2 + size_t prefix = 0; + if (buf_starts_with_str(soname_buf, "lib")) { + prefix = 3; + } + size_t end = buf_len(soname_buf); + if (buf_ends_with_str(soname_buf, ".so")) { + end -= 3; + } else { + bool found_digit = false; + while (end > 0 && isdigit(buf_ptr(soname_buf)[end - 1])) { + found_digit = true; + end -= 1; + } + if (found_digit && end > 0 && buf_ptr(soname_buf)[end - 1] == '.') { + end -= 1; + } else { + end = buf_len(soname_buf); + } + if (buf_ends_with_str(buf_slice(soname_buf, prefix, end), ".so")) { + end -= 3; + } + } + out_name = buf_ptr(buf_slice(soname_buf, prefix, end)); + } else if (buf_eql_str(arg, "-rpath")) { + i += 1; + if (i >= linker_args.length) { + fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg)); + return EXIT_FAILURE; + } + Buf *rpath = linker_args.at(i); + rpath_list.append(buf_ptr(rpath)); + } else if (buf_eql_str(arg, "-I") || + buf_eql_str(arg, "--dynamic-linker") || + buf_eql_str(arg, "-dynamic-linker")) + { + i += 1; + if (i >= linker_args.length) { + fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg)); + return EXIT_FAILURE; + } + dynamic_linker = buf_ptr(linker_args.at(i)); + } else { + fprintf(stderr, "warning: unsupported linker arg: %s\n", buf_ptr(arg)); + } + } + + if (want_sanitize_c == WantCSanitizeEnabled && build_mode == BuildModeFastRelease) { + build_mode = BuildModeSafeRelease; + } + + if (!nostdlib && !have_libc) { + have_libc = true; + link_libs.append("c"); + } + if (only_preprocess) { + cmd = CmdBuild; + out_type = OutTypeObj; + emit_bin = false; + // Transfer "objects" into c_source_files + for (size_t i = 0; i < objects.length; i += 1) { + CFile *c_file = heap::c_allocator.create(); + c_file->source_path = objects.at(i); + c_source_files.append(c_file); + } + for (size_t i = 0; i < c_source_files.length; i += 1) { + Buf *src_path; + if (emit_bin_override_path != nullptr) { + src_path = buf_create_from_str(emit_bin_override_path); + } else { + src_path = buf_create_from_str(c_source_files.at(i)->source_path); + } + Buf basename = BUF_INIT; + os_path_split(src_path, nullptr, &basename); + c_source_files.at(i)->preprocessor_only_basename = buf_ptr(&basename); + } + } else if (!c_arg) { + cmd = CmdBuild; + if (is_shared_lib) { + out_type = OutTypeLib; + } else { + out_type = OutTypeExe; + } + if (emit_bin_override_path == nullptr) { + emit_bin_override_path = "a.out"; + } + } else { + cmd = CmdBuild; + out_type = OutTypeObj; + } + if (c_source_files.length == 0 && objects.length == 0) { + // For example `zig cc` and no args should print the "no input files" message. + return ZigClang_main(argc, argv); + } + } else for (int i = 1; i < argc; i += 1) { char *arg = argv[i]; if (arg[0] == '-') { @@ -660,9 +895,7 @@ static int main0(int argc, char **argv) { } else if (strcmp(arg, "--system-linker-hack") == 0) { system_linker_hack = true; } else if (strcmp(arg, "--single-threaded") == 0) { - want_single_threaded = true; - } else if (strcmp(arg, "--disable-gen-h") == 0) { - disable_gen_h = true; + want_single_threaded = true;; } else if (strcmp(arg, "--bundle-compiler-rt") == 0) { bundle_compiler_rt = true; } else if (strcmp(arg, "--test-cmd-bin") == 0) { @@ -719,6 +952,11 @@ static int main0(int argc, char **argv) { emit_llvm_ir = true; } else if (strcmp(arg, "-fno-emit-llvm-ir") == 0) { emit_llvm_ir = false; + } else if (strcmp(arg, "-femit-h") == 0) { + emit_h = true; + } else if (strcmp(arg, "-fno-emit-h") == 0 || strcmp(arg, "--disable-gen-h") == 0) { + // the --disable-gen-h is there to support godbolt. once they upgrade to -fno-emit-h then we can remove this + emit_h = false; } else if (str_starts_with(arg, "-mcpu=")) { mcpu = arg + strlen("-mcpu="); } else if (i + 1 >= argc) { @@ -1134,6 +1372,18 @@ static int main0(int argc, char **argv) { buf_out_name = buf_alloc(); os_path_extname(&basename, buf_out_name, nullptr); } + if (need_name && buf_out_name == nullptr && objects.length == 1) { + Buf basename = BUF_INIT; + os_path_split(buf_create_from_str(objects.at(0)), nullptr, &basename); + buf_out_name = buf_alloc(); + os_path_extname(&basename, buf_out_name, nullptr); + } + if (need_name && buf_out_name == nullptr && emit_bin_override_path != nullptr) { + Buf basename = BUF_INIT; + os_path_split(buf_create_from_str(emit_bin_override_path), nullptr, &basename); + buf_out_name = buf_alloc(); + os_path_extname(&basename, buf_out_name, nullptr); + } if (need_name && buf_out_name == nullptr) { fprintf(stderr, "--name [name] not provided and unable to infer\n\n"); @@ -1202,13 +1452,17 @@ static int main0(int argc, char **argv) { g->verbose_cc = verbose_cc; g->verbose_llvm_cpu_features = verbose_llvm_cpu_features; g->output_dir = output_dir; - g->disable_gen_h = disable_gen_h; + g->disable_gen_h = !emit_h; g->bundle_compiler_rt = bundle_compiler_rt; codegen_set_errmsg_color(g, color); g->system_linker_hack = system_linker_hack; g->function_sections = function_sections; g->code_model = code_model; + if (override_soname) { + g->override_soname = buf_create_from_str(override_soname); + } + for (size_t i = 0; i < lib_dirs.length; i += 1) { codegen_add_lib_dir(g, lib_dirs.at(i)); } @@ -1287,9 +1541,46 @@ static int main0(int argc, char **argv) { os_spawn_process(args, &term); return term.code; } else if (cmd == CmdBuild) { - if (g->enable_cache) { + if (emit_bin_override_path != nullptr) { +#if defined(ZIG_OS_WINDOWS) + buf_replace(g->output_dir, '/', '\\'); +#endif + Buf *dest_path = buf_create_from_str(emit_bin_override_path); + Buf *source_path; + if (only_preprocess) { + source_path = buf_alloc(); + Buf *pp_only_basename = buf_create_from_str( + c_source_files.at(0)->preprocessor_only_basename); + os_path_join(g->output_dir, pp_only_basename, source_path); + + } else { + source_path = &g->bin_file_output_path; + } + if ((err = os_update_file(source_path, dest_path))) { + fprintf(stderr, "unable to copy %s to %s: %s\n", buf_ptr(source_path), + buf_ptr(dest_path), err_str(err)); + return main_exit(root_progress_node, EXIT_FAILURE); + } + } else if (only_preprocess) { +#if defined(ZIG_OS_WINDOWS) + buf_replace(g->c_artifact_dir, '/', '\\'); +#endif + // dump the preprocessed output to stdout + for (size_t i = 0; i < c_source_files.length; i += 1) { + Buf *source_path = buf_alloc(); + Buf *pp_only_basename = buf_create_from_str( + c_source_files.at(i)->preprocessor_only_basename); + os_path_join(g->c_artifact_dir, pp_only_basename, source_path); + if ((err = os_dump_file(source_path, stdout))) { + fprintf(stderr, "unable to read %s: %s\n", buf_ptr(source_path), + err_str(err)); + return main_exit(root_progress_node, EXIT_FAILURE); + } + } + } else if (g->enable_cache) { #if defined(ZIG_OS_WINDOWS) buf_replace(&g->bin_file_output_path, '/', '\\'); + buf_replace(g->output_dir, '/', '\\'); #endif if (final_output_dir_step != nullptr) { Buf *dest_basename = buf_alloc(); @@ -1303,7 +1594,7 @@ static int main0(int argc, char **argv) { return main_exit(root_progress_node, EXIT_FAILURE); } } else { - if (g->emit_bin && printf("%s\n", buf_ptr(&g->bin_file_output_path)) < 0) + if (printf("%s\n", buf_ptr(g->output_dir)) < 0) return main_exit(root_progress_node, EXIT_FAILURE); } } diff --git a/src/os.cpp b/src/os.cpp index f65a578e17..351b61cd66 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -1051,6 +1051,30 @@ static Error copy_open_files(FILE *src_f, FILE *dest_f) { } } +Error os_dump_file(Buf *src_path, FILE *dest_file) { + Error err; + + FILE *src_f = fopen(buf_ptr(src_path), "rb"); + if (!src_f) { + int err = errno; + if (err == ENOENT) { + return ErrorFileNotFound; + } else if (err == EACCES || err == EPERM) { + return ErrorAccess; + } else { + return ErrorFileSystem; + } + } + copy_open_files(src_f, dest_file); + if ((err = copy_open_files(src_f, dest_file))) { + fclose(src_f); + return err; + } + + fclose(src_f); + return ErrorNone; +} + #if defined(ZIG_OS_WINDOWS) static void windows_filetime_to_os_timestamp(FILETIME *ft, OsTimeStamp *mtime) { mtime->sec = (((ULONGLONG) ft->dwHighDateTime) << 32) + ft->dwLowDateTime; diff --git a/src/os.hpp b/src/os.hpp index 116861e8b5..e73e5e3aaa 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -129,6 +129,7 @@ void os_file_close(OsFile *file); Error ATTRIBUTE_MUST_USE os_write_file(Buf *full_path, Buf *contents); Error ATTRIBUTE_MUST_USE os_copy_file(Buf *src_path, Buf *dest_path); Error ATTRIBUTE_MUST_USE os_update_file(Buf *src_path, Buf *dest_path); +Error ATTRIBUTE_MUST_USE os_dump_file(Buf *src_path, FILE *dest_file); Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents); Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents); diff --git a/src/parse_f128.c b/src/parse_f128.c index cffb3796b4..9b5c287a3c 100644 --- a/src/parse_f128.c +++ b/src/parse_f128.c @@ -165,22 +165,36 @@ static long long scanexp(struct MuslFILE *f, int pok) int x; long long y; int neg = 0; - + c = shgetc(f); if (c=='+' || c=='-') { neg = (c=='-'); c = shgetc(f); if (c-'0'>=10U && pok) shunget(f); } - if (c-'0'>=10U) { + if (c-'0'>=10U && c!='_') { shunget(f); return LLONG_MIN; } - for (x=0; c-'0'<10U && xid == TokenIdKeywordErrdefer) ? + ast_parse_payload(pc) : nullptr; AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement); AstNode *res = ast_create_node(pc, NodeTypeDefer, defer); + res->data.defer.kind = ReturnKindUnconditional; res->data.defer.expr = statement; - if (defer->id == TokenIdKeywordErrdefer) + if (defer->id == TokenIdKeywordErrdefer) { res->data.defer.kind = ReturnKindError; + if (payload != nullptr) + res->data.defer.err_payload = token_symbol(pc, payload); + } return res; } @@ -3032,6 +3038,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont break; case NodeTypeDefer: visit_field(&node->data.defer.expr, visit, context); + visit_field(&node->data.defer.err_payload, visit, context); break; case NodeTypeVariableDeclaration: visit_field(&node->data.variable_declaration.type, visit, context); diff --git a/src/stage2.cpp b/src/stage2.cpp index a8d8b7cf97..c83b1aa77c 100644 --- a/src/stage2.cpp +++ b/src/stage2.cpp @@ -304,3 +304,15 @@ enum Error stage2_detect_native_paths(struct Stage2NativePaths *native_paths) { return ErrorNone; } + +void stage2_clang_arg_iterator(struct Stage2ClangArgIterator *it, + size_t argc, char **argv) +{ + const char *msg = "stage0 called stage2_clang_arg_iterator"; + stage2_panic(msg, strlen(msg)); +} + +enum Error stage2_clang_arg_next(struct Stage2ClangArgIterator *it) { + const char *msg = "stage0 called stage2_clang_arg_next"; + stage2_panic(msg, strlen(msg)); +} diff --git a/src/stage2.h b/src/stage2.h index 24fd664b3c..82c40074f0 100644 --- a/src/stage2.h +++ b/src/stage2.h @@ -105,6 +105,10 @@ enum Error { ErrorTargetHasNoDynamicLinker, ErrorInvalidAbiVersion, ErrorInvalidOperatingSystemVersion, + ErrorUnknownClangOption, + ErrorPermissionDenied, + ErrorFileBusy, + ErrorLocked, }; // ABI warning @@ -291,6 +295,7 @@ struct ZigTarget { size_t cache_hash_len; const char *os_builtin_str; const char *dynamic_linker; + const char *standard_dynamic_linker_path; }; // ABI warning @@ -315,4 +320,46 @@ struct Stage2NativePaths { // ABI warning ZIG_EXTERN_C enum Error stage2_detect_native_paths(struct Stage2NativePaths *native_paths); +// ABI warning +enum Stage2ClangArg { + Stage2ClangArgTarget, + Stage2ClangArgO, + Stage2ClangArgC, + Stage2ClangArgOther, + Stage2ClangArgPositional, + Stage2ClangArgL, + Stage2ClangArgIgnore, + Stage2ClangArgDriverPunt, + Stage2ClangArgPIC, + Stage2ClangArgNoPIC, + Stage2ClangArgNoStdLib, + Stage2ClangArgShared, + Stage2ClangArgRDynamic, + Stage2ClangArgWL, + Stage2ClangArgPreprocess, + Stage2ClangArgOptimize, + Stage2ClangArgDebug, + Stage2ClangArgSanitize, +}; + +// ABI warning +struct Stage2ClangArgIterator { + bool has_next; + enum Stage2ClangArg kind; + const char *only_arg; + const char *second_arg; + const char **other_args_ptr; + size_t other_args_len; + const char **argv_ptr; + size_t argv_len; + size_t next_index; +}; + +// ABI warning +ZIG_EXTERN_C void stage2_clang_arg_iterator(struct Stage2ClangArgIterator *it, + size_t argc, char **argv); + +// ABI warning +ZIG_EXTERN_C enum Error stage2_clang_arg_next(struct Stage2ClangArgIterator *it); + #endif diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index d3390aef3c..22d63568bf 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -177,10 +177,13 @@ enum TokenizeState { TokenizeStateSymbol, TokenizeStateZero, // "0", which might lead to "0x" TokenizeStateNumber, // "123", "0x123" + TokenizeStateNumberNoUnderscore, // "12_", "0x12_" next char must be digit TokenizeStateNumberDot, TokenizeStateFloatFraction, // "123.456", "0x123.456" + TokenizeStateFloatFractionNoUnderscore, // "123.45_", "0x123.45_" TokenizeStateFloatExponentUnsigned, // "123.456e", "123e", "0x123p" - TokenizeStateFloatExponentNumber, // "123.456e-", "123.456e5", "123.456e5e-5" + TokenizeStateFloatExponentNumber, // "123.456e7", "123.456e+7", "123.456e-7" + TokenizeStateFloatExponentNumberNoUnderscore, // "123.456e7_", "123.456e+7_", "123.456e-7_" TokenizeStateString, TokenizeStateStringEscape, TokenizeStateStringEscapeUnicodeStart, @@ -233,14 +236,10 @@ struct Tokenize { Token *cur_tok; Tokenization *out; uint32_t radix; - int32_t exp_add_amt; - bool is_exp_negative; + bool is_trailing_underscore; size_t char_code_index; bool unicode; uint32_t char_code; - int exponent_in_bin_or_dec; - BigInt specified_exponent; - BigInt significand; size_t remaining_code_units; }; @@ -426,20 +425,16 @@ void tokenize(Buf *buf, Tokenization *out) { case '0': t.state = TokenizeStateZero; begin_token(&t, TokenIdIntLiteral); + t.is_trailing_underscore = false; t.radix = 10; - t.exp_add_amt = 1; - t.exponent_in_bin_or_dec = 0; bigint_init_unsigned(&t.cur_tok->data.int_lit.bigint, 0); - bigint_init_unsigned(&t.specified_exponent, 0); break; case DIGIT_NON_ZERO: t.state = TokenizeStateNumber; begin_token(&t, TokenIdIntLiteral); + t.is_trailing_underscore = false; t.radix = 10; - t.exp_add_amt = 1; - t.exponent_in_bin_or_dec = 0; bigint_init_unsigned(&t.cur_tok->data.int_lit.bigint, get_digit_value(c)); - bigint_init_unsigned(&t.specified_exponent, 0); break; case '"': begin_token(&t, TokenIdStringLiteral); @@ -1189,17 +1184,15 @@ void tokenize(Buf *buf, Tokenization *out) { switch (c) { case 'b': t.radix = 2; - t.state = TokenizeStateNumber; + t.state = TokenizeStateNumberNoUnderscore; break; case 'o': t.radix = 8; - t.exp_add_amt = 3; - t.state = TokenizeStateNumber; + t.state = TokenizeStateNumberNoUnderscore; break; case 'x': t.radix = 16; - t.exp_add_amt = 4; - t.state = TokenizeStateNumber; + t.state = TokenizeStateNumberNoUnderscore; break; default: // reinterpret as normal number @@ -1208,9 +1201,27 @@ void tokenize(Buf *buf, Tokenization *out) { continue; } break; + case TokenizeStateNumberNoUnderscore: + if (c == '_') { + invalid_char_error(&t, c); + break; + } else if (get_digit_value(c) < t.radix) { + t.is_trailing_underscore = false; + t.state = TokenizeStateNumber; + } + // fall through case TokenizeStateNumber: { + if (c == '_') { + t.is_trailing_underscore = true; + t.state = TokenizeStateNumberNoUnderscore; + break; + } if (c == '.') { + if (t.is_trailing_underscore) { + invalid_char_error(&t, c); + break; + } if (t.radix != 16 && t.radix != 10) { invalid_char_error(&t, c); } @@ -1218,17 +1229,26 @@ void tokenize(Buf *buf, Tokenization *out) { break; } if (is_exponent_signifier(c, t.radix)) { + if (t.is_trailing_underscore) { + invalid_char_error(&t, c); + break; + } if (t.radix != 16 && t.radix != 10) { invalid_char_error(&t, c); } t.state = TokenizeStateFloatExponentUnsigned; + t.radix = 10; // exponent is always base 10 assert(t.cur_tok->id == TokenIdIntLiteral); - bigint_init_bigint(&t.significand, &t.cur_tok->data.int_lit.bigint); set_token_id(&t, t.cur_tok, TokenIdFloatLiteral); break; } uint32_t digit_value = get_digit_value(c); if (digit_value >= t.radix) { + if (t.is_trailing_underscore) { + invalid_char_error(&t, c); + break; + } + if (is_symbol_char(c)) { invalid_char_error(&t, c); } @@ -1259,20 +1279,41 @@ void tokenize(Buf *buf, Tokenization *out) { continue; } t.pos -= 1; - t.state = TokenizeStateFloatFraction; + t.state = TokenizeStateFloatFractionNoUnderscore; assert(t.cur_tok->id == TokenIdIntLiteral); - bigint_init_bigint(&t.significand, &t.cur_tok->data.int_lit.bigint); set_token_id(&t, t.cur_tok, TokenIdFloatLiteral); continue; } + case TokenizeStateFloatFractionNoUnderscore: + if (c == '_') { + invalid_char_error(&t, c); + } else if (get_digit_value(c) < t.radix) { + t.is_trailing_underscore = false; + t.state = TokenizeStateFloatFraction; + } + // fall through case TokenizeStateFloatFraction: { + if (c == '_') { + t.is_trailing_underscore = true; + t.state = TokenizeStateFloatFractionNoUnderscore; + break; + } if (is_exponent_signifier(c, t.radix)) { + if (t.is_trailing_underscore) { + invalid_char_error(&t, c); + break; + } t.state = TokenizeStateFloatExponentUnsigned; + t.radix = 10; // exponent is always base 10 break; } uint32_t digit_value = get_digit_value(c); if (digit_value >= t.radix) { + if (t.is_trailing_underscore) { + invalid_char_error(&t, c); + break; + } if (is_symbol_char(c)) { invalid_char_error(&t, c); } @@ -1282,46 +1323,47 @@ void tokenize(Buf *buf, Tokenization *out) { t.state = TokenizeStateStart; continue; } - t.exponent_in_bin_or_dec -= t.exp_add_amt; - if (t.radix == 10) { - // For now we use strtod to parse decimal floats, so we just have to get to the - // end of the token. - break; - } - BigInt digit_value_bi; - bigint_init_unsigned(&digit_value_bi, digit_value); - BigInt radix_bi; - bigint_init_unsigned(&radix_bi, t.radix); - - BigInt multiplied; - bigint_mul(&multiplied, &t.significand, &radix_bi); - - bigint_add(&t.significand, &multiplied, &digit_value_bi); - break; + // we use parse_f128 to generate the float literal, so just + // need to get to the end of the token } + break; case TokenizeStateFloatExponentUnsigned: switch (c) { case '+': - t.is_exp_negative = false; - t.state = TokenizeStateFloatExponentNumber; + t.state = TokenizeStateFloatExponentNumberNoUnderscore; break; case '-': - t.is_exp_negative = true; - t.state = TokenizeStateFloatExponentNumber; + t.state = TokenizeStateFloatExponentNumberNoUnderscore; break; default: // reinterpret as normal exponent number t.pos -= 1; - t.is_exp_negative = false; - t.state = TokenizeStateFloatExponentNumber; + t.state = TokenizeStateFloatExponentNumberNoUnderscore; continue; } break; + case TokenizeStateFloatExponentNumberNoUnderscore: + if (c == '_') { + invalid_char_error(&t, c); + } else if (get_digit_value(c) < t.radix) { + t.is_trailing_underscore = false; + t.state = TokenizeStateFloatExponentNumber; + } + // fall through case TokenizeStateFloatExponentNumber: { + if (c == '_') { + t.is_trailing_underscore = true; + t.state = TokenizeStateFloatExponentNumberNoUnderscore; + break; + } uint32_t digit_value = get_digit_value(c); if (digit_value >= t.radix) { + if (t.is_trailing_underscore) { + invalid_char_error(&t, c); + break; + } if (is_symbol_char(c)) { invalid_char_error(&t, c); } @@ -1331,21 +1373,9 @@ void tokenize(Buf *buf, Tokenization *out) { t.state = TokenizeStateStart; continue; } - if (t.radix == 10) { - // For now we use strtod to parse decimal floats, so we just have to get to the - // end of the token. - break; - } - BigInt digit_value_bi; - bigint_init_unsigned(&digit_value_bi, digit_value); - BigInt radix_bi; - bigint_init_unsigned(&radix_bi, 10); - - BigInt multiplied; - bigint_mul(&multiplied, &t.specified_exponent, &radix_bi); - - bigint_add(&t.specified_exponent, &multiplied, &digit_value_bi); + // we use parse_f128 to generate the float literal, so just + // need to get to the end of the token } break; case TokenizeStateSawDash: @@ -1399,6 +1429,9 @@ void tokenize(Buf *buf, Tokenization *out) { case TokenizeStateStart: case TokenizeStateError: break; + case TokenizeStateNumberNoUnderscore: + case TokenizeStateFloatFractionNoUnderscore: + case TokenizeStateFloatExponentNumberNoUnderscore: case TokenizeStateNumberDot: tokenize_error(&t, "unterminated number literal"); break; diff --git a/test/cli.zig b/test/cli.zig index 9bc4a21c90..4c067d16ae 100644 --- a/test/cli.zig +++ b/test/cli.zig @@ -36,7 +36,7 @@ pub fn main() !void { testMissingOutputPath, }; for (test_fns) |testFn| { - try fs.deleteTree(dir_path); + try fs.cwd().deleteTree(dir_path); try fs.cwd().makeDir(dir_path); try testFn(zig_exe, dir_path); } diff --git a/test/compare_output.zig b/test/compare_output.zig index 1a0179c4c2..46c475e046 100644 --- a/test/compare_output.zig +++ b/test/compare_output.zig @@ -292,7 +292,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\pub export fn main() c_int { \\ var array = [_]u32{ 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 }; \\ - \\ c.qsort(@ptrCast(?*c_void, array[0..].ptr), @intCast(c_ulong, array.len), @sizeOf(i32), compare_fn); + \\ c.qsort(@ptrCast(?*c_void, &array), @intCast(c_ulong, array.len), @sizeOf(i32), compare_fn); \\ \\ for (array) |item, i| { \\ if (item != i) { diff --git a/test/compile_errors.zig b/test/compile_errors.zig index f894a152a7..d762f5bdc9 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,29 @@ const tests = @import("tests.zig"); const std = @import("std"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest("unused variable error on errdefer", + \\fn foo() !void { + \\ errdefer |a| unreachable; + \\ return error.A; + \\} + \\export fn entry() void { + \\ foo() catch unreachable; + \\} + , &[_][]const u8{ + "tmp.zig:2:15: error: unused variable: 'a'", + }); + + cases.addTest("comparison of non-tagged union and enum literal", + \\export fn entry() void { + \\ const U = union { A: u32, B: u64 }; + \\ var u = U{ .A = 42 }; + \\ var ok = u == .A; + \\} + , &[_][]const u8{ + "tmp.zig:4:16: error: comparison of union and enum literal is only valid for tagged union types", + "tmp.zig:2:15: note: type U is not a tagged union", + }); + cases.addTest("shift on type with non-power-of-two size", \\export fn entry() void { \\ const S = struct { @@ -103,18 +126,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:3:23: error: pointer to size 0 type has no address", }); - cases.addTest("slice to pointer conversion mismatch", - \\pub fn bytesAsSlice(bytes: var) [*]align(1) const u16 { - \\ return @ptrCast([*]align(1) const u16, bytes.ptr)[0..1]; - \\} - \\test "bytesAsSlice" { - \\ const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; - \\ const slice = bytesAsSlice(bytes[0..]); - \\} - , &[_][]const u8{ - "tmp.zig:2:54: error: expected type '[*]align(1) const u16', found '[]align(1) const u16'", - }); - cases.addTest("access invalid @typeInfo decl", \\const A = B; \\test "Crash" { @@ -384,11 +395,163 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var bad_float :f32 = 0.0; \\ bad_float = bad_float + .20; \\ std.debug.assert(bad_float < 1.0); - \\}) + \\} , &[_][]const u8{ "tmp.zig:5:29: error: invalid token: '.'", }); + cases.add("invalid exponent in float literal - 1", + \\fn main() void { + \\ var bad: f128 = 0x1.0p1ab1; + \\} + , &[_][]const u8{ + "tmp.zig:2:28: error: invalid character: 'a'", + }); + + cases.add("invalid exponent in float literal - 2", + \\fn main() void { + \\ var bad: f128 = 0x1.0p50F; + \\} + , &[_][]const u8{ + "tmp.zig:2:29: error: invalid character: 'F'", + }); + + cases.add("invalid underscore placement in float literal - 1", + \\fn main() void { + \\ var bad: f128 = 0._0; + \\} + , &[_][]const u8{ + "tmp.zig:2:23: error: invalid character: '_'", + }); + + cases.add("invalid underscore placement in float literal - 2", + \\fn main() void { + \\ var bad: f128 = 0_.0; + \\} + , &[_][]const u8{ + "tmp.zig:2:23: error: invalid character: '.'", + }); + + cases.add("invalid underscore placement in float literal - 3", + \\fn main() void { + \\ var bad: f128 = 0.0_; + \\} + , &[_][]const u8{ + "tmp.zig:2:25: error: invalid character: ';'", + }); + + cases.add("invalid underscore placement in float literal - 4", + \\fn main() void { + \\ var bad: f128 = 1.0e_1; + \\} + , &[_][]const u8{ + "tmp.zig:2:25: error: invalid character: '_'", + }); + + cases.add("invalid underscore placement in float literal - 5", + \\fn main() void { + \\ var bad: f128 = 1.0e+_1; + \\} + , &[_][]const u8{ + "tmp.zig:2:26: error: invalid character: '_'", + }); + + cases.add("invalid underscore placement in float literal - 6", + \\fn main() void { + \\ var bad: f128 = 1.0e-_1; + \\} + , &[_][]const u8{ + "tmp.zig:2:26: error: invalid character: '_'", + }); + + cases.add("invalid underscore placement in float literal - 7", + \\fn main() void { + \\ var bad: f128 = 1.0e-1_; + \\} + , &[_][]const u8{ + "tmp.zig:2:28: error: invalid character: ';'", + }); + + cases.add("invalid underscore placement in float literal - 9", + \\fn main() void { + \\ var bad: f128 = 1__0.0e-1; + \\} + , &[_][]const u8{ + "tmp.zig:2:23: error: invalid character: '_'", + }); + + cases.add("invalid underscore placement in float literal - 10", + \\fn main() void { + \\ var bad: f128 = 1.0__0e-1; + \\} + , &[_][]const u8{ + "tmp.zig:2:25: error: invalid character: '_'", + }); + + cases.add("invalid underscore placement in float literal - 11", + \\fn main() void { + \\ var bad: f128 = 1.0e-1__0; + \\} + , &[_][]const u8{ + "tmp.zig:2:28: error: invalid character: '_'", + }); + + cases.add("invalid underscore placement in float literal - 12", + \\fn main() void { + \\ var bad: f128 = 0_x0.0; + \\} + , &[_][]const u8{ + "tmp.zig:2:23: error: invalid character: 'x'", + }); + + cases.add("invalid underscore placement in float literal - 13", + \\fn main() void { + \\ var bad: f128 = 0x_0.0; + \\} + , &[_][]const u8{ + "tmp.zig:2:23: error: invalid character: '_'", + }); + + cases.add("invalid underscore placement in float literal - 14", + \\fn main() void { + \\ var bad: f128 = 0x0.0_p1; + \\} + , &[_][]const u8{ + "tmp.zig:2:27: error: invalid character: 'p'", + }); + + cases.add("invalid underscore placement in int literal - 1", + \\fn main() void { + \\ var bad: u128 = 0010_; + \\} + , &[_][]const u8{ + "tmp.zig:2:26: error: invalid character: ';'", + }); + + cases.add("invalid underscore placement in int literal - 2", + \\fn main() void { + \\ var bad: u128 = 0b0010_; + \\} + , &[_][]const u8{ + "tmp.zig:2:28: error: invalid character: ';'", + }); + + cases.add("invalid underscore placement in int literal - 3", + \\fn main() void { + \\ var bad: u128 = 0o0010_; + \\} + , &[_][]const u8{ + "tmp.zig:2:28: error: invalid character: ';'", + }); + + cases.add("invalid underscore placement in int literal - 4", + \\fn main() void { + \\ var bad: u128 = 0x0010_; + \\} + , &[_][]const u8{ + "tmp.zig:2:28: error: invalid character: ';'", + }); + cases.add("var args without c calling conv", \\fn foo(args: ...) void {} \\comptime { @@ -1918,8 +2081,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add("reading past end of pointer casted array", \\comptime { \\ const array: [4]u8 = "aoeu".*; - \\ const slice = array[1..]; - \\ const int_ptr = @ptrCast(*const u24, slice.ptr); + \\ const sub_array = array[1..]; + \\ const int_ptr = @ptrCast(*const u24, sub_array); \\ const deref = int_ptr.*; \\} , &[_][]const u8{ diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig index 5047bfd0d0..b8ab47ddac 100644 --- a/test/runtime_safety.zig +++ b/test/runtime_safety.zig @@ -69,7 +69,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\} \\pub fn main() void { \\ var buf: [4]u8 = undefined; - \\ const ptr = buf[0..].ptr; + \\ const ptr: [*]u8 = &buf; \\ const slice = ptr[0..3 :0]; \\} ); diff --git a/test/stage1/behavior/align.zig b/test/stage1/behavior/align.zig index 5a5138d567..e9b7e0f1d6 100644 --- a/test/stage1/behavior/align.zig +++ b/test/stage1/behavior/align.zig @@ -5,10 +5,17 @@ const builtin = @import("builtin"); var foo: u8 align(4) = 100; test "global variable alignment" { - expect(@TypeOf(&foo).alignment == 4); - expect(@TypeOf(&foo) == *align(4) u8); - const slice = @as(*[1]u8, &foo)[0..]; - expect(@TypeOf(slice) == []align(4) u8); + comptime expect(@TypeOf(&foo).alignment == 4); + comptime expect(@TypeOf(&foo) == *align(4) u8); + { + const slice = @as(*[1]u8, &foo)[0..]; + comptime expect(@TypeOf(slice) == *align(4) [1]u8); + } + { + var runtime_zero: usize = 0; + const slice = @as(*[1]u8, &foo)[runtime_zero..]; + comptime expect(@TypeOf(slice) == []align(4) u8); + } } fn derp() align(@sizeOf(usize) * 2) i32 { @@ -171,18 +178,19 @@ test "runtime known array index has best alignment possible" { // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2 var smaller align(2) = [_]u32{ 1, 2, 3, 4 }; - comptime expect(@TypeOf(smaller[0..]) == []align(2) u32); - comptime expect(@TypeOf(smaller[0..].ptr) == [*]align(2) u32); - testIndex(smaller[0..].ptr, 0, *align(2) u32); - testIndex(smaller[0..].ptr, 1, *align(2) u32); - testIndex(smaller[0..].ptr, 2, *align(2) u32); - testIndex(smaller[0..].ptr, 3, *align(2) u32); + var runtime_zero: usize = 0; + comptime expect(@TypeOf(smaller[runtime_zero..]) == []align(2) u32); + comptime expect(@TypeOf(smaller[runtime_zero..].ptr) == [*]align(2) u32); + testIndex(smaller[runtime_zero..].ptr, 0, *align(2) u32); + testIndex(smaller[runtime_zero..].ptr, 1, *align(2) u32); + testIndex(smaller[runtime_zero..].ptr, 2, *align(2) u32); + testIndex(smaller[runtime_zero..].ptr, 3, *align(2) u32); // has to use ABI alignment because index known at runtime only - testIndex2(array[0..].ptr, 0, *u8); - testIndex2(array[0..].ptr, 1, *u8); - testIndex2(array[0..].ptr, 2, *u8); - testIndex2(array[0..].ptr, 3, *u8); + testIndex2(array[runtime_zero..].ptr, 0, *u8); + testIndex2(array[runtime_zero..].ptr, 1, *u8); + testIndex2(array[runtime_zero..].ptr, 2, *u8); + testIndex2(array[runtime_zero..].ptr, 3, *u8); } fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void { comptime expect(@TypeOf(&smaller[index]) == T); diff --git a/test/stage1/behavior/array.zig b/test/stage1/behavior/array.zig index da56864cc9..792c0e70d1 100644 --- a/test/stage1/behavior/array.zig +++ b/test/stage1/behavior/array.zig @@ -28,6 +28,24 @@ fn getArrayLen(a: []const u32) usize { return a.len; } +test "array with sentinels" { + const S = struct { + fn doTheTest(is_ct: bool) void { + var zero_sized: [0:0xde]u8 = [_:0xde]u8{}; + expectEqual(@as(u8, 0xde), zero_sized[0]); + // Disabled at runtime because of + // https://github.com/ziglang/zig/issues/4372 + if (is_ct) { + var reinterpreted = @ptrCast(*[1]u8, &zero_sized); + expectEqual(@as(u8, 0xde), reinterpreted[0]); + } + } + }; + + S.doTheTest(false); + comptime S.doTheTest(true); +} + test "void arrays" { var array: [4]void = undefined; array[0] = void{}; @@ -376,3 +394,23 @@ test "type deduction for array subscript expression" { S.doTheTest(); comptime S.doTheTest(); } + +test "sentinel element count towards the ABI size calculation" { + const S = struct { + fn doTheTest() void { + const T = packed struct { + fill_pre: u8 = 0x55, + data: [0:0]u8 = undefined, + fill_post: u8 = 0xAA, + }; + var x = T{}; + var as_slice = mem.asBytes(&x); + expectEqual(@as(usize, 3), as_slice.len); + expectEqual(@as(u8, 0x55), as_slice[0]); + expectEqual(@as(u8, 0xAA), as_slice[2]); + } + }; + + S.doTheTest(); + comptime S.doTheTest(); +} diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig index 0304ddfa9c..f1936069f1 100644 --- a/test/stage1/behavior/cast.zig +++ b/test/stage1/behavior/cast.zig @@ -435,7 +435,8 @@ fn incrementVoidPtrValue(value: ?*c_void) void { test "implicit cast from [*]T to ?*c_void" { var a = [_]u8{ 3, 2, 1 }; - incrementVoidPtrArray(a[0..].ptr, 3); + var runtime_zero: usize = 0; + incrementVoidPtrArray(a[runtime_zero..].ptr, 3); expect(std.mem.eql(u8, &a, &[_]u8{ 4, 3, 2 })); } diff --git a/test/stage1/behavior/defer.zig b/test/stage1/behavior/defer.zig index 5a643609fd..6bfeb485cc 100644 --- a/test/stage1/behavior/defer.zig +++ b/test/stage1/behavior/defer.zig @@ -1,4 +1,7 @@ -const expect = @import("std").testing.expect; +const std = @import("std"); +const expect = std.testing.expect; +const expectEqual = std.testing.expectEqual; +const expectError = std.testing.expectError; var result: [3]u8 = undefined; var index: usize = undefined; @@ -93,3 +96,19 @@ test "return variable while defer expression in scope to modify it" { S.doTheTest(); comptime S.doTheTest(); } + +test "errdefer with payload" { + const S = struct { + fn foo() !i32 { + errdefer |a| { + expectEqual(error.One, a); + } + return error.One; + } + fn doTheTest() void { + expectError(error.One, foo()); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig index 55ace6198c..2af34eaf7e 100644 --- a/test/stage1/behavior/eval.zig +++ b/test/stage1/behavior/eval.zig @@ -524,7 +524,7 @@ test "comptime slice of slice preserves comptime var" { test "comptime slice of pointer preserves comptime var" { comptime { var buff: [10]u8 = undefined; - var a = buff[0..].ptr; + var a = @ptrCast([*]u8, &buff); a[0..1][0] = 1; expect(buff[0..][0..][0] == 1); } diff --git a/test/stage1/behavior/math.zig b/test/stage1/behavior/math.zig index fb70fb7e44..b342597acf 100644 --- a/test/stage1/behavior/math.zig +++ b/test/stage1/behavior/math.zig @@ -411,6 +411,34 @@ test "quad hex float literal parsing accurate" { comptime S.doTheTest(); } +test "underscore separator parsing" { + expect(0_0_0_0 == 0); + expect(1_234_567 == 1234567); + expect(001_234_567 == 1234567); + expect(0_0_1_2_3_4_5_6_7 == 1234567); + + expect(0b0_0_0_0 == 0); + expect(0b1010_1010 == 0b10101010); + expect(0b0000_1010_1010 == 0b10101010); + expect(0b1_0_1_0_1_0_1_0 == 0b10101010); + + expect(0o0_0_0_0 == 0); + expect(0o1010_1010 == 0o10101010); + expect(0o0000_1010_1010 == 0o10101010); + expect(0o1_0_1_0_1_0_1_0 == 0o10101010); + + expect(0x0_0_0_0 == 0); + expect(0x1010_1010 == 0x10101010); + expect(0x0000_1010_1010 == 0x10101010); + expect(0x1_0_1_0_1_0_1_0 == 0x10101010); + + expect(123_456.789_000e1_0 == 123456.789000e10); + expect(0_1_2_3_4_5_6.7_8_9_0_0_0e0_0_1_0 == 123456.789000e10); + + expect(0x1234_5678.9ABC_DEF0p-1_0 == 0x12345678.9ABCDEF0p-10); + expect(0x1_2_3_4_5_6_7_8.9_A_B_C_D_E_F_0p-0_0_0_1_0 == 0x12345678.9ABCDEF0p-10); +} + test "hex float literal within range" { const a = 0x1.0p16383; const b = 0x0.1p16387; diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig index 44a8334b5d..51ee6f3a4f 100644 --- a/test/stage1/behavior/misc.zig +++ b/test/stage1/behavior/misc.zig @@ -102,8 +102,8 @@ test "memcpy and memset intrinsics" { var foo: [20]u8 = undefined; var bar: [20]u8 = undefined; - @memset(foo[0..].ptr, 'A', foo.len); - @memcpy(bar[0..].ptr, foo[0..].ptr, bar.len); + @memset(&foo, 'A', foo.len); + @memcpy(&bar, &foo, bar.len); if (bar[11] != 'A') unreachable; } @@ -565,12 +565,16 @@ test "volatile load and store" { expect(ptr.* == 1235); } -test "slice string literal has type []const u8" { +test "slice string literal has correct type" { comptime { - expect(@TypeOf("aoeu"[0..]) == []const u8); + expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8); const array = [_]i32{ 1, 2, 3, 4 }; - expect(@TypeOf(array[0..]) == []const i32); + expect(@TypeOf(array[0..]) == *const [4]i32); } + var runtime_zero: usize = 0; + comptime expect(@TypeOf("aoeu"[runtime_zero..]) == [:0]const u8); + const array = [_]i32{ 1, 2, 3, 4 }; + comptime expect(@TypeOf(array[runtime_zero..]) == []const i32); } test "pointer child field" { diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index bcc1d62df3..fbce9731f0 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -159,12 +159,13 @@ test "allowzero pointer and slice" { var opt_ptr: ?[*]allowzero i32 = ptr; expect(opt_ptr != null); expect(@ptrToInt(ptr) == 0); - var slice = ptr[0..10]; - expect(@TypeOf(slice) == []allowzero i32); + var runtime_zero: usize = 0; + var slice = ptr[runtime_zero..10]; + comptime expect(@TypeOf(slice) == []allowzero i32); expect(@ptrToInt(&slice[5]) == 20); - expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero); - expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero); + comptime expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero); + comptime expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero); } test "assign null directly to C pointer and test null equality" { diff --git a/test/stage1/behavior/ptrcast.zig b/test/stage1/behavior/ptrcast.zig index 1c1cf251a0..3925325e61 100644 --- a/test/stage1/behavior/ptrcast.zig +++ b/test/stage1/behavior/ptrcast.zig @@ -13,7 +13,7 @@ fn testReinterpretBytesAsInteger() void { builtin.Endian.Little => 0xab785634, builtin.Endian.Big => 0x345678ab, }; - expect(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected); + expect(@ptrCast(*align(1) const u32, bytes[1..5]).* == expected); } test "reinterpret bytes of an array into an extern struct" { diff --git a/test/stage1/behavior/slice.zig b/test/stage1/behavior/slice.zig index 9dd57f474e..e357ad2f0f 100644 --- a/test/stage1/behavior/slice.zig +++ b/test/stage1/behavior/slice.zig @@ -7,10 +7,10 @@ const mem = std.mem; const x = @intToPtr([*]i32, 0x1000)[0..0x500]; const y = x[0x100..]; test "compile time slice of pointer to hard coded address" { - expect(@ptrToInt(x.ptr) == 0x1000); + expect(@ptrToInt(x) == 0x1000); expect(x.len == 0x500); - expect(@ptrToInt(y.ptr) == 0x1100); + expect(@ptrToInt(y) == 0x1100); expect(y.len == 0x400); } @@ -47,7 +47,9 @@ test "C pointer slice access" { var buf: [10]u32 = [1]u32{42} ** 10; const c_ptr = @ptrCast([*c]const u32, &buf); - comptime expectEqual([]const u32, @TypeOf(c_ptr[0..1])); + var runtime_zero: usize = 0; + comptime expectEqual([]const u32, @TypeOf(c_ptr[runtime_zero..1])); + comptime expectEqual(*const [1]u32, @TypeOf(c_ptr[0..1])); for (c_ptr[0..5]) |*cl| { expectEqual(@as(u32, 42), cl.*); @@ -107,7 +109,9 @@ test "obtaining a null terminated slice" { const ptr2 = buf[0..runtime_len :0]; // ptr2 is a null-terminated slice comptime expect(@TypeOf(ptr2) == [:0]u8); - comptime expect(@TypeOf(ptr2[0..2]) == []u8); + comptime expect(@TypeOf(ptr2[0..2]) == *[2]u8); + var runtime_zero: usize = 0; + comptime expect(@TypeOf(ptr2[runtime_zero..2]) == []u8); } test "empty array to slice" { @@ -126,3 +130,172 @@ test "empty array to slice" { S.doTheTest(); comptime S.doTheTest(); } + +test "@ptrCast slice to pointer" { + const S = struct { + fn doTheTest() void { + var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff }; + var slice: []u8 = &array; + var ptr = @ptrCast(*u16, slice); + expect(ptr.* == 65535); + } + }; + + S.doTheTest(); + comptime S.doTheTest(); +} + +test "slice syntax resulting in pointer-to-array" { + const S = struct { + fn doTheTest() void { + testArray(); + testArrayZ(); + testArray0(); + testArrayAlign(); + testPointer(); + testPointerZ(); + testPointer0(); + testPointerAlign(); + testSlice(); + testSliceZ(); + testSlice0(); + testSliceOpt(); + testSliceAlign(); + } + + fn testArray() void { + var array = [5]u8{ 1, 2, 3, 4, 5 }; + var slice = array[1..3]; + comptime expect(@TypeOf(slice) == *[2]u8); + expect(slice[0] == 2); + expect(slice[1] == 3); + } + + fn testArrayZ() void { + var array = [5:0]u8{ 1, 2, 3, 4, 5 }; + comptime expect(@TypeOf(array[1..3]) == *[2]u8); + comptime expect(@TypeOf(array[1..5]) == *[4:0]u8); + comptime expect(@TypeOf(array[1..]) == *[4:0]u8); + comptime expect(@TypeOf(array[1..3 :4]) == *[2:4]u8); + } + + fn testArray0() void { + { + var array = [0]u8{}; + var slice = array[0..0]; + comptime expect(@TypeOf(slice) == *[0]u8); + } + { + var array = [0:0]u8{}; + var slice = array[0..0]; + comptime expect(@TypeOf(slice) == *[0:0]u8); + expect(slice[0] == 0); + } + } + + fn testArrayAlign() void { + var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; + var slice = array[4..5]; + comptime expect(@TypeOf(slice) == *align(4) [1]u8); + expect(slice[0] == 5); + comptime expect(@TypeOf(array[0..2]) == *align(4) [2]u8); + } + + fn testPointer() void { + var array = [5]u8{ 1, 2, 3, 4, 5 }; + var pointer: [*]u8 = &array; + var slice = pointer[1..3]; + comptime expect(@TypeOf(slice) == *[2]u8); + expect(slice[0] == 2); + expect(slice[1] == 3); + } + + fn testPointerZ() void { + var array = [5:0]u8{ 1, 2, 3, 4, 5 }; + var pointer: [*:0]u8 = &array; + comptime expect(@TypeOf(pointer[1..3]) == *[2]u8); + comptime expect(@TypeOf(pointer[1..3 :4]) == *[2:4]u8); + } + + fn testPointer0() void { + var pointer: [*]u0 = &[1]u0{0}; + var slice = pointer[0..1]; + comptime expect(@TypeOf(slice) == *[1]u0); + expect(slice[0] == 0); + } + + fn testPointerAlign() void { + var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; + var pointer: [*]align(4) u8 = &array; + var slice = pointer[4..5]; + comptime expect(@TypeOf(slice) == *align(4) [1]u8); + expect(slice[0] == 5); + comptime expect(@TypeOf(pointer[0..2]) == *align(4) [2]u8); + } + + fn testSlice() void { + var array = [5]u8{ 1, 2, 3, 4, 5 }; + var src_slice: []u8 = &array; + var slice = src_slice[1..3]; + comptime expect(@TypeOf(slice) == *[2]u8); + expect(slice[0] == 2); + expect(slice[1] == 3); + } + + fn testSliceZ() void { + var array = [5:0]u8{ 1, 2, 3, 4, 5 }; + var slice: [:0]u8 = &array; + comptime expect(@TypeOf(slice[1..3]) == *[2]u8); + comptime expect(@TypeOf(slice[1..]) == [:0]u8); + comptime expect(@TypeOf(slice[1..3 :4]) == *[2:4]u8); + } + + fn testSliceOpt() void { + var array: [2]u8 = [2]u8{ 1, 2 }; + var slice: ?[]u8 = &array; + comptime expect(@TypeOf(&array, slice) == ?[]u8); + comptime expect(@TypeOf(slice.?[0..2]) == *[2]u8); + } + + fn testSlice0() void { + { + var array = [0]u8{}; + var src_slice: []u8 = &array; + var slice = src_slice[0..0]; + comptime expect(@TypeOf(slice) == *[0]u8); + } + { + var array = [0:0]u8{}; + var src_slice: [:0]u8 = &array; + var slice = src_slice[0..0]; + comptime expect(@TypeOf(slice) == *[0]u8); + } + } + + fn testSliceAlign() void { + var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; + var src_slice: []align(4) u8 = &array; + var slice = src_slice[4..5]; + comptime expect(@TypeOf(slice) == *align(4) [1]u8); + expect(slice[0] == 5); + comptime expect(@TypeOf(src_slice[0..2]) == *align(4) [2]u8); + } + }; + + S.doTheTest(); + comptime S.doTheTest(); +} + +test "slice of hardcoded address to pointer" { + const S = struct { + fn doTheTest() void { + const pointer = @intToPtr([*]u8, 0x04)[0..2]; + comptime expect(@TypeOf(pointer) == *[2]u8); + const slice: []const u8 = pointer; + expect(@ptrToInt(slice.ptr) == 4); + expect(slice.len == 2); + } + }; + + S.doTheTest(); +} diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index ecec7fe5d6..0365991ed3 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -409,8 +409,8 @@ const Bitfields = packed struct { test "native bit field understands endianness" { var all: u64 = 0x7765443322221111; var bytes: [8]u8 = undefined; - @memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8); - var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*; + @memcpy(&bytes, @ptrCast([*]u8, &all), 8); + var bitfields = @ptrCast(*Bitfields, &bytes).*; expect(bitfields.f1 == 0x1111); expect(bitfields.f2 == 0x2222); diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig index 7f49049f58..be7a84c5b4 100644 --- a/test/stage1/behavior/union.zig +++ b/test/stage1/behavior/union.zig @@ -1,5 +1,6 @@ const std = @import("std"); const expect = std.testing.expect; +const expectEqual = std.testing.expectEqual; const Value = union(enum) { Int: u64, @@ -638,3 +639,30 @@ test "runtime tag name with single field" { var v = U{ .A = 42 }; expect(std.mem.eql(u8, @tagName(v), "A")); } + +test "cast from anonymous struct to union" { + const S = struct { + const U = union(enum) { + A: u32, + B: []const u8, + C: void, + }; + fn doTheTest() void { + var y: u32 = 42; + const t0 = .{ .A = 123 }; + const t1 = .{ .B = "foo" }; + const t2 = .{ .C = {} }; + const t3 = .{ .A = y }; + const x0: U = t0; + var x1: U = t1; + const x2: U = t2; + var x3: U = t3; + expect(x0.A == 123); + expect(std.mem.eql(u8, x1.B, "foo")); + expect(x2 == .C); + expect(x3.A == y); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} diff --git a/test/standalone/mix_o_files/test.c b/test/standalone/mix_o_files/test.c index 7f9f751a4a..e5e77a8f3e 100644 --- a/test/standalone/mix_o_files/test.c +++ b/test/standalone/mix_o_files/test.c @@ -1,10 +1,12 @@ -// This header is generated by zig from base64.zig -#include "base64.h" - #include #include #include +// TODO we would like to #include "base64.h" here but this feature has been disabled in +// the stage1 compiler. Users will have to wait until self-hosted is available for +// the "generate .h file" feature. +size_t decode_base_64(uint8_t *dest_ptr, size_t dest_len, const uint8_t *source_ptr, size_t source_len); + extern int *x_ptr; int main(int argc, char **argv) { diff --git a/test/standalone/shared_library/test.c b/test/standalone/shared_library/test.c index b60a6a5a75..f178f78b45 100644 --- a/test/standalone/shared_library/test.c +++ b/test/standalone/shared_library/test.c @@ -1,6 +1,12 @@ -#include "mathtest.h" #include +// TODO we would like to #include "mathtest.h" here but this feature has been disabled in +// the stage1 compiler. Users will have to wait until self-hosted is available for +// the "generate .h file" feature. + +#include +int32_t add(int32_t a, int32_t b); + int main(int argc, char **argv) { assert(add(42, 1337) == 1379); return 0; diff --git a/tools/process_headers.zig b/tools/process_headers.zig index abdc9fabf9..7c9befcffa 100644 --- a/tools/process_headers.zig +++ b/tools/process_headers.zig @@ -1,14 +1,14 @@ -// To get started, run this tool with no args and read the help message. -// -// The build systems of musl-libc and glibc require specifying a single target -// architecture. Meanwhile, Zig supports out-of-the-box cross compilation for -// every target. So the process to create libc headers that Zig ships is to use -// this tool. -// First, use the musl/glibc build systems to create installations of all the -// targets in the `glibc_targets`/`musl_targets` variables. -// Next, run this tool to create a new directory which puts .h files into -// subdirectories, with `generic` being files that apply to all architectures. -// You'll then have to manually update Zig source repo with these new files. +//! To get started, run this tool with no args and read the help message. +//! +//! The build systems of musl-libc and glibc require specifying a single target +//! architecture. Meanwhile, Zig supports out-of-the-box cross compilation for +//! every target. So the process to create libc headers that Zig ships is to use +//! this tool. +//! First, use the musl/glibc build systems to create installations of all the +//! targets in the `glibc_targets`/`musl_targets` variables. +//! Next, run this tool to create a new directory which puts .h files into +//! subdirectories, with `generic` being files that apply to all architectures. +//! You'll then have to manually update Zig source repo with these new files. const std = @import("std"); const Arch = std.Target.Cpu.Arch; diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig new file mode 100644 index 0000000000..f65c89c258 --- /dev/null +++ b/tools/update_clang_options.zig @@ -0,0 +1,460 @@ +//! To get started, run this tool with no args and read the help message. +//! +//! Clang has a file "options.td" which describes all of its command line parameter options. +//! When using `zig cc`, Zig acts as a proxy between the user and Clang. It does not need +//! to understand all the parameters, but it does need to understand some of them, such as +//! the target. This means that Zig must understand when a C command line parameter expects +//! to "consume" the next parameter on the command line. +//! +//! For example, `-z -target` would mean to pass `-target` to the linker, whereas `-E -target` +//! would mean that the next parameter specifies the target. + +const std = @import("std"); +const fs = std.fs; +const assert = std.debug.assert; +const json = std.json; + +const KnownOpt = struct { + name: []const u8, + + /// Corresponds to stage.zig ClangArgIterator.Kind + ident: []const u8, +}; + +const known_options = [_]KnownOpt{ + .{ + .name = "target", + .ident = "target", + }, + .{ + .name = "o", + .ident = "o", + }, + .{ + .name = "c", + .ident = "c", + }, + .{ + .name = "l", + .ident = "l", + }, + .{ + .name = "pipe", + .ident = "ignore", + }, + .{ + .name = "help", + .ident = "driver_punt", + }, + .{ + .name = "fPIC", + .ident = "pic", + }, + .{ + .name = "fno-PIC", + .ident = "no_pic", + }, + .{ + .name = "nostdlib", + .ident = "nostdlib", + }, + .{ + .name = "no-standard-libraries", + .ident = "nostdlib", + }, + .{ + .name = "shared", + .ident = "shared", + }, + .{ + .name = "rdynamic", + .ident = "rdynamic", + }, + .{ + .name = "Wl,", + .ident = "wl", + }, + .{ + .name = "E", + .ident = "preprocess", + }, + .{ + .name = "preprocess", + .ident = "preprocess", + }, + .{ + .name = "S", + .ident = "driver_punt", + }, + .{ + .name = "assemble", + .ident = "driver_punt", + }, + .{ + .name = "O1", + .ident = "optimize", + }, + .{ + .name = "O2", + .ident = "optimize", + }, + .{ + .name = "Og", + .ident = "optimize", + }, + .{ + .name = "O", + .ident = "optimize", + }, + .{ + .name = "Ofast", + .ident = "optimize", + }, + .{ + .name = "optimize", + .ident = "optimize", + }, + .{ + .name = "g", + .ident = "debug", + }, + .{ + .name = "debug", + .ident = "debug", + }, + .{ + .name = "g-dwarf", + .ident = "debug", + }, + .{ + .name = "g-dwarf-2", + .ident = "debug", + }, + .{ + .name = "g-dwarf-3", + .ident = "debug", + }, + .{ + .name = "g-dwarf-4", + .ident = "debug", + }, + .{ + .name = "g-dwarf-5", + .ident = "debug", + }, + .{ + .name = "fsanitize", + .ident = "sanitize", + }, +}; + +const blacklisted_options = [_][]const u8{}; + +fn knownOption(name: []const u8) ?[]const u8 { + const chopped_name = if (std.mem.endsWith(u8, name, "=")) name[0 .. name.len - 1] else name; + for (known_options) |item| { + if (std.mem.eql(u8, chopped_name, item.name)) { + return item.ident; + } + } + return null; +} + +pub fn main() anyerror!void { + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer arena.deinit(); + + const allocator = &arena.allocator; + const args = try std.process.argsAlloc(allocator); + + if (args.len <= 1) { + usageAndExit(std.io.getStdErr(), args[0], 1); + } + if (std.mem.eql(u8, args[1], "--help")) { + usageAndExit(std.io.getStdOut(), args[0], 0); + } + if (args.len < 3) { + usageAndExit(std.io.getStdErr(), args[0], 1); + } + + const llvm_tblgen_exe = args[1]; + if (std.mem.startsWith(u8, llvm_tblgen_exe, "-")) { + usageAndExit(std.io.getStdErr(), args[0], 1); + } + + const llvm_src_root = args[2]; + if (std.mem.startsWith(u8, llvm_src_root, "-")) { + usageAndExit(std.io.getStdErr(), args[0], 1); + } + + const child_args = [_][]const u8{ + llvm_tblgen_exe, + "--dump-json", + try std.fmt.allocPrint(allocator, "{}/clang/include/clang/Driver/Options.td", .{llvm_src_root}), + try std.fmt.allocPrint(allocator, "-I={}/llvm/include", .{llvm_src_root}), + try std.fmt.allocPrint(allocator, "-I={}/clang/include/clang/Driver", .{llvm_src_root}), + }; + + const child_result = try std.ChildProcess.exec2(.{ + .allocator = allocator, + .argv = &child_args, + .max_output_bytes = 100 * 1024 * 1024, + }); + + std.debug.warn("{}\n", .{child_result.stderr}); + + const json_text = switch (child_result.term) { + .Exited => |code| if (code == 0) child_result.stdout else { + std.debug.warn("llvm-tblgen exited with code {}\n", .{code}); + std.process.exit(1); + }, + else => { + std.debug.warn("llvm-tblgen crashed\n", .{}); + std.process.exit(1); + }, + }; + + var parser = json.Parser.init(allocator, false); + const tree = try parser.parse(json_text); + const root_map = &tree.root.Object; + + var all_objects = std.ArrayList(*json.ObjectMap).init(allocator); + { + var it = root_map.iterator(); + it_map: while (it.next()) |kv| { + if (kv.key.len == 0) continue; + if (kv.key[0] == '!') continue; + if (kv.value != .Object) continue; + if (!kv.value.Object.contains("NumArgs")) continue; + if (!kv.value.Object.contains("Name")) continue; + for (blacklisted_options) |blacklisted_key| { + if (std.mem.eql(u8, blacklisted_key, kv.key)) continue :it_map; + } + if (kv.value.Object.get("Name").?.value.String.len == 0) continue; + try all_objects.append(&kv.value.Object); + } + } + // Some options have multiple matches. As an example, "-Wl,foo" matches both + // "W" and "Wl,". So we sort this list in order of descending priority. + std.sort.sort(*json.ObjectMap, all_objects.span(), objectLessThan); + + var stdout_bos = std.io.bufferedOutStream(std.io.getStdOut().outStream()); + const stdout = stdout_bos.outStream(); + try stdout.writeAll( + \\// This file is generated by tools/update_clang_options.zig. + \\// zig fmt: off + \\usingnamespace @import("clang_options.zig"); + \\pub const data = blk: { @setEvalBranchQuota(6000); break :blk &[_]CliArg{ + \\ + ); + + for (all_objects.span()) |obj| { + const name = obj.get("Name").?.value.String; + var pd1 = false; + var pd2 = false; + var pslash = false; + for (obj.get("Prefixes").?.value.Array.span()) |prefix_json| { + const prefix = prefix_json.String; + if (std.mem.eql(u8, prefix, "-")) { + pd1 = true; + } else if (std.mem.eql(u8, prefix, "--")) { + pd2 = true; + } else if (std.mem.eql(u8, prefix, "/")) { + pslash = true; + } else { + std.debug.warn("{} has unrecognized prefix '{}'\n", .{ name, prefix }); + std.process.exit(1); + } + } + const syntax = objSyntax(obj); + + if (knownOption(name)) |ident| { + try stdout.print( + \\.{{ + \\ .name = "{}", + \\ .syntax = {}, + \\ .zig_equivalent = .{}, + \\ .pd1 = {}, + \\ .pd2 = {}, + \\ .psl = {}, + \\}}, + \\ + , .{ name, syntax, ident, pd1, pd2, pslash }); + } else if (pd1 and !pd2 and !pslash and syntax == .flag) { + try stdout.print("flagpd1(\"{}\"),\n", .{name}); + } else if (pd1 and !pd2 and !pslash and syntax == .joined) { + try stdout.print("joinpd1(\"{}\"),\n", .{name}); + } else if (pd1 and !pd2 and !pslash and syntax == .joined_or_separate) { + try stdout.print("jspd1(\"{}\"),\n", .{name}); + } else if (pd1 and !pd2 and !pslash and syntax == .separate) { + try stdout.print("sepd1(\"{}\"),\n", .{name}); + } else { + try stdout.print( + \\.{{ + \\ .name = "{}", + \\ .syntax = {}, + \\ .zig_equivalent = .other, + \\ .pd1 = {}, + \\ .pd2 = {}, + \\ .psl = {}, + \\}}, + \\ + , .{ name, syntax, pd1, pd2, pslash }); + } + } + + try stdout.writeAll( + \\};}; + \\ + ); + + try stdout_bos.flush(); +} + +// TODO we should be able to import clang_options.zig but currently this is problematic because it will +// import stage2.zig and that causes a bunch of stuff to get exported +const Syntax = union(enum) { + /// A flag with no values. + flag, + + /// An option which prefixes its (single) value. + joined, + + /// An option which is followed by its value. + separate, + + /// An option which is either joined to its (non-empty) value, or followed by its value. + joined_or_separate, + + /// An option which is both joined to its (first) value, and followed by its (second) value. + joined_and_separate, + + /// An option followed by its values, which are separated by commas. + comma_joined, + + /// An option which consumes an optional joined argument and any other remaining arguments. + remaining_args_joined, + + /// An option which is which takes multiple (separate) arguments. + multi_arg: u8, + + pub fn format( + self: Syntax, + comptime fmt: []const u8, + options: std.fmt.FormatOptions, + out_stream: var, + ) !void { + switch (self) { + .multi_arg => |n| return out_stream.print(".{{.{}={}}}", .{ @tagName(self), n }), + else => return out_stream.print(".{}", .{@tagName(self)}), + } + } +}; + +fn objSyntax(obj: *json.ObjectMap) Syntax { + const num_args = @intCast(u8, obj.get("NumArgs").?.value.Integer); + for (obj.get("!superclasses").?.value.Array.span()) |superclass_json| { + const superclass = superclass_json.String; + if (std.mem.eql(u8, superclass, "Joined")) { + return .joined; + } else if (std.mem.eql(u8, superclass, "CLJoined")) { + return .joined; + } else if (std.mem.eql(u8, superclass, "CLIgnoredJoined")) { + return .joined; + } else if (std.mem.eql(u8, superclass, "CLCompileJoined")) { + return .joined; + } else if (std.mem.eql(u8, superclass, "JoinedOrSeparate")) { + return .joined_or_separate; + } else if (std.mem.eql(u8, superclass, "CLJoinedOrSeparate")) { + return .joined_or_separate; + } else if (std.mem.eql(u8, superclass, "CLCompileJoinedOrSeparate")) { + return .joined_or_separate; + } else if (std.mem.eql(u8, superclass, "Flag")) { + return .flag; + } else if (std.mem.eql(u8, superclass, "CLFlag")) { + return .flag; + } else if (std.mem.eql(u8, superclass, "CLIgnoredFlag")) { + return .flag; + } else if (std.mem.eql(u8, superclass, "Separate")) { + return .separate; + } else if (std.mem.eql(u8, superclass, "JoinedAndSeparate")) { + return .joined_and_separate; + } else if (std.mem.eql(u8, superclass, "CommaJoined")) { + return .comma_joined; + } else if (std.mem.eql(u8, superclass, "CLRemainingArgsJoined")) { + return .remaining_args_joined; + } else if (std.mem.eql(u8, superclass, "MultiArg")) { + return .{ .multi_arg = num_args }; + } + } + const name = obj.get("Name").?.value.String; + if (std.mem.eql(u8, name, "")) { + return .flag; + } else if (std.mem.eql(u8, name, "")) { + return .flag; + } + const kind_def = obj.get("Kind").?.value.Object.get("def").?.value.String; + if (std.mem.eql(u8, kind_def, "KIND_FLAG")) { + return .flag; + } + const key = obj.get("!name").?.value.String; + std.debug.warn("{} (key {}) has unrecognized superclasses:\n", .{ name, key }); + for (obj.get("!superclasses").?.value.Array.span()) |superclass_json| { + std.debug.warn(" {}\n", .{superclass_json.String}); + } + std.process.exit(1); +} + +fn syntaxMatchesWithEql(syntax: Syntax) bool { + return switch (syntax) { + .flag, + .separate, + .multi_arg, + => true, + + .joined, + .joined_or_separate, + .joined_and_separate, + .comma_joined, + .remaining_args_joined, + => false, + }; +} + +fn objectLessThan(a: *json.ObjectMap, b: *json.ObjectMap) bool { + // Priority is determined by exact matches first, followed by prefix matches in descending + // length, with key as a final tiebreaker. + const a_syntax = objSyntax(a); + const b_syntax = objSyntax(b); + + const a_match_with_eql = syntaxMatchesWithEql(a_syntax); + const b_match_with_eql = syntaxMatchesWithEql(b_syntax); + + if (a_match_with_eql and !b_match_with_eql) { + return true; + } else if (!a_match_with_eql and b_match_with_eql) { + return false; + } + + if (!a_match_with_eql and !b_match_with_eql) { + const a_name = a.get("Name").?.value.String; + const b_name = b.get("Name").?.value.String; + if (a_name.len != b_name.len) { + return a_name.len > b_name.len; + } + } + + const a_key = a.get("!name").?.value.String; + const b_key = b.get("!name").?.value.String; + return std.mem.lessThan(u8, a_key, b_key); +} + +fn usageAndExit(file: fs.File, arg0: []const u8, code: u8) noreturn { + file.outStream().print( + \\Usage: {} /path/to/llvm-tblgen /path/to/git/llvm/llvm-project + \\ + \\Prints to stdout Zig code which you can use to replace the file src-self-hosted/clang_options_data.zig. + \\ + , .{arg0}) catch std.process.exit(1); + std.process.exit(code); +} diff --git a/tools/update_glibc.zig b/tools/update_glibc.zig index 84522aabe4..4a5b1751a2 100644 --- a/tools/update_glibc.zig +++ b/tools/update_glibc.zig @@ -20,6 +20,7 @@ const lib_names = [_][]const u8{ "m", "pthread", "rt", + "ld", }; // fpu/nofpu are hardcoded elsewhere, based on .gnueabi/.gnueabihf with an exception for .arm @@ -154,22 +155,24 @@ pub fn main() !void { const fn_set = &target_funcs_gop.kv.value.list; for (lib_names) |lib_name, lib_name_index| { - const basename = try fmt.allocPrint(allocator, "lib{}.abilist", .{lib_name}); + const lib_prefix = if (std.mem.eql(u8, lib_name, "ld")) "" else "lib"; + const basename = try fmt.allocPrint(allocator, "{}{}.abilist", .{ lib_prefix, lib_name }); const abi_list_filename = blk: { - if (abi_list.targets[0].abi == .gnuabi64 and std.mem.eql(u8, lib_name, "c")) { + const is_c = std.mem.eql(u8, lib_name, "c"); + const is_m = std.mem.eql(u8, lib_name, "m"); + const is_ld = std.mem.eql(u8, lib_name, "ld"); + if (abi_list.targets[0].abi == .gnuabi64 and (is_c or is_ld)) { break :blk try fs.path.join(allocator, &[_][]const u8{ prefix, abi_list.path, "n64", basename }); - } else if (abi_list.targets[0].abi == .gnuabin32 and std.mem.eql(u8, lib_name, "c")) { + } else if (abi_list.targets[0].abi == .gnuabin32 and (is_c or is_ld)) { break :blk try fs.path.join(allocator, &[_][]const u8{ prefix, abi_list.path, "n32", basename }); } else if (abi_list.targets[0].arch != .arm and abi_list.targets[0].abi == .gnueabihf and - (std.mem.eql(u8, lib_name, "c") or - (std.mem.eql(u8, lib_name, "m") and abi_list.targets[0].arch == .powerpc))) + (is_c or (is_m and abi_list.targets[0].arch == .powerpc))) { break :blk try fs.path.join(allocator, &[_][]const u8{ prefix, abi_list.path, "fpu", basename }); } else if (abi_list.targets[0].arch != .arm and abi_list.targets[0].abi == .gnueabi and - (std.mem.eql(u8, lib_name, "c") or - (std.mem.eql(u8, lib_name, "m") and abi_list.targets[0].arch == .powerpc))) + (is_c or (is_m and abi_list.targets[0].arch == .powerpc))) { break :blk try fs.path.join(allocator, &[_][]const u8{ prefix, abi_list.path, "nofpu", basename }); } else if (abi_list.targets[0].arch == .arm) { @@ -234,8 +237,8 @@ pub fn main() !void { const vers_txt_path = try fs.path.join(allocator, &[_][]const u8{ glibc_out_dir, "vers.txt" }); const vers_txt_file = try fs.cwd().createFile(vers_txt_path, .{}); defer vers_txt_file.close(); - var buffered = std.io.BufferedOutStream(fs.File.WriteError).init(&vers_txt_file.outStream().stream); - const vers_txt = &buffered.stream; + var buffered = std.io.bufferedOutStream(vers_txt_file.outStream()); + const vers_txt = buffered.outStream(); for (global_ver_list) |name, i| { _ = global_ver_set.put(name, i) catch unreachable; try vers_txt.print("{}\n", .{name}); @@ -246,8 +249,8 @@ pub fn main() !void { const fns_txt_path = try fs.path.join(allocator, &[_][]const u8{ glibc_out_dir, "fns.txt" }); const fns_txt_file = try fs.cwd().createFile(fns_txt_path, .{}); defer fns_txt_file.close(); - var buffered = std.io.BufferedOutStream(fs.File.WriteError).init(&fns_txt_file.outStream().stream); - const fns_txt = &buffered.stream; + var buffered = std.io.bufferedOutStream(fns_txt_file.outStream()); + const fns_txt = buffered.outStream(); for (global_fn_list) |name, i| { const kv = global_fn_set.get(name).?; kv.value.index = i; @@ -277,8 +280,8 @@ pub fn main() !void { const abilist_txt_path = try fs.path.join(allocator, &[_][]const u8{ glibc_out_dir, "abi.txt" }); const abilist_txt_file = try fs.cwd().createFile(abilist_txt_path, .{}); defer abilist_txt_file.close(); - var buffered = std.io.BufferedOutStream(fs.File.WriteError).init(&abilist_txt_file.outStream().stream); - const abilist_txt = &buffered.stream; + var buffered = std.io.bufferedOutStream(abilist_txt_file.outStream()); + const abilist_txt = buffered.outStream(); // first iterate over the abi lists for (abi_lists) |*abi_list, abi_index| {