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| {