authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-19 22:19:24-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-19 22:19:24-04:00
log53b5aa812bd9c0229054121a1c196c9b18994d64
tree3c2961c8b70690351a25d3cee22fd52bbb11a60f
parent75bda408cd69f3d3b0cdb00caa26eb8cbeab5f3e
parent28a6c136e9dc9bcf3e04ab0aa38edc21918c78b9
signature Commit is signed but in an unrecognized format.

Merge remote-tracking branch 'origin/master' into llvm10


78 files changed, 2332 insertions(+), 1436 deletions(-)

build.zig+9-5
...@@ -305,10 +305,14 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {...@@ -305,10 +305,14 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
305 dependOnLib(b, exe, ctx.llvm);305 dependOnLib(b, exe, ctx.llvm);
306306
307 if (exe.target.getOsTag() == .linux) {307 if (exe.target.getOsTag() == .linux) {
308 try addCxxKnownPath(b, ctx, exe, "libstdc++.a",308 // First we try to static link against gcc libstdc++. If that doesn't work,
309 \\Unable to determine path to libstdc++.a309 // we fall back to -lc++ and cross our fingers.
310 \\On Fedora, install libstdc++-static and try again.310 addCxxKnownPath(b, ctx, exe, "libstdc++.a", "") catch |err| switch (err) {
311 );311 error.RequiredLibraryNotFound => {
312 exe.linkSystemLibrary("c++");
313 },
314 else => |e| return e,
315 };
312316
313 exe.linkSystemLibrary("pthread");317 exe.linkSystemLibrary("pthread");
314 } else if (exe.target.isFreeBSD()) {318 } else if (exe.target.isFreeBSD()) {
...@@ -327,7 +331,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {...@@ -327,7 +331,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
327 // System compiler, not gcc.331 // System compiler, not gcc.
328 exe.linkSystemLibrary("c++");332 exe.linkSystemLibrary("c++");
329 },333 },
330 else => return err,334 else => |e| return e,
331 }335 }
332 }336 }
333337
doc/docgen.zig+19-3
...@@ -48,7 +48,7 @@ pub fn main() !void {...@@ -48,7 +48,7 @@ pub fn main() !void {
48 var toc = try genToc(allocator, &tokenizer);48 var toc = try genToc(allocator, &tokenizer);
4949
50 try fs.cwd().makePath(tmp_dir_name);50 try fs.cwd().makePath(tmp_dir_name);
51 defer fs.deleteTree(tmp_dir_name) catch {};51 defer fs.cwd().deleteTree(tmp_dir_name) catch {};
5252
53 try genHtml(allocator, &tokenizer, &toc, buffered_out_stream.outStream(), zig_exe);53 try genHtml(allocator, &tokenizer, &toc, buffered_out_stream.outStream(), zig_exe);
54 try buffered_out_stream.flush();54 try buffered_out_stream.flush();
...@@ -1096,6 +1096,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1096,6 +1096,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1096 try build_args.append("-lc");1096 try build_args.append("-lc");
1097 try out.print(" -lc", .{});1097 try out.print(" -lc", .{});
1098 }1098 }
1099 const target = try std.zig.CrossTarget.parse(.{
1100 .arch_os_abi = code.target_str orelse "native",
1101 });
1099 if (code.target_str) |triple| {1102 if (code.target_str) |triple| {
1100 try build_args.appendSlice(&[_][]const u8{ "-target", triple });1103 try build_args.appendSlice(&[_][]const u8{ "-target", triple });
1101 if (!code.is_inline) {1104 if (!code.is_inline) {
...@@ -1150,7 +1153,15 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1150,7 +1153,15 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1150 }1153 }
1151 }1154 }
11521155
1153 const path_to_exe = mem.trim(u8, exec_result.stdout, " \r\n");1156 const path_to_exe_dir = mem.trim(u8, exec_result.stdout, " \r\n");
1157 const path_to_exe_basename = try std.fmt.allocPrint(allocator, "{}{}", .{
1158 code.name,
1159 target.exeFileExt(),
1160 });
1161 const path_to_exe = try fs.path.join(allocator, &[_][]const u8{
1162 path_to_exe_dir,
1163 path_to_exe_basename,
1164 });
1154 const run_args = &[_][]const u8{path_to_exe};1165 const run_args = &[_][]const u8{path_to_exe};
11551166
1156 var exited_with_signal = false;1167 var exited_with_signal = false;
...@@ -1486,7 +1497,12 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var...@@ -1486,7 +1497,12 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var
1486}1497}
14871498
1488fn exec(allocator: *mem.Allocator, env_map: *std.BufMap, args: []const []const u8) !ChildProcess.ExecResult {1499fn exec(allocator: *mem.Allocator, env_map: *std.BufMap, args: []const []const u8) !ChildProcess.ExecResult {
1489 const result = try ChildProcess.exec(allocator, args, null, env_map, max_doc_file_size);1500 const result = try ChildProcess.exec2(.{
1501 .allocator = allocator,
1502 .argv = args,
1503 .env_map = env_map,
1504 .max_output_bytes = max_doc_file_size,
1505 });
1490 switch (result.term) {1506 switch (result.term) {
1491 .Exited => |exit_code| {1507 .Exited => |exit_code| {
1492 if (exit_code != 0) {1508 if (exit_code != 0) {
doc/langref.html.in+16-20
...@@ -2093,8 +2093,9 @@ var foo: u8 align(4) = 100;...@@ -2093,8 +2093,9 @@ var foo: u8 align(4) = 100;
2093test "global variable alignment" {2093test "global variable alignment" {
2094 assert(@TypeOf(&foo).alignment == 4);2094 assert(@TypeOf(&foo).alignment == 4);
2095 assert(@TypeOf(&foo) == *align(4) u8);2095 assert(@TypeOf(&foo) == *align(4) u8);
2096 const slice = @as(*[1]u8, &foo)[0..];2096 const as_pointer_to_array: *[1]u8 = &foo;
2097 assert(@TypeOf(slice) == []align(4) u8);2097 const as_slice: []u8 = as_pointer_to_array;
2098 assert(@TypeOf(as_slice) == []align(4) u8);
2098}2099}
20992100
2100fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; }2101fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; }
...@@ -2187,7 +2188,8 @@ test "basic slices" {...@@ -2187,7 +2188,8 @@ test "basic slices" {
2187 // a slice is that the array's length is part of the type and known at2188 // a slice is that the array's length is part of the type and known at
2188 // compile-time, whereas the slice's length is known at runtime.2189 // compile-time, whereas the slice's length is known at runtime.
2189 // Both can be accessed with the `len` field.2190 // Both can be accessed with the `len` field.
2190 const slice = array[0..array.len];2191 var known_at_runtime_zero: usize = 0;
2192 const slice = array[known_at_runtime_zero..array.len];
2191 assert(&slice[0] == &array[0]);2193 assert(&slice[0] == &array[0]);
2192 assert(slice.len == array.len);2194 assert(slice.len == array.len);
21932195
...@@ -2207,13 +2209,15 @@ test "basic slices" {...@@ -2207,13 +2209,15 @@ test "basic slices" {
2207 {#code_end#}2209 {#code_end#}
2208 <p>This is one reason we prefer slices to pointers.</p>2210 <p>This is one reason we prefer slices to pointers.</p>
2209 {#code_begin|test|slices#}2211 {#code_begin|test|slices#}
2210const assert = @import("std").debug.assert;2212const std = @import("std");
2211const mem = @import("std").mem;2213const assert = std.debug.assert;
2212const fmt = @import("std").fmt;2214const mem = std.mem;
2215const fmt = std.fmt;
22132216
2214test "using slices for strings" {2217test "using slices for strings" {
2215 // Zig has no concept of strings. String literals are arrays of u8, and2218 // Zig has no concept of strings. String literals are const pointers to
2216 // in general the string type is []u8 (slice of u8).2219 // arrays of u8, and by convention parameters that are "strings" are
2220 // expected to be UTF-8 encoded slices of u8.
2217 // Here we coerce [5]u8 to []const u82221 // Here we coerce [5]u8 to []const u8
2218 const hello: []const u8 = "hello";2222 const hello: []const u8 = "hello";
2219 const world: []const u8 = "世界";2223 const world: []const u8 = "世界";
...@@ -2222,7 +2226,7 @@ test "using slices for strings" {...@@ -2222,7 +2226,7 @@ test "using slices for strings" {
2222 // You can use slice syntax on an array to convert an array into a slice.2226 // You can use slice syntax on an array to convert an array into a slice.
2223 const all_together_slice = all_together[0..];2227 const all_together_slice = all_together[0..];
2224 // String concatenation example.2228 // String concatenation example.
2225 const hello_world = try fmt.bufPrint(all_together_slice, "{} {}", .{hello, world});2229 const hello_world = try fmt.bufPrint(all_together_slice, "{} {}", .{ hello, world });
22262230
2227 // Generally, you can use UTF-8 and not worry about whether something is a2231 // Generally, you can use UTF-8 and not worry about whether something is a
2228 // string. If you don't need to deal with individual characters, no need2232 // string. If you don't need to deal with individual characters, no need
...@@ -2239,23 +2243,15 @@ test "slice pointer" {...@@ -2239,23 +2243,15 @@ test "slice pointer" {
2239 slice[2] = 3;2243 slice[2] = 3;
2240 assert(slice[2] == 3);2244 assert(slice[2] == 3);
2241 // The slice is mutable because we sliced a mutable pointer.2245 // The slice is mutable because we sliced a mutable pointer.
2242 assert(@TypeOf(slice) == []u8);2246 // Furthermore, it is actually a pointer to an array, since the start
2247 // and end indexes were both comptime-known.
2248 assert(@TypeOf(slice) == *[5]u8);
22432249
2244 // You can also slice a slice:2250 // You can also slice a slice:
2245 const slice2 = slice[2..3];2251 const slice2 = slice[2..3];
2246 assert(slice2.len == 1);2252 assert(slice2.len == 1);
2247 assert(slice2[0] == 3);2253 assert(slice2[0] == 3);
2248}2254}
2249
2250test "slice widening" {
2251 // Zig supports slice widening and slice narrowing. Cast a slice of u8
2252 // to a slice of anything else, and Zig will perform the length conversion.
2253 const array align(@alignOf(u32)) = [_]u8{ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13 };
2254 const slice = mem.bytesAsSlice(u32, array[0..]);
2255 assert(slice.len == 2);
2256 assert(slice[0] == 0x12121212);
2257 assert(slice[1] == 0x13131313);
2258}
2259 {#code_end#}2255 {#code_end#}
2260 {#see_also|Pointers|for|Arrays#}2256 {#see_also|Pointers|for|Arrays#}
22612257
lib/std/build.zig+26-12
...@@ -377,7 +377,7 @@ pub const Builder = struct {...@@ -377,7 +377,7 @@ pub const Builder = struct {
377 if (self.verbose) {377 if (self.verbose) {
378 warn("rm {}\n", .{full_path});378 warn("rm {}\n", .{full_path});
379 }379 }
380 fs.deleteTree(full_path) catch {};380 fs.cwd().deleteTree(full_path) catch {};
381 }381 }
382382
383 // TODO remove empty directories383 // TODO remove empty directories
...@@ -847,7 +847,8 @@ pub const Builder = struct {...@@ -847,7 +847,8 @@ pub const Builder = struct {
847 if (self.verbose) {847 if (self.verbose) {
848 warn("cp {} {} ", .{ source_path, dest_path });848 warn("cp {} {} ", .{ source_path, dest_path });
849 }849 }
850 const prev_status = try fs.updateFile(source_path, dest_path);850 const cwd = fs.cwd();
851 const prev_status = try fs.Dir.updateFile(cwd, source_path, cwd, dest_path, .{});
851 if (self.verbose) switch (prev_status) {852 if (self.verbose) switch (prev_status) {
852 .stale => warn("# installed\n", .{}),853 .stale => warn("# installed\n", .{}),
853 .fresh => warn("# up-to-date\n", .{}),854 .fresh => warn("# up-to-date\n", .{}),
...@@ -1157,8 +1158,14 @@ pub const LibExeObjStep = struct {...@@ -1157,8 +1158,14 @@ pub const LibExeObjStep = struct {
11571158
1158 valgrind_support: ?bool = null,1159 valgrind_support: ?bool = null,
11591160
1161 /// Create a .eh_frame_hdr section and a PT_GNU_EH_FRAME segment in the ELF
1162 /// file.
1160 link_eh_frame_hdr: bool = false,1163 link_eh_frame_hdr: bool = false,
11611164
1165 /// Place every function in its own section so that unused ones may be
1166 /// safely garbage-collected during the linking phase.
1167 link_function_sections: bool = false,
1168
1162 /// Uses system Wine installation to run cross compiled Windows build artifacts.1169 /// Uses system Wine installation to run cross compiled Windows build artifacts.
1163 enable_wine: bool = false,1170 enable_wine: bool = false,
11641171
...@@ -1884,7 +1891,9 @@ pub const LibExeObjStep = struct {...@@ -1884,7 +1891,9 @@ pub const LibExeObjStep = struct {
1884 if (self.link_eh_frame_hdr) {1891 if (self.link_eh_frame_hdr) {
1885 try zig_args.append("--eh-frame-hdr");1892 try zig_args.append("--eh-frame-hdr");
1886 }1893 }
18871894 if (self.link_function_sections) {
1895 try zig_args.append("-ffunction-sections");
1896 }
1888 if (self.single_threaded) {1897 if (self.single_threaded) {
1889 try zig_args.append("--single-threaded");1898 try zig_args.append("--single-threaded");
1890 }1899 }
...@@ -2144,17 +2153,22 @@ pub const LibExeObjStep = struct {...@@ -2144,17 +2153,22 @@ pub const LibExeObjStep = struct {
2144 try zig_args.append("--cache");2153 try zig_args.append("--cache");
2145 try zig_args.append("on");2154 try zig_args.append("on");
21462155
2147 const output_path_nl = try builder.execFromStep(zig_args.toSliceConst(), &self.step);2156 const output_dir_nl = try builder.execFromStep(zig_args.toSliceConst(), &self.step);
2148 const output_path = mem.trimRight(u8, output_path_nl, "\r\n");2157 const build_output_dir = mem.trimRight(u8, output_dir_nl, "\r\n");
21492158
2150 if (self.output_dir) |output_dir| {2159 if (self.output_dir) |output_dir| {
2151 const full_dest = try fs.path.join(builder.allocator, &[_][]const u8{2160 var src_dir = try std.fs.cwd().openDir(build_output_dir, .{ .iterate = true });
2152 output_dir,2161 defer src_dir.close();
2153 fs.path.basename(output_path),2162
2154 });2163 var dest_dir = try std.fs.cwd().openDir(output_dir, .{});
2155 try builder.updateFile(output_path, full_dest);2164 defer dest_dir.close();
2165
2166 var it = src_dir.iterate();
2167 while (try it.next()) |entry| {
2168 _ = try src_dir.updateFile(entry.name, dest_dir, entry.name, .{});
2169 }
2156 } else {2170 } else {
2157 self.output_dir = fs.path.dirname(output_path).?;2171 self.output_dir = build_output_dir;
2158 }2172 }
2159 }2173 }
21602174
...@@ -2352,7 +2366,7 @@ pub const RemoveDirStep = struct {...@@ -2352,7 +2366,7 @@ pub const RemoveDirStep = struct {
2352 const self = @fieldParentPtr(RemoveDirStep, "step", step);2366 const self = @fieldParentPtr(RemoveDirStep, "step", step);
23532367
2354 const full_path = self.builder.pathFromRoot(self.dir_path);2368 const full_path = self.builder.pathFromRoot(self.dir_path);
2355 fs.deleteTree(full_path) catch |err| {2369 fs.cwd().deleteTree(full_path) catch |err| {
2356 warn("Unable to remove {}: {}\n", .{ full_path, @errorName(err) });2370 warn("Unable to remove {}: {}\n", .{ full_path, @errorName(err) });
2357 return err;2371 return err;
2358 };2372 };
lib/std/build/run.zig+3-1
...@@ -29,6 +29,8 @@ pub const RunStep = struct {...@@ -29,6 +29,8 @@ pub const RunStep = struct {
29 stdout_action: StdIoAction = .inherit,29 stdout_action: StdIoAction = .inherit,
30 stderr_action: StdIoAction = .inherit,30 stderr_action: StdIoAction = .inherit,
3131
32 stdin_behavior: std.ChildProcess.StdIo = .Inherit,
33
32 expected_exit_code: u8 = 0,34 expected_exit_code: u8 = 0,
3335
34 pub const StdIoAction = union(enum) {36 pub const StdIoAction = union(enum) {
...@@ -159,7 +161,7 @@ pub const RunStep = struct {...@@ -159,7 +161,7 @@ pub const RunStep = struct {
159 child.cwd = cwd;161 child.cwd = cwd;
160 child.env_map = self.env_map orelse self.builder.env_map;162 child.env_map = self.env_map orelse self.builder.env_map;
161163
162 child.stdin_behavior = .Ignore;164 child.stdin_behavior = self.stdin_behavior;
163 child.stdout_behavior = stdIoActionToBehavior(self.stdout_action);165 child.stdout_behavior = stdIoActionToBehavior(self.stdout_action);
164 child.stderr_behavior = stdIoActionToBehavior(self.stderr_action);166 child.stderr_behavior = stdIoActionToBehavior(self.stderr_action);
165167
lib/std/build/write_file.zig+1-1
...@@ -78,7 +78,7 @@ pub const WriteFileStep = struct {...@@ -78,7 +78,7 @@ pub const WriteFileStep = struct {
78 warn("unable to make path {}: {}\n", .{ self.output_dir, @errorName(err) });78 warn("unable to make path {}: {}\n", .{ self.output_dir, @errorName(err) });
79 return err;79 return err;
80 };80 };
81 var dir = try fs.cwd().openDirTraverse(self.output_dir);81 var dir = try fs.cwd().openDir(self.output_dir, .{});
82 defer dir.close();82 defer dir.close();
83 for (self.files.toSliceConst()) |file| {83 for (self.files.toSliceConst()) |file| {
84 dir.writeFile(file.basename, file.bytes) catch |err| {84 dir.writeFile(file.basename, file.bytes) catch |err| {
lib/std/c.zig+1
...@@ -106,6 +106,7 @@ pub extern "c" fn mkdir(path: [*:0]const u8, mode: c_uint) c_int;...@@ -106,6 +106,7 @@ pub extern "c" fn mkdir(path: [*:0]const u8, mode: c_uint) c_int;
106pub extern "c" fn mkdirat(dirfd: fd_t, path: [*:0]const u8, mode: u32) c_int;106pub extern "c" fn mkdirat(dirfd: fd_t, path: [*:0]const u8, mode: u32) c_int;
107pub extern "c" fn symlink(existing: [*:0]const u8, new: [*:0]const u8) c_int;107pub extern "c" fn symlink(existing: [*:0]const u8, new: [*:0]const u8) c_int;
108pub extern "c" fn rename(old: [*:0]const u8, new: [*:0]const u8) c_int;108pub extern "c" fn rename(old: [*:0]const u8, new: [*:0]const u8) c_int;
109pub extern "c" fn renameat(olddirfd: fd_t, old: [*:0]const u8, newdirfd: fd_t, new: [*:0]const u8) c_int;
109pub extern "c" fn chdir(path: [*:0]const u8) c_int;110pub extern "c" fn chdir(path: [*:0]const u8) c_int;
110pub extern "c" fn fchdir(fd: fd_t) c_int;111pub extern "c" fn fchdir(fd: fd_t) c_int;
111pub extern "c" fn execve(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) c_int;112pub extern "c" fn execve(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) c_int;
lib/std/crypto/aes.zig+19-19
...@@ -15,10 +15,10 @@ fn rotw(w: u32) u32 {...@@ -15,10 +15,10 @@ fn rotw(w: u32) u32 {
1515
16// Encrypt one block from src into dst, using the expanded key xk.16// Encrypt one block from src into dst, using the expanded key xk.
17fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {17fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {
18 var s0 = mem.readIntSliceBig(u32, src[0..4]);18 var s0 = mem.readIntBig(u32, src[0..4]);
19 var s1 = mem.readIntSliceBig(u32, src[4..8]);19 var s1 = mem.readIntBig(u32, src[4..8]);
20 var s2 = mem.readIntSliceBig(u32, src[8..12]);20 var s2 = mem.readIntBig(u32, src[8..12]);
21 var s3 = mem.readIntSliceBig(u32, src[12..16]);21 var s3 = mem.readIntBig(u32, src[12..16]);
2222
23 // First round just XORs input with key.23 // First round just XORs input with key.
24 s0 ^= xk[0];24 s0 ^= xk[0];
...@@ -58,18 +58,18 @@ fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {...@@ -58,18 +58,18 @@ fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {
58 s2 ^= xk[k + 2];58 s2 ^= xk[k + 2];
59 s3 ^= xk[k + 3];59 s3 ^= xk[k + 3];
6060
61 mem.writeIntSliceBig(u32, dst[0..4], s0);61 mem.writeIntBig(u32, dst[0..4], s0);
62 mem.writeIntSliceBig(u32, dst[4..8], s1);62 mem.writeIntBig(u32, dst[4..8], s1);
63 mem.writeIntSliceBig(u32, dst[8..12], s2);63 mem.writeIntBig(u32, dst[8..12], s2);
64 mem.writeIntSliceBig(u32, dst[12..16], s3);64 mem.writeIntBig(u32, dst[12..16], s3);
65}65}
6666
67// Decrypt one block from src into dst, using the expanded key xk.67// Decrypt one block from src into dst, using the expanded key xk.
68pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {68pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {
69 var s0 = mem.readIntSliceBig(u32, src[0..4]);69 var s0 = mem.readIntBig(u32, src[0..4]);
70 var s1 = mem.readIntSliceBig(u32, src[4..8]);70 var s1 = mem.readIntBig(u32, src[4..8]);
71 var s2 = mem.readIntSliceBig(u32, src[8..12]);71 var s2 = mem.readIntBig(u32, src[8..12]);
72 var s3 = mem.readIntSliceBig(u32, src[12..16]);72 var s3 = mem.readIntBig(u32, src[12..16]);
7373
74 // First round just XORs input with key.74 // First round just XORs input with key.
75 s0 ^= xk[0];75 s0 ^= xk[0];
...@@ -109,10 +109,10 @@ pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {...@@ -109,10 +109,10 @@ pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void {
109 s2 ^= xk[k + 2];109 s2 ^= xk[k + 2];
110 s3 ^= xk[k + 3];110 s3 ^= xk[k + 3];
111111
112 mem.writeIntSliceBig(u32, dst[0..4], s0);112 mem.writeIntBig(u32, dst[0..4], s0);
113 mem.writeIntSliceBig(u32, dst[4..8], s1);113 mem.writeIntBig(u32, dst[4..8], s1);
114 mem.writeIntSliceBig(u32, dst[8..12], s2);114 mem.writeIntBig(u32, dst[8..12], s2);
115 mem.writeIntSliceBig(u32, dst[12..16], s3);115 mem.writeIntBig(u32, dst[12..16], s3);
116}116}
117117
118fn xorBytes(dst: []u8, a: []const u8, b: []const u8) usize {118fn xorBytes(dst: []u8, a: []const u8, b: []const u8) usize {
...@@ -154,8 +154,8 @@ fn AES(comptime keysize: usize) type {...@@ -154,8 +154,8 @@ fn AES(comptime keysize: usize) type {
154 var n: usize = 0;154 var n: usize = 0;
155 while (n < src.len) {155 while (n < src.len) {
156 ctx.encrypt(keystream[0..], ctrbuf[0..]);156 ctx.encrypt(keystream[0..], ctrbuf[0..]);
157 var ctr_i = std.mem.readIntSliceBig(u128, ctrbuf[0..]);157 var ctr_i = std.mem.readIntBig(u128, ctrbuf[0..]);
158 std.mem.writeIntSliceBig(u128, ctrbuf[0..], ctr_i +% 1);158 std.mem.writeIntBig(u128, ctrbuf[0..], ctr_i +% 1);
159159
160 n += xorBytes(dst[n..], src[n..], &keystream);160 n += xorBytes(dst[n..], src[n..], &keystream);
161 }161 }
...@@ -251,7 +251,7 @@ fn expandKey(key: []const u8, enc: []u32, dec: []u32) void {...@@ -251,7 +251,7 @@ fn expandKey(key: []const u8, enc: []u32, dec: []u32) void {
251 var i: usize = 0;251 var i: usize = 0;
252 var nk = key.len / 4;252 var nk = key.len / 4;
253 while (i < nk) : (i += 1) {253 while (i < nk) : (i += 1) {
254 enc[i] = mem.readIntSliceBig(u32, key[4 * i .. 4 * i + 4]);254 enc[i] = mem.readIntBig(u32, key[4 * i ..][0..4]);
255 }255 }
256 while (i < enc.len) : (i += 1) {256 while (i < enc.len) : (i += 1) {
257 var t = enc[i - 1];257 var t = enc[i - 1];
lib/std/crypto/blake2.zig+4-7
...@@ -123,8 +123,7 @@ fn Blake2s(comptime out_len: usize) type {...@@ -123,8 +123,7 @@ fn Blake2s(comptime out_len: usize) type {
123 const rr = d.h[0 .. out_len / 32];123 const rr = d.h[0 .. out_len / 32];
124124
125 for (rr) |s, j| {125 for (rr) |s, j| {
126 // TODO https://github.com/ziglang/zig/issues/863126 mem.writeIntLittle(u32, out[4 * j ..][0..4], s);
127 mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s);
128 }127 }
129 }128 }
130129
...@@ -135,8 +134,7 @@ fn Blake2s(comptime out_len: usize) type {...@@ -135,8 +134,7 @@ fn Blake2s(comptime out_len: usize) type {
135 var v: [16]u32 = undefined;134 var v: [16]u32 = undefined;
136135
137 for (m) |*r, i| {136 for (m) |*r, i| {
138 // TODO https://github.com/ziglang/zig/issues/863137 r.* = mem.readIntLittle(u32, b[4 * i ..][0..4]);
139 r.* = mem.readIntSliceLittle(u32, b[4 * i .. 4 * i + 4]);
140 }138 }
141139
142 var k: usize = 0;140 var k: usize = 0;
...@@ -358,8 +356,7 @@ fn Blake2b(comptime out_len: usize) type {...@@ -358,8 +356,7 @@ fn Blake2b(comptime out_len: usize) type {
358 const rr = d.h[0 .. out_len / 64];356 const rr = d.h[0 .. out_len / 64];
359357
360 for (rr) |s, j| {358 for (rr) |s, j| {
361 // TODO https://github.com/ziglang/zig/issues/863359 mem.writeIntLittle(u64, out[8 * j ..][0..8], s);
362 mem.writeIntSliceLittle(u64, out[8 * j .. 8 * j + 8], s);
363 }360 }
364 }361 }
365362
...@@ -370,7 +367,7 @@ fn Blake2b(comptime out_len: usize) type {...@@ -370,7 +367,7 @@ fn Blake2b(comptime out_len: usize) type {
370 var v: [16]u64 = undefined;367 var v: [16]u64 = undefined;
371368
372 for (m) |*r, i| {369 for (m) |*r, i| {
373 r.* = mem.readIntSliceLittle(u64, b[8 * i .. 8 * i + 8]);370 r.* = mem.readIntLittle(u64, b[8 * i ..][0..8]);
374 }371 }
375372
376 var k: usize = 0;373 var k: usize = 0;
lib/std/crypto/chacha20.zig+30-31
...@@ -61,8 +61,7 @@ fn salsa20_wordtobyte(out: []u8, input: [16]u32) void {...@@ -61,8 +61,7 @@ fn salsa20_wordtobyte(out: []u8, input: [16]u32) void {
61 }61 }
6262
63 for (x) |_, i| {63 for (x) |_, i| {
64 // TODO https://github.com/ziglang/zig/issues/86364 mem.writeIntLittle(u32, out[4 * i ..][0..4], x[i] +% input[i]);
65 mem.writeIntSliceLittle(u32, out[4 * i .. 4 * i + 4], x[i] +% input[i]);
66 }65 }
67}66}
6867
...@@ -73,10 +72,10 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo...@@ -73,10 +72,10 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo
7372
74 const c = "expand 32-byte k";73 const c = "expand 32-byte k";
75 const constant_le = [_]u32{74 const constant_le = [_]u32{
76 mem.readIntSliceLittle(u32, c[0..4]),75 mem.readIntLittle(u32, c[0..4]),
77 mem.readIntSliceLittle(u32, c[4..8]),76 mem.readIntLittle(u32, c[4..8]),
78 mem.readIntSliceLittle(u32, c[8..12]),77 mem.readIntLittle(u32, c[8..12]),
79 mem.readIntSliceLittle(u32, c[12..16]),78 mem.readIntLittle(u32, c[12..16]),
80 };79 };
8180
82 mem.copy(u32, ctx[0..], constant_le[0..4]);81 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:...@@ -120,19 +119,19 @@ pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce:
120 var k: [8]u32 = undefined;119 var k: [8]u32 = undefined;
121 var c: [4]u32 = undefined;120 var c: [4]u32 = undefined;
122121
123 k[0] = mem.readIntSliceLittle(u32, key[0..4]);122 k[0] = mem.readIntLittle(u32, key[0..4]);
124 k[1] = mem.readIntSliceLittle(u32, key[4..8]);123 k[1] = mem.readIntLittle(u32, key[4..8]);
125 k[2] = mem.readIntSliceLittle(u32, key[8..12]);124 k[2] = mem.readIntLittle(u32, key[8..12]);
126 k[3] = mem.readIntSliceLittle(u32, key[12..16]);125 k[3] = mem.readIntLittle(u32, key[12..16]);
127 k[4] = mem.readIntSliceLittle(u32, key[16..20]);126 k[4] = mem.readIntLittle(u32, key[16..20]);
128 k[5] = mem.readIntSliceLittle(u32, key[20..24]);127 k[5] = mem.readIntLittle(u32, key[20..24]);
129 k[6] = mem.readIntSliceLittle(u32, key[24..28]);128 k[6] = mem.readIntLittle(u32, key[24..28]);
130 k[7] = mem.readIntSliceLittle(u32, key[28..32]);129 k[7] = mem.readIntLittle(u32, key[28..32]);
131130
132 c[0] = counter;131 c[0] = counter;
133 c[1] = mem.readIntSliceLittle(u32, nonce[0..4]);132 c[1] = mem.readIntLittle(u32, nonce[0..4]);
134 c[2] = mem.readIntSliceLittle(u32, nonce[4..8]);133 c[2] = mem.readIntLittle(u32, nonce[4..8]);
135 c[3] = mem.readIntSliceLittle(u32, nonce[8..12]);134 c[3] = mem.readIntLittle(u32, nonce[8..12]);
136 chaCha20_internal(out, in, k, c);135 chaCha20_internal(out, in, k, c);
137}136}
138137
...@@ -147,19 +146,19 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32]...@@ -147,19 +146,19 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32]
147 var k: [8]u32 = undefined;146 var k: [8]u32 = undefined;
148 var c: [4]u32 = undefined;147 var c: [4]u32 = undefined;
149148
150 k[0] = mem.readIntSliceLittle(u32, key[0..4]);149 k[0] = mem.readIntLittle(u32, key[0..4]);
151 k[1] = mem.readIntSliceLittle(u32, key[4..8]);150 k[1] = mem.readIntLittle(u32, key[4..8]);
152 k[2] = mem.readIntSliceLittle(u32, key[8..12]);151 k[2] = mem.readIntLittle(u32, key[8..12]);
153 k[3] = mem.readIntSliceLittle(u32, key[12..16]);152 k[3] = mem.readIntLittle(u32, key[12..16]);
154 k[4] = mem.readIntSliceLittle(u32, key[16..20]);153 k[4] = mem.readIntLittle(u32, key[16..20]);
155 k[5] = mem.readIntSliceLittle(u32, key[20..24]);154 k[5] = mem.readIntLittle(u32, key[20..24]);
156 k[6] = mem.readIntSliceLittle(u32, key[24..28]);155 k[6] = mem.readIntLittle(u32, key[24..28]);
157 k[7] = mem.readIntSliceLittle(u32, key[28..32]);156 k[7] = mem.readIntLittle(u32, key[28..32]);
158157
159 c[0] = @truncate(u32, counter);158 c[0] = @truncate(u32, counter);
160 c[1] = @truncate(u32, counter >> 32);159 c[1] = @truncate(u32, counter >> 32);
161 c[2] = mem.readIntSliceLittle(u32, nonce[0..4]);160 c[2] = mem.readIntLittle(u32, nonce[0..4]);
162 c[3] = mem.readIntSliceLittle(u32, nonce[4..8]);161 c[3] = mem.readIntLittle(u32, nonce[4..8]);
163162
164 const block_size = (1 << 6);163 const block_size = (1 << 6);
165 // The full block size is greater than the address space on a 32bit machine164 // 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,...@@ -463,8 +462,8 @@ pub fn chacha20poly1305Seal(dst: []u8, plaintext: []const u8, data: []const u8,
463 mac.update(zeros[0..padding]);462 mac.update(zeros[0..padding]);
464 }463 }
465 var lens: [16]u8 = undefined;464 var lens: [16]u8 = undefined;
466 mem.writeIntSliceLittle(u64, lens[0..8], data.len);465 mem.writeIntLittle(u64, lens[0..8], data.len);
467 mem.writeIntSliceLittle(u64, lens[8..16], plaintext.len);466 mem.writeIntLittle(u64, lens[8..16], plaintext.len);
468 mac.update(lens[0..]);467 mac.update(lens[0..]);
469 mac.final(dst[plaintext.len..]);468 mac.final(dst[plaintext.len..]);
470}469}
...@@ -500,8 +499,8 @@ pub fn chacha20poly1305Open(dst: []u8, msgAndTag: []const u8, data: []const u8,...@@ -500,8 +499,8 @@ pub fn chacha20poly1305Open(dst: []u8, msgAndTag: []const u8, data: []const u8,
500 mac.update(zeros[0..padding]);499 mac.update(zeros[0..padding]);
501 }500 }
502 var lens: [16]u8 = undefined;501 var lens: [16]u8 = undefined;
503 mem.writeIntSliceLittle(u64, lens[0..8], data.len);502 mem.writeIntLittle(u64, lens[0..8], data.len);
504 mem.writeIntSliceLittle(u64, lens[8..16], ciphertext.len);503 mem.writeIntLittle(u64, lens[8..16], ciphertext.len);
505 mac.update(lens[0..]);504 mac.update(lens[0..]);
506 var computedTag: [16]u8 = undefined;505 var computedTag: [16]u8 = undefined;
507 mac.final(computedTag[0..]);506 mac.final(computedTag[0..]);
lib/std/crypto/md5.zig+1-2
...@@ -112,8 +112,7 @@ pub const Md5 = struct {...@@ -112,8 +112,7 @@ pub const Md5 = struct {
112 d.round(d.buf[0..]);112 d.round(d.buf[0..]);
113113
114 for (d.s) |s, j| {114 for (d.s) |s, j| {
115 // TODO https://github.com/ziglang/zig/issues/863115 mem.writeIntLittle(u32, out[4 * j ..][0..4], s);
116 mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s);
117 }116 }
118 }117 }
119118
lib/std/crypto/poly1305.zig+14-15
...@@ -3,11 +3,11 @@...@@ -3,11 +3,11 @@
3// https://monocypher.org/3// https://monocypher.org/
44
5const std = @import("../std.zig");5const std = @import("../std.zig");
6const builtin = @import("builtin");6const builtin = std.builtin;
77
8const Endian = builtin.Endian;8const Endian = builtin.Endian;
9const readIntSliceLittle = std.mem.readIntSliceLittle;9const readIntLittle = std.mem.readIntLittle;
10const writeIntSliceLittle = std.mem.writeIntSliceLittle;10const writeIntLittle = std.mem.writeIntLittle;
1111
12pub const Poly1305 = struct {12pub const Poly1305 = struct {
13 const Self = @This();13 const Self = @This();
...@@ -59,19 +59,19 @@ pub const Poly1305 = struct {...@@ -59,19 +59,19 @@ pub const Poly1305 = struct {
59 {59 {
60 var i: usize = 0;60 var i: usize = 0;
61 while (i < 1) : (i += 1) {61 while (i < 1) : (i += 1) {
62 ctx.r[0] = readIntSliceLittle(u32, key[0..4]) & 0x0fffffff;62 ctx.r[0] = readIntLittle(u32, key[0..4]) & 0x0fffffff;
63 }63 }
64 }64 }
65 {65 {
66 var i: usize = 1;66 var i: usize = 1;
67 while (i < 4) : (i += 1) {67 while (i < 4) : (i += 1) {
68 ctx.r[i] = readIntSliceLittle(u32, key[i * 4 .. i * 4 + 4]) & 0x0ffffffc;68 ctx.r[i] = readIntLittle(u32, key[i * 4 ..][0..4]) & 0x0ffffffc;
69 }69 }
70 }70 }
71 {71 {
72 var i: usize = 0;72 var i: usize = 0;
73 while (i < 4) : (i += 1) {73 while (i < 4) : (i += 1) {
74 ctx.pad[i] = readIntSliceLittle(u32, key[i * 4 + 16 .. i * 4 + 16 + 4]);74 ctx.pad[i] = readIntLittle(u32, key[i * 4 + 16 ..][0..4]);
75 }75 }
76 }76 }
7777
...@@ -168,10 +168,10 @@ pub const Poly1305 = struct {...@@ -168,10 +168,10 @@ pub const Poly1305 = struct {
168 const nb_blocks = nmsg.len >> 4;168 const nb_blocks = nmsg.len >> 4;
169 var i: usize = 0;169 var i: usize = 0;
170 while (i < nb_blocks) : (i += 1) {170 while (i < nb_blocks) : (i += 1) {
171 ctx.c[0] = readIntSliceLittle(u32, nmsg[0..4]);171 ctx.c[0] = readIntLittle(u32, nmsg[0..4]);
172 ctx.c[1] = readIntSliceLittle(u32, nmsg[4..8]);172 ctx.c[1] = readIntLittle(u32, nmsg[4..8]);
173 ctx.c[2] = readIntSliceLittle(u32, nmsg[8..12]);173 ctx.c[2] = readIntLittle(u32, nmsg[8..12]);
174 ctx.c[3] = readIntSliceLittle(u32, nmsg[12..16]);174 ctx.c[3] = readIntLittle(u32, nmsg[12..16]);
175 polyBlock(ctx);175 polyBlock(ctx);
176 nmsg = nmsg[16..];176 nmsg = nmsg[16..];
177 }177 }
...@@ -210,11 +210,10 @@ pub const Poly1305 = struct {...@@ -210,11 +210,10 @@ pub const Poly1305 = struct {
210 const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000210 const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000
211 const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000211 const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000
212212
213 // TODO https://github.com/ziglang/zig/issues/863213 writeIntLittle(u32, out[0..4], @truncate(u32, uu0));
214 writeIntSliceLittle(u32, out[0..], @truncate(u32, uu0));214 writeIntLittle(u32, out[4..8], @truncate(u32, uu1));
215 writeIntSliceLittle(u32, out[4..], @truncate(u32, uu1));215 writeIntLittle(u32, out[8..12], @truncate(u32, uu2));
216 writeIntSliceLittle(u32, out[8..], @truncate(u32, uu2));216 writeIntLittle(u32, out[12..16], @truncate(u32, uu3));
217 writeIntSliceLittle(u32, out[12..], @truncate(u32, uu3));
218217
219 ctx.secureZero();218 ctx.secureZero();
220 }219 }
lib/std/crypto/sha1.zig+1-2
...@@ -109,8 +109,7 @@ pub const Sha1 = struct {...@@ -109,8 +109,7 @@ pub const Sha1 = struct {
109 d.round(d.buf[0..]);109 d.round(d.buf[0..]);
110110
111 for (d.s) |s, j| {111 for (d.s) |s, j| {
112 // TODO https://github.com/ziglang/zig/issues/863112 mem.writeIntBig(u32, out[4 * j ..][0..4], s);
113 mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s);
114 }113 }
115 }114 }
116115
lib/std/crypto/sha2.zig+2-4
...@@ -167,8 +167,7 @@ fn Sha2_32(comptime params: Sha2Params32) type {...@@ -167,8 +167,7 @@ fn Sha2_32(comptime params: Sha2Params32) type {
167 const rr = d.s[0 .. params.out_len / 32];167 const rr = d.s[0 .. params.out_len / 32];
168168
169 for (rr) |s, j| {169 for (rr) |s, j| {
170 // TODO https://github.com/ziglang/zig/issues/863170 mem.writeIntBig(u32, out[4 * j ..][0..4], s);
171 mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s);
172 }171 }
173 }172 }
174173
...@@ -509,8 +508,7 @@ fn Sha2_64(comptime params: Sha2Params64) type {...@@ -509,8 +508,7 @@ fn Sha2_64(comptime params: Sha2Params64) type {
509 const rr = d.s[0 .. params.out_len / 64];508 const rr = d.s[0 .. params.out_len / 64];
510509
511 for (rr) |s, j| {510 for (rr) |s, j| {
512 // TODO https://github.com/ziglang/zig/issues/863511 mem.writeIntBig(u64, out[8 * j ..][0..8], s);
513 mem.writeIntSliceBig(u64, out[8 * j .. 8 * j + 8], s);
514 }512 }
515 }513 }
516514
lib/std/crypto/sha3.zig+2-3
...@@ -120,7 +120,7 @@ fn keccak_f(comptime F: usize, d: []u8) void {...@@ -120,7 +120,7 @@ fn keccak_f(comptime F: usize, d: []u8) void {
120 var c = [_]u64{0} ** 5;120 var c = [_]u64{0} ** 5;
121121
122 for (s) |*r, i| {122 for (s) |*r, i| {
123 r.* = mem.readIntSliceLittle(u64, d[8 * i .. 8 * i + 8]);123 r.* = mem.readIntLittle(u64, d[8 * i ..][0..8]);
124 }124 }
125125
126 comptime var x: usize = 0;126 comptime var x: usize = 0;
...@@ -167,8 +167,7 @@ fn keccak_f(comptime F: usize, d: []u8) void {...@@ -167,8 +167,7 @@ fn keccak_f(comptime F: usize, d: []u8) void {
167 }167 }
168168
169 for (s) |r, i| {169 for (s) |r, i| {
170 // TODO https://github.com/ziglang/zig/issues/863170 mem.writeIntLittle(u64, d[8 * i ..][0..8], r);
171 mem.writeIntSliceLittle(u64, d[8 * i .. 8 * i + 8], r);
172 }171 }
173}172}
174173
lib/std/crypto/x25519.zig+20-21
...@@ -7,8 +7,8 @@ const builtin = @import("builtin");...@@ -7,8 +7,8 @@ const builtin = @import("builtin");
7const fmt = std.fmt;7const fmt = std.fmt;
88
9const Endian = builtin.Endian;9const Endian = builtin.Endian;
10const readIntSliceLittle = std.mem.readIntSliceLittle;10const readIntLittle = std.mem.readIntLittle;
11const writeIntSliceLittle = std.mem.writeIntSliceLittle;11const writeIntLittle = std.mem.writeIntLittle;
1212
13// Based on Supercop's ref10 implementation.13// Based on Supercop's ref10 implementation.
14pub const X25519 = struct {14pub const X25519 = struct {
...@@ -255,16 +255,16 @@ const Fe = struct {...@@ -255,16 +255,16 @@ const Fe = struct {
255255
256 var t: [10]i64 = undefined;256 var t: [10]i64 = undefined;
257257
258 t[0] = readIntSliceLittle(u32, s[0..4]);258 t[0] = readIntLittle(u32, s[0..4]);
259 t[1] = @as(u32, readIntSliceLittle(u24, s[4..7])) << 6;259 t[1] = @as(u32, readIntLittle(u24, s[4..7])) << 6;
260 t[2] = @as(u32, readIntSliceLittle(u24, s[7..10])) << 5;260 t[2] = @as(u32, readIntLittle(u24, s[7..10])) << 5;
261 t[3] = @as(u32, readIntSliceLittle(u24, s[10..13])) << 3;261 t[3] = @as(u32, readIntLittle(u24, s[10..13])) << 3;
262 t[4] = @as(u32, readIntSliceLittle(u24, s[13..16])) << 2;262 t[4] = @as(u32, readIntLittle(u24, s[13..16])) << 2;
263 t[5] = readIntSliceLittle(u32, s[16..20]);263 t[5] = readIntLittle(u32, s[16..20]);
264 t[6] = @as(u32, readIntSliceLittle(u24, s[20..23])) << 7;264 t[6] = @as(u32, readIntLittle(u24, s[20..23])) << 7;
265 t[7] = @as(u32, readIntSliceLittle(u24, s[23..26])) << 5;265 t[7] = @as(u32, readIntLittle(u24, s[23..26])) << 5;
266 t[8] = @as(u32, readIntSliceLittle(u24, s[26..29])) << 4;266 t[8] = @as(u32, readIntLittle(u24, s[26..29])) << 4;
267 t[9] = (@as(u32, readIntSliceLittle(u24, s[29..32])) & 0x7fffff) << 2;267 t[9] = (@as(u32, readIntLittle(u24, s[29..32])) & 0x7fffff) << 2;
268268
269 carry1(h, t[0..]);269 carry1(h, t[0..]);
270 }270 }
...@@ -544,15 +544,14 @@ const Fe = struct {...@@ -544,15 +544,14 @@ const Fe = struct {
544 ut[i] = @bitCast(u32, @intCast(i32, t[i]));544 ut[i] = @bitCast(u32, @intCast(i32, t[i]));
545 }545 }
546546
547 // TODO https://github.com/ziglang/zig/issues/863547 writeIntLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26));
548 writeIntSliceLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26));548 writeIntLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19));
549 writeIntSliceLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19));549 writeIntLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13));
550 writeIntSliceLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13));550 writeIntLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6));
551 writeIntSliceLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6));551 writeIntLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25));
552 writeIntSliceLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25));552 writeIntLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19));
553 writeIntSliceLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19));553 writeIntLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12));
554 writeIntSliceLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12));554 writeIntLittle(u32, s[28..32], (ut[8] >> 20) | (ut[9] << 6));
555 writeIntSliceLittle(u32, s[28..], (ut[8] >> 20) | (ut[9] << 6));
556555
557 std.mem.secureZero(i64, t[0..]);556 std.mem.secureZero(i64, t[0..]);
558 }557 }
lib/std/fmt.zig+2-1
...@@ -1223,7 +1223,8 @@ test "slice" {...@@ -1223,7 +1223,8 @@ test "slice" {
1223 try testFmt("slice: abc\n", "slice: {}\n", .{value});1223 try testFmt("slice: abc\n", "slice: {}\n", .{value});
1224 }1224 }
1225 {1225 {
1226 const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[0..0];1226 var runtime_zero: usize = 0;
1227 const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[runtime_zero..runtime_zero];
1227 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value});1228 try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value});
1228 }1229 }
12291230
lib/std/fs.zig+231-294
...@@ -81,134 +81,74 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path:...@@ -81,134 +81,74 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path:
81 }81 }
82}82}
8383
84// TODO fix enum literal not casting to error union84pub const PrevStatus = enum {
85const PrevStatus = enum {
86 stale,85 stale,
87 fresh,86 fresh,
88};87};
8988
90pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus {89pub const CopyFileOptions = struct {
91 return updateFileMode(source_path, dest_path, null);90 /// When this is `null` the mode is copied from the source file.
92}91 override_mode: ?File.Mode = null,
92};
9393
94/// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing.94/// Same as `Dir.updateFile`, except asserts that both `source_path` and `dest_path`
95/// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime,95/// are absolute. See `Dir.updateFile` for a function that operates on both
96/// atime, and mode of the source file so that the next call to `updateFile` will not need a copy.96/// absolute and relative paths.
97/// Returns the previous status of the file before updating.97pub fn updateFileAbsolute(
98/// If any of the directories do not exist for dest_path, they are created.98 source_path: []const u8,
99/// TODO rework this to integrate with Dir99 dest_path: []const u8,
100pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !PrevStatus {100 args: CopyFileOptions,
101) !PrevStatus {
102 assert(path.isAbsolute(source_path));
103 assert(path.isAbsolute(dest_path));
101 const my_cwd = cwd();104 const my_cwd = cwd();
102105 return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, args);
103 var src_file = try my_cwd.openFile(source_path, .{});
104 defer src_file.close();
105
106 const src_stat = try src_file.stat();
107 check_dest_stat: {
108 const dest_stat = blk: {
109 var dest_file = my_cwd.openFile(dest_path, .{}) catch |err| switch (err) {
110 error.FileNotFound => break :check_dest_stat,
111 else => |e| return e,
112 };
113 defer dest_file.close();
114
115 break :blk try dest_file.stat();
116 };
117
118 if (src_stat.size == dest_stat.size and
119 src_stat.mtime == dest_stat.mtime and
120 src_stat.mode == dest_stat.mode)
121 {
122 return PrevStatus.fresh;
123 }
124 }
125 const actual_mode = mode orelse src_stat.mode;
126
127 if (path.dirname(dest_path)) |dirname| {
128 try cwd().makePath(dirname);
129 }
130
131 var atomic_file = try AtomicFile.init(dest_path, actual_mode);
132 defer atomic_file.deinit();
133
134 try atomic_file.file.writeFileAll(src_file, .{ .in_len = src_stat.size });
135 try atomic_file.file.updateTimes(src_stat.atime, src_stat.mtime);
136 try atomic_file.finish();
137 return PrevStatus.stale;
138}106}
139107
140/// Guaranteed to be atomic.108/// Same as `Dir.copyFile`, except asserts that both `source_path` and `dest_path`
141/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available,109/// are absolute. See `Dir.copyFile` for a function that operates on both
142/// there is a possibility of power loss or application termination leaving temporary files present110/// absolute and relative paths.
143/// in the same directory as dest_path.111pub fn copyFileAbsolute(source_path: []const u8, dest_path: []const u8, args: CopyFileOptions) !void {
144/// Destination file will have the same mode as the source file.112 assert(path.isAbsolute(source_path));
145/// TODO rework this to integrate with Dir113 assert(path.isAbsolute(dest_path));
146pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void {114 const my_cwd = cwd();
147 var in_file = try cwd().openFile(source_path, .{});115 return Dir.copyFile(my_cwd, source_path, my_cwd, dest_path, args);
148 defer in_file.close();
149
150 const stat = try in_file.stat();
151
152 var atomic_file = try AtomicFile.init(dest_path, stat.mode);
153 defer atomic_file.deinit();
154
155 try atomic_file.file.writeFileAll(in_file, .{ .in_len = stat.size });
156 return atomic_file.finish();
157}
158
159/// Guaranteed to be atomic.
160/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available,
161/// there is a possibility of power loss or application termination leaving temporary files present
162/// in the same directory as dest_path.
163/// TODO rework this to integrate with Dir
164pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void {
165 var in_file = try cwd().openFile(source_path, .{});
166 defer in_file.close();
167
168 var atomic_file = try AtomicFile.init(dest_path, mode);
169 defer atomic_file.deinit();
170
171 try atomic_file.file.writeFileAll(in_file, .{});
172 return atomic_file.finish();
173}116}
174117
175/// TODO update this API to avoid a getrandom syscall for every operation. It118/// TODO update this API to avoid a getrandom syscall for every operation.
176/// should accept a random interface.
177/// TODO rework this to integrate with Dir
178pub const AtomicFile = struct {119pub const AtomicFile = struct {
179 file: File,120 file: File,
180 tmp_path_buf: [MAX_PATH_BYTES]u8,121 tmp_path_buf: [MAX_PATH_BYTES - 1:0]u8,
181 dest_path: []const u8,122 dest_path: []const u8,
182 finished: bool,123 file_open: bool,
124 file_exists: bool,
125 dir: Dir,
183126
184 const InitError = File.OpenError;127 const InitError = File.OpenError;
185128
186 /// dest_path must remain valid for the lifetime of AtomicFile129 /// TODO rename this. Callers should go through Dir API
187 /// call finish to atomically replace dest_path with contents130 pub fn init2(dest_path: []const u8, mode: File.Mode, dir: Dir) InitError!AtomicFile {
188 pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile {
189 const dirname = path.dirname(dest_path);131 const dirname = path.dirname(dest_path);
190 var rand_buf: [12]u8 = undefined;132 var rand_buf: [12]u8 = undefined;
191 const dirname_component_len = if (dirname) |d| d.len + 1 else 0;133 const dirname_component_len = if (dirname) |d| d.len + 1 else 0;
192 const encoded_rand_len = comptime base64.Base64Encoder.calcSize(rand_buf.len);134 const encoded_rand_len = comptime base64.Base64Encoder.calcSize(rand_buf.len);
193 const tmp_path_len = dirname_component_len + encoded_rand_len;135 const tmp_path_len = dirname_component_len + encoded_rand_len;
194 var tmp_path_buf: [MAX_PATH_BYTES]u8 = undefined;136 var tmp_path_buf: [MAX_PATH_BYTES - 1:0]u8 = undefined;
195 if (tmp_path_len >= tmp_path_buf.len) return error.NameTooLong;137 if (tmp_path_len > tmp_path_buf.len) return error.NameTooLong;
196138
197 if (dirname) |dir| {139 if (dirname) |dn| {
198 mem.copy(u8, tmp_path_buf[0..], dir);140 mem.copy(u8, tmp_path_buf[0..], dn);
199 tmp_path_buf[dir.len] = path.sep;141 tmp_path_buf[dn.len] = path.sep;
200 }142 }
201143
202 tmp_path_buf[tmp_path_len] = 0;144 tmp_path_buf[tmp_path_len] = 0;
203 const tmp_path_slice = tmp_path_buf[0..tmp_path_len :0];145 const tmp_path_slice = tmp_path_buf[0..tmp_path_len :0];
204146
205 const my_cwd = cwd();
206
207 while (true) {147 while (true) {
208 try crypto.randomBytes(rand_buf[0..]);148 try crypto.randomBytes(rand_buf[0..]);
209 base64_encoder.encode(tmp_path_slice[dirname_component_len..tmp_path_len], &rand_buf);149 base64_encoder.encode(tmp_path_slice[dirname_component_len..tmp_path_len], &rand_buf);
210150
211 const file = my_cwd.createFileC(151 const file = dir.createFileC(
212 tmp_path_slice,152 tmp_path_slice,
213 .{ .mode = mode, .exclusive = true },153 .{ .mode = mode, .exclusive = true },
214 ) catch |err| switch (err) {154 ) catch |err| switch (err) {
...@@ -220,33 +160,46 @@ pub const AtomicFile = struct {...@@ -220,33 +160,46 @@ pub const AtomicFile = struct {
220 .file = file,160 .file = file,
221 .tmp_path_buf = tmp_path_buf,161 .tmp_path_buf = tmp_path_buf,
222 .dest_path = dest_path,162 .dest_path = dest_path,
223 .finished = false,163 .file_open = true,
164 .file_exists = true,
165 .dir = dir,
224 };166 };
225 }167 }
226 }168 }
227169
170 /// Deprecated. Use `Dir.atomicFile`.
171 pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile {
172 return init2(dest_path, mode, cwd());
173 }
174
228 /// always call deinit, even after successful finish()175 /// always call deinit, even after successful finish()
229 pub fn deinit(self: *AtomicFile) void {176 pub fn deinit(self: *AtomicFile) void {
230 if (!self.finished) {177 if (self.file_open) {
231 self.file.close();178 self.file.close();
232 cwd().deleteFileC(@ptrCast([*:0]u8, &self.tmp_path_buf)) catch {};179 self.file_open = false;
233 self.finished = true;180 }
181 if (self.file_exists) {
182 self.dir.deleteFileC(&self.tmp_path_buf) catch {};
183 self.file_exists = false;
234 }184 }
185 self.* = undefined;
235 }186 }
236187
237 pub fn finish(self: *AtomicFile) !void {188 pub fn finish(self: *AtomicFile) !void {
238 assert(!self.finished);189 assert(self.file_exists);
190 if (self.file_open) {
191 self.file.close();
192 self.file_open = false;
193 }
239 if (std.Target.current.os.tag == .windows) {194 if (std.Target.current.os.tag == .windows) {
240 const dest_path_w = try os.windows.sliceToPrefixedFileW(self.dest_path);195 const dest_path_w = try os.windows.sliceToPrefixedFileW(self.dest_path);
241 const tmp_path_w = try os.windows.cStrToPrefixedFileW(@ptrCast([*:0]u8, &self.tmp_path_buf));196 const tmp_path_w = try os.windows.cStrToPrefixedFileW(&self.tmp_path_buf);
242 self.file.close();197 try os.renameatW(self.dir.fd, &tmp_path_w, self.dir.fd, &dest_path_w, os.windows.TRUE);
243 self.finished = true;198 self.file_exists = false;
244 return os.renameW(&tmp_path_w, &dest_path_w);
245 } else {199 } else {
246 const dest_path_c = try os.toPosixPath(self.dest_path);200 const dest_path_c = try os.toPosixPath(self.dest_path);
247 self.file.close();201 try os.renameatZ(self.dir.fd, &self.tmp_path_buf, self.dir.fd, &dest_path_c);
248 self.finished = true;202 self.file_exists = false;
249 return os.renameC(@ptrCast([*:0]u8, &self.tmp_path_buf), &dest_path_c);
250 }203 }
251 }204 }
252};205};
...@@ -274,44 +227,21 @@ pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void {...@@ -274,44 +227,21 @@ pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void {
274 os.windows.CloseHandle(handle);227 os.windows.CloseHandle(handle);
275}228}
276229
277/// Returns `error.DirNotEmpty` if the directory is not empty.230/// Deprecated; use `Dir.deleteDir`.
278/// To delete a directory recursively, see `deleteTree`.
279pub fn deleteDir(dir_path: []const u8) !void {231pub fn deleteDir(dir_path: []const u8) !void {
280 return os.rmdir(dir_path);232 return os.rmdir(dir_path);
281}233}
282234
283/// Same as `deleteDir` except the parameter is a null-terminated UTF8-encoded string.235/// Deprecated; use `Dir.deleteDirC`.
284pub fn deleteDirC(dir_path: [*:0]const u8) !void {236pub fn deleteDirC(dir_path: [*:0]const u8) !void {
285 return os.rmdirC(dir_path);237 return os.rmdirC(dir_path);
286}238}
287239
288/// Same as `deleteDir` except the parameter is a null-terminated UTF16LE-encoded string.240/// Deprecated; use `Dir.deleteDirW`.
289pub fn deleteDirW(dir_path: [*:0]const u16) !void {241pub fn deleteDirW(dir_path: [*:0]const u16) !void {
290 return os.rmdirW(dir_path);242 return os.rmdirW(dir_path);
291}243}
292244
293/// Removes a symlink, file, or directory.
294/// If `full_path` is relative, this is equivalent to `Dir.deleteTree` with the
295/// current working directory as the open directory handle.
296/// If `full_path` is absolute, this is equivalent to `Dir.deleteTree` with the
297/// base directory.
298pub fn deleteTree(full_path: []const u8) !void {
299 if (path.isAbsolute(full_path)) {
300 const dirname = path.dirname(full_path) orelse return error{
301 /// Attempt to remove the root file system path.
302 /// This error is unreachable if `full_path` is relative.
303 CannotDeleteRootDirectory,
304 }.CannotDeleteRootDirectory;
305
306 var dir = try cwd().openDirList(dirname);
307 defer dir.close();
308
309 return dir.deleteTree(path.basename(full_path));
310 } else {
311 return cwd().deleteTree(full_path);
312 }
313}
314
315pub const Dir = struct {245pub const Dir = struct {
316 fd: os.fd_t,246 fd: os.fd_t,
317247
...@@ -368,7 +298,7 @@ pub const Dir = struct {...@@ -368,7 +298,7 @@ pub const Dir = struct {
368 if (rc == 0) return null;298 if (rc == 0) return null;
369 if (rc < 0) {299 if (rc < 0) {
370 switch (os.errno(rc)) {300 switch (os.errno(rc)) {
371 os.EBADF => unreachable,301 os.EBADF => unreachable, // Dir is invalid or was opened without iteration ability
372 os.EFAULT => unreachable,302 os.EFAULT => unreachable,
373 os.ENOTDIR => unreachable,303 os.ENOTDIR => unreachable,
374 os.EINVAL => unreachable,304 os.EINVAL => unreachable,
...@@ -411,13 +341,13 @@ pub const Dir = struct {...@@ -411,13 +341,13 @@ pub const Dir = struct {
411 if (self.index >= self.end_index) {341 if (self.index >= self.end_index) {
412 const rc = os.system.getdirentries(342 const rc = os.system.getdirentries(
413 self.dir.fd,343 self.dir.fd,
414 self.buf[0..].ptr,344 &self.buf,
415 self.buf.len,345 self.buf.len,
416 &self.seek,346 &self.seek,
417 );347 );
418 switch (os.errno(rc)) {348 switch (os.errno(rc)) {
419 0 => {},349 0 => {},
420 os.EBADF => unreachable,350 os.EBADF => unreachable, // Dir is invalid or was opened without iteration ability
421 os.EFAULT => unreachable,351 os.EFAULT => unreachable,
422 os.ENOTDIR => unreachable,352 os.ENOTDIR => unreachable,
423 os.EINVAL => unreachable,353 os.EINVAL => unreachable,
...@@ -473,7 +403,7 @@ pub const Dir = struct {...@@ -473,7 +403,7 @@ pub const Dir = struct {
473 const rc = os.linux.getdents64(self.dir.fd, &self.buf, self.buf.len);403 const rc = os.linux.getdents64(self.dir.fd, &self.buf, self.buf.len);
474 switch (os.linux.getErrno(rc)) {404 switch (os.linux.getErrno(rc)) {
475 0 => {},405 0 => {},
476 os.EBADF => unreachable,406 os.EBADF => unreachable, // Dir is invalid or was opened without iteration ability
477 os.EFAULT => unreachable,407 os.EFAULT => unreachable,
478 os.ENOTDIR => unreachable,408 os.ENOTDIR => unreachable,
479 os.EINVAL => unreachable,409 os.EINVAL => unreachable,
...@@ -547,7 +477,8 @@ pub const Dir = struct {...@@ -547,7 +477,8 @@ pub const Dir = struct {
547 self.end_index = io.Information;477 self.end_index = io.Information;
548 switch (rc) {478 switch (rc) {
549 .SUCCESS => {},479 .SUCCESS => {},
550 .ACCESS_DENIED => return error.AccessDenied,480 .ACCESS_DENIED => return error.AccessDenied, // Double-check that the Dir was opened with iteration ability
481
551 else => return w.unexpectedStatus(rc),482 else => return w.unexpectedStatus(rc),
552 }483 }
553 }484 }
...@@ -625,16 +556,6 @@ pub const Dir = struct {...@@ -625,16 +556,6 @@ pub const Dir = struct {
625 DeviceBusy,556 DeviceBusy,
626 } || os.UnexpectedError;557 } || os.UnexpectedError;
627558
628 /// Deprecated; call `cwd().openDirList` directly.
629 pub fn open(dir_path: []const u8) OpenError!Dir {
630 return cwd().openDirList(dir_path);
631 }
632
633 /// Deprecated; call `cwd().openDirListC` directly.
634 pub fn openC(dir_path_c: [*:0]const u8) OpenError!Dir {
635 return cwd().openDirListC(dir_path_c);
636 }
637
638 pub fn close(self: *Dir) void {559 pub fn close(self: *Dir) void {
639 if (need_async_thread) {560 if (need_async_thread) {
640 std.event.Loop.instance.?.close(self.fd);561 std.event.Loop.instance.?.close(self.fd);
...@@ -694,7 +615,10 @@ pub const Dir = struct {...@@ -694,7 +615,10 @@ pub const Dir = struct {
694 const access_mask = w.SYNCHRONIZE |615 const access_mask = w.SYNCHRONIZE |
695 (if (flags.read) @as(u32, w.GENERIC_READ) else 0) |616 (if (flags.read) @as(u32, w.GENERIC_READ) else 0) |
696 (if (flags.write) @as(u32, w.GENERIC_WRITE) else 0);617 (if (flags.write) @as(u32, w.GENERIC_WRITE) else 0);
697 return self.openFileWindows(sub_path_w, access_mask, w.FILE_OPEN);618 return @as(File, .{
619 .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, w.FILE_OPEN),
620 .io_mode = .blocking,
621 });
698 }622 }
699623
700 /// Creates, opens, or overwrites a file with write access.624 /// Creates, opens, or overwrites a file with write access.
...@@ -739,7 +663,10 @@ pub const Dir = struct {...@@ -739,7 +663,10 @@ pub const Dir = struct {
739 @as(u32, w.FILE_OVERWRITE_IF)663 @as(u32, w.FILE_OVERWRITE_IF)
740 else664 else
741 @as(u32, w.FILE_OPEN_IF);665 @as(u32, w.FILE_OPEN_IF);
742 return self.openFileWindows(sub_path_w, access_mask, creation);666 return @as(File, .{
667 .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, creation),
668 .io_mode = .blocking,
669 });
743 }670 }
744671
745 /// Deprecated; call `openFile` directly.672 /// Deprecated; call `openFile` directly.
...@@ -757,72 +684,6 @@ pub const Dir = struct {...@@ -757,72 +684,6 @@ pub const Dir = struct {
757 return self.openFileW(sub_path, .{});684 return self.openFileW(sub_path, .{});
758 }685 }
759686
760 pub fn openFileWindows(
761 self: Dir,
762 sub_path_w: [*:0]const u16,
763 access_mask: os.windows.ACCESS_MASK,
764 creation: os.windows.ULONG,
765 ) File.OpenError!File {
766 const w = os.windows;
767
768 if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
769 return error.IsDir;
770 }
771 if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
772 return error.IsDir;
773 }
774
775 var result = File{
776 .handle = undefined,
777 .io_mode = .blocking,
778 };
779
780 const path_len_bytes = math.cast(u16, mem.toSliceConst(u16, sub_path_w).len * 2) catch |err| switch (err) {
781 error.Overflow => return error.NameTooLong,
782 };
783 var nt_name = w.UNICODE_STRING{
784 .Length = path_len_bytes,
785 .MaximumLength = path_len_bytes,
786 .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)),
787 };
788 var attr = w.OBJECT_ATTRIBUTES{
789 .Length = @sizeOf(w.OBJECT_ATTRIBUTES),
790 .RootDirectory = if (path.isAbsoluteWindowsW(sub_path_w)) null else self.fd,
791 .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
792 .ObjectName = &nt_name,
793 .SecurityDescriptor = null,
794 .SecurityQualityOfService = null,
795 };
796 var io: w.IO_STATUS_BLOCK = undefined;
797 const rc = w.ntdll.NtCreateFile(
798 &result.handle,
799 access_mask,
800 &attr,
801 &io,
802 null,
803 w.FILE_ATTRIBUTE_NORMAL,
804 w.FILE_SHARE_WRITE | w.FILE_SHARE_READ | w.FILE_SHARE_DELETE,
805 creation,
806 w.FILE_NON_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT,
807 null,
808 0,
809 );
810 switch (rc) {
811 .SUCCESS => return result,
812 .OBJECT_NAME_INVALID => unreachable,
813 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
814 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
815 .NO_MEDIA_IN_DEVICE => return error.NoDevice,
816 .INVALID_PARAMETER => unreachable,
817 .SHARING_VIOLATION => return error.SharingViolation,
818 .ACCESS_DENIED => return error.AccessDenied,
819 .PIPE_BUSY => return error.PipeBusy,
820 .OBJECT_PATH_SYNTAX_BAD => unreachable,
821 .OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
822 else => return w.unexpectedStatus(rc),
823 }
824 }
825
826 pub fn makeDir(self: Dir, sub_path: []const u8) !void {687 pub fn makeDir(self: Dir, sub_path: []const u8) !void {
827 try os.mkdirat(self.fd, sub_path, default_new_dir_mode);688 try os.mkdirat(self.fd, sub_path, default_new_dir_mode);
828 }689 }
...@@ -881,77 +742,61 @@ pub const Dir = struct {...@@ -881,77 +742,61 @@ pub const Dir = struct {
881 try os.fchdir(self.fd);742 try os.fchdir(self.fd);
882 }743 }
883744
884 /// Deprecated; call `openDirList` directly.745 pub const OpenDirOptions = struct {
885 pub fn openDir(self: Dir, sub_path: []const u8) OpenError!Dir {746 /// `true` means the opened directory can be used as the `Dir` parameter
886 return self.openDirList(sub_path);747 /// for functions which operate based on an open directory handle. When `false`,
887 }748 /// such operations are Illegal Behavior.
888749 access_sub_paths: bool = true,
889 /// Deprecated; call `openDirListC` directly.
890 pub fn openDirC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir {
891 return self.openDirListC(sub_path_c);
892 }
893750
894 /// Opens a directory at the given path with the ability to access subpaths751 /// `true` means the opened directory can be scanned for the files and sub-directories
895 /// of the result. Calling `iterate` on the result is illegal behavior; to752 /// of the result. It means the `iterate` function can be called.
896 /// list the contents of a directory, open it with `openDirList`.753 iterate: bool = false,
897 ///754 };
898 /// Call `close` on the result when done.
899 ///
900 /// Asserts that the path parameter has no null bytes.
901 pub fn openDirTraverse(self: Dir, sub_path: []const u8) OpenError!Dir {
902 if (builtin.os.tag == .windows) {
903 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
904 return self.openDirTraverseW(&sub_path_w);
905 }
906
907 const sub_path_c = try os.toPosixPath(sub_path);
908 return self.openDirTraverseC(&sub_path_c);
909 }
910755
911 /// Opens a directory at the given path with the ability to access subpaths and list contents756 /// Opens a directory at the given path. The directory is a system resource that remains
912 /// of the result. If the ability to list contents is unneeded, `openDirTraverse` acts the757 /// open until `close` is called on the result.
913 /// same and may be more efficient.
914 ///
915 /// Call `close` on the result when done.
916 ///758 ///
917 /// Asserts that the path parameter has no null bytes.759 /// Asserts that the path parameter has no null bytes.
918 pub fn openDirList(self: Dir, sub_path: []const u8) OpenError!Dir {760 pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir {
919 if (builtin.os.tag == .windows) {761 if (builtin.os.tag == .windows) {
920 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);762 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
921 return self.openDirListW(&sub_path_w);763 return self.openDirW(&sub_path_w, args);
764 } else {
765 const sub_path_c = try os.toPosixPath(sub_path);
766 return self.openDirC(&sub_path_c, args);
922 }767 }
923
924 const sub_path_c = try os.toPosixPath(sub_path);
925 return self.openDirListC(&sub_path_c);
926 }768 }
927769
928 /// Same as `openDirTraverse` except the parameter is null-terminated.770 /// Same as `openDir` except the parameter is null-terminated.
929 pub fn openDirTraverseC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir {771 pub fn openDirC(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions) OpenError!Dir {
930 if (builtin.os.tag == .windows) {772 if (builtin.os.tag == .windows) {
931 const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);773 const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);
932 return self.openDirTraverseW(&sub_path_w);774 return self.openDirW(&sub_path_w, args);
933 } else {775 } else if (!args.iterate) {
934 const O_PATH = if (@hasDecl(os, "O_PATH")) os.O_PATH else 0;776 const O_PATH = if (@hasDecl(os, "O_PATH")) os.O_PATH else 0;
935 return self.openDirFlagsC(sub_path_c, os.O_RDONLY | os.O_CLOEXEC | O_PATH);777 return self.openDirFlagsC(sub_path_c, os.O_DIRECTORY | os.O_RDONLY | os.O_CLOEXEC | O_PATH);
778 } else {
779 return self.openDirFlagsC(sub_path_c, os.O_DIRECTORY | os.O_RDONLY | os.O_CLOEXEC);
936 }780 }
937 }781 }
938782
939 /// Same as `openDirList` except the parameter is null-terminated.783 /// Same as `openDir` except the path parameter is WTF-16 encoded, NT-prefixed.
940 pub fn openDirListC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir {784 /// This function asserts the target OS is Windows.
941 if (builtin.os.tag == .windows) {785 pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) OpenError!Dir {
942 const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);786 const w = os.windows;
943 return self.openDirListW(&sub_path_w);787 // TODO remove some of these flags if args.access_sub_paths is false
944 } else {788 const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA |
945 return self.openDirFlagsC(sub_path_c, os.O_RDONLY | os.O_CLOEXEC);789 w.SYNCHRONIZE | w.FILE_TRAVERSE;
946 }790 const flags: u32 = if (args.iterate) base_flags | w.FILE_LIST_DIRECTORY else base_flags;
791 return self.openDirAccessMaskW(sub_path_w, flags);
947 }792 }
948793
794 /// `flags` must contain `os.O_DIRECTORY`.
949 fn openDirFlagsC(self: Dir, sub_path_c: [*:0]const u8, flags: u32) OpenError!Dir {795 fn openDirFlagsC(self: Dir, sub_path_c: [*:0]const u8, flags: u32) OpenError!Dir {
950 const os_flags = flags | os.O_DIRECTORY;
951 const result = if (need_async_thread)796 const result = if (need_async_thread)
952 std.event.Loop.instance.?.openatZ(self.fd, sub_path_c, os_flags, 0)797 std.event.Loop.instance.?.openatZ(self.fd, sub_path_c, flags, 0)
953 else798 else
954 os.openatC(self.fd, sub_path_c, os_flags, 0);799 os.openatC(self.fd, sub_path_c, flags, 0);
955 const fd = result catch |err| switch (err) {800 const fd = result catch |err| switch (err) {
956 error.FileTooBig => unreachable, // can't happen for directories801 error.FileTooBig => unreachable, // can't happen for directories
957 error.IsDir => unreachable, // we're providing O_DIRECTORY802 error.IsDir => unreachable, // we're providing O_DIRECTORY
...@@ -962,22 +807,6 @@ pub const Dir = struct {...@@ -962,22 +807,6 @@ pub const Dir = struct {
962 return Dir{ .fd = fd };807 return Dir{ .fd = fd };
963 }808 }
964809
965 /// Same as `openDirTraverse` except the path parameter is UTF16LE, NT-prefixed.
966 /// This function is Windows-only.
967 pub fn openDirTraverseW(self: Dir, sub_path_w: [*:0]const u16) OpenError!Dir {
968 const w = os.windows;
969
970 return self.openDirAccessMaskW(sub_path_w, w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | w.SYNCHRONIZE | w.FILE_TRAVERSE);
971 }
972
973 /// Same as `openDirList` except the path parameter is UTF16LE, NT-prefixed.
974 /// This function is Windows-only.
975 pub fn openDirListW(self: Dir, sub_path_w: [*:0]const u16) OpenError!Dir {
976 const w = os.windows;
977
978 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);
979 }
980
981 fn openDirAccessMaskW(self: Dir, sub_path_w: [*:0]const u16, access_mask: u32) OpenError!Dir {810 fn openDirAccessMaskW(self: Dir, sub_path_w: [*:0]const u16, access_mask: u32) OpenError!Dir {
982 const w = os.windows;811 const w = os.windows;
983812
...@@ -1198,7 +1027,7 @@ pub const Dir = struct {...@@ -1198,7 +1027,7 @@ pub const Dir = struct {
1198 error.Unexpected,1027 error.Unexpected,
1199 => |e| return e,1028 => |e| return e,
1200 }1029 }
1201 var dir = self.openDirList(sub_path) catch |err| switch (err) {1030 var dir = self.openDir(sub_path, .{ .iterate = true }) catch |err| switch (err) {
1202 error.NotDir => {1031 error.NotDir => {
1203 if (got_access_denied) {1032 if (got_access_denied) {
1204 return error.AccessDenied;1033 return error.AccessDenied;
...@@ -1231,7 +1060,6 @@ pub const Dir = struct {...@@ -1231,7 +1060,6 @@ pub const Dir = struct {
12311060
1232 var dir_name_buf: [MAX_PATH_BYTES]u8 = undefined;1061 var dir_name_buf: [MAX_PATH_BYTES]u8 = undefined;
1233 var dir_name: []const u8 = sub_path;1062 var dir_name: []const u8 = sub_path;
1234 var parent_dir = self;
12351063
1236 // Here we must avoid recursion, in order to provide O(1) memory guarantee of this function.1064 // Here we must avoid recursion, in order to provide O(1) memory guarantee of this function.
1237 // Go through each entry and if it is not a directory, delete it. If it is a directory,1065 // Go through each entry and if it is not a directory, delete it. If it is a directory,
...@@ -1263,7 +1091,7 @@ pub const Dir = struct {...@@ -1263,7 +1091,7 @@ pub const Dir = struct {
1263 => |e| return e,1091 => |e| return e,
1264 }1092 }
12651093
1266 const new_dir = dir.openDirList(entry.name) catch |err| switch (err) {1094 const new_dir = dir.openDir(entry.name, .{ .iterate = true }) catch |err| switch (err) {
1267 error.NotDir => {1095 error.NotDir => {
1268 if (got_access_denied) {1096 if (got_access_denied) {
1269 return error.AccessDenied;1097 return error.AccessDenied;
...@@ -1370,9 +1198,96 @@ pub const Dir = struct {...@@ -1370,9 +1198,96 @@ pub const Dir = struct {
1370 pub fn accessW(self: Dir, sub_path_w: [*:0]const u16, flags: File.OpenFlags) AccessError!void {1198 pub fn accessW(self: Dir, sub_path_w: [*:0]const u16, flags: File.OpenFlags) AccessError!void {
1371 return os.faccessatW(self.fd, sub_path_w, 0, 0);1199 return os.faccessatW(self.fd, sub_path_w, 0, 0);
1372 }1200 }
1201
1202 /// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing.
1203 /// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime,
1204 /// atime, and mode of the source file so that the next call to `updateFile` will not need a copy.
1205 /// Returns the previous status of the file before updating.
1206 /// If any of the directories do not exist for dest_path, they are created.
1207 pub fn updateFile(
1208 source_dir: Dir,
1209 source_path: []const u8,
1210 dest_dir: Dir,
1211 dest_path: []const u8,
1212 options: CopyFileOptions,
1213 ) !PrevStatus {
1214 var src_file = try source_dir.openFile(source_path, .{});
1215 defer src_file.close();
1216
1217 const src_stat = try src_file.stat();
1218 const actual_mode = options.override_mode orelse src_stat.mode;
1219 check_dest_stat: {
1220 const dest_stat = blk: {
1221 var dest_file = dest_dir.openFile(dest_path, .{}) catch |err| switch (err) {
1222 error.FileNotFound => break :check_dest_stat,
1223 else => |e| return e,
1224 };
1225 defer dest_file.close();
1226
1227 break :blk try dest_file.stat();
1228 };
1229
1230 if (src_stat.size == dest_stat.size and
1231 src_stat.mtime == dest_stat.mtime and
1232 actual_mode == dest_stat.mode)
1233 {
1234 return PrevStatus.fresh;
1235 }
1236 }
1237
1238 if (path.dirname(dest_path)) |dirname| {
1239 try dest_dir.makePath(dirname);
1240 }
1241
1242 var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = actual_mode });
1243 defer atomic_file.deinit();
1244
1245 try atomic_file.file.writeFileAll(src_file, .{ .in_len = src_stat.size });
1246 try atomic_file.file.updateTimes(src_stat.atime, src_stat.mtime);
1247 try atomic_file.finish();
1248 return PrevStatus.stale;
1249 }
1250
1251 /// Guaranteed to be atomic.
1252 /// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available,
1253 /// there is a possibility of power loss or application termination leaving temporary files present
1254 /// in the same directory as dest_path.
1255 pub fn copyFile(
1256 source_dir: Dir,
1257 source_path: []const u8,
1258 dest_dir: Dir,
1259 dest_path: []const u8,
1260 options: CopyFileOptions,
1261 ) !void {
1262 var in_file = try source_dir.openFile(source_path, .{});
1263 defer in_file.close();
1264
1265 var size: ?u64 = null;
1266 const mode = options.override_mode orelse blk: {
1267 const stat = try in_file.stat();
1268 size = stat.size;
1269 break :blk stat.mode;
1270 };
1271
1272 var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = mode });
1273 defer atomic_file.deinit();
1274
1275 try atomic_file.file.writeFileAll(in_file, .{ .in_len = size });
1276 return atomic_file.finish();
1277 }
1278
1279 pub const AtomicFileOptions = struct {
1280 mode: File.Mode = File.default_mode,
1281 };
1282
1283 /// `dest_path` must remain valid for the lifetime of `AtomicFile`.
1284 /// Call `AtomicFile.finish` to atomically replace `dest_path` with contents.
1285 pub fn atomicFile(self: Dir, dest_path: []const u8, options: AtomicFileOptions) !AtomicFile {
1286 return AtomicFile.init2(dest_path, options.mode, self);
1287 }
1373};1288};
13741289
1375/// Returns an handle to the current working directory that is open for traversal.1290/// Returns an handle to the current working directory. It is not opened with iteration capability.
1376/// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior.1291/// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior.
1377/// On POSIX targets, this function is comptime-callable.1292/// On POSIX targets, this function is comptime-callable.
1378pub fn cwd() Dir {1293pub fn cwd() Dir {
...@@ -1450,6 +1365,25 @@ pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) DeleteFileError!void...@@ -1450,6 +1365,25 @@ pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) DeleteFileError!void
1450 return cwd().deleteFileW(absolute_path_w);1365 return cwd().deleteFileW(absolute_path_w);
1451}1366}
14521367
1368/// Removes a symlink, file, or directory.
1369/// This is equivalent to `Dir.deleteTree` with the base directory.
1370/// Asserts that the path is absolute. See `Dir.deleteTree` for a function that
1371/// operates on both absolute and relative paths.
1372/// Asserts that the path parameter has no null bytes.
1373pub fn deleteTreeAbsolute(absolute_path: []const u8) !void {
1374 assert(path.isAbsolute(absolute_path));
1375 const dirname = path.dirname(absolute_path) orelse return error{
1376 /// Attempt to remove the root file system path.
1377 /// This error is unreachable if `absolute_path` is relative.
1378 CannotDeleteRootDirectory,
1379 }.CannotDeleteRootDirectory;
1380
1381 var dir = try cwd().openDir(dirname, .{});
1382 defer dir.close();
1383
1384 return dir.deleteTree(path.basename(absolute_path));
1385}
1386
1453pub const Walker = struct {1387pub const Walker = struct {
1454 stack: std.ArrayList(StackItem),1388 stack: std.ArrayList(StackItem),
1455 name_buffer: std.Buffer,1389 name_buffer: std.Buffer,
...@@ -1484,7 +1418,7 @@ pub const Walker = struct {...@@ -1484,7 +1418,7 @@ pub const Walker = struct {
1484 try self.name_buffer.appendByte(path.sep);1418 try self.name_buffer.appendByte(path.sep);
1485 try self.name_buffer.append(base.name);1419 try self.name_buffer.append(base.name);
1486 if (base.kind == .Directory) {1420 if (base.kind == .Directory) {
1487 var new_dir = top.dir_it.dir.openDirList(base.name) catch |err| switch (err) {1421 var new_dir = top.dir_it.dir.openDir(base.name, .{ .iterate = true }) catch |err| switch (err) {
1488 error.NameTooLong => unreachable, // no path sep in base.name1422 error.NameTooLong => unreachable, // no path sep in base.name
1489 else => |e| return e,1423 else => |e| return e,
1490 };1424 };
...@@ -1522,7 +1456,7 @@ pub const Walker = struct {...@@ -1522,7 +1456,7 @@ pub const Walker = struct {
1522pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker {1456pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker {
1523 assert(!mem.endsWith(u8, dir_path, path.sep_str));1457 assert(!mem.endsWith(u8, dir_path, path.sep_str));
15241458
1525 var dir = try cwd().openDirList(dir_path);1459 var dir = try cwd().openDir(dir_path, .{ .iterate = true });
1526 errdefer dir.close();1460 errdefer dir.close();
15271461
1528 var name_buffer = try std.Buffer.init(allocator, dir_path);1462 var name_buffer = try std.Buffer.init(allocator, dir_path);
...@@ -1541,13 +1475,12 @@ pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker {...@@ -1541,13 +1475,12 @@ pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker {
1541 return walker;1475 return walker;
1542}1476}
15431477
1544/// Read value of a symbolic link.1478/// Deprecated; use `Dir.readLink`.
1545/// The return value is a slice of buffer, from index `0`.
1546pub fn readLink(pathname: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {1479pub fn readLink(pathname: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
1547 return os.readlink(pathname, buffer);1480 return os.readlink(pathname, buffer);
1548}1481}
15491482
1550/// Same as `readLink`, except the parameter is null-terminated.1483/// Deprecated; use `Dir.readLinkC`.
1551pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {1484pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
1552 return os.readlinkC(pathname_c, buffer);1485 return os.readlinkC(pathname_c, buffer);
1553}1486}
...@@ -1654,6 +1587,7 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const...@@ -1654,6 +1587,7 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const
1654}1587}
16551588
1656/// `realpath`, except caller must free the returned memory.1589/// `realpath`, except caller must free the returned memory.
1590/// TODO integrate with `Dir`
1657pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 {1591pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 {
1658 var buf: [MAX_PATH_BYTES]u8 = undefined;1592 var buf: [MAX_PATH_BYTES]u8 = undefined;
1659 return mem.dupe(allocator, u8, try os.realpath(pathname, &buf));1593 return mem.dupe(allocator, u8, try os.realpath(pathname, &buf));
...@@ -1662,6 +1596,9 @@ pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 {...@@ -1662,6 +1596,9 @@ pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 {
1662test "" {1596test "" {
1663 _ = makeDirAbsolute;1597 _ = makeDirAbsolute;
1664 _ = makeDirAbsoluteZ;1598 _ = makeDirAbsoluteZ;
1599 _ = copyFileAbsolute;
1600 _ = updateFileAbsolute;
1601 _ = Dir.copyFile;
1665 _ = @import("fs/path.zig");1602 _ = @import("fs/path.zig");
1666 _ = @import("fs/file.zig");1603 _ = @import("fs/file.zig");
1667 _ = @import("fs/get_app_data_dir.zig");1604 _ = @import("fs/get_app_data_dir.zig");
lib/std/fs/watch.zig+1-1
...@@ -619,7 +619,7 @@ test "write a file, watch it, write it again" {...@@ -619,7 +619,7 @@ test "write a file, watch it, write it again" {
619 if (true) return error.SkipZigTest;619 if (true) return error.SkipZigTest;
620620
621 try fs.cwd().makePath(test_tmp_dir);621 try fs.cwd().makePath(test_tmp_dir);
622 defer os.deleteTree(test_tmp_dir) catch {};622 defer fs.cwd().deleteTree(test_tmp_dir) catch {};
623623
624 const allocator = std.heap.page_allocator;624 const allocator = std.heap.page_allocator;
625 return testFsWatch(&allocator);625 return testFsWatch(&allocator);
lib/std/hash/auto_hash.zig+8-4
...@@ -40,7 +40,9 @@ pub fn hashPointer(hasher: var, key: var, comptime strat: HashStrategy) void {...@@ -40,7 +40,9 @@ pub fn hashPointer(hasher: var, key: var, comptime strat: HashStrategy) void {
40 .DeepRecursive => hashArray(hasher, key, .DeepRecursive),40 .DeepRecursive => hashArray(hasher, key, .DeepRecursive),
41 },41 },
4242
43 .Many, .C, => switch (strat) {43 .Many,
44 .C,
45 => switch (strat) {
44 .Shallow => hash(hasher, @ptrToInt(key), .Shallow),46 .Shallow => hash(hasher, @ptrToInt(key), .Shallow),
45 else => @compileError(47 else => @compileError(
46 \\ unknown-length pointers and C pointers cannot be hashed deeply.48 \\ unknown-length pointers and C pointers cannot be hashed deeply.
...@@ -236,9 +238,11 @@ test "hash slice shallow" {...@@ -236,9 +238,11 @@ test "hash slice shallow" {
236 defer std.testing.allocator.destroy(array1);238 defer std.testing.allocator.destroy(array1);
237 array1.* = [_]u32{ 1, 2, 3, 4, 5, 6 };239 array1.* = [_]u32{ 1, 2, 3, 4, 5, 6 };
238 const array2 = [_]u32{ 1, 2, 3, 4, 5, 6 };240 const array2 = [_]u32{ 1, 2, 3, 4, 5, 6 };
239 const a = array1[0..];241 // TODO audit deep/shallow - maybe it has the wrong behavior with respect to array pointers and slices
240 const b = array2[0..];242 var runtime_zero: usize = 0;
241 const c = array1[0..3];243 const a = array1[runtime_zero..];
244 const b = array2[runtime_zero..];
245 const c = array1[runtime_zero..3];
242 testing.expect(testHashShallow(a) == testHashShallow(a));246 testing.expect(testHashShallow(a) == testHashShallow(a));
243 testing.expect(testHashShallow(a) != testHashShallow(array1));247 testing.expect(testHashShallow(a) != testHashShallow(array1));
244 testing.expect(testHashShallow(a) != testHashShallow(b));248 testing.expect(testHashShallow(a) != testHashShallow(b));
lib/std/hash/siphash.zig+3-3
...@@ -39,8 +39,8 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round...@@ -39,8 +39,8 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round
39 pub fn init(key: []const u8) Self {39 pub fn init(key: []const u8) Self {
40 assert(key.len >= 16);40 assert(key.len >= 16);
4141
42 const k0 = mem.readIntSliceLittle(u64, key[0..8]);42 const k0 = mem.readIntLittle(u64, key[0..8]);
43 const k1 = mem.readIntSliceLittle(u64, key[8..16]);43 const k1 = mem.readIntLittle(u64, key[8..16]);
4444
45 var d = Self{45 var d = Self{
46 .v0 = k0 ^ 0x736f6d6570736575,46 .v0 = k0 ^ 0x736f6d6570736575,
...@@ -111,7 +111,7 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round...@@ -111,7 +111,7 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round
111 fn round(self: *Self, b: []const u8) void {111 fn round(self: *Self, b: []const u8) void {
112 assert(b.len == 8);112 assert(b.len == 8);
113113
114 const m = mem.readIntSliceLittle(u64, b[0..]);114 const m = mem.readIntLittle(u64, b[0..8]);
115 self.v3 ^= m;115 self.v3 ^= m;
116116
117 // TODO this is a workaround, should be able to supply the value without a separate variable117 // TODO this is a workaround, should be able to supply the value without a separate variable
lib/std/hash/wyhash.zig+1-1
...@@ -11,7 +11,7 @@ const primes = [_]u64{...@@ -11,7 +11,7 @@ const primes = [_]u64{
1111
12fn read_bytes(comptime bytes: u8, data: []const u8) u64 {12fn read_bytes(comptime bytes: u8, data: []const u8) u64 {
13 const T = std.meta.IntType(false, 8 * bytes);13 const T = std.meta.IntType(false, 8 * bytes);
14 return mem.readIntSliceLittle(T, data[0..bytes]);14 return mem.readIntLittle(T, data[0..bytes]);
15}15}
1616
17fn read_8bytes_swapped(data: []const u8) u64 {17fn read_8bytes_swapped(data: []const u8) u64 {
lib/std/io/serialization.zig+5-1
...@@ -1,6 +1,10 @@...@@ -1,6 +1,10 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const builtin = std.builtin;2const builtin = std.builtin;
3const io = std.io;3const io = std.io;
4const assert = std.debug.assert;
5const math = std.math;
6const meta = std.meta;
7const trait = meta.trait;
48
5pub const Packing = enum {9pub const Packing = enum {
6 /// Pack data to byte alignment10 /// Pack data to byte alignment
...@@ -252,7 +256,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co...@@ -252,7 +256,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co
252 byte.* = if (t_bit_count < u8_bit_count) v else @truncate(u8, v);256 byte.* = if (t_bit_count < u8_bit_count) v else @truncate(u8, v);
253 }257 }
254258
255 try self.out_stream.write(&buffer);259 try self.out_stream.writeAll(&buffer);
256 }260 }
257261
258 /// Serializes the passed value into the stream262 /// Serializes the passed value into the stream
lib/std/json.zig+16-7
...@@ -2249,11 +2249,16 @@ pub const StringifyOptions = struct {...@@ -2249,11 +2249,16 @@ pub const StringifyOptions = struct {
2249 // TODO: allow picking if []u8 is string or array?2249 // TODO: allow picking if []u8 is string or array?
2250};2250};
22512251
2252pub const StringifyError = error{
2253 TooMuchData,
2254 DifferentData,
2255};
2256
2252pub fn stringify(2257pub fn stringify(
2253 value: var,2258 value: var,
2254 options: StringifyOptions,2259 options: StringifyOptions,
2255 out_stream: var,2260 out_stream: var,
2256) !void {2261) StringifyError!void {
2257 const T = @TypeOf(value);2262 const T = @TypeOf(value);
2258 switch (@typeInfo(T)) {2263 switch (@typeInfo(T)) {
2259 .Float, .ComptimeFloat => {2264 .Float, .ComptimeFloat => {
...@@ -2320,9 +2325,15 @@ pub fn stringify(...@@ -2320,9 +2325,15 @@ pub fn stringify(
2320 return;2325 return;
2321 },2326 },
2322 .Pointer => |ptr_info| switch (ptr_info.size) {2327 .Pointer => |ptr_info| switch (ptr_info.size) {
2323 .One => {2328 .One => switch (@typeInfo(ptr_info.child)) {
2324 // TODO: avoid loops?2329 .Array => {
2325 return try stringify(value.*, options, out_stream);2330 const Slice = []const std.meta.Elem(ptr_info.child);
2331 return stringify(@as(Slice, value), options, out_stream);
2332 },
2333 else => {
2334 // TODO: avoid loops?
2335 return stringify(value.*, options, out_stream);
2336 },
2326 },2337 },
2327 // TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972)2338 // TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972)
2328 .Slice => {2339 .Slice => {
...@@ -2381,9 +2392,7 @@ pub fn stringify(...@@ -2381,9 +2392,7 @@ pub fn stringify(
2381 },2392 },
2382 else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"),2393 else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"),
2383 },2394 },
2384 .Array => |info| {2395 .Array => return stringify(&value, options, out_stream),
2385 return try stringify(value[0..], options, out_stream);
2386 },
2387 else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"),2396 else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"),
2388 }2397 }
2389 unreachable;2398 unreachable;
lib/std/math/big/int.zig+2-2
...@@ -520,13 +520,13 @@ pub const Int = struct {...@@ -520,13 +520,13 @@ pub const Int = struct {
520 comptime fmt: []const u8,520 comptime fmt: []const u8,
521 options: std.fmt.FormatOptions,521 options: std.fmt.FormatOptions,
522 out_stream: var,522 out_stream: var,
523 ) FmtError!void {523 ) !void {
524 self.assertWritable();524 self.assertWritable();
525 // TODO look at fmt and support other bases525 // TODO look at fmt and support other bases
526 // TODO support read-only fixed integers526 // TODO support read-only fixed integers
527 const str = self.toString(self.allocator.?, 10) catch @panic("TODO make this non allocating");527 const str = self.toString(self.allocator.?, 10) catch @panic("TODO make this non allocating");
528 defer self.allocator.?.free(str);528 defer self.allocator.?.free(str);
529 return out_stream.print(str);529 return out_stream.writeAll(str);
530 }530 }
531531
532 /// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.532 /// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.
lib/std/mem.zig+137-75
...@@ -116,7 +116,7 @@ pub const Allocator = struct {...@@ -116,7 +116,7 @@ pub const Allocator = struct {
116 pub fn allocSentinel(self: *Allocator, comptime Elem: type, n: usize, comptime sentinel: Elem) Error![:sentinel]Elem {116 pub fn allocSentinel(self: *Allocator, comptime Elem: type, n: usize, comptime sentinel: Elem) Error![:sentinel]Elem {
117 var ptr = try self.alloc(Elem, n + 1);117 var ptr = try self.alloc(Elem, n + 1);
118 ptr[n] = sentinel;118 ptr[n] = sentinel;
119 return ptr[0 .. n :sentinel];119 return ptr[0..n :sentinel];
120 }120 }
121121
122 pub fn alignedAlloc(122 pub fn alignedAlloc(
...@@ -496,14 +496,14 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {...@@ -496,14 +496,14 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
496 return true;496 return true;
497}497}
498498
499/// Deprecated. Use `span`.499/// Deprecated. Use `spanZ`.
500pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T {500pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T {
501 return ptr[0..len(ptr) :0];501 return ptr[0..lenZ(ptr) :0];
502}502}
503503
504/// Deprecated. Use `span`.504/// Deprecated. Use `spanZ`.
505pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {505pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T {
506 return ptr[0..len(ptr) :0];506 return ptr[0..lenZ(ptr) :0];
507}507}
508508
509/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and509/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and
...@@ -548,6 +548,9 @@ test "Span" {...@@ -548,6 +548,9 @@ test "Span" {
548/// returns a slice. If there is a sentinel on the input type, there will be a548/// returns a slice. If there is a sentinel on the input type, there will be a
549/// sentinel on the output type. The constness of the output type matches549/// sentinel on the output type. The constness of the output type matches
550/// the constness of the input type.550/// the constness of the input type.
551///
552/// When there is both a sentinel and an array length or slice length, the
553/// length value is used instead of the sentinel.
551pub fn span(ptr: var) Span(@TypeOf(ptr)) {554pub fn span(ptr: var) Span(@TypeOf(ptr)) {
552 const Result = Span(@TypeOf(ptr));555 const Result = Span(@TypeOf(ptr));
553 const l = len(ptr);556 const l = len(ptr);
...@@ -560,20 +563,42 @@ pub fn span(ptr: var) Span(@TypeOf(ptr)) {...@@ -560,20 +563,42 @@ pub fn span(ptr: var) Span(@TypeOf(ptr)) {
560563
561test "span" {564test "span" {
562 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };565 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
563 const ptr = array[0..2 :3].ptr;566 const ptr = @as([*:3]u16, array[0..2 :3]);
564 testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 }));567 testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 }));
565 testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 }));568 testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 }));
566}569}
567570
571/// Same as `span`, except when there is both a sentinel and an array
572/// length or slice length, scans the memory for the sentinel value
573/// rather than using the length.
574pub fn spanZ(ptr: var) Span(@TypeOf(ptr)) {
575 const Result = Span(@TypeOf(ptr));
576 const l = lenZ(ptr);
577 if (@typeInfo(Result).Pointer.sentinel) |s| {
578 return ptr[0..l :s];
579 } else {
580 return ptr[0..l];
581 }
582}
583
584test "spanZ" {
585 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
586 const ptr = @as([*:3]u16, array[0..2 :3]);
587 testing.expect(eql(u16, spanZ(ptr), &[_]u16{ 1, 2 }));
588 testing.expect(eql(u16, spanZ(&array), &[_]u16{ 1, 2, 3, 4, 5 }));
589}
590
568/// Takes a pointer to an array, an array, a sentinel-terminated pointer,591/// Takes a pointer to an array, an array, a sentinel-terminated pointer,
569/// or a slice, and returns the length.592/// or a slice, and returns the length.
593/// In the case of a sentinel-terminated array, it uses the array length.
594/// For C pointers it assumes it is a pointer-to-many with a 0 sentinel.
570pub fn len(ptr: var) usize {595pub fn len(ptr: var) usize {
571 return switch (@typeInfo(@TypeOf(ptr))) {596 return switch (@typeInfo(@TypeOf(ptr))) {
572 .Array => |info| info.len,597 .Array => |info| info.len,
573 .Pointer => |info| switch (info.size) {598 .Pointer => |info| switch (info.size) {
574 .One => switch (@typeInfo(info.child)) {599 .One => switch (@typeInfo(info.child)) {
575 .Array => |x| x.len,600 .Array => ptr.len,
576 else => @compileError("invalid type given to std.mem.length"),601 else => @compileError("invalid type given to std.mem.len"),
577 },602 },
578 .Many => if (info.sentinel) |sentinel|603 .Many => if (info.sentinel) |sentinel|
579 indexOfSentinel(info.child, sentinel, ptr)604 indexOfSentinel(info.child, sentinel, ptr)
...@@ -582,7 +607,7 @@ pub fn len(ptr: var) usize {...@@ -582,7 +607,7 @@ pub fn len(ptr: var) usize {
582 .C => indexOfSentinel(info.child, 0, ptr),607 .C => indexOfSentinel(info.child, 0, ptr),
583 .Slice => ptr.len,608 .Slice => ptr.len,
584 },609 },
585 else => @compileError("invalid type given to std.mem.length"),610 else => @compileError("invalid type given to std.mem.len"),
586 };611 };
587}612}
588613
...@@ -594,9 +619,67 @@ test "len" {...@@ -594,9 +619,67 @@ test "len" {
594 testing.expect(len(&array) == 5);619 testing.expect(len(&array) == 5);
595 testing.expect(len(array[0..3]) == 3);620 testing.expect(len(array[0..3]) == 3);
596 array[2] = 0;621 array[2] = 0;
597 const ptr = array[0..2 :0].ptr;622 const ptr = @as([*:0]u16, array[0..2 :0]);
598 testing.expect(len(ptr) == 2);623 testing.expect(len(ptr) == 2);
599 }624 }
625 {
626 var array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 };
627 testing.expect(len(&array) == 5);
628 array[2] = 0;
629 testing.expect(len(&array) == 5);
630 }
631}
632
633/// Takes a pointer to an array, an array, a sentinel-terminated pointer,
634/// or a slice, and returns the length.
635/// In the case of a sentinel-terminated array, it scans the array
636/// for a sentinel and uses that for the length, rather than using the array length.
637/// For C pointers it assumes it is a pointer-to-many with a 0 sentinel.
638pub fn lenZ(ptr: var) usize {
639 return switch (@typeInfo(@TypeOf(ptr))) {
640 .Array => |info| if (info.sentinel) |sentinel|
641 indexOfSentinel(info.child, sentinel, &ptr)
642 else
643 info.len,
644 .Pointer => |info| switch (info.size) {
645 .One => switch (@typeInfo(info.child)) {
646 .Array => |x| if (x.sentinel) |sentinel|
647 indexOfSentinel(x.child, sentinel, ptr)
648 else
649 ptr.len,
650 else => @compileError("invalid type given to std.mem.lenZ"),
651 },
652 .Many => if (info.sentinel) |sentinel|
653 indexOfSentinel(info.child, sentinel, ptr)
654 else
655 @compileError("length of pointer with no sentinel"),
656 .C => indexOfSentinel(info.child, 0, ptr),
657 .Slice => if (info.sentinel) |sentinel|
658 indexOfSentinel(info.child, sentinel, ptr.ptr)
659 else
660 ptr.len,
661 },
662 else => @compileError("invalid type given to std.mem.lenZ"),
663 };
664}
665
666test "lenZ" {
667 testing.expect(lenZ("aoeu") == 4);
668
669 {
670 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
671 testing.expect(lenZ(&array) == 5);
672 testing.expect(lenZ(array[0..3]) == 3);
673 array[2] = 0;
674 const ptr = @as([*:0]u16, array[0..2 :0]);
675 testing.expect(lenZ(ptr) == 2);
676 }
677 {
678 var array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 };
679 testing.expect(lenZ(&array) == 5);
680 array[2] = 0;
681 testing.expect(lenZ(&array) == 2);
682 }
600}683}
601684
602pub fn indexOfSentinel(comptime Elem: type, comptime sentinel: Elem, ptr: [*:sentinel]const Elem) usize {685pub fn indexOfSentinel(comptime Elem: type, comptime sentinel: Elem, ptr: [*:sentinel]const Elem) usize {
...@@ -810,8 +893,7 @@ pub const readIntBig = switch (builtin.endian) {...@@ -810,8 +893,7 @@ pub const readIntBig = switch (builtin.endian) {
810pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T {893pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T {
811 const n = @divExact(T.bit_count, 8);894 const n = @divExact(T.bit_count, 8);
812 assert(bytes.len >= n);895 assert(bytes.len >= n);
813 // TODO https://github.com/ziglang/zig/issues/863896 return readIntNative(T, bytes[0..n]);
814 return readIntNative(T, @ptrCast(*const [n]u8, bytes.ptr));
815}897}
816898
817/// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0899/// 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...@@ -849,8 +931,7 @@ pub fn readInt(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8, en
849pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T {931pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T {
850 const n = @divExact(T.bit_count, 8);932 const n = @divExact(T.bit_count, 8);
851 assert(bytes.len >= n);933 assert(bytes.len >= n);
852 // TODO https://github.com/ziglang/zig/issues/863934 return readInt(T, bytes[0..n], endian);
853 return readInt(T, @ptrCast(*const [n]u8, bytes.ptr), endian);
854}935}
855936
856test "comptime read/write int" {937test "comptime read/write int" {
...@@ -1572,24 +1653,24 @@ pub fn nativeToBig(comptime T: type, x: T) T {...@@ -1572,24 +1653,24 @@ pub fn nativeToBig(comptime T: type, x: T) T {
1572}1653}
15731654
1574fn AsBytesReturnType(comptime P: type) type {1655fn AsBytesReturnType(comptime P: type) type {
1575 if (comptime !trait.isSingleItemPtr(P))1656 if (!trait.isSingleItemPtr(P))
1576 @compileError("expected single item pointer, passed " ++ @typeName(P));1657 @compileError("expected single item pointer, passed " ++ @typeName(P));
15771658
1578 const size = @as(usize, @sizeOf(meta.Child(P)));1659 const size = @sizeOf(meta.Child(P));
1579 const alignment = comptime meta.alignment(P);1660 const alignment = meta.alignment(P);
15801661
1581 if (alignment == 0) {1662 if (alignment == 0) {
1582 if (comptime trait.isConstPtr(P))1663 if (trait.isConstPtr(P))
1583 return *const [size]u8;1664 return *const [size]u8;
1584 return *[size]u8;1665 return *[size]u8;
1585 }1666 }
15861667
1587 if (comptime trait.isConstPtr(P))1668 if (trait.isConstPtr(P))
1588 return *align(alignment) const [size]u8;1669 return *align(alignment) const [size]u8;
1589 return *align(alignment) [size]u8;1670 return *align(alignment) [size]u8;
1590}1671}
15911672
1592///Given a pointer to a single item, returns a slice of the underlying bytes, preserving constness.1673/// Given a pointer to a single item, returns a slice of the underlying bytes, preserving constness.
1593pub fn asBytes(ptr: var) AsBytesReturnType(@TypeOf(ptr)) {1674pub fn asBytes(ptr: var) AsBytesReturnType(@TypeOf(ptr)) {
1594 const P = @TypeOf(ptr);1675 const P = @TypeOf(ptr);
1595 return @ptrCast(AsBytesReturnType(P), ptr);1676 return @ptrCast(AsBytesReturnType(P), ptr);
...@@ -1736,34 +1817,50 @@ fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type {...@@ -1736,34 +1817,50 @@ fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type {
1736}1817}
17371818
1738pub fn bytesAsSlice(comptime T: type, bytes: var) BytesAsSliceReturnType(T, @TypeOf(bytes)) {1819pub fn bytesAsSlice(comptime T: type, bytes: var) BytesAsSliceReturnType(T, @TypeOf(bytes)) {
1739 const bytesSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(bytes))) bytes[0..] else bytes;
1740
1741 // let's not give an undefined pointer to @ptrCast1820 // let's not give an undefined pointer to @ptrCast
1742 // it may be equal to zero and fail a null check1821 // it may be equal to zero and fail a null check
1743 if (bytesSlice.len == 0) {1822 if (bytes.len == 0) {
1744 return &[0]T{};1823 return &[0]T{};
1745 }1824 }
17461825
1747 const bytesType = @TypeOf(bytesSlice);1826 const Bytes = @TypeOf(bytes);
1748 const alignment = comptime meta.alignment(bytesType);1827 const alignment = comptime meta.alignment(Bytes);
17491828
1750 const castTarget = if (comptime trait.isConstPtr(bytesType)) [*]align(alignment) const T else [*]align(alignment) T;1829 const cast_target = if (comptime trait.isConstPtr(Bytes)) [*]align(alignment) const T else [*]align(alignment) T;
17511830
1752 return @ptrCast(castTarget, bytesSlice.ptr)[0..@divExact(bytes.len, @sizeOf(T))];1831 return @ptrCast(cast_target, bytes)[0..@divExact(bytes.len, @sizeOf(T))];
1753}1832}
17541833
1755test "bytesAsSlice" {1834test "bytesAsSlice" {
1756 const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };1835 {
1757 const slice = bytesAsSlice(u16, bytes[0..]);1836 const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
1758 testing.expect(slice.len == 2);1837 const slice = bytesAsSlice(u16, bytes[0..]);
1759 testing.expect(bigToNative(u16, slice[0]) == 0xDEAD);1838 testing.expect(slice.len == 2);
1760 testing.expect(bigToNative(u16, slice[1]) == 0xBEEF);1839 testing.expect(bigToNative(u16, slice[0]) == 0xDEAD);
1840 testing.expect(bigToNative(u16, slice[1]) == 0xBEEF);
1841 }
1842 {
1843 const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
1844 var runtime_zero: usize = 0;
1845 const slice = bytesAsSlice(u16, bytes[runtime_zero..]);
1846 testing.expect(slice.len == 2);
1847 testing.expect(bigToNative(u16, slice[0]) == 0xDEAD);
1848 testing.expect(bigToNative(u16, slice[1]) == 0xBEEF);
1849 }
1761}1850}
17621851
1763test "bytesAsSlice keeps pointer alignment" {1852test "bytesAsSlice keeps pointer alignment" {
1764 var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 };1853 {
1765 const numbers = bytesAsSlice(u32, bytes[0..]);1854 var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 };
1766 comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32);1855 const numbers = bytesAsSlice(u32, bytes[0..]);
1856 comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32);
1857 }
1858 {
1859 var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 };
1860 var runtime_zero: usize = 0;
1861 const numbers = bytesAsSlice(u32, bytes[runtime_zero..]);
1862 comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32);
1863 }
1767}1864}
17681865
1769test "bytesAsSlice on a packed struct" {1866test "bytesAsSlice on a packed struct" {
...@@ -1799,21 +1896,19 @@ fn SliceAsBytesReturnType(comptime sliceType: type) type {...@@ -1799,21 +1896,19 @@ fn SliceAsBytesReturnType(comptime sliceType: type) type {
1799}1896}
18001897
1801pub fn sliceAsBytes(slice: var) SliceAsBytesReturnType(@TypeOf(slice)) {1898pub fn sliceAsBytes(slice: var) SliceAsBytesReturnType(@TypeOf(slice)) {
1802 const actualSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(slice))) slice[0..] else slice;1899 const Slice = @TypeOf(slice);
1803 const actualSliceTypeInfo = @typeInfo(@TypeOf(actualSlice)).Pointer;
18041900
1805 // let's not give an undefined pointer to @ptrCast1901 // let's not give an undefined pointer to @ptrCast
1806 // it may be equal to zero and fail a null check1902 // it may be equal to zero and fail a null check
1807 if (actualSlice.len == 0 and actualSliceTypeInfo.sentinel == null) {1903 if (slice.len == 0 and comptime meta.sentinel(Slice) == null) {
1808 return &[0]u8{};1904 return &[0]u8{};
1809 }1905 }
18101906
1811 const sliceType = @TypeOf(actualSlice);1907 const alignment = comptime meta.alignment(Slice);
1812 const alignment = comptime meta.alignment(sliceType);
18131908
1814 const castTarget = if (comptime trait.isConstPtr(sliceType)) [*]align(alignment) const u8 else [*]align(alignment) u8;1909 const cast_target = if (comptime trait.isConstPtr(Slice)) [*]align(alignment) const u8 else [*]align(alignment) u8;
18151910
1816 return @ptrCast(castTarget, actualSlice.ptr)[0 .. actualSlice.len * @sizeOf(comptime meta.Child(sliceType))];1911 return @ptrCast(cast_target, slice)[0 .. slice.len * @sizeOf(meta.Elem(Slice))];
1817}1912}
18181913
1819test "sliceAsBytes" {1914test "sliceAsBytes" {
...@@ -1883,39 +1978,6 @@ test "sliceAsBytes and bytesAsSlice back" {...@@ -1883,39 +1978,6 @@ test "sliceAsBytes and bytesAsSlice back" {
1883 testing.expect(bytes[11] == math.maxInt(u8));1978 testing.expect(bytes[11] == math.maxInt(u8));
1884}1979}
18851980
1886fn SubArrayPtrReturnType(comptime T: type, comptime length: usize) type {
1887 if (trait.isConstPtr(T))
1888 return *const [length]meta.Child(meta.Child(T));
1889 return *[length]meta.Child(meta.Child(T));
1890}
1891
1892/// Given a pointer to an array, returns a pointer to a portion of that array, preserving constness.
1893/// TODO this will be obsoleted by https://github.com/ziglang/zig/issues/863
1894pub fn subArrayPtr(
1895 ptr: var,
1896 comptime start: usize,
1897 comptime length: usize,
1898) SubArrayPtrReturnType(@TypeOf(ptr), length) {
1899 assert(start + length <= ptr.*.len);
1900
1901 const ReturnType = SubArrayPtrReturnType(@TypeOf(ptr), length);
1902 const T = meta.Child(meta.Child(@TypeOf(ptr)));
1903 return @ptrCast(ReturnType, &ptr[start]);
1904}
1905
1906test "subArrayPtr" {
1907 const a1: [6]u8 = "abcdef".*;
1908 const sub1 = subArrayPtr(&a1, 2, 3);
1909 testing.expect(eql(u8, sub1, "cde"));
1910
1911 var a2: [6]u8 = "abcdef".*;
1912 var sub2 = subArrayPtr(&a2, 2, 3);
1913
1914 testing.expect(eql(u8, sub2, "cde"));
1915 sub2[1] = 'X';
1916 testing.expect(eql(u8, &a2, "abcXef"));
1917}
1918
1919/// Round an address up to the nearest aligned address1981/// Round an address up to the nearest aligned address
1920/// The alignment must be a power of 2 and greater than 0.1982/// The alignment must be a power of 2 and greater than 0.
1921pub fn alignForward(addr: usize, alignment: usize) usize {1983pub fn alignForward(addr: usize, alignment: usize) usize {
lib/std/meta.zig+50-15
...@@ -104,7 +104,7 @@ pub fn Child(comptime T: type) type {...@@ -104,7 +104,7 @@ pub fn Child(comptime T: type) type {
104 .Array => |info| info.child,104 .Array => |info| info.child,
105 .Pointer => |info| info.child,105 .Pointer => |info| info.child,
106 .Optional => |info| info.child,106 .Optional => |info| info.child,
107 else => @compileError("Expected pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"),107 else => @compileError("Expected pointer, optional, or array type, found '" ++ @typeName(T) ++ "'"),
108 };108 };
109}109}
110110
...@@ -115,30 +115,65 @@ test "std.meta.Child" {...@@ -115,30 +115,65 @@ test "std.meta.Child" {
115 testing.expect(Child(?u8) == u8);115 testing.expect(Child(?u8) == u8);
116}116}
117117
118/// Given a type with a sentinel e.g. `[:0]u8`, returns the sentinel118/// Given a "memory span" type, returns the "element type".
119pub fn Sentinel(comptime T: type) Child(T) {119pub fn Elem(comptime T: type) type {
120 // comptime asserts that ptr has a sentinel
121 switch (@typeInfo(T)) {120 switch (@typeInfo(T)) {
122 .Array => |arrayInfo| {121 .Array => |info| return info.child,
123 return comptime arrayInfo.sentinel.?;122 .Pointer => |info| switch (info.size) {
123 .One => switch (@typeInfo(info.child)) {
124 .Array => |array_info| return array_info.child,
125 else => {},
126 },
127 .Many, .C, .Slice => return info.child,
124 },128 },
125 .Pointer => |ptrInfo| {129 else => {},
126 switch (ptrInfo.size) {130 }
127 .Many, .Slice => {131 @compileError("Expected pointer, slice, or array, found '" ++ @typeName(T) ++ "'");
128 return comptime ptrInfo.sentinel.?;132}
133
134test "std.meta.Elem" {
135 testing.expect(Elem([1]u8) == u8);
136 testing.expect(Elem([*]u8) == u8);
137 testing.expect(Elem([]u8) == u8);
138 testing.expect(Elem(*[10]u8) == u8);
139}
140
141/// Given a type which can have a sentinel e.g. `[:0]u8`, returns the sentinel value,
142/// or `null` if there is not one.
143/// Types which cannot possibly have a sentinel will be a compile error.
144pub fn sentinel(comptime T: type) ?Elem(T) {
145 switch (@typeInfo(T)) {
146 .Array => |info| return info.sentinel,
147 .Pointer => |info| {
148 switch (info.size) {
149 .Many, .Slice => return info.sentinel,
150 .One => switch (@typeInfo(info.child)) {
151 .Array => |array_info| return array_info.sentinel,
152 else => {},
129 },153 },
130 else => {},154 else => {},
131 }155 }
132 },156 },
133 else => {},157 else => {},
134 }158 }
135 @compileError("not a sentinel type, found '" ++ @typeName(T) ++ "'");159 @compileError("type '" ++ @typeName(T) ++ "' cannot possibly have a sentinel");
136}160}
137161
138test "std.meta.Sentinel" {162test "std.meta.sentinel" {
139 testing.expectEqual(@as(u8, 0), Sentinel([:0]u8));163 testSentinel();
140 testing.expectEqual(@as(u8, 0), Sentinel([*:0]u8));164 comptime testSentinel();
141 testing.expectEqual(@as(u8, 0), Sentinel([5:0]u8));165}
166
167fn testSentinel() void {
168 testing.expectEqual(@as(u8, 0), sentinel([:0]u8).?);
169 testing.expectEqual(@as(u8, 0), sentinel([*:0]u8).?);
170 testing.expectEqual(@as(u8, 0), sentinel([5:0]u8).?);
171 testing.expectEqual(@as(u8, 0), sentinel(*const [5:0]u8).?);
172
173 testing.expect(sentinel([]u8) == null);
174 testing.expect(sentinel([*]u8) == null);
175 testing.expect(sentinel([5]u8) == null);
176 testing.expect(sentinel(*const [5]u8) == null);
142}177}
143178
144pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {179pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout {
lib/std/meta/trait.zig+7-5
...@@ -230,9 +230,10 @@ pub fn isSingleItemPtr(comptime T: type) bool {...@@ -230,9 +230,10 @@ pub fn isSingleItemPtr(comptime T: type) bool {
230230
231test "std.meta.trait.isSingleItemPtr" {231test "std.meta.trait.isSingleItemPtr" {
232 const array = [_]u8{0} ** 10;232 const array = [_]u8{0} ** 10;
233 testing.expect(isSingleItemPtr(@TypeOf(&array[0])));233 comptime testing.expect(isSingleItemPtr(@TypeOf(&array[0])));
234 testing.expect(!isSingleItemPtr(@TypeOf(array)));234 comptime testing.expect(!isSingleItemPtr(@TypeOf(array)));
235 testing.expect(!isSingleItemPtr(@TypeOf(array[0..1])));235 var runtime_zero: usize = 0;
236 testing.expect(!isSingleItemPtr(@TypeOf(array[runtime_zero..1])));
236}237}
237238
238pub fn isManyItemPtr(comptime T: type) bool {239pub fn isManyItemPtr(comptime T: type) bool {
...@@ -259,7 +260,8 @@ pub fn isSlice(comptime T: type) bool {...@@ -259,7 +260,8 @@ pub fn isSlice(comptime T: type) bool {
259260
260test "std.meta.trait.isSlice" {261test "std.meta.trait.isSlice" {
261 const array = [_]u8{0} ** 10;262 const array = [_]u8{0} ** 10;
262 testing.expect(isSlice(@TypeOf(array[0..])));263 var runtime_zero: usize = 0;
264 testing.expect(isSlice(@TypeOf(array[runtime_zero..])));
263 testing.expect(!isSlice(@TypeOf(array)));265 testing.expect(!isSlice(@TypeOf(array)));
264 testing.expect(!isSlice(@TypeOf(&array[0])));266 testing.expect(!isSlice(@TypeOf(&array[0])));
265}267}
...@@ -276,7 +278,7 @@ pub fn isIndexable(comptime T: type) bool {...@@ -276,7 +278,7 @@ pub fn isIndexable(comptime T: type) bool {
276278
277test "std.meta.trait.isIndexable" {279test "std.meta.trait.isIndexable" {
278 const array = [_]u8{0} ** 10;280 const array = [_]u8{0} ** 10;
279 const slice = array[0..];281 const slice = @as([]const u8, &array);
280282
281 testing.expect(isIndexable(@TypeOf(array)));283 testing.expect(isIndexable(@TypeOf(array)));
282 testing.expect(isIndexable(@TypeOf(&array)));284 testing.expect(isIndexable(@TypeOf(&array)));
lib/std/net.zig+7-5
...@@ -612,8 +612,7 @@ fn linuxLookupName(...@@ -612,8 +612,7 @@ fn linuxLookupName(
612 } else {612 } else {
613 mem.copy(u8, &sa6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff");613 mem.copy(u8, &sa6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff");
614 mem.copy(u8, &da6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff");614 mem.copy(u8, &da6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff");
615 // TODO https://github.com/ziglang/zig/issues/863615 mem.writeIntNative(u32, da6.addr[12..], addr.addr.in.addr);
616 mem.writeIntNative(u32, @ptrCast(*[4]u8, da6.addr[12..].ptr), addr.addr.in.addr);
617 da4.addr = addr.addr.in.addr;616 da4.addr = addr.addr.in.addr;
618 da = @ptrCast(*os.sockaddr, &da4);617 da = @ptrCast(*os.sockaddr, &da4);
619 dalen = @sizeOf(os.sockaddr_in);618 dalen = @sizeOf(os.sockaddr_in);
...@@ -821,7 +820,7 @@ fn linuxLookupNameFromHosts(...@@ -821,7 +820,7 @@ fn linuxLookupNameFromHosts(
821 // Skip to the delimiter in the stream, to fix parsing820 // Skip to the delimiter in the stream, to fix parsing
822 try stream.skipUntilDelimiterOrEof('\n');821 try stream.skipUntilDelimiterOrEof('\n');
823 // Use the truncated line. A truncated comment or hostname will be handled correctly.822 // Use the truncated line. A truncated comment or hostname will be handled correctly.
824 break :blk line_buf[0..];823 break :blk @as([]u8, &line_buf); // TODO the cast should not be necessary
825 },824 },
826 else => |e| return e,825 else => |e| return e,
827 }) |line| {826 }) |line| {
...@@ -958,7 +957,10 @@ fn linuxLookupNameFromDns(...@@ -958,7 +957,10 @@ fn linuxLookupNameFromDns(
958 }957 }
959 }958 }
960959
961 var ap = [2][]u8{ apbuf[0][0..0], apbuf[1][0..0] };960 var ap = [2][]u8{ apbuf[0], apbuf[1] };
961 ap[0].len = 0;
962 ap[1].len = 0;
963
962 try resMSendRc(qp[0..nq], ap[0..nq], apbuf[0..nq], rc);964 try resMSendRc(qp[0..nq], ap[0..nq], apbuf[0..nq], rc);
963965
964 var i: usize = 0;966 var i: usize = 0;
...@@ -1015,7 +1017,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {...@@ -1015,7 +1017,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {
1015 // Skip to the delimiter in the stream, to fix parsing1017 // Skip to the delimiter in the stream, to fix parsing
1016 try stream.skipUntilDelimiterOrEof('\n');1018 try stream.skipUntilDelimiterOrEof('\n');
1017 // Give an empty line to the while loop, which will be skipped.1019 // Give an empty line to the while loop, which will be skipped.
1018 break :blk line_buf[0..0];1020 break :blk @as([]u8, line_buf[0..0]); // TODO the cast should not be necessary
1019 },1021 },
1020 else => |e| return e,1022 else => |e| return e,
1021 }) |line| {1023 }) |line| {
lib/std/os.zig+143-5
...@@ -461,13 +461,11 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {...@@ -461,13 +461,11 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
461 );461 );
462462
463 switch (rc) {463 switch (rc) {
464 .SUCCESS => {},464 .SUCCESS => return,
465 .INVALID_HANDLE => unreachable, // Handle not open for writing465 .INVALID_HANDLE => unreachable, // Handle not open for writing
466 .ACCESS_DENIED => return error.CannotTruncate,466 .ACCESS_DENIED => return error.CannotTruncate,
467 else => return windows.unexpectedStatus(rc),467 else => return windows.unexpectedStatus(rc),
468 }468 }
469
470 return;
471 }469 }
472470
473 while (true) {471 while (true) {
...@@ -852,6 +850,7 @@ pub const OpenError = error{...@@ -852,6 +850,7 @@ pub const OpenError = error{
852850
853/// Open and possibly create a file. Keeps trying if it gets interrupted.851/// Open and possibly create a file. Keeps trying if it gets interrupted.
854/// See also `openC`.852/// See also `openC`.
853/// TODO support windows
855pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t {854pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t {
856 const file_path_c = try toPosixPath(file_path);855 const file_path_c = try toPosixPath(file_path);
857 return openC(&file_path_c, flags, perm);856 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 {...@@ -859,6 +858,7 @@ pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t {
859858
860/// Open and possibly create a file. Keeps trying if it gets interrupted.859/// Open and possibly create a file. Keeps trying if it gets interrupted.
861/// See also `open`.860/// See also `open`.
861/// TODO support windows
862pub fn openC(file_path: [*:0]const u8, flags: u32, perm: usize) OpenError!fd_t {862pub fn openC(file_path: [*:0]const u8, flags: u32, perm: usize) OpenError!fd_t {
863 while (true) {863 while (true) {
864 const rc = system.open(file_path, flags, perm);864 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 {...@@ -892,6 +892,7 @@ pub fn openC(file_path: [*:0]const u8, flags: u32, perm: usize) OpenError!fd_t {
892/// Open and possibly create a file. Keeps trying if it gets interrupted.892/// Open and possibly create a file. Keeps trying if it gets interrupted.
893/// `file_path` is relative to the open directory handle `dir_fd`.893/// `file_path` is relative to the open directory handle `dir_fd`.
894/// See also `openatC`.894/// See also `openatC`.
895/// TODO support windows
895pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) OpenError!fd_t {896pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) OpenError!fd_t {
896 const file_path_c = try toPosixPath(file_path);897 const file_path_c = try toPosixPath(file_path);
897 return openatC(dir_fd, &file_path_c, flags, mode);898 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...@@ -900,6 +901,7 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope
900/// Open and possibly create a file. Keeps trying if it gets interrupted.901/// Open and possibly create a file. Keeps trying if it gets interrupted.
901/// `file_path` is relative to the open directory handle `dir_fd`.902/// `file_path` is relative to the open directory handle `dir_fd`.
902/// See also `openat`.903/// See also `openat`.
904/// TODO support windows
903pub fn openatC(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t) OpenError!fd_t {905pub fn openatC(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t) OpenError!fd_t {
904 while (true) {906 while (true) {
905 const rc = system.openat(dir_fd, file_path, flags, mode);907 const rc = system.openat(dir_fd, file_path, flags, mode);
...@@ -1527,6 +1529,9 @@ const RenameError = error{...@@ -1527,6 +1529,9 @@ const RenameError = error{
1527 RenameAcrossMountPoints,1529 RenameAcrossMountPoints,
1528 InvalidUtf8,1530 InvalidUtf8,
1529 BadPathName,1531 BadPathName,
1532 NoDevice,
1533 SharingViolation,
1534 PipeBusy,
1530} || UnexpectedError;1535} || UnexpectedError;
15311536
1532/// Change the name or location of a file.1537/// Change the name or location of a file.
...@@ -1580,6 +1585,113 @@ pub fn renameW(old_path: [*:0]const u16, new_path: [*:0]const u16) RenameError!v...@@ -1580,6 +1585,113 @@ pub fn renameW(old_path: [*:0]const u16, new_path: [*:0]const u16) RenameError!v
1580 return windows.MoveFileExW(old_path, new_path, flags);1585 return windows.MoveFileExW(old_path, new_path, flags);
1581}1586}
15821587
1588/// Change the name or location of a file based on an open directory handle.
1589pub fn renameat(
1590 old_dir_fd: fd_t,
1591 old_path: []const u8,
1592 new_dir_fd: fd_t,
1593 new_path: []const u8,
1594) RenameError!void {
1595 if (builtin.os.tag == .windows) {
1596 const old_path_w = try windows.sliceToPrefixedFileW(old_path);
1597 const new_path_w = try windows.sliceToPrefixedFileW(new_path);
1598 return renameatW(old_dir_fd, &old_path_w, new_dir_fd, &new_path_w, windows.TRUE);
1599 } else {
1600 const old_path_c = try toPosixPath(old_path);
1601 const new_path_c = try toPosixPath(new_path);
1602 return renameatZ(old_dir_fd, &old_path_c, new_dir_fd, &new_path_c);
1603 }
1604}
1605
1606/// Same as `renameat` except the parameters are null-terminated byte arrays.
1607pub fn renameatZ(
1608 old_dir_fd: fd_t,
1609 old_path: [*:0]const u8,
1610 new_dir_fd: fd_t,
1611 new_path: [*:0]const u8,
1612) RenameError!void {
1613 if (builtin.os.tag == .windows) {
1614 const old_path_w = try windows.cStrToPrefixedFileW(old_path);
1615 const new_path_w = try windows.cStrToPrefixedFileW(new_path);
1616 return renameatW(old_dir_fd, &old_path_w, new_dir_fd, &new_path_w, windows.TRUE);
1617 }
1618
1619 switch (errno(system.renameat(old_dir_fd, old_path, new_dir_fd, new_path))) {
1620 0 => return,
1621 EACCES => return error.AccessDenied,
1622 EPERM => return error.AccessDenied,
1623 EBUSY => return error.FileBusy,
1624 EDQUOT => return error.DiskQuota,
1625 EFAULT => unreachable,
1626 EINVAL => unreachable,
1627 EISDIR => return error.IsDir,
1628 ELOOP => return error.SymLinkLoop,
1629 EMLINK => return error.LinkQuotaExceeded,
1630 ENAMETOOLONG => return error.NameTooLong,
1631 ENOENT => return error.FileNotFound,
1632 ENOTDIR => return error.NotDir,
1633 ENOMEM => return error.SystemResources,
1634 ENOSPC => return error.NoSpaceLeft,
1635 EEXIST => return error.PathAlreadyExists,
1636 ENOTEMPTY => return error.PathAlreadyExists,
1637 EROFS => return error.ReadOnlyFileSystem,
1638 EXDEV => return error.RenameAcrossMountPoints,
1639 else => |err| return unexpectedErrno(err),
1640 }
1641}
1642
1643/// Same as `renameat` except the parameters are null-terminated UTF16LE encoded byte arrays.
1644/// Assumes target is Windows.
1645/// TODO these args can actually be slices when using ntdll. audit the rest of the W functions too.
1646pub fn renameatW(
1647 old_dir_fd: fd_t,
1648 old_path: [*:0]const u16,
1649 new_dir_fd: fd_t,
1650 new_path_w: [*:0]const u16,
1651 ReplaceIfExists: windows.BOOLEAN,
1652) RenameError!void {
1653 const access_mask = windows.SYNCHRONIZE | windows.GENERIC_WRITE | windows.DELETE;
1654 const src_fd = try windows.OpenFileW(old_dir_fd, old_path, null, access_mask, windows.FILE_OPEN);
1655 defer windows.CloseHandle(src_fd);
1656
1657 const struct_buf_len = @sizeOf(windows.FILE_RENAME_INFORMATION) + (MAX_PATH_BYTES - 1);
1658 var rename_info_buf: [struct_buf_len]u8 align(@alignOf(windows.FILE_RENAME_INFORMATION)) = undefined;
1659 const new_path = mem.span(new_path_w);
1660 const struct_len = @sizeOf(windows.FILE_RENAME_INFORMATION) - 1 + new_path.len * 2;
1661 if (struct_len > struct_buf_len) return error.NameTooLong;
1662
1663 const rename_info = @ptrCast(*windows.FILE_RENAME_INFORMATION, &rename_info_buf);
1664
1665 rename_info.* = .{
1666 .ReplaceIfExists = ReplaceIfExists,
1667 .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(new_path_w)) null else new_dir_fd,
1668 .FileNameLength = @intCast(u32, new_path.len * 2), // already checked error.NameTooLong
1669 .FileName = undefined,
1670 };
1671 std.mem.copy(u16, @as([*]u16, &rename_info.FileName)[0..new_path.len], new_path);
1672
1673 var io_status_block: windows.IO_STATUS_BLOCK = undefined;
1674
1675 const rc = windows.ntdll.NtSetInformationFile(
1676 src_fd,
1677 &io_status_block,
1678 rename_info,
1679 @intCast(u32, struct_len), // already checked for error.NameTooLong
1680 .FileRenameInformation,
1681 );
1682
1683 switch (rc) {
1684 .SUCCESS => return,
1685 .INVALID_HANDLE => unreachable,
1686 .INVALID_PARAMETER => unreachable,
1687 .OBJECT_PATH_SYNTAX_BAD => unreachable,
1688 .ACCESS_DENIED => return error.AccessDenied,
1689 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
1690 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
1691 else => return windows.unexpectedStatus(rc),
1692 }
1693}
1694
1583pub const MakeDirError = error{1695pub const MakeDirError = error{
1584 AccessDenied,1696 AccessDenied,
1585 DiskQuota,1697 DiskQuota,
...@@ -2072,7 +2184,7 @@ const ListenError = error{...@@ -2072,7 +2184,7 @@ const ListenError = error{
2072 OperationNotSupported,2184 OperationNotSupported,
2073} || UnexpectedError;2185} || UnexpectedError;
20742186
2075pub fn listen(sockfd: i32, backlog: u32) ListenError!void {2187pub fn listen(sockfd: fd_t, backlog: u32) ListenError!void {
2076 const rc = system.listen(sockfd, backlog);2188 const rc = system.listen(sockfd, backlog);
2077 switch (errno(rc)) {2189 switch (errno(rc)) {
2078 0 => return,2190 0 => return,
...@@ -2363,7 +2475,7 @@ pub fn connect(sockfd: fd_t, sock_addr: *const sockaddr, len: socklen_t) Connect...@@ -2363,7 +2475,7 @@ pub fn connect(sockfd: fd_t, sock_addr: *const sockaddr, len: socklen_t) Connect
2363 }2475 }
2364}2476}
23652477
2366pub fn getsockoptError(sockfd: i32) ConnectError!void {2478pub fn getsockoptError(sockfd: fd_t) ConnectError!void {
2367 var err_code: u32 = undefined;2479 var err_code: u32 = undefined;
2368 var size: u32 = @sizeOf(u32);2480 var size: u32 = @sizeOf(u32);
2369 const rc = system.getsockopt(sockfd, SOL_SOCKET, SO_ERROR, @ptrCast([*]u8, &err_code), &size);2481 const rc = system.getsockopt(sockfd, SOL_SOCKET, SO_ERROR, @ptrCast([*]u8, &err_code), &size);
...@@ -3051,6 +3163,31 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {...@@ -3051,6 +3163,31 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {
3051 }3163 }
3052}3164}
30533165
3166pub const FcntlError = error{
3167 PermissionDenied,
3168 FileBusy,
3169 ProcessFdQuotaExceeded,
3170 Locked,
3171} || UnexpectedError;
3172
3173pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) FcntlError!usize {
3174 while (true) {
3175 const rc = system.fcntl(fd, cmd, arg);
3176 switch (errno(rc)) {
3177 0 => return @intCast(usize, rc),
3178 EINTR => continue,
3179 EACCES => return error.Locked,
3180 EBADF => unreachable,
3181 EBUSY => return error.FileBusy,
3182 EINVAL => unreachable, // invalid parameters
3183 EPERM => return error.PermissionDenied,
3184 EMFILE => return error.ProcessFdQuotaExceeded,
3185 ENOTDIR => unreachable, // invalid parameter
3186 else => |err| return unexpectedErrno(err),
3187 }
3188 }
3189}
3190
3054pub const RealPathError = error{3191pub const RealPathError = error{
3055 FileNotFound,3192 FileNotFound,
3056 AccessDenied,3193 AccessDenied,
...@@ -3125,6 +3262,7 @@ pub fn realpathC(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealP...@@ -3125,6 +3262,7 @@ pub fn realpathC(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealP
3125}3262}
31263263
3127/// Same as `realpath` except `pathname` is null-terminated and UTF16LE-encoded.3264/// Same as `realpath` except `pathname` is null-terminated and UTF16LE-encoded.
3265/// TODO use ntdll for better semantics
3128pub fn realpathW(pathname: [*:0]const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {3266pub fn realpathW(pathname: [*:0]const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
3129 const h_file = try windows.CreateFileW(3267 const h_file = try windows.CreateFileW(
3130 pathname,3268 pathname,
lib/std/os/bits/dragonfly.zig+2
...@@ -283,6 +283,8 @@ pub const F_LOCK = 1;...@@ -283,6 +283,8 @@ pub const F_LOCK = 1;
283pub const F_TLOCK = 2;283pub const F_TLOCK = 2;
284pub const F_TEST = 3;284pub const F_TEST = 3;
285285
286pub const FD_CLOEXEC = 1;
287
286pub const AT_FDCWD = -328243;288pub const AT_FDCWD = -328243;
287pub const AT_SYMLINK_NOFOLLOW = 1;289pub const AT_SYMLINK_NOFOLLOW = 1;
288pub const AT_REMOVEDIR = 2;290pub const AT_REMOVEDIR = 2;
lib/std/os/bits/freebsd.zig+2
...@@ -355,6 +355,8 @@ pub const F_GETOWN_EX = 16;...@@ -355,6 +355,8 @@ pub const F_GETOWN_EX = 16;
355355
356pub const F_GETOWNER_UIDS = 17;356pub const F_GETOWNER_UIDS = 17;
357357
358pub const FD_CLOEXEC = 1;
359
358pub const SEEK_SET = 0;360pub const SEEK_SET = 0;
359pub const SEEK_CUR = 1;361pub const SEEK_CUR = 1;
360pub const SEEK_END = 2;362pub const SEEK_END = 2;
lib/std/os/bits/linux.zig+2
...@@ -136,6 +136,8 @@ pub const MAP_FIXED_NOREPLACE = 0x100000;...@@ -136,6 +136,8 @@ pub const MAP_FIXED_NOREPLACE = 0x100000;
136/// For anonymous mmap, memory could be uninitialized136/// For anonymous mmap, memory could be uninitialized
137pub const MAP_UNINITIALIZED = 0x4000000;137pub const MAP_UNINITIALIZED = 0x4000000;
138138
139pub const FD_CLOEXEC = 1;
140
139pub const F_OK = 0;141pub const F_OK = 0;
140pub const X_OK = 1;142pub const X_OK = 1;
141pub const W_OK = 2;143pub const W_OK = 2;
lib/std/os/bits/netbsd.zig+2
...@@ -312,6 +312,8 @@ pub const F_GETLK = 7;...@@ -312,6 +312,8 @@ pub const F_GETLK = 7;
312pub const F_SETLK = 8;312pub const F_SETLK = 8;
313pub const F_SETLKW = 9;313pub const F_SETLKW = 9;
314314
315pub const FD_CLOEXEC = 1;
316
315pub const SEEK_SET = 0;317pub const SEEK_SET = 0;
316pub const SEEK_CUR = 1;318pub const SEEK_CUR = 1;
317pub const SEEK_END = 2;319pub const SEEK_END = 2;
lib/std/os/linux.zig+8-4
...@@ -465,17 +465,17 @@ pub fn renameat(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const...@@ -465,17 +465,17 @@ pub fn renameat(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const
465 return syscall4(465 return syscall4(
466 SYS_renameat,466 SYS_renameat,
467 @bitCast(usize, @as(isize, oldfd)),467 @bitCast(usize, @as(isize, oldfd)),
468 @ptrToInt(old),468 @ptrToInt(oldpath),
469 @bitCast(usize, @as(isize, newfd)),469 @bitCast(usize, @as(isize, newfd)),
470 @ptrToInt(new),470 @ptrToInt(newpath),
471 );471 );
472 } else {472 } else {
473 return syscall5(473 return syscall5(
474 SYS_renameat2,474 SYS_renameat2,
475 @bitCast(usize, @as(isize, oldfd)),475 @bitCast(usize, @as(isize, oldfd)),
476 @ptrToInt(old),476 @ptrToInt(oldpath),
477 @bitCast(usize, @as(isize, newfd)),477 @bitCast(usize, @as(isize, newfd)),
478 @ptrToInt(new),478 @ptrToInt(newpath),
479 0,479 0,
480 );480 );
481 }481 }
...@@ -588,6 +588,10 @@ pub fn waitpid(pid: pid_t, status: *u32, flags: u32) usize {...@@ -588,6 +588,10 @@ pub fn waitpid(pid: pid_t, status: *u32, flags: u32) usize {
588 return syscall4(SYS_wait4, @bitCast(usize, @as(isize, pid)), @ptrToInt(status), flags, 0);588 return syscall4(SYS_wait4, @bitCast(usize, @as(isize, pid)), @ptrToInt(status), flags, 0);
589}589}
590590
591pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) usize {
592 return syscall3(SYS_fcntl, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, cmd)), arg);
593}
594
591var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime);595var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime);
592596
593// We must follow the C calling convention when we call into the VDSO597// We must follow the C calling convention when we call into the VDSO
lib/std/os/test.zig+44-12
...@@ -1,7 +1,8 @@...@@ -1,7 +1,8 @@
1const std = @import("../std.zig");1const std = @import("../std.zig");
2const os = std.os;2const os = std.os;
3const testing = std.testing;3const testing = std.testing;
4const expect = std.testing.expect;4const expect = testing.expect;
5const expectEqual = testing.expectEqual;
5const io = std.io;6const io = std.io;
6const fs = std.fs;7const fs = std.fs;
7const mem = std.mem;8const mem = std.mem;
...@@ -19,8 +20,8 @@ test "makePath, put some files in it, deleteTree" {...@@ -19,8 +20,8 @@ test "makePath, put some files in it, deleteTree" {
19 try fs.cwd().makePath("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c");20 try fs.cwd().makePath("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c");
20 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c" ++ fs.path.sep_str ++ "file.txt", "nonsense");21 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c" ++ fs.path.sep_str ++ "file.txt", "nonsense");
21 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah");22 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah");
22 try fs.deleteTree("os_test_tmp");23 try fs.cwd().deleteTree("os_test_tmp");
23 if (fs.cwd().openDirTraverse("os_test_tmp")) |dir| {24 if (fs.cwd().openDir("os_test_tmp", .{})) |dir| {
24 @panic("expected error");25 @panic("expected error");
25 } else |err| {26 } else |err| {
26 expect(err == error.FileNotFound);27 expect(err == error.FileNotFound);
...@@ -37,7 +38,7 @@ test "access file" {...@@ -37,7 +38,7 @@ test "access file" {
3738
38 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", "");39 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", "");
39 try os.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", os.F_OK);40 try os.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", os.F_OK);
40 try fs.deleteTree("os_test_tmp");41 try fs.cwd().deleteTree("os_test_tmp");
41}42}
4243
43fn testThreadIdFn(thread_id: *Thread.Id) void {44fn testThreadIdFn(thread_id: *Thread.Id) void {
...@@ -46,9 +47,9 @@ fn testThreadIdFn(thread_id: *Thread.Id) void {...@@ -46,9 +47,9 @@ fn testThreadIdFn(thread_id: *Thread.Id) void {
4647
47test "sendfile" {48test "sendfile" {
48 try fs.cwd().makePath("os_test_tmp");49 try fs.cwd().makePath("os_test_tmp");
49 defer fs.deleteTree("os_test_tmp") catch {};50 defer fs.cwd().deleteTree("os_test_tmp") catch {};
5051
51 var dir = try fs.cwd().openDirList("os_test_tmp");52 var dir = try fs.cwd().openDir("os_test_tmp", .{});
52 defer dir.close();53 defer dir.close();
5354
54 const line1 = "line1\n";55 const line1 = "line1\n";
...@@ -112,14 +113,16 @@ test "fs.copyFile" {...@@ -112,14 +113,16 @@ test "fs.copyFile" {
112 const dest_file = "tmp_test_copy_file2.txt";113 const dest_file = "tmp_test_copy_file2.txt";
113 const dest_file2 = "tmp_test_copy_file3.txt";114 const dest_file2 = "tmp_test_copy_file3.txt";
114115
115 try fs.cwd().writeFile(src_file, data);116 const cwd = fs.cwd();
116 defer fs.cwd().deleteFile(src_file) catch {};
117117
118 try fs.copyFile(src_file, dest_file);118 try cwd.writeFile(src_file, data);
119 defer fs.cwd().deleteFile(dest_file) catch {};119 defer cwd.deleteFile(src_file) catch {};
120120
121 try fs.copyFileMode(src_file, dest_file2, File.default_mode);121 try cwd.copyFile(src_file, cwd, dest_file, .{});
122 defer fs.cwd().deleteFile(dest_file2) catch {};122 defer cwd.deleteFile(dest_file) catch {};
123
124 try cwd.copyFile(src_file, cwd, dest_file2, .{ .override_mode = File.default_mode });
125 defer cwd.deleteFile(dest_file2) catch {};
123126
124 try expectFileContents(dest_file, data);127 try expectFileContents(dest_file, data);
125 try expectFileContents(dest_file2, data);128 try expectFileContents(dest_file2, data);
...@@ -446,3 +449,32 @@ test "getenv" {...@@ -446,3 +449,32 @@ test "getenv" {
446 expect(os.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null);449 expect(os.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null);
447 }450 }
448}451}
452
453test "fcntl" {
454 if (builtin.os.tag == .windows)
455 return error.SkipZigTest;
456
457 const test_out_file = "os_tmp_test";
458
459 const file = try fs.cwd().createFile(test_out_file, .{});
460 defer {
461 file.close();
462 fs.cwd().deleteFile(test_out_file) catch {};
463 }
464
465 // Note: The test assumes createFile opens the file with O_CLOEXEC
466 {
467 const flags = try os.fcntl(file.handle, os.F_GETFD, 0);
468 expect((flags & os.FD_CLOEXEC) != 0);
469 }
470 {
471 _ = try os.fcntl(file.handle, os.F_SETFD, 0);
472 const flags = try os.fcntl(file.handle, os.F_GETFD, 0);
473 expect((flags & os.FD_CLOEXEC) == 0);
474 }
475 {
476 _ = try os.fcntl(file.handle, os.F_SETFD, os.FD_CLOEXEC);
477 const flags = try os.fcntl(file.handle, os.F_GETFD, 0);
478 expect((flags & os.FD_CLOEXEC) != 0);
479 }
480}
lib/std/os/windows.zig+85-1
...@@ -88,6 +88,82 @@ pub fn CreateFileW(...@@ -88,6 +88,82 @@ pub fn CreateFileW(
88 return result;88 return result;
89}89}
9090
91pub const OpenError = error{
92 IsDir,
93 FileNotFound,
94 NoDevice,
95 SharingViolation,
96 AccessDenied,
97 PipeBusy,
98 PathAlreadyExists,
99 Unexpected,
100 NameTooLong,
101};
102
103/// TODO rename to CreateFileW
104/// TODO actually we don't need the path parameter to be null terminated
105pub fn OpenFileW(
106 dir: ?HANDLE,
107 sub_path_w: [*:0]const u16,
108 sa: ?*SECURITY_ATTRIBUTES,
109 access_mask: ACCESS_MASK,
110 creation: ULONG,
111) OpenError!HANDLE {
112 if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
113 return error.IsDir;
114 }
115 if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
116 return error.IsDir;
117 }
118
119 var result: HANDLE = undefined;
120
121 const path_len_bytes = math.cast(u16, mem.toSliceConst(u16, sub_path_w).len * 2) catch |err| switch (err) {
122 error.Overflow => return error.NameTooLong,
123 };
124 var nt_name = UNICODE_STRING{
125 .Length = path_len_bytes,
126 .MaximumLength = path_len_bytes,
127 .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)),
128 };
129 var attr = OBJECT_ATTRIBUTES{
130 .Length = @sizeOf(OBJECT_ATTRIBUTES),
131 .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w)) null else dir,
132 .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here.
133 .ObjectName = &nt_name,
134 .SecurityDescriptor = if (sa) |ptr| ptr.lpSecurityDescriptor else null,
135 .SecurityQualityOfService = null,
136 };
137 var io: IO_STATUS_BLOCK = undefined;
138 const rc = ntdll.NtCreateFile(
139 &result,
140 access_mask,
141 &attr,
142 &io,
143 null,
144 FILE_ATTRIBUTE_NORMAL,
145 FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
146 creation,
147 FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
148 null,
149 0,
150 );
151 switch (rc) {
152 .SUCCESS => return result,
153 .OBJECT_NAME_INVALID => unreachable,
154 .OBJECT_NAME_NOT_FOUND => return error.FileNotFound,
155 .OBJECT_PATH_NOT_FOUND => return error.FileNotFound,
156 .NO_MEDIA_IN_DEVICE => return error.NoDevice,
157 .INVALID_PARAMETER => unreachable,
158 .SHARING_VIOLATION => return error.SharingViolation,
159 .ACCESS_DENIED => return error.AccessDenied,
160 .PIPE_BUSY => return error.PipeBusy,
161 .OBJECT_PATH_SYNTAX_BAD => unreachable,
162 .OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
163 else => return unexpectedStatus(rc),
164 }
165}
166
91pub const CreatePipeError = error{Unexpected};167pub const CreatePipeError = error{Unexpected};
92168
93pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) CreatePipeError!void {169pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) CreatePipeError!void {
...@@ -1200,7 +1276,15 @@ pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError {...@@ -1200,7 +1276,15 @@ pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError {
1200 // 614 is the length of the longest windows error desciption1276 // 614 is the length of the longest windows error desciption
1201 var buf_u16: [614]u16 = undefined;1277 var buf_u16: [614]u16 = undefined;
1202 var buf_u8: [614]u8 = undefined;1278 var buf_u8: [614]u8 = undefined;
1203 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);1279 const len = kernel32.FormatMessageW(
1280 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
1281 null,
1282 err,
1283 MAKELANGID(LANG.NEUTRAL, SUBLANG.DEFAULT),
1284 &buf_u16,
1285 buf_u16.len / @sizeOf(TCHAR),
1286 null,
1287 );
1204 _ = std.unicode.utf16leToUtf8(&buf_u8, buf_u16[0..len]) catch unreachable;1288 _ = std.unicode.utf16leToUtf8(&buf_u8, buf_u16[0..len]) catch unreachable;
1205 std.debug.warn("error.Unexpected: GetLastError({}): {}\n", .{ @enumToInt(err), buf_u8[0..len] });1289 std.debug.warn("error.Unexpected: GetLastError({}): {}\n", .{ @enumToInt(err), buf_u8[0..len] });
1206 std.debug.dumpCurrentStackTrace(null);1290 std.debug.dumpCurrentStackTrace(null);
lib/std/os/windows/bits.zig+7
...@@ -242,6 +242,13 @@ pub const FILE_NAME_INFORMATION = extern struct {...@@ -242,6 +242,13 @@ pub const FILE_NAME_INFORMATION = extern struct {
242 FileName: [1]WCHAR,242 FileName: [1]WCHAR,
243};243};
244244
245pub const FILE_RENAME_INFORMATION = extern struct {
246 ReplaceIfExists: BOOLEAN,
247 RootDirectory: ?HANDLE,
248 FileNameLength: ULONG,
249 FileName: [1]WCHAR,
250};
251
245pub const IO_STATUS_BLOCK = extern struct {252pub const IO_STATUS_BLOCK = extern struct {
246 // "DUMMYUNIONNAME" expands to "u"253 // "DUMMYUNIONNAME" expands to "u"
247 u: extern union {254 u: extern union {
lib/std/rand.zig+1-1
...@@ -5,7 +5,7 @@...@@ -5,7 +5,7 @@
5// ```5// ```
6// var buf: [8]u8 = undefined;6// var buf: [8]u8 = undefined;
7// try std.crypto.randomBytes(buf[0..]);7// try std.crypto.randomBytes(buf[0..]);
8// const seed = mem.readIntSliceLittle(u64, buf[0..8]);8// const seed = mem.readIntLittle(u64, buf[0..8]);
9//9//
10// var r = DefaultPrng.init(seed);10// var r = DefaultPrng.init(seed);
11//11//
lib/std/thread.zig+45-6
...@@ -6,6 +6,8 @@ const windows = std.os.windows;...@@ -6,6 +6,8 @@ const windows = std.os.windows;
6const c = std.c;6const c = std.c;
7const assert = std.debug.assert;7const assert = std.debug.assert;
88
9const bad_startfn_ret = "expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'";
10
9pub const Thread = struct {11pub const Thread = struct {
10 data: Data,12 data: Data,
1113
...@@ -158,15 +160,34 @@ pub const Thread = struct {...@@ -158,15 +160,34 @@ pub const Thread = struct {
158 };160 };
159 fn threadMain(raw_arg: windows.LPVOID) callconv(.C) windows.DWORD {161 fn threadMain(raw_arg: windows.LPVOID) callconv(.C) windows.DWORD {
160 const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*;162 const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*;
163
161 switch (@typeInfo(@TypeOf(startFn).ReturnType)) {164 switch (@typeInfo(@TypeOf(startFn).ReturnType)) {
162 .Int => {165 .NoReturn => {
163 return startFn(arg);166 startFn(arg);
164 },167 },
165 .Void => {168 .Void => {
166 startFn(arg);169 startFn(arg);
167 return 0;170 return 0;
168 },171 },
169 else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),172 .Int => |info| {
173 if (info.bits != 8) {
174 @compileError(bad_startfn_ret);
175 }
176 return startFn(arg);
177 },
178 .ErrorUnion => |info| {
179 if (info.payload != void) {
180 @compileError(bad_startfn_ret);
181 }
182 startFn(arg) catch |err| {
183 std.debug.warn("error: {}\n", .{@errorName(err)});
184 if (@errorReturnTrace()) |trace| {
185 std.debug.dumpStackTrace(trace.*);
186 }
187 };
188 return 0;
189 },
190 else => @compileError(bad_startfn_ret),
170 }191 }
171 }192 }
172 };193 };
...@@ -202,14 +223,32 @@ pub const Thread = struct {...@@ -202,14 +223,32 @@ pub const Thread = struct {
202 const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*;223 const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*;
203224
204 switch (@typeInfo(@TypeOf(startFn).ReturnType)) {225 switch (@typeInfo(@TypeOf(startFn).ReturnType)) {
205 .Int => {226 .NoReturn => {
206 return startFn(arg);227 startFn(arg);
207 },228 },
208 .Void => {229 .Void => {
209 startFn(arg);230 startFn(arg);
210 return 0;231 return 0;
211 },232 },
212 else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"),233 .Int => |info| {
234 if (info.bits != 8) {
235 @compileError(bad_startfn_ret);
236 }
237 return startFn(arg);
238 },
239 .ErrorUnion => |info| {
240 if (info.payload != void) {
241 @compileError(bad_startfn_ret);
242 }
243 startFn(arg) catch |err| {
244 std.debug.warn("error: {}\n", .{@errorName(err)});
245 if (@errorReturnTrace()) |trace| {
246 std.debug.dumpStackTrace(trace.*);
247 }
248 };
249 return 0;
250 },
251 else => @compileError(bad_startfn_ret),
213 }252 }
214 }253 }
215 fn posixThreadMain(ctx: ?*c_void) callconv(.C) ?*c_void {254 fn posixThreadMain(ctx: ?*c_void) callconv(.C) ?*c_void {
lib/std/unicode.zig+10-10
...@@ -251,12 +251,12 @@ pub const Utf16LeIterator = struct {...@@ -251,12 +251,12 @@ pub const Utf16LeIterator = struct {
251 pub fn nextCodepoint(it: *Utf16LeIterator) !?u21 {251 pub fn nextCodepoint(it: *Utf16LeIterator) !?u21 {
252 assert(it.i <= it.bytes.len);252 assert(it.i <= it.bytes.len);
253 if (it.i == it.bytes.len) return null;253 if (it.i == it.bytes.len) return null;
254 const c0: u21 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]);254 const c0: u21 = mem.readIntLittle(u16, it.bytes[it.i..][0..2]);
255 if (c0 & ~@as(u21, 0x03ff) == 0xd800) {255 if (c0 & ~@as(u21, 0x03ff) == 0xd800) {
256 // surrogate pair256 // surrogate pair
257 it.i += 2;257 it.i += 2;
258 if (it.i >= it.bytes.len) return error.DanglingSurrogateHalf;258 if (it.i >= it.bytes.len) return error.DanglingSurrogateHalf;
259 const c1: u21 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]);259 const c1: u21 = mem.readIntLittle(u16, it.bytes[it.i..][0..2]);
260 if (c1 & ~@as(u21, 0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf;260 if (c1 & ~@as(u21, 0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf;
261 it.i += 2;261 it.i += 2;
262 return 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff));262 return 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff));
...@@ -630,11 +630,11 @@ test "utf8ToUtf16LeWithNull" {...@@ -630,11 +630,11 @@ test "utf8ToUtf16LeWithNull" {
630 }630 }
631}631}
632632
633/// Converts a UTF-8 string literal into a UTF-16LE string literal. 633/// Converts a UTF-8 string literal into a UTF-16LE string literal.
634pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16LeLen(utf8) :0] u16 {634pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16LeLen(utf8):0]u16 {
635 comptime {635 comptime {
636 const len: usize = calcUtf16LeLen(utf8);636 const len: usize = calcUtf16LeLen(utf8);
637 var utf16le: [len :0]u16 = [_ :0]u16{0} ** len;637 var utf16le: [len:0]u16 = [_:0]u16{0} ** len;
638 const utf16le_len = utf8ToUtf16Le(&utf16le, utf8[0..]) catch |err| @compileError(err);638 const utf16le_len = utf8ToUtf16Le(&utf16le, utf8[0..]) catch |err| @compileError(err);
639 assert(len == utf16le_len);639 assert(len == utf16le_len);
640 return &utf16le;640 return &utf16le;
...@@ -660,8 +660,8 @@ fn calcUtf16LeLen(utf8: []const u8) usize {...@@ -660,8 +660,8 @@ fn calcUtf16LeLen(utf8: []const u8) usize {
660}660}
661661
662test "utf8ToUtf16LeStringLiteral" {662test "utf8ToUtf16LeStringLiteral" {
663{663 {
664 const bytes = [_:0]u16{ 0x41 };664 const bytes = [_:0]u16{0x41};
665 const utf16 = utf8ToUtf16LeStringLiteral("A");665 const utf16 = utf8ToUtf16LeStringLiteral("A");
666 testing.expectEqualSlices(u16, &bytes, utf16);666 testing.expectEqualSlices(u16, &bytes, utf16);
667 testing.expect(utf16[1] == 0);667 testing.expect(utf16[1] == 0);
...@@ -673,19 +673,19 @@ test "utf8ToUtf16LeStringLiteral" {...@@ -673,19 +673,19 @@ test "utf8ToUtf16LeStringLiteral" {
673 testing.expect(utf16[2] == 0);673 testing.expect(utf16[2] == 0);
674 }674 }
675 {675 {
676 const bytes = [_:0]u16{ 0x02FF };676 const bytes = [_:0]u16{0x02FF};
677 const utf16 = utf8ToUtf16LeStringLiteral("\u{02FF}");677 const utf16 = utf8ToUtf16LeStringLiteral("\u{02FF}");
678 testing.expectEqualSlices(u16, &bytes, utf16);678 testing.expectEqualSlices(u16, &bytes, utf16);
679 testing.expect(utf16[1] == 0);679 testing.expect(utf16[1] == 0);
680 }680 }
681 {681 {
682 const bytes = [_:0]u16{ 0x7FF };682 const bytes = [_:0]u16{0x7FF};
683 const utf16 = utf8ToUtf16LeStringLiteral("\u{7FF}");683 const utf16 = utf8ToUtf16LeStringLiteral("\u{7FF}");
684 testing.expectEqualSlices(u16, &bytes, utf16);684 testing.expectEqualSlices(u16, &bytes, utf16);
685 testing.expect(utf16[1] == 0);685 testing.expect(utf16[1] == 0);
686 }686 }
687 {687 {
688 const bytes = [_:0]u16{ 0x801 };688 const bytes = [_:0]u16{0x801};
689 const utf16 = utf8ToUtf16LeStringLiteral("\u{801}");689 const utf16 = utf8ToUtf16LeStringLiteral("\u{801}");
690 testing.expectEqualSlices(u16, &bytes, utf16);690 testing.expectEqualSlices(u16, &bytes, utf16);
691 testing.expect(utf16[1] == 0);691 testing.expect(utf16[1] == 0);
lib/std/zig/ast.zig+66-92
...@@ -743,11 +743,11 @@ pub const Node = struct {...@@ -743,11 +743,11 @@ pub const Node = struct {
743 var i = index;743 var i = index;
744744
745 switch (self.init_arg_expr) {745 switch (self.init_arg_expr) {
746 InitArg.Type => |t| {746 .Type => |t| {
747 if (i < 1) return t;747 if (i < 1) return t;
748 i -= 1;748 i -= 1;
749 },749 },
750 InitArg.None, InitArg.Enum => {},750 .None, .Enum => {},
751 }751 }
752752
753 if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i).*;753 if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i).*;
...@@ -907,12 +907,7 @@ pub const Node = struct {...@@ -907,12 +907,7 @@ pub const Node = struct {
907 }907 }
908908
909 switch (self.return_type) {909 switch (self.return_type) {
910 // TODO allow this and next prong to share bodies since the types are the same910 .Explicit, .InferErrorSet => |node| {
911 ReturnType.Explicit => |node| {
912 if (i < 1) return node;
913 i -= 1;
914 },
915 ReturnType.InferErrorSet => |node| {
916 if (i < 1) return node;911 if (i < 1) return node;
917 i -= 1;912 i -= 1;
918 },913 },
...@@ -937,9 +932,7 @@ pub const Node = struct {...@@ -937,9 +932,7 @@ pub const Node = struct {
937 pub fn lastToken(self: *const FnProto) TokenIndex {932 pub fn lastToken(self: *const FnProto) TokenIndex {
938 if (self.body_node) |body_node| return body_node.lastToken();933 if (self.body_node) |body_node| return body_node.lastToken();
939 switch (self.return_type) {934 switch (self.return_type) {
940 // TODO allow this and next prong to share bodies since the types are the same935 .Explicit, .InferErrorSet => |node| return node.lastToken(),
941 ReturnType.Explicit => |node| return node.lastToken(),
942 ReturnType.InferErrorSet => |node| return node.lastToken(),
943 }936 }
944 }937 }
945 };938 };
...@@ -1515,55 +1508,55 @@ pub const Node = struct {...@@ -1515,55 +1508,55 @@ pub const Node = struct {
1515 i -= 1;1508 i -= 1;
15161509
1517 switch (self.op) {1510 switch (self.op) {
1518 Op.Catch => |maybe_payload| {1511 .Catch => |maybe_payload| {
1519 if (maybe_payload) |payload| {1512 if (maybe_payload) |payload| {
1520 if (i < 1) return payload;1513 if (i < 1) return payload;
1521 i -= 1;1514 i -= 1;
1522 }1515 }
1523 },1516 },
15241517
1525 Op.Add,1518 .Add,
1526 Op.AddWrap,1519 .AddWrap,
1527 Op.ArrayCat,1520 .ArrayCat,
1528 Op.ArrayMult,1521 .ArrayMult,
1529 Op.Assign,1522 .Assign,
1530 Op.AssignBitAnd,1523 .AssignBitAnd,
1531 Op.AssignBitOr,1524 .AssignBitOr,
1532 Op.AssignBitShiftLeft,1525 .AssignBitShiftLeft,
1533 Op.AssignBitShiftRight,1526 .AssignBitShiftRight,
1534 Op.AssignBitXor,1527 .AssignBitXor,
1535 Op.AssignDiv,1528 .AssignDiv,
1536 Op.AssignSub,1529 .AssignSub,
1537 Op.AssignSubWrap,1530 .AssignSubWrap,
1538 Op.AssignMod,1531 .AssignMod,
1539 Op.AssignAdd,1532 .AssignAdd,
1540 Op.AssignAddWrap,1533 .AssignAddWrap,
1541 Op.AssignMul,1534 .AssignMul,
1542 Op.AssignMulWrap,1535 .AssignMulWrap,
1543 Op.BangEqual,1536 .BangEqual,
1544 Op.BitAnd,1537 .BitAnd,
1545 Op.BitOr,1538 .BitOr,
1546 Op.BitShiftLeft,1539 .BitShiftLeft,
1547 Op.BitShiftRight,1540 .BitShiftRight,
1548 Op.BitXor,1541 .BitXor,
1549 Op.BoolAnd,1542 .BoolAnd,
1550 Op.BoolOr,1543 .BoolOr,
1551 Op.Div,1544 .Div,
1552 Op.EqualEqual,1545 .EqualEqual,
1553 Op.ErrorUnion,1546 .ErrorUnion,
1554 Op.GreaterOrEqual,1547 .GreaterOrEqual,
1555 Op.GreaterThan,1548 .GreaterThan,
1556 Op.LessOrEqual,1549 .LessOrEqual,
1557 Op.LessThan,1550 .LessThan,
1558 Op.MergeErrorSets,1551 .MergeErrorSets,
1559 Op.Mod,1552 .Mod,
1560 Op.Mul,1553 .Mul,
1561 Op.MulWrap,1554 .MulWrap,
1562 Op.Period,1555 .Period,
1563 Op.Range,1556 .Range,
1564 Op.Sub,1557 .Sub,
1565 Op.SubWrap,1558 .SubWrap,
1566 Op.UnwrapOptional,1559 .UnwrapOptional,
1567 => {},1560 => {},
1568 }1561 }
15691562
...@@ -1594,7 +1587,6 @@ pub const Node = struct {...@@ -1594,7 +1587,6 @@ pub const Node = struct {
1594 Await,1587 Await,
1595 BitNot,1588 BitNot,
1596 BoolNot,1589 BoolNot,
1597 Cancel,
1598 OptionalType,1590 OptionalType,
1599 Negation,1591 Negation,
1600 NegationWrap,1592 NegationWrap,
...@@ -1631,8 +1623,7 @@ pub const Node = struct {...@@ -1631,8 +1623,7 @@ pub const Node = struct {
1631 var i = index;1623 var i = index;
16321624
1633 switch (self.op) {1625 switch (self.op) {
1634 // TODO https://github.com/ziglang/zig/issues/11071626 .PtrType, .SliceType => |addr_of_info| {
1635 Op.SliceType => |addr_of_info| {
1636 if (addr_of_info.sentinel) |sentinel| {1627 if (addr_of_info.sentinel) |sentinel| {
1637 if (i < 1) return sentinel;1628 if (i < 1) return sentinel;
1638 i -= 1;1629 i -= 1;
...@@ -1644,14 +1635,7 @@ pub const Node = struct {...@@ -1644,14 +1635,7 @@ pub const Node = struct {
1644 }1635 }
1645 },1636 },
16461637
1647 Op.PtrType => |addr_of_info| {1638 .ArrayType => |array_info| {
1648 if (addr_of_info.align_info) |align_info| {
1649 if (i < 1) return align_info.node;
1650 i -= 1;
1651 }
1652 },
1653
1654 Op.ArrayType => |array_info| {
1655 if (i < 1) return array_info.len_expr;1639 if (i < 1) return array_info.len_expr;
1656 i -= 1;1640 i -= 1;
1657 if (array_info.sentinel) |sentinel| {1641 if (array_info.sentinel) |sentinel| {
...@@ -1660,16 +1644,15 @@ pub const Node = struct {...@@ -1660,16 +1644,15 @@ pub const Node = struct {
1660 }1644 }
1661 },1645 },
16621646
1663 Op.AddressOf,1647 .AddressOf,
1664 Op.Await,1648 .Await,
1665 Op.BitNot,1649 .BitNot,
1666 Op.BoolNot,1650 .BoolNot,
1667 Op.Cancel,1651 .OptionalType,
1668 Op.OptionalType,1652 .Negation,
1669 Op.Negation,1653 .NegationWrap,
1670 Op.NegationWrap,1654 .Try,
1671 Op.Try,1655 .Resume,
1672 Op.Resume,
1673 => {},1656 => {},
1674 }1657 }
16751658
...@@ -1853,19 +1836,14 @@ pub const Node = struct {...@@ -1853,19 +1836,14 @@ pub const Node = struct {
1853 var i = index;1836 var i = index;
18541837
1855 switch (self.kind) {1838 switch (self.kind) {
1856 Kind.Break => |maybe_label| {1839 .Break,
1840 .Continue => |maybe_label| {
1857 if (maybe_label) |label| {1841 if (maybe_label) |label| {
1858 if (i < 1) return label;1842 if (i < 1) return label;
1859 i -= 1;1843 i -= 1;
1860 }1844 }
1861 },1845 },
1862 Kind.Continue => |maybe_label| {1846 .Return => {},
1863 if (maybe_label) |label| {
1864 if (i < 1) return label;
1865 i -= 1;
1866 }
1867 },
1868 Kind.Return => {},
1869 }1847 }
18701848
1871 if (self.rhs) |rhs| {1849 if (self.rhs) |rhs| {
...@@ -1886,17 +1864,13 @@ pub const Node = struct {...@@ -1886,17 +1864,13 @@ pub const Node = struct {
1886 }1864 }
18871865
1888 switch (self.kind) {1866 switch (self.kind) {
1889 Kind.Break => |maybe_label| {1867 .Break,
1890 if (maybe_label) |label| {1868 .Continue => |maybe_label| {
1891 return label.lastToken();
1892 }
1893 },
1894 Kind.Continue => |maybe_label| {
1895 if (maybe_label) |label| {1869 if (maybe_label) |label| {
1896 return label.lastToken();1870 return label.lastToken();
1897 }1871 }
1898 },1872 },
1899 Kind.Return => return self.ltoken,1873 .Return => return self.ltoken,
1900 }1874 }
19011875
1902 return self.ltoken;1876 return self.ltoken;
...@@ -2137,11 +2111,11 @@ pub const Node = struct {...@@ -2137,11 +2111,11 @@ pub const Node = struct {
2137 i -= 1;2111 i -= 1;
21382112
2139 switch (self.kind) {2113 switch (self.kind) {
2140 Kind.Variable => |variable_name| {2114 .Variable => |variable_name| {
2141 if (i < 1) return &variable_name.base;2115 if (i < 1) return &variable_name.base;
2142 i -= 1;2116 i -= 1;
2143 },2117 },
2144 Kind.Return => |return_type| {2118 .Return => |return_type| {
2145 if (i < 1) return return_type;2119 if (i < 1) return return_type;
2146 i -= 1;2120 i -= 1;
2147 },2121 },
lib/std/zig/parse.zig+336-351
...@@ -23,7 +23,7 @@ pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree {...@@ -23,7 +23,7 @@ pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree {
23 var arena = std.heap.ArenaAllocator.init(allocator);23 var arena = std.heap.ArenaAllocator.init(allocator);
24 errdefer arena.deinit();24 errdefer arena.deinit();
25 const tree = try arena.allocator.create(ast.Tree);25 const tree = try arena.allocator.create(ast.Tree);
26 tree.* = ast.Tree{26 tree.* = .{
27 .source = source,27 .source = source,
28 .root_node = undefined,28 .root_node = undefined,
29 .arena_allocator = arena,29 .arena_allocator = arena,
...@@ -66,10 +66,10 @@ pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree {...@@ -66,10 +66,10 @@ pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree {
66/// Root <- skip ContainerMembers eof66/// Root <- skip ContainerMembers eof
67fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!*Node.Root {67fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!*Node.Root {
68 const node = try arena.create(Node.Root);68 const node = try arena.create(Node.Root);
69 node.* = Node.Root{69 node.* = .{
70 .decls = try parseContainerMembers(arena, it, tree),70 .decls = try parseContainerMembers(arena, it, tree),
71 .eof_token = eatToken(it, .Eof) orelse {71 .eof_token = eatToken(it, .Eof) orelse {
72 try tree.errors.push(AstError{72 try tree.errors.push(.{
73 .ExpectedContainerMembers = .{ .token = it.index },73 .ExpectedContainerMembers = .{ .token = it.index },
74 });74 });
75 return error.ParseError;75 return error.ParseError;
...@@ -139,8 +139,8 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No...@@ -139,8 +139,8 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No
139 }139 }
140140
141 if (visib_token != null) {141 if (visib_token != null) {
142 try tree.errors.push(AstError{142 try tree.errors.push(.{
143 .ExpectedPubItem = AstError.ExpectedPubItem{ .token = it.index },143 .ExpectedPubItem = .{ .token = it.index },
144 });144 });
145 return error.ParseError;145 return error.ParseError;
146 }146 }
...@@ -157,8 +157,8 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No...@@ -157,8 +157,8 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No
157157
158 // Dangling doc comment158 // Dangling doc comment
159 if (doc_comments != null) {159 if (doc_comments != null) {
160 try tree.errors.push(AstError{160 try tree.errors.push(.{
161 .UnattachedDocComment = AstError.UnattachedDocComment{ .token = doc_comments.?.firstToken() },161 .UnattachedDocComment = .{ .token = doc_comments.?.firstToken() },
162 });162 });
163 }163 }
164 break;164 break;
...@@ -177,7 +177,7 @@ fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree)...@@ -177,7 +177,7 @@ fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree)
177 if (lines.len == 0) return null;177 if (lines.len == 0) return null;
178178
179 const node = try arena.create(Node.DocComment);179 const node = try arena.create(Node.DocComment);
180 node.* = Node.DocComment{180 node.* = .{
181 .lines = lines,181 .lines = lines,
182 };182 };
183 return &node.base;183 return &node.base;
...@@ -186,15 +186,15 @@ fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree)...@@ -186,15 +186,15 @@ fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree)
186/// TestDecl <- KEYWORD_test STRINGLITERALSINGLE Block186/// TestDecl <- KEYWORD_test STRINGLITERALSINGLE Block
187fn parseTestDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {187fn parseTestDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
188 const test_token = eatToken(it, .Keyword_test) orelse return null;188 const test_token = eatToken(it, .Keyword_test) orelse return null;
189 const name_node = try expectNode(arena, it, tree, parseStringLiteralSingle, AstError{189 const name_node = try expectNode(arena, it, tree, parseStringLiteralSingle, .{
190 .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index },190 .ExpectedStringLiteral = .{ .token = it.index },
191 });191 });
192 const block_node = try expectNode(arena, it, tree, parseBlock, AstError{192 const block_node = try expectNode(arena, it, tree, parseBlock, .{
193 .ExpectedLBrace = AstError.ExpectedLBrace{ .token = it.index },193 .ExpectedLBrace = .{ .token = it.index },
194 });194 });
195195
196 const test_node = try arena.create(Node.TestDecl);196 const test_node = try arena.create(Node.TestDecl);
197 test_node.* = Node.TestDecl{197 test_node.* = .{
198 .doc_comments = null,198 .doc_comments = null,
199 .test_token = test_token,199 .test_token = test_token,
200 .name = name_node,200 .name = name_node,
...@@ -211,12 +211,12 @@ fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*...@@ -211,12 +211,12 @@ fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*
211 return null;211 return null;
212 };212 };
213 putBackToken(it, lbrace);213 putBackToken(it, lbrace);
214 const block_node = try expectNode(arena, it, tree, parseBlockExpr, AstError{214 const block_node = try expectNode(arena, it, tree, parseBlockExpr, .{
215 .ExpectedLabelOrLBrace = AstError.ExpectedLabelOrLBrace{ .token = it.index },215 .ExpectedLabelOrLBrace = .{ .token = it.index },
216 });216 });
217217
218 const comptime_node = try arena.create(Node.Comptime);218 const comptime_node = try arena.create(Node.Comptime);
219 comptime_node.* = Node.Comptime{219 comptime_node.* = .{
220 .doc_comments = null,220 .doc_comments = null,
221 .comptime_token = tok,221 .comptime_token = tok,
222 .expr = block_node,222 .expr = block_node,
...@@ -250,8 +250,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -250,8 +250,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
250 fn_node.body_node = body_node;250 fn_node.body_node = body_node;
251 return node;251 return node;
252 }252 }
253 try tree.errors.push(AstError{253 try tree.errors.push(.{
254 .ExpectedSemiOrLBrace = AstError.ExpectedSemiOrLBrace{ .token = it.index },254 .ExpectedSemiOrLBrace = .{ .token = it.index },
255 });255 });
256 return null;256 return null;
257 }257 }
...@@ -277,8 +277,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -277,8 +277,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
277 }277 }
278278
279 if (thread_local_token != null) {279 if (thread_local_token != null) {
280 try tree.errors.push(AstError{280 try tree.errors.push(.{
281 .ExpectedVarDecl = AstError.ExpectedVarDecl{ .token = it.index },281 .ExpectedVarDecl = .{ .token = it.index },
282 });282 });
283 return error.ParseError;283 return error.ParseError;
284 }284 }
...@@ -291,8 +291,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -291,8 +291,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
291 }291 }
292292
293 const use_node = (try parseUse(arena, it, tree)) orelse return null;293 const use_node = (try parseUse(arena, it, tree)) orelse return null;
294 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{294 const expr_node = try expectNode(arena, it, tree, parseExpr, .{
295 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },295 .ExpectedExpr = .{ .token = it.index },
296 });296 });
297 const semicolon_token = try expectToken(it, tree, .Semicolon);297 const semicolon_token = try expectToken(it, tree, .Semicolon);
298 const use_node_raw = use_node.cast(Node.Use).?;298 const use_node_raw = use_node.cast(Node.Use).?;
...@@ -310,7 +310,7 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -310,7 +310,7 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
310 if (fnCC == .Extern) {310 if (fnCC == .Extern) {
311 putBackToken(it, fnCC.Extern); // 'extern' is also used in ContainerDecl311 putBackToken(it, fnCC.Extern); // 'extern' is also used in ContainerDecl
312 } else {312 } else {
313 try tree.errors.push(AstError{313 try tree.errors.push(.{
314 .ExpectedToken = .{ .token = it.index, .expected_id = .Keyword_fn },314 .ExpectedToken = .{ .token = it.index, .expected_id = .Keyword_fn },
315 });315 });
316 return error.ParseError;316 return error.ParseError;
...@@ -328,16 +328,16 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -328,16 +328,16 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
328 const exclamation_token = eatToken(it, .Bang);328 const exclamation_token = eatToken(it, .Bang);
329329
330 const return_type_expr = (try parseVarType(arena, it, tree)) orelse330 const return_type_expr = (try parseVarType(arena, it, tree)) orelse
331 try expectNode(arena, it, tree, parseTypeExpr, AstError{331 try expectNode(arena, it, tree, parseTypeExpr, .{
332 .ExpectedReturnType = AstError.ExpectedReturnType{ .token = it.index },332 .ExpectedReturnType = .{ .token = it.index },
333 });333 });
334334
335 const return_type = if (exclamation_token != null)335 const return_type: Node.FnProto.ReturnType = if (exclamation_token != null)
336 Node.FnProto.ReturnType{336 .{
337 .InferErrorSet = return_type_expr,337 .InferErrorSet = return_type_expr,
338 }338 }
339 else339 else
340 Node.FnProto.ReturnType{340 .{
341 .Explicit = return_type_expr,341 .Explicit = return_type_expr,
342 };342 };
343343
...@@ -347,7 +347,7 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -347,7 +347,7 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
347 null;347 null;
348348
349 const fn_proto_node = try arena.create(Node.FnProto);349 const fn_proto_node = try arena.create(Node.FnProto);
350 fn_proto_node.* = Node.FnProto{350 fn_proto_node.* = .{
351 .doc_comments = null,351 .doc_comments = null,
352 .visib_token = null,352 .visib_token = null,
353 .fn_token = fn_token,353 .fn_token = fn_token,
...@@ -382,8 +382,8 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -382,8 +382,8 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
382382
383 const name_token = try expectToken(it, tree, .Identifier);383 const name_token = try expectToken(it, tree, .Identifier);
384 const type_node = if (eatToken(it, .Colon) != null)384 const type_node = if (eatToken(it, .Colon) != null)
385 try expectNode(arena, it, tree, parseTypeExpr, AstError{385 try expectNode(arena, it, tree, parseTypeExpr, .{
386 .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },386 .ExpectedTypeExpr = .{ .token = it.index },
387 })387 })
388 else388 else
389 null;389 null;
...@@ -391,14 +391,14 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -391,14 +391,14 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
391 const section_node = try parseLinkSection(arena, it, tree);391 const section_node = try parseLinkSection(arena, it, tree);
392 const eq_token = eatToken(it, .Equal);392 const eq_token = eatToken(it, .Equal);
393 const init_node = if (eq_token != null) blk: {393 const init_node = if (eq_token != null) blk: {
394 break :blk try expectNode(arena, it, tree, parseExpr, AstError{394 break :blk try expectNode(arena, it, tree, parseExpr, .{
395 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },395 .ExpectedExpr = .{ .token = it.index },
396 });396 });
397 } else null;397 } else null;
398 const semicolon_token = try expectToken(it, tree, .Semicolon);398 const semicolon_token = try expectToken(it, tree, .Semicolon);
399399
400 const node = try arena.create(Node.VarDecl);400 const node = try arena.create(Node.VarDecl);
401 node.* = Node.VarDecl{401 node.* = .{
402 .doc_comments = null,402 .doc_comments = null,
403 .visib_token = null,403 .visib_token = null,
404 .thread_local_token = null,404 .thread_local_token = null,
...@@ -433,22 +433,22 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No...@@ -433,22 +433,22 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
433 node.* = .{ .token = var_tok };433 node.* = .{ .token = var_tok };
434 type_expr = &node.base;434 type_expr = &node.base;
435 } else {435 } else {
436 type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{436 type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{
437 .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },437 .ExpectedTypeExpr = .{ .token = it.index },
438 });438 });
439 align_expr = try parseByteAlign(arena, it, tree);439 align_expr = try parseByteAlign(arena, it, tree);
440 }440 }
441 }441 }
442442
443 const value_expr = if (eatToken(it, .Equal)) |_|443 const value_expr = if (eatToken(it, .Equal)) |_|
444 try expectNode(arena, it, tree, parseExpr, AstError{444 try expectNode(arena, it, tree, parseExpr, .{
445 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },445 .ExpectedExpr = .{ .token = it.index },
446 })446 })
447 else447 else
448 null;448 null;
449449
450 const node = try arena.create(Node.ContainerField);450 const node = try arena.create(Node.ContainerField);
451 node.* = Node.ContainerField{451 node.* = .{
452 .doc_comments = null,452 .doc_comments = null,
453 .comptime_token = comptime_token,453 .comptime_token = comptime_token,
454 .name_token = name_token,454 .name_token = name_token,
...@@ -481,12 +481,12 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No...@@ -481,12 +481,12 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No
481 }481 }
482482
483 if (comptime_token) |token| {483 if (comptime_token) |token| {
484 const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, AstError{484 const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, .{
485 .ExpectedBlockOrAssignment = AstError.ExpectedBlockOrAssignment{ .token = it.index },485 .ExpectedBlockOrAssignment = .{ .token = it.index },
486 });486 });
487487
488 const node = try arena.create(Node.Comptime);488 const node = try arena.create(Node.Comptime);
489 node.* = Node.Comptime{489 node.* = .{
490 .doc_comments = null,490 .doc_comments = null,
491 .comptime_token = token,491 .comptime_token = token,
492 .expr = block_expr,492 .expr = block_expr,
...@@ -511,13 +511,13 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No...@@ -511,13 +511,13 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No
511 const semicolon = eatToken(it, .Semicolon);511 const semicolon = eatToken(it, .Semicolon);
512512
513 const body_node = if (semicolon == null) blk: {513 const body_node = if (semicolon == null) blk: {
514 break :blk try expectNode(arena, it, tree, parseBlockExprStatement, AstError{514 break :blk try expectNode(arena, it, tree, parseBlockExprStatement, .{
515 .ExpectedBlockOrExpression = AstError.ExpectedBlockOrExpression{ .token = it.index },515 .ExpectedBlockOrExpression = .{ .token = it.index },
516 });516 });
517 } else null;517 } else null;
518518
519 const node = try arena.create(Node.Suspend);519 const node = try arena.create(Node.Suspend);
520 node.* = Node.Suspend{520 node.* = .{
521 .suspend_token = suspend_token,521 .suspend_token = suspend_token,
522 .body = body_node,522 .body = body_node,
523 };523 };
...@@ -526,11 +526,11 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No...@@ -526,11 +526,11 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No
526526
527 const defer_token = eatToken(it, .Keyword_defer) orelse eatToken(it, .Keyword_errdefer);527 const defer_token = eatToken(it, .Keyword_defer) orelse eatToken(it, .Keyword_errdefer);
528 if (defer_token) |token| {528 if (defer_token) |token| {
529 const expr_node = try expectNode(arena, it, tree, parseBlockExprStatement, AstError{529 const expr_node = try expectNode(arena, it, tree, parseBlockExprStatement, .{
530 .ExpectedBlockOrExpression = AstError.ExpectedBlockOrExpression{ .token = it.index },530 .ExpectedBlockOrExpression = .{ .token = it.index },
531 });531 });
532 const node = try arena.create(Node.Defer);532 const node = try arena.create(Node.Defer);
533 node.* = Node.Defer{533 node.* = .{
534 .defer_token = token,534 .defer_token = token,
535 .expr = expr_node,535 .expr = expr_node,
536 };536 };
...@@ -561,8 +561,8 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -561,8 +561,8 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
561 } else null;561 } else null;
562562
563 if (block_expr == null and assign_expr == null) {563 if (block_expr == null and assign_expr == null) {
564 try tree.errors.push(AstError{564 try tree.errors.push(.{
565 .ExpectedBlockOrAssignment = AstError.ExpectedBlockOrAssignment{ .token = it.index },565 .ExpectedBlockOrAssignment = .{ .token = it.index },
566 });566 });
567 return error.ParseError;567 return error.ParseError;
568 }568 }
...@@ -572,12 +572,12 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -572,12 +572,12 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
572 const else_node = if (semicolon == null) blk: {572 const else_node = if (semicolon == null) blk: {
573 const else_token = eatToken(it, .Keyword_else) orelse break :blk null;573 const else_token = eatToken(it, .Keyword_else) orelse break :blk null;
574 const payload = try parsePayload(arena, it, tree);574 const payload = try parsePayload(arena, it, tree);
575 const else_body = try expectNode(arena, it, tree, parseStatement, AstError{575 const else_body = try expectNode(arena, it, tree, parseStatement, .{
576 .InvalidToken = AstError.InvalidToken{ .token = it.index },576 .InvalidToken = .{ .token = it.index },
577 });577 });
578578
579 const node = try arena.create(Node.Else);579 const node = try arena.create(Node.Else);
580 node.* = Node.Else{580 node.* = .{
581 .else_token = else_token,581 .else_token = else_token,
582 .payload = payload,582 .payload = payload,
583 .body = else_body,583 .body = else_body,
...@@ -599,8 +599,8 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -599,8 +599,8 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
599 if_prefix.@"else" = else_node;599 if_prefix.@"else" = else_node;
600 return if_node;600 return if_node;
601 }601 }
602 try tree.errors.push(AstError{602 try tree.errors.push(.{
603 .ExpectedSemiOrElse = AstError.ExpectedSemiOrElse{ .token = it.index },603 .ExpectedSemiOrElse = .{ .token = it.index },
604 });604 });
605 return error.ParseError;605 return error.ParseError;
606 }606 }
...@@ -628,8 +628,8 @@ fn parseLabeledStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*...@@ -628,8 +628,8 @@ fn parseLabeledStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*
628 }628 }
629629
630 if (label_token != null) {630 if (label_token != null) {
631 try tree.errors.push(AstError{631 try tree.errors.push(.{
632 .ExpectedLabelable = AstError.ExpectedLabelable{ .token = it.index },632 .ExpectedLabelable = .{ .token = it.index },
633 });633 });
634 return error.ParseError;634 return error.ParseError;
635 }635 }
...@@ -665,12 +665,12 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -665,12 +665,12 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
665 for_prefix.body = block_expr_node;665 for_prefix.body = block_expr_node;
666666
667 if (eatToken(it, .Keyword_else)) |else_token| {667 if (eatToken(it, .Keyword_else)) |else_token| {
668 const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{668 const statement_node = try expectNode(arena, it, tree, parseStatement, .{
669 .InvalidToken = AstError.InvalidToken{ .token = it.index },669 .InvalidToken = .{ .token = it.index },
670 });670 });
671671
672 const else_node = try arena.create(Node.Else);672 const else_node = try arena.create(Node.Else);
673 else_node.* = Node.Else{673 else_node.* = .{
674 .else_token = else_token,674 .else_token = else_token,
675 .payload = null,675 .payload = null,
676 .body = statement_node,676 .body = statement_node,
...@@ -689,12 +689,12 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -689,12 +689,12 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
689 if (eatToken(it, .Semicolon) != null) return node;689 if (eatToken(it, .Semicolon) != null) return node;
690690
691 if (eatToken(it, .Keyword_else)) |else_token| {691 if (eatToken(it, .Keyword_else)) |else_token| {
692 const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{692 const statement_node = try expectNode(arena, it, tree, parseStatement, .{
693 .ExpectedStatement = AstError.ExpectedStatement{ .token = it.index },693 .ExpectedStatement = .{ .token = it.index },
694 });694 });
695695
696 const else_node = try arena.create(Node.Else);696 const else_node = try arena.create(Node.Else);
697 else_node.* = Node.Else{697 else_node.* = .{
698 .else_token = else_token,698 .else_token = else_token,
699 .payload = null,699 .payload = null,
700 .body = statement_node,700 .body = statement_node,
...@@ -703,8 +703,8 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -703,8 +703,8 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
703 return node;703 return node;
704 }704 }
705705
706 try tree.errors.push(AstError{706 try tree.errors.push(.{
707 .ExpectedSemiOrElse = AstError.ExpectedSemiOrElse{ .token = it.index },707 .ExpectedSemiOrElse = .{ .token = it.index },
708 });708 });
709 return null;709 return null;
710 }710 }
...@@ -725,12 +725,12 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No...@@ -725,12 +725,12 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
725 if (eatToken(it, .Keyword_else)) |else_token| {725 if (eatToken(it, .Keyword_else)) |else_token| {
726 const payload = try parsePayload(arena, it, tree);726 const payload = try parsePayload(arena, it, tree);
727727
728 const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{728 const statement_node = try expectNode(arena, it, tree, parseStatement, .{
729 .InvalidToken = AstError.InvalidToken{ .token = it.index },729 .InvalidToken = .{ .token = it.index },
730 });730 });
731731
732 const else_node = try arena.create(Node.Else);732 const else_node = try arena.create(Node.Else);
733 else_node.* = Node.Else{733 else_node.* = .{
734 .else_token = else_token,734 .else_token = else_token,
735 .payload = payload,735 .payload = payload,
736 .body = statement_node,736 .body = statement_node,
...@@ -751,12 +751,12 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No...@@ -751,12 +751,12 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
751 if (eatToken(it, .Keyword_else)) |else_token| {751 if (eatToken(it, .Keyword_else)) |else_token| {
752 const payload = try parsePayload(arena, it, tree);752 const payload = try parsePayload(arena, it, tree);
753753
754 const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{754 const statement_node = try expectNode(arena, it, tree, parseStatement, .{
755 .ExpectedStatement = AstError.ExpectedStatement{ .token = it.index },755 .ExpectedStatement = .{ .token = it.index },
756 });756 });
757757
758 const else_node = try arena.create(Node.Else);758 const else_node = try arena.create(Node.Else);
759 else_node.* = Node.Else{759 else_node.* = .{
760 .else_token = else_token,760 .else_token = else_token,
761 .payload = payload,761 .payload = payload,
762 .body = statement_node,762 .body = statement_node,
...@@ -765,8 +765,8 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No...@@ -765,8 +765,8 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
765 return node;765 return node;
766 }766 }
767767
768 try tree.errors.push(AstError{768 try tree.errors.push(.{
769 .ExpectedSemiOrElse = AstError.ExpectedSemiOrElse{ .token = it.index },769 .ExpectedSemiOrElse = .{ .token = it.index },
770 });770 });
771 return null;771 return null;
772 }772 }
...@@ -894,8 +894,8 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -894,8 +894,8 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
894 }894 }
895895
896 if (eatToken(it, .Keyword_comptime)) |token| {896 if (eatToken(it, .Keyword_comptime)) |token| {
897 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{897 const expr_node = try expectNode(arena, it, tree, parseExpr, .{
898 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },898 .ExpectedExpr = .{ .token = it.index },
899 });899 });
900 const node = try arena.create(Node.Comptime);900 const node = try arena.create(Node.Comptime);
901 node.* = .{901 node.* = .{
...@@ -907,8 +907,8 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -907,8 +907,8 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
907 }907 }
908908
909 if (eatToken(it, .Keyword_noasync)) |token| {909 if (eatToken(it, .Keyword_noasync)) |token| {
910 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{910 const expr_node = try expectNode(arena, it, tree, parseExpr, .{
911 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },911 .ExpectedExpr = .{ .token = it.index },
912 });912 });
913 const node = try arena.create(Node.Noasync);913 const node = try arena.create(Node.Noasync);
914 node.* = .{914 node.* = .{
...@@ -930,13 +930,13 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -930,13 +930,13 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
930 }930 }
931931
932 if (eatToken(it, .Keyword_resume)) |token| {932 if (eatToken(it, .Keyword_resume)) |token| {
933 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{933 const expr_node = try expectNode(arena, it, tree, parseExpr, .{
934 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },934 .ExpectedExpr = .{ .token = it.index },
935 });935 });
936 const node = try arena.create(Node.PrefixOp);936 const node = try arena.create(Node.PrefixOp);
937 node.* = .{937 node.* = .{
938 .op_token = token,938 .op_token = token,
939 .op = Node.PrefixOp.Op.Resume,939 .op = .Resume,
940 .rhs = expr_node,940 .rhs = expr_node,
941 };941 };
942 return &node.base;942 return &node.base;
...@@ -992,7 +992,7 @@ fn parseBlock(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -992,7 +992,7 @@ fn parseBlock(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
992 const rbrace = try expectToken(it, tree, .RBrace);992 const rbrace = try expectToken(it, tree, .RBrace);
993993
994 const block_node = try arena.create(Node.Block);994 const block_node = try arena.create(Node.Block);
995 block_node.* = Node.Block{995 block_node.* = .{
996 .label = null,996 .label = null,
997 .lbrace = lbrace,997 .lbrace = lbrace,
998 .statements = statements,998 .statements = statements,
...@@ -1019,8 +1019,8 @@ fn parseLoopExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1019,8 +1019,8 @@ fn parseLoopExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1019 if (inline_token == null) return null;1019 if (inline_token == null) return null;
10201020
1021 // If we've seen "inline", there should have been a "for" or "while"1021 // If we've seen "inline", there should have been a "for" or "while"
1022 try tree.errors.push(AstError{1022 try tree.errors.push(.{
1023 .ExpectedInlinable = AstError.ExpectedInlinable{ .token = it.index },1023 .ExpectedInlinable = .{ .token = it.index },
1024 });1024 });
1025 return error.ParseError;1025 return error.ParseError;
1026}1026}
...@@ -1030,18 +1030,18 @@ fn parseForExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1030,18 +1030,18 @@ fn parseForExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1030 const node = (try parseForPrefix(arena, it, tree)) orelse return null;1030 const node = (try parseForPrefix(arena, it, tree)) orelse return null;
1031 const for_prefix = node.cast(Node.For).?;1031 const for_prefix = node.cast(Node.For).?;
10321032
1033 const body_node = try expectNode(arena, it, tree, parseExpr, AstError{1033 const body_node = try expectNode(arena, it, tree, parseExpr, .{
1034 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },1034 .ExpectedExpr = .{ .token = it.index },
1035 });1035 });
1036 for_prefix.body = body_node;1036 for_prefix.body = body_node;
10371037
1038 if (eatToken(it, .Keyword_else)) |else_token| {1038 if (eatToken(it, .Keyword_else)) |else_token| {
1039 const body = try expectNode(arena, it, tree, parseExpr, AstError{1039 const body = try expectNode(arena, it, tree, parseExpr, .{
1040 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },1040 .ExpectedExpr = .{ .token = it.index },
1041 });1041 });
10421042
1043 const else_node = try arena.create(Node.Else);1043 const else_node = try arena.create(Node.Else);
1044 else_node.* = Node.Else{1044 else_node.* = .{
1045 .else_token = else_token,1045 .else_token = else_token,
1046 .payload = null,1046 .payload = null,
1047 .body = body,1047 .body = body,
...@@ -1058,19 +1058,19 @@ fn parseWhileExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1058,19 +1058,19 @@ fn parseWhileExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1058 const node = (try parseWhilePrefix(arena, it, tree)) orelse return null;1058 const node = (try parseWhilePrefix(arena, it, tree)) orelse return null;
1059 const while_prefix = node.cast(Node.While).?;1059 const while_prefix = node.cast(Node.While).?;
10601060
1061 const body_node = try expectNode(arena, it, tree, parseExpr, AstError{1061 const body_node = try expectNode(arena, it, tree, parseExpr, .{
1062 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },1062 .ExpectedExpr = .{ .token = it.index },
1063 });1063 });
1064 while_prefix.body = body_node;1064 while_prefix.body = body_node;
10651065
1066 if (eatToken(it, .Keyword_else)) |else_token| {1066 if (eatToken(it, .Keyword_else)) |else_token| {
1067 const payload = try parsePayload(arena, it, tree);1067 const payload = try parsePayload(arena, it, tree);
1068 const body = try expectNode(arena, it, tree, parseExpr, AstError{1068 const body = try expectNode(arena, it, tree, parseExpr, .{
1069 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },1069 .ExpectedExpr = .{ .token = it.index },
1070 });1070 });
10711071
1072 const else_node = try arena.create(Node.Else);1072 const else_node = try arena.create(Node.Else);
1073 else_node.* = Node.Else{1073 else_node.* = .{
1074 .else_token = else_token,1074 .else_token = else_token,
1075 .payload = payload,1075 .payload = payload,
1076 .body = body,1076 .body = body,
...@@ -1098,14 +1098,14 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf...@@ -1098,14 +1098,14 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf
1098 const lbrace = eatToken(it, .LBrace) orelse return null;1098 const lbrace = eatToken(it, .LBrace) orelse return null;
1099 var init_list = Node.SuffixOp.Op.InitList.init(arena);1099 var init_list = Node.SuffixOp.Op.InitList.init(arena);
11001100
1101 const op = blk: {1101 const op: Node.SuffixOp.Op = blk: {
1102 if (try parseFieldInit(arena, it, tree)) |field_init| {1102 if (try parseFieldInit(arena, it, tree)) |field_init| {
1103 try init_list.push(field_init);1103 try init_list.push(field_init);
1104 while (eatToken(it, .Comma)) |_| {1104 while (eatToken(it, .Comma)) |_| {
1105 const next = (try parseFieldInit(arena, it, tree)) orelse break;1105 const next = (try parseFieldInit(arena, it, tree)) orelse break;
1106 try init_list.push(next);1106 try init_list.push(next);
1107 }1107 }
1108 break :blk Node.SuffixOp.Op{ .StructInitializer = init_list };1108 break :blk .{ .StructInitializer = init_list };
1109 }1109 }
11101110
1111 if (try parseExpr(arena, it, tree)) |expr| {1111 if (try parseExpr(arena, it, tree)) |expr| {
...@@ -1114,14 +1114,14 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf...@@ -1114,14 +1114,14 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf
1114 const next = (try parseExpr(arena, it, tree)) orelse break;1114 const next = (try parseExpr(arena, it, tree)) orelse break;
1115 try init_list.push(next);1115 try init_list.push(next);
1116 }1116 }
1117 break :blk Node.SuffixOp.Op{ .ArrayInitializer = init_list };1117 break :blk .{ .ArrayInitializer = init_list };
1118 }1118 }
11191119
1120 break :blk Node.SuffixOp.Op{ .StructInitializer = init_list };1120 break :blk .{ .StructInitializer = init_list };
1121 };1121 };
11221122
1123 const node = try arena.create(Node.SuffixOp);1123 const node = try arena.create(Node.SuffixOp);
1124 node.* = Node.SuffixOp{1124 node.* = .{
1125 .lhs = .{ .node = undefined }, // set by caller1125 .lhs = .{ .node = undefined }, // set by caller
1126 .op = op,1126 .op = op,
1127 .rtoken = try expectToken(it, tree, .RBrace),1127 .rtoken = try expectToken(it, tree, .RBrace),
...@@ -1140,8 +1140,8 @@ fn parseErrorUnionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No...@@ -1140,8 +1140,8 @@ fn parseErrorUnionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
11401140
1141 if (try SimpleBinOpParseFn(.Bang, Node.InfixOp.Op.ErrorUnion)(arena, it, tree)) |node| {1141 if (try SimpleBinOpParseFn(.Bang, Node.InfixOp.Op.ErrorUnion)(arena, it, tree)) |node| {
1142 const error_union = node.cast(Node.InfixOp).?;1142 const error_union = node.cast(Node.InfixOp).?;
1143 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{1143 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{
1144 .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },1144 .ExpectedTypeExpr = .{ .token = it.index },
1145 });1145 });
1146 error_union.lhs = suffix_expr;1146 error_union.lhs = suffix_expr;
1147 error_union.rhs = type_expr;1147 error_union.rhs = type_expr;
...@@ -1168,8 +1168,8 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1168,8 +1168,8 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1168 return parsePrimaryTypeExpr(arena, it, tree);1168 return parsePrimaryTypeExpr(arena, it, tree);
1169 }1169 }
1170 // TODO: Implement hack for parsing `async fn ...` in ast_parse_suffix_expr1170 // TODO: Implement hack for parsing `async fn ...` in ast_parse_suffix_expr
1171 var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, AstError{1171 var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, .{
1172 .ExpectedPrimaryTypeExpr = AstError.ExpectedPrimaryTypeExpr{ .token = it.index },1172 .ExpectedPrimaryTypeExpr = .{ .token = it.index },
1173 });1173 });
11741174
1175 while (try parseSuffixOp(arena, it, tree)) |node| {1175 while (try parseSuffixOp(arena, it, tree)) |node| {
...@@ -1182,16 +1182,16 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1182,16 +1182,16 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1182 }1182 }
11831183
1184 const params = (try parseFnCallArguments(arena, it, tree)) orelse {1184 const params = (try parseFnCallArguments(arena, it, tree)) orelse {
1185 try tree.errors.push(AstError{1185 try tree.errors.push(.{
1186 .ExpectedParamList = AstError.ExpectedParamList{ .token = it.index },1186 .ExpectedParamList = .{ .token = it.index },
1187 });1187 });
1188 return null;1188 return null;
1189 };1189 };
1190 const node = try arena.create(Node.SuffixOp);1190 const node = try arena.create(Node.SuffixOp);
1191 node.* = Node.SuffixOp{1191 node.* = .{
1192 .lhs = .{ .node = res },1192 .lhs = .{ .node = res },
1193 .op = Node.SuffixOp.Op{1193 .op = .{
1194 .Call = Node.SuffixOp.Op.Call{1194 .Call = .{
1195 .params = params.list,1195 .params = params.list,
1196 .async_token = async_token,1196 .async_token = async_token,
1197 },1197 },
...@@ -1215,10 +1215,10 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1215,10 +1215,10 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1215 }1215 }
1216 if (try parseFnCallArguments(arena, it, tree)) |params| {1216 if (try parseFnCallArguments(arena, it, tree)) |params| {
1217 const call = try arena.create(Node.SuffixOp);1217 const call = try arena.create(Node.SuffixOp);
1218 call.* = Node.SuffixOp{1218 call.* = .{
1219 .lhs = .{ .node = res },1219 .lhs = .{ .node = res },
1220 .op = Node.SuffixOp.Op{1220 .op = .{
1221 .Call = Node.SuffixOp.Op.Call{1221 .Call = .{
1222 .params = params.list,1222 .params = params.list,
1223 .async_token = null,1223 .async_token = null,
1224 },1224 },
...@@ -1264,7 +1264,7 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N...@@ -1264,7 +1264,7 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
1264 if (try parseBuiltinCall(arena, it, tree)) |node| return node;1264 if (try parseBuiltinCall(arena, it, tree)) |node| return node;
1265 if (eatToken(it, .CharLiteral)) |token| {1265 if (eatToken(it, .CharLiteral)) |token| {
1266 const node = try arena.create(Node.CharLiteral);1266 const node = try arena.create(Node.CharLiteral);
1267 node.* = Node.CharLiteral{1267 node.* = .{
1268 .token = token,1268 .token = token,
1269 };1269 };
1270 return &node.base;1270 return &node.base;
...@@ -1300,15 +1300,15 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N...@@ -1300,15 +1300,15 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N
1300 }1300 }
1301 if (eatToken(it, .Keyword_error)) |token| {1301 if (eatToken(it, .Keyword_error)) |token| {
1302 const period = try expectToken(it, tree, .Period);1302 const period = try expectToken(it, tree, .Period);
1303 const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{1303 const identifier = try expectNode(arena, it, tree, parseIdentifier, .{
1304 .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index },1304 .ExpectedIdentifier = .{ .token = it.index },
1305 });1305 });
1306 const global_error_set = try createLiteral(arena, Node.ErrorType, token);1306 const global_error_set = try createLiteral(arena, Node.ErrorType, token);
1307 const node = try arena.create(Node.InfixOp);1307 const node = try arena.create(Node.InfixOp);
1308 node.* = .{1308 node.* = .{
1309 .op_token = period,1309 .op_token = period,
1310 .lhs = global_error_set,1310 .lhs = global_error_set,
1311 .op = Node.InfixOp.Op.Period,1311 .op = .Period,
1312 .rhs = identifier,1312 .rhs = identifier,
1313 };1313 };
1314 return &node.base;1314 return &node.base;
...@@ -1358,7 +1358,7 @@ fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -1358,7 +1358,7 @@ fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
1358 const rbrace = try expectToken(it, tree, .RBrace);1358 const rbrace = try expectToken(it, tree, .RBrace);
13591359
1360 const node = try arena.create(Node.ErrorSetDecl);1360 const node = try arena.create(Node.ErrorSetDecl);
1361 node.* = Node.ErrorSetDecl{1361 node.* = .{
1362 .error_token = error_token,1362 .error_token = error_token,
1363 .decls = decls,1363 .decls = decls,
1364 .rbrace_token = rbrace,1364 .rbrace_token = rbrace,
...@@ -1369,13 +1369,13 @@ fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -1369,13 +1369,13 @@ fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
1369/// GroupedExpr <- LPAREN Expr RPAREN1369/// GroupedExpr <- LPAREN Expr RPAREN
1370fn parseGroupedExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1370fn parseGroupedExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1371 const lparen = eatToken(it, .LParen) orelse return null;1371 const lparen = eatToken(it, .LParen) orelse return null;
1372 const expr = try expectNode(arena, it, tree, parseExpr, AstError{1372 const expr = try expectNode(arena, it, tree, parseExpr, .{
1373 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },1373 .ExpectedExpr = .{ .token = it.index },
1374 });1374 });
1375 const rparen = try expectToken(it, tree, .RParen);1375 const rparen = try expectToken(it, tree, .RParen);
13761376
1377 const node = try arena.create(Node.GroupedExpression);1377 const node = try arena.create(Node.GroupedExpression);
1378 node.* = Node.GroupedExpression{1378 node.* = .{
1379 .lparen = lparen,1379 .lparen = lparen,
1380 .expr = expr,1380 .expr = expr,
1381 .rparen = rparen,1381 .rparen = rparen,
...@@ -1435,8 +1435,8 @@ fn parseLoopTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -1435,8 +1435,8 @@ fn parseLoopTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
1435 if (inline_token == null) return null;1435 if (inline_token == null) return null;
14361436
1437 // If we've seen "inline", there should have been a "for" or "while"1437 // If we've seen "inline", there should have been a "for" or "while"
1438 try tree.errors.push(AstError{1438 try tree.errors.push(.{
1439 .ExpectedInlinable = AstError.ExpectedInlinable{ .token = it.index },1439 .ExpectedInlinable = .{ .token = it.index },
1440 });1440 });
1441 return error.ParseError;1441 return error.ParseError;
1442}1442}
...@@ -1446,18 +1446,18 @@ fn parseForTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -1446,18 +1446,18 @@ fn parseForTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
1446 const node = (try parseForPrefix(arena, it, tree)) orelse return null;1446 const node = (try parseForPrefix(arena, it, tree)) orelse return null;
1447 const for_prefix = node.cast(Node.For).?;1447 const for_prefix = node.cast(Node.For).?;
14481448
1449 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{1449 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{
1450 .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },1450 .ExpectedTypeExpr = .{ .token = it.index },
1451 });1451 });
1452 for_prefix.body = type_expr;1452 for_prefix.body = type_expr;
14531453
1454 if (eatToken(it, .Keyword_else)) |else_token| {1454 if (eatToken(it, .Keyword_else)) |else_token| {
1455 const else_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{1455 const else_expr = try expectNode(arena, it, tree, parseTypeExpr, .{
1456 .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },1456 .ExpectedTypeExpr = .{ .token = it.index },
1457 });1457 });
14581458
1459 const else_node = try arena.create(Node.Else);1459 const else_node = try arena.create(Node.Else);
1460 else_node.* = Node.Else{1460 else_node.* = .{
1461 .else_token = else_token,1461 .else_token = else_token,
1462 .payload = null,1462 .payload = null,
1463 .body = else_expr,1463 .body = else_expr,
...@@ -1474,20 +1474,20 @@ fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod...@@ -1474,20 +1474,20 @@ fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod
1474 const node = (try parseWhilePrefix(arena, it, tree)) orelse return null;1474 const node = (try parseWhilePrefix(arena, it, tree)) orelse return null;
1475 const while_prefix = node.cast(Node.While).?;1475 const while_prefix = node.cast(Node.While).?;
14761476
1477 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{1477 const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{
1478 .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },1478 .ExpectedTypeExpr = .{ .token = it.index },
1479 });1479 });
1480 while_prefix.body = type_expr;1480 while_prefix.body = type_expr;
14811481
1482 if (eatToken(it, .Keyword_else)) |else_token| {1482 if (eatToken(it, .Keyword_else)) |else_token| {
1483 const payload = try parsePayload(arena, it, tree);1483 const payload = try parsePayload(arena, it, tree);
14841484
1485 const else_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{1485 const else_expr = try expectNode(arena, it, tree, parseTypeExpr, .{
1486 .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },1486 .ExpectedTypeExpr = .{ .token = it.index },
1487 });1487 });
14881488
1489 const else_node = try arena.create(Node.Else);1489 const else_node = try arena.create(Node.Else);
1490 else_node.* = Node.Else{1490 else_node.* = .{
1491 .else_token = else_token,1491 .else_token = else_token,
1492 .payload = null,1492 .payload = null,
1493 .body = else_expr,1493 .body = else_expr,
...@@ -1503,8 +1503,8 @@ fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod...@@ -1503,8 +1503,8 @@ fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod
1503fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1503fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1504 const switch_token = eatToken(it, .Keyword_switch) orelse return null;1504 const switch_token = eatToken(it, .Keyword_switch) orelse return null;
1505 _ = try expectToken(it, tree, .LParen);1505 _ = try expectToken(it, tree, .LParen);
1506 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{1506 const expr_node = try expectNode(arena, it, tree, parseExpr, .{
1507 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },1507 .ExpectedExpr = .{ .token = it.index },
1508 });1508 });
1509 _ = try expectToken(it, tree, .RParen);1509 _ = try expectToken(it, tree, .RParen);
1510 _ = try expectToken(it, tree, .LBrace);1510 _ = try expectToken(it, tree, .LBrace);
...@@ -1512,7 +1512,7 @@ fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1512,7 +1512,7 @@ fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1512 const rbrace = try expectToken(it, tree, .RBrace);1512 const rbrace = try expectToken(it, tree, .RBrace);
15131513
1514 const node = try arena.create(Node.Switch);1514 const node = try arena.create(Node.Switch);
1515 node.* = Node.Switch{1515 node.* = .{
1516 .switch_token = switch_token,1516 .switch_token = switch_token,
1517 .expr = expr_node,1517 .expr = expr_node,
1518 .cases = cases,1518 .cases = cases,
...@@ -1526,12 +1526,12 @@ fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1526,12 +1526,12 @@ fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1526 const asm_token = eatToken(it, .Keyword_asm) orelse return null;1526 const asm_token = eatToken(it, .Keyword_asm) orelse return null;
1527 const volatile_token = eatToken(it, .Keyword_volatile);1527 const volatile_token = eatToken(it, .Keyword_volatile);
1528 _ = try expectToken(it, tree, .LParen);1528 _ = try expectToken(it, tree, .LParen);
1529 const template = try expectNode(arena, it, tree, parseExpr, AstError{1529 const template = try expectNode(arena, it, tree, parseExpr, .{
1530 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },1530 .ExpectedExpr = .{ .token = it.index },
1531 });1531 });
15321532
1533 const node = try arena.create(Node.Asm);1533 const node = try arena.create(Node.Asm);
1534 node.* = Node.Asm{1534 node.* = .{
1535 .asm_token = asm_token,1535 .asm_token = asm_token,
1536 .volatile_token = volatile_token,1536 .volatile_token = volatile_token,
1537 .template = template,1537 .template = template,
...@@ -1553,7 +1553,7 @@ fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -1553,7 +1553,7 @@ fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
1553 // anon enum literal1553 // anon enum literal
1554 if (eatToken(it, .Identifier)) |name| {1554 if (eatToken(it, .Identifier)) |name| {
1555 const node = try arena.create(Node.EnumLiteral);1555 const node = try arena.create(Node.EnumLiteral);
1556 node.* = Node.EnumLiteral{1556 node.* = .{
1557 .dot = dot,1557 .dot = dot,
1558 .name = name,1558 .name = name,
1559 };1559 };
...@@ -1580,32 +1580,32 @@ fn parseAsmOutput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node:...@@ -1580,32 +1580,32 @@ fn parseAsmOutput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node:
1580/// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN1580/// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
1581fn parseAsmOutputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmOutput {1581fn parseAsmOutputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmOutput {
1582 const lbracket = eatToken(it, .LBracket) orelse return null;1582 const lbracket = eatToken(it, .LBracket) orelse return null;
1583 const name = try expectNode(arena, it, tree, parseIdentifier, AstError{1583 const name = try expectNode(arena, it, tree, parseIdentifier, .{
1584 .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index },1584 .ExpectedIdentifier = .{ .token = it.index },
1585 });1585 });
1586 _ = try expectToken(it, tree, .RBracket);1586 _ = try expectToken(it, tree, .RBracket);
15871587
1588 const constraint = try expectNode(arena, it, tree, parseStringLiteral, AstError{1588 const constraint = try expectNode(arena, it, tree, parseStringLiteral, .{
1589 .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index },1589 .ExpectedStringLiteral = .{ .token = it.index },
1590 });1590 });
15911591
1592 _ = try expectToken(it, tree, .LParen);1592 _ = try expectToken(it, tree, .LParen);
1593 const kind = blk: {1593 const kind: Node.AsmOutput.Kind = blk: {
1594 if (eatToken(it, .Arrow) != null) {1594 if (eatToken(it, .Arrow) != null) {
1595 const return_ident = try expectNode(arena, it, tree, parseTypeExpr, AstError{1595 const return_ident = try expectNode(arena, it, tree, parseTypeExpr, .{
1596 .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index },1596 .ExpectedTypeExpr = .{ .token = it.index },
1597 });1597 });
1598 break :blk Node.AsmOutput.Kind{ .Return = return_ident };1598 break :blk .{ .Return = return_ident };
1599 }1599 }
1600 const variable = try expectNode(arena, it, tree, parseIdentifier, AstError{1600 const variable = try expectNode(arena, it, tree, parseIdentifier, .{
1601 .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index },1601 .ExpectedIdentifier = .{ .token = it.index },
1602 });1602 });
1603 break :blk Node.AsmOutput.Kind{ .Variable = variable.cast(Node.Identifier).? };1603 break :blk .{ .Variable = variable.cast(Node.Identifier).? };
1604 };1604 };
1605 const rparen = try expectToken(it, tree, .RParen);1605 const rparen = try expectToken(it, tree, .RParen);
16061606
1607 const node = try arena.create(Node.AsmOutput);1607 const node = try arena.create(Node.AsmOutput);
1608 node.* = Node.AsmOutput{1608 node.* = .{
1609 .lbracket = lbracket,1609 .lbracket = lbracket,
1610 .symbolic_name = name,1610 .symbolic_name = name,
1611 .constraint = constraint,1611 .constraint = constraint,
...@@ -1625,23 +1625,23 @@ fn parseAsmInput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: *...@@ -1625,23 +1625,23 @@ fn parseAsmInput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: *
1625/// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN1625/// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN
1626fn parseAsmInputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmInput {1626fn parseAsmInputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmInput {
1627 const lbracket = eatToken(it, .LBracket) orelse return null;1627 const lbracket = eatToken(it, .LBracket) orelse return null;
1628 const name = try expectNode(arena, it, tree, parseIdentifier, AstError{1628 const name = try expectNode(arena, it, tree, parseIdentifier, .{
1629 .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index },1629 .ExpectedIdentifier = .{ .token = it.index },
1630 });1630 });
1631 _ = try expectToken(it, tree, .RBracket);1631 _ = try expectToken(it, tree, .RBracket);
16321632
1633 const constraint = try expectNode(arena, it, tree, parseStringLiteral, AstError{1633 const constraint = try expectNode(arena, it, tree, parseStringLiteral, .{
1634 .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index },1634 .ExpectedStringLiteral = .{ .token = it.index },
1635 });1635 });
16361636
1637 _ = try expectToken(it, tree, .LParen);1637 _ = try expectToken(it, tree, .LParen);
1638 const expr = try expectNode(arena, it, tree, parseExpr, AstError{1638 const expr = try expectNode(arena, it, tree, parseExpr, .{
1639 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },1639 .ExpectedExpr = .{ .token = it.index },
1640 });1640 });
1641 const rparen = try expectToken(it, tree, .RParen);1641 const rparen = try expectToken(it, tree, .RParen);
16421642
1643 const node = try arena.create(Node.AsmInput);1643 const node = try arena.create(Node.AsmInput);
1644 node.* = Node.AsmInput{1644 node.* = .{
1645 .lbracket = lbracket,1645 .lbracket = lbracket,
1646 .symbolic_name = name,1646 .symbolic_name = name,
1647 .constraint = constraint,1647 .constraint = constraint,
...@@ -1664,8 +1664,8 @@ fn parseAsmClobbers(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node...@@ -1664,8 +1664,8 @@ fn parseAsmClobbers(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node
1664/// BreakLabel <- COLON IDENTIFIER1664/// BreakLabel <- COLON IDENTIFIER
1665fn parseBreakLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1665fn parseBreakLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1666 _ = eatToken(it, .Colon) orelse return null;1666 _ = eatToken(it, .Colon) orelse return null;
1667 return try expectNode(arena, it, tree, parseIdentifier, AstError{1667 return try expectNode(arena, it, tree, parseIdentifier, .{
1668 .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index },1668 .ExpectedIdentifier = .{ .token = it.index },
1669 });1669 });
1670}1670}
16711671
...@@ -1694,12 +1694,12 @@ fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1694,12 +1694,12 @@ fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1694 putBackToken(it, period_token);1694 putBackToken(it, period_token);
1695 return null;1695 return null;
1696 };1696 };
1697 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{1697 const expr_node = try expectNode(arena, it, tree, parseExpr, .{
1698 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },1698 .ExpectedExpr = .{ .token = it.index },
1699 });1699 });
17001700
1701 const node = try arena.create(Node.FieldInitializer);1701 const node = try arena.create(Node.FieldInitializer);
1702 node.* = Node.FieldInitializer{1702 node.* = .{
1703 .period_token = period_token,1703 .period_token = period_token,
1704 .name_token = name_token,1704 .name_token = name_token,
1705 .expr = expr_node,1705 .expr = expr_node,
...@@ -1711,8 +1711,8 @@ fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1711,8 +1711,8 @@ fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1711fn parseWhileContinueExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1711fn parseWhileContinueExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1712 _ = eatToken(it, .Colon) orelse return null;1712 _ = eatToken(it, .Colon) orelse return null;
1713 _ = try expectToken(it, tree, .LParen);1713 _ = try expectToken(it, tree, .LParen);
1714 const node = try expectNode(arena, it, tree, parseAssignExpr, AstError{1714 const node = try expectNode(arena, it, tree, parseAssignExpr, .{
1715 .ExpectedExprOrAssignment = AstError.ExpectedExprOrAssignment{ .token = it.index },1715 .ExpectedExprOrAssignment = .{ .token = it.index },
1716 });1716 });
1717 _ = try expectToken(it, tree, .RParen);1717 _ = try expectToken(it, tree, .RParen);
1718 return node;1718 return node;
...@@ -1722,8 +1722,8 @@ fn parseWhileContinueExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?...@@ -1722,8 +1722,8 @@ fn parseWhileContinueExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?
1722fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1722fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1723 _ = eatToken(it, .Keyword_linksection) orelse return null;1723 _ = eatToken(it, .Keyword_linksection) orelse return null;
1724 _ = try expectToken(it, tree, .LParen);1724 _ = try expectToken(it, tree, .LParen);
1725 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{1725 const expr_node = try expectNode(arena, it, tree, parseExpr, .{
1726 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },1726 .ExpectedExpr = .{ .token = it.index },
1727 });1727 });
1728 _ = try expectToken(it, tree, .RParen);1728 _ = try expectToken(it, tree, .RParen);
1729 return expr_node;1729 return expr_node;
...@@ -1733,8 +1733,8 @@ fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -1733,8 +1733,8 @@ fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
1733fn parseCallconv(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1733fn parseCallconv(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1734 _ = eatToken(it, .Keyword_callconv) orelse return null;1734 _ = eatToken(it, .Keyword_callconv) orelse return null;
1735 _ = try expectToken(it, tree, .LParen);1735 _ = try expectToken(it, tree, .LParen);
1736 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{1736 const expr_node = try expectNode(arena, it, tree, parseExpr, .{
1737 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },1737 .ExpectedExpr = .{ .token = it.index },
1738 });1738 });
1739 _ = try expectToken(it, tree, .RParen);1739 _ = try expectToken(it, tree, .RParen);
1740 return expr_node;1740 return expr_node;
...@@ -1775,14 +1775,14 @@ fn parseParamDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1775,14 +1775,14 @@ fn parseParamDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1775 comptime_token == null and1775 comptime_token == null and
1776 name_token == null and1776 name_token == null and
1777 doc_comments == null) return null;1777 doc_comments == null) return null;
1778 try tree.errors.push(AstError{1778 try tree.errors.push(.{
1779 .ExpectedParamType = AstError.ExpectedParamType{ .token = it.index },1779 .ExpectedParamType = .{ .token = it.index },
1780 });1780 });
1781 return error.ParseError;1781 return error.ParseError;
1782 };1782 };
17831783
1784 const param_decl = try arena.create(Node.ParamDecl);1784 const param_decl = try arena.create(Node.ParamDecl);
1785 param_decl.* = Node.ParamDecl{1785 param_decl.* = .{
1786 .doc_comments = doc_comments,1786 .doc_comments = doc_comments,
1787 .comptime_token = comptime_token,1787 .comptime_token = comptime_token,
1788 .noalias_token = noalias_token,1788 .noalias_token = noalias_token,
...@@ -1821,14 +1821,14 @@ const ParamType = union(enum) {...@@ -1821,14 +1821,14 @@ const ParamType = union(enum) {
1821fn parseIfPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1821fn parseIfPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1822 const if_token = eatToken(it, .Keyword_if) orelse return null;1822 const if_token = eatToken(it, .Keyword_if) orelse return null;
1823 _ = try expectToken(it, tree, .LParen);1823 _ = try expectToken(it, tree, .LParen);
1824 const condition = try expectNode(arena, it, tree, parseExpr, AstError{1824 const condition = try expectNode(arena, it, tree, parseExpr, .{
1825 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },1825 .ExpectedExpr = .{ .token = it.index },
1826 });1826 });
1827 _ = try expectToken(it, tree, .RParen);1827 _ = try expectToken(it, tree, .RParen);
1828 const payload = try parsePtrPayload(arena, it, tree);1828 const payload = try parsePtrPayload(arena, it, tree);
18291829
1830 const node = try arena.create(Node.If);1830 const node = try arena.create(Node.If);
1831 node.* = Node.If{1831 node.* = .{
1832 .if_token = if_token,1832 .if_token = if_token,
1833 .condition = condition,1833 .condition = condition,
1834 .payload = payload,1834 .payload = payload,
...@@ -1843,8 +1843,8 @@ fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -1843,8 +1843,8 @@ fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
1843 const while_token = eatToken(it, .Keyword_while) orelse return null;1843 const while_token = eatToken(it, .Keyword_while) orelse return null;
18441844
1845 _ = try expectToken(it, tree, .LParen);1845 _ = try expectToken(it, tree, .LParen);
1846 const condition = try expectNode(arena, it, tree, parseExpr, AstError{1846 const condition = try expectNode(arena, it, tree, parseExpr, .{
1847 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },1847 .ExpectedExpr = .{ .token = it.index },
1848 });1848 });
1849 _ = try expectToken(it, tree, .RParen);1849 _ = try expectToken(it, tree, .RParen);
18501850
...@@ -1852,7 +1852,7 @@ fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -1852,7 +1852,7 @@ fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
1852 const continue_expr = try parseWhileContinueExpr(arena, it, tree);1852 const continue_expr = try parseWhileContinueExpr(arena, it, tree);
18531853
1854 const node = try arena.create(Node.While);1854 const node = try arena.create(Node.While);
1855 node.* = Node.While{1855 node.* = .{
1856 .label = null,1856 .label = null,
1857 .inline_token = null,1857 .inline_token = null,
1858 .while_token = while_token,1858 .while_token = while_token,
...@@ -1870,17 +1870,17 @@ fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1870,17 +1870,17 @@ fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1870 const for_token = eatToken(it, .Keyword_for) orelse return null;1870 const for_token = eatToken(it, .Keyword_for) orelse return null;
18711871
1872 _ = try expectToken(it, tree, .LParen);1872 _ = try expectToken(it, tree, .LParen);
1873 const array_expr = try expectNode(arena, it, tree, parseExpr, AstError{1873 const array_expr = try expectNode(arena, it, tree, parseExpr, .{
1874 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },1874 .ExpectedExpr = .{ .token = it.index },
1875 });1875 });
1876 _ = try expectToken(it, tree, .RParen);1876 _ = try expectToken(it, tree, .RParen);
18771877
1878 const payload = try expectNode(arena, it, tree, parsePtrIndexPayload, AstError{1878 const payload = try expectNode(arena, it, tree, parsePtrIndexPayload, .{
1879 .ExpectedPayload = AstError.ExpectedPayload{ .token = it.index },1879 .ExpectedPayload = .{ .token = it.index },
1880 });1880 });
18811881
1882 const node = try arena.create(Node.For);1882 const node = try arena.create(Node.For);
1883 node.* = Node.For{1883 node.* = .{
1884 .label = null,1884 .label = null,
1885 .inline_token = null,1885 .inline_token = null,
1886 .for_token = for_token,1886 .for_token = for_token,
...@@ -1895,13 +1895,13 @@ fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1895,13 +1895,13 @@ fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1895/// Payload <- PIPE IDENTIFIER PIPE1895/// Payload <- PIPE IDENTIFIER PIPE
1896fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1896fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1897 const lpipe = eatToken(it, .Pipe) orelse return null;1897 const lpipe = eatToken(it, .Pipe) orelse return null;
1898 const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{1898 const identifier = try expectNode(arena, it, tree, parseIdentifier, .{
1899 .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index },1899 .ExpectedIdentifier = .{ .token = it.index },
1900 });1900 });
1901 const rpipe = try expectToken(it, tree, .Pipe);1901 const rpipe = try expectToken(it, tree, .Pipe);
19021902
1903 const node = try arena.create(Node.Payload);1903 const node = try arena.create(Node.Payload);
1904 node.* = Node.Payload{1904 node.* = .{
1905 .lpipe = lpipe,1905 .lpipe = lpipe,
1906 .error_symbol = identifier,1906 .error_symbol = identifier,
1907 .rpipe = rpipe,1907 .rpipe = rpipe,
...@@ -1913,13 +1913,13 @@ fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1913,13 +1913,13 @@ fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1913fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1913fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1914 const lpipe = eatToken(it, .Pipe) orelse return null;1914 const lpipe = eatToken(it, .Pipe) orelse return null;
1915 const asterisk = eatToken(it, .Asterisk);1915 const asterisk = eatToken(it, .Asterisk);
1916 const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{1916 const identifier = try expectNode(arena, it, tree, parseIdentifier, .{
1917 .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index },1917 .ExpectedIdentifier = .{ .token = it.index },
1918 });1918 });
1919 const rpipe = try expectToken(it, tree, .Pipe);1919 const rpipe = try expectToken(it, tree, .Pipe);
19201920
1921 const node = try arena.create(Node.PointerPayload);1921 const node = try arena.create(Node.PointerPayload);
1922 node.* = Node.PointerPayload{1922 node.* = .{
1923 .lpipe = lpipe,1923 .lpipe = lpipe,
1924 .ptr_token = asterisk,1924 .ptr_token = asterisk,
1925 .value_symbol = identifier,1925 .value_symbol = identifier,
...@@ -1932,21 +1932,21 @@ fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1932,21 +1932,21 @@ fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1932fn parsePtrIndexPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {1932fn parsePtrIndexPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1933 const lpipe = eatToken(it, .Pipe) orelse return null;1933 const lpipe = eatToken(it, .Pipe) orelse return null;
1934 const asterisk = eatToken(it, .Asterisk);1934 const asterisk = eatToken(it, .Asterisk);
1935 const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{1935 const identifier = try expectNode(arena, it, tree, parseIdentifier, .{
1936 .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index },1936 .ExpectedIdentifier = .{ .token = it.index },
1937 });1937 });
19381938
1939 const index = if (eatToken(it, .Comma) == null)1939 const index = if (eatToken(it, .Comma) == null)
1940 null1940 null
1941 else1941 else
1942 try expectNode(arena, it, tree, parseIdentifier, AstError{1942 try expectNode(arena, it, tree, parseIdentifier, .{
1943 .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index },1943 .ExpectedIdentifier = .{ .token = it.index },
1944 });1944 });
19451945
1946 const rpipe = try expectToken(it, tree, .Pipe);1946 const rpipe = try expectToken(it, tree, .Pipe);
19471947
1948 const node = try arena.create(Node.PointerIndexPayload);1948 const node = try arena.create(Node.PointerIndexPayload);
1949 node.* = Node.PointerIndexPayload{1949 node.* = .{
1950 .lpipe = lpipe,1950 .lpipe = lpipe,
1951 .ptr_token = asterisk,1951 .ptr_token = asterisk,
1952 .value_symbol = identifier,1952 .value_symbol = identifier,
...@@ -1961,8 +1961,8 @@ fn parseSwitchProng(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -1961,8 +1961,8 @@ fn parseSwitchProng(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
1961 const node = (try parseSwitchCase(arena, it, tree)) orelse return null;1961 const node = (try parseSwitchCase(arena, it, tree)) orelse return null;
1962 const arrow = try expectToken(it, tree, .EqualAngleBracketRight);1962 const arrow = try expectToken(it, tree, .EqualAngleBracketRight);
1963 const payload = try parsePtrPayload(arena, it, tree);1963 const payload = try parsePtrPayload(arena, it, tree);
1964 const expr = try expectNode(arena, it, tree, parseAssignExpr, AstError{1964 const expr = try expectNode(arena, it, tree, parseAssignExpr, .{
1965 .ExpectedExprOrAssignment = AstError.ExpectedExprOrAssignment{ .token = it.index },1965 .ExpectedExprOrAssignment = .{ .token = it.index },
1966 });1966 });
19671967
1968 const switch_case = node.cast(Node.SwitchCase).?;1968 const switch_case = node.cast(Node.SwitchCase).?;
...@@ -1987,14 +1987,14 @@ fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -1987,14 +1987,14 @@ fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
1987 }1987 }
1988 } else if (eatToken(it, .Keyword_else)) |else_token| {1988 } else if (eatToken(it, .Keyword_else)) |else_token| {
1989 const else_node = try arena.create(Node.SwitchElse);1989 const else_node = try arena.create(Node.SwitchElse);
1990 else_node.* = Node.SwitchElse{1990 else_node.* = .{
1991 .token = else_token,1991 .token = else_token,
1992 };1992 };
1993 try list.push(&else_node.base);1993 try list.push(&else_node.base);
1994 } else return null;1994 } else return null;
19951995
1996 const node = try arena.create(Node.SwitchCase);1996 const node = try arena.create(Node.SwitchCase);
1997 node.* = Node.SwitchCase{1997 node.* = .{
1998 .items = list,1998 .items = list,
1999 .arrow_token = undefined, // set by caller1999 .arrow_token = undefined, // set by caller
2000 .payload = null,2000 .payload = null,
...@@ -2007,15 +2007,15 @@ fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2007,15 +2007,15 @@ fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2007fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2007fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2008 const expr = (try parseExpr(arena, it, tree)) orelse return null;2008 const expr = (try parseExpr(arena, it, tree)) orelse return null;
2009 if (eatToken(it, .Ellipsis3)) |token| {2009 if (eatToken(it, .Ellipsis3)) |token| {
2010 const range_end = try expectNode(arena, it, tree, parseExpr, AstError{2010 const range_end = try expectNode(arena, it, tree, parseExpr, .{
2011 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },2011 .ExpectedExpr = .{ .token = it.index },
2012 });2012 });
20132013
2014 const node = try arena.create(Node.InfixOp);2014 const node = try arena.create(Node.InfixOp);
2015 node.* = Node.InfixOp{2015 node.* = .{
2016 .op_token = token,2016 .op_token = token,
2017 .lhs = expr,2017 .lhs = expr,
2018 .op = Node.InfixOp.Op{ .Range = {} },2018 .op = .Range,
2019 .rhs = range_end,2019 .rhs = range_end,
2020 };2020 };
2021 return &node.base;2021 return &node.base;
...@@ -2039,24 +2039,22 @@ fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2039,24 +2039,22 @@ fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2039/// / MINUSPERCENTEQUAL2039/// / MINUSPERCENTEQUAL
2040/// / EQUAL2040/// / EQUAL
2041fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2041fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2042 const Op = Node.InfixOp.Op;
2043
2044 const token = nextToken(it);2042 const token = nextToken(it);
2045 const op = switch (token.ptr.id) {2043 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2046 .AsteriskEqual => Op{ .AssignMul = {} },2044 .AsteriskEqual => .AssignMul,
2047 .SlashEqual => Op{ .AssignDiv = {} },2045 .SlashEqual => .AssignDiv,
2048 .PercentEqual => Op{ .AssignMod = {} },2046 .PercentEqual => .AssignMod,
2049 .PlusEqual => Op{ .AssignAdd = {} },2047 .PlusEqual => .AssignAdd,
2050 .MinusEqual => Op{ .AssignSub = {} },2048 .MinusEqual => .AssignSub,
2051 .AngleBracketAngleBracketLeftEqual => Op{ .AssignBitShiftLeft = {} },2049 .AngleBracketAngleBracketLeftEqual => .AssignBitShiftLeft,
2052 .AngleBracketAngleBracketRightEqual => Op{ .AssignBitShiftRight = {} },2050 .AngleBracketAngleBracketRightEqual => .AssignBitShiftRight,
2053 .AmpersandEqual => Op{ .AssignBitAnd = {} },2051 .AmpersandEqual => .AssignBitAnd,
2054 .CaretEqual => Op{ .AssignBitXor = {} },2052 .CaretEqual => .AssignBitXor,
2055 .PipeEqual => Op{ .AssignBitOr = {} },2053 .PipeEqual => .AssignBitOr,
2056 .AsteriskPercentEqual => Op{ .AssignMulWrap = {} },2054 .AsteriskPercentEqual => .AssignMulWrap,
2057 .PlusPercentEqual => Op{ .AssignAddWrap = {} },2055 .PlusPercentEqual => .AssignAddWrap,
2058 .MinusPercentEqual => Op{ .AssignSubWrap = {} },2056 .MinusPercentEqual => .AssignSubWrap,
2059 .Equal => Op{ .Assign = {} },2057 .Equal => .Assign,
2060 else => {2058 else => {
2061 putBackToken(it, token.index);2059 putBackToken(it, token.index);
2062 return null;2060 return null;
...@@ -2064,7 +2062,7 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2064,7 +2062,7 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2064 };2062 };
20652063
2066 const node = try arena.create(Node.InfixOp);2064 const node = try arena.create(Node.InfixOp);
2067 node.* = Node.InfixOp{2065 node.* = .{
2068 .op_token = token.index,2066 .op_token = token.index,
2069 .lhs = undefined, // set by caller2067 .lhs = undefined, // set by caller
2070 .op = op,2068 .op = op,
...@@ -2081,16 +2079,14 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2081,16 +2079,14 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2081/// / LARROWEQUAL2079/// / LARROWEQUAL
2082/// / RARROWEQUAL2080/// / RARROWEQUAL
2083fn parseCompareOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2081fn parseCompareOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2084 const ops = Node.InfixOp.Op;
2085
2086 const token = nextToken(it);2082 const token = nextToken(it);
2087 const op = switch (token.ptr.id) {2083 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2088 .EqualEqual => ops{ .EqualEqual = {} },2084 .EqualEqual => .EqualEqual,
2089 .BangEqual => ops{ .BangEqual = {} },2085 .BangEqual => .BangEqual,
2090 .AngleBracketLeft => ops{ .LessThan = {} },2086 .AngleBracketLeft => .LessThan,
2091 .AngleBracketRight => ops{ .GreaterThan = {} },2087 .AngleBracketRight => .GreaterThan,
2092 .AngleBracketLeftEqual => ops{ .LessOrEqual = {} },2088 .AngleBracketLeftEqual => .LessOrEqual,
2093 .AngleBracketRightEqual => ops{ .GreaterOrEqual = {} },2089 .AngleBracketRightEqual => .GreaterOrEqual,
2094 else => {2090 else => {
2095 putBackToken(it, token.index);2091 putBackToken(it, token.index);
2096 return null;2092 return null;
...@@ -2107,15 +2103,13 @@ fn parseCompareOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2107,15 +2103,13 @@ fn parseCompareOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2107/// / KEYWORD_orelse2103/// / KEYWORD_orelse
2108/// / KEYWORD_catch Payload?2104/// / KEYWORD_catch Payload?
2109fn parseBitwiseOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2105fn parseBitwiseOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2110 const ops = Node.InfixOp.Op;
2111
2112 const token = nextToken(it);2106 const token = nextToken(it);
2113 const op = switch (token.ptr.id) {2107 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2114 .Ampersand => ops{ .BitAnd = {} },2108 .Ampersand => .BitAnd,
2115 .Caret => ops{ .BitXor = {} },2109 .Caret => .BitXor,
2116 .Pipe => ops{ .BitOr = {} },2110 .Pipe => .BitOr,
2117 .Keyword_orelse => ops{ .UnwrapOptional = {} },2111 .Keyword_orelse => .UnwrapOptional,
2118 .Keyword_catch => ops{ .Catch = try parsePayload(arena, it, tree) },2112 .Keyword_catch => .{ .Catch = try parsePayload(arena, it, tree) },
2119 else => {2113 else => {
2120 putBackToken(it, token.index);2114 putBackToken(it, token.index);
2121 return null;2115 return null;
...@@ -2129,12 +2123,10 @@ fn parseBitwiseOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2129,12 +2123,10 @@ fn parseBitwiseOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2129/// <- LARROW22123/// <- LARROW2
2130/// / RARROW22124/// / RARROW2
2131fn parseBitShiftOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2125fn parseBitShiftOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2132 const ops = Node.InfixOp.Op;
2133
2134 const token = nextToken(it);2126 const token = nextToken(it);
2135 const op = switch (token.ptr.id) {2127 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2136 .AngleBracketAngleBracketLeft => ops{ .BitShiftLeft = {} },2128 .AngleBracketAngleBracketLeft => .BitShiftLeft,
2137 .AngleBracketAngleBracketRight => ops{ .BitShiftRight = {} },2129 .AngleBracketAngleBracketRight => .BitShiftRight,
2138 else => {2130 else => {
2139 putBackToken(it, token.index);2131 putBackToken(it, token.index);
2140 return null;2132 return null;
...@@ -2151,15 +2143,13 @@ fn parseBitShiftOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2151,15 +2143,13 @@ fn parseBitShiftOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2151/// / PLUSPERCENT2143/// / PLUSPERCENT
2152/// / MINUSPERCENT2144/// / MINUSPERCENT
2153fn parseAdditionOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2145fn parseAdditionOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2154 const ops = Node.InfixOp.Op;
2155
2156 const token = nextToken(it);2146 const token = nextToken(it);
2157 const op = switch (token.ptr.id) {2147 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2158 .Plus => ops{ .Add = {} },2148 .Plus => .Add,
2159 .Minus => ops{ .Sub = {} },2149 .Minus => .Sub,
2160 .PlusPlus => ops{ .ArrayCat = {} },2150 .PlusPlus => .ArrayCat,
2161 .PlusPercent => ops{ .AddWrap = {} },2151 .PlusPercent => .AddWrap,
2162 .MinusPercent => ops{ .SubWrap = {} },2152 .MinusPercent => .SubWrap,
2163 else => {2153 else => {
2164 putBackToken(it, token.index);2154 putBackToken(it, token.index);
2165 return null;2155 return null;
...@@ -2177,16 +2167,14 @@ fn parseAdditionOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2177,16 +2167,14 @@ fn parseAdditionOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2177/// / ASTERISK22167/// / ASTERISK2
2178/// / ASTERISKPERCENT2168/// / ASTERISKPERCENT
2179fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2169fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2180 const ops = Node.InfixOp.Op;
2181
2182 const token = nextToken(it);2170 const token = nextToken(it);
2183 const op = switch (token.ptr.id) {2171 const op: Node.InfixOp.Op = switch (token.ptr.id) {
2184 .PipePipe => ops{ .BoolOr = {} },2172 .PipePipe => .MergeErrorSets,
2185 .Asterisk => ops{ .Mul = {} },2173 .Asterisk => .Mul,
2186 .Slash => ops{ .Div = {} },2174 .Slash => .Div,
2187 .Percent => ops{ .Mod = {} },2175 .Percent => .Mod,
2188 .AsteriskAsterisk => ops{ .ArrayMult = {} },2176 .AsteriskAsterisk => .ArrayMult,
2189 .AsteriskPercent => ops{ .MulWrap = {} },2177 .AsteriskPercent => .MulWrap,
2190 else => {2178 else => {
2191 putBackToken(it, token.index);2179 putBackToken(it, token.index);
2192 return null;2180 return null;
...@@ -2205,17 +2193,15 @@ fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2205,17 +2193,15 @@ fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2205/// / KEYWORD_try2193/// / KEYWORD_try
2206/// / KEYWORD_await2194/// / KEYWORD_await
2207fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2195fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2208 const ops = Node.PrefixOp.Op;
2209
2210 const token = nextToken(it);2196 const token = nextToken(it);
2211 const op = switch (token.ptr.id) {2197 const op: Node.PrefixOp.Op = switch (token.ptr.id) {
2212 .Bang => ops{ .BoolNot = {} },2198 .Bang => .BoolNot,
2213 .Minus => ops{ .Negation = {} },2199 .Minus => .Negation,
2214 .Tilde => ops{ .BitNot = {} },2200 .Tilde => .BitNot,
2215 .MinusPercent => ops{ .NegationWrap = {} },2201 .MinusPercent => .NegationWrap,
2216 .Ampersand => ops{ .AddressOf = {} },2202 .Ampersand => .AddressOf,
2217 .Keyword_try => ops{ .Try = {} },2203 .Keyword_try => .Try,
2218 .Keyword_await => ops{ .Await = .{} },2204 .Keyword_await => .Await,
2219 else => {2205 else => {
2220 putBackToken(it, token.index);2206 putBackToken(it, token.index);
2221 return null;2207 return null;
...@@ -2223,7 +2209,7 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2223,7 +2209,7 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2223 };2209 };
22242210
2225 const node = try arena.create(Node.PrefixOp);2211 const node = try arena.create(Node.PrefixOp);
2226 node.* = Node.PrefixOp{2212 node.* = .{
2227 .op_token = token.index,2213 .op_token = token.index,
2228 .op = op,2214 .op = op,
2229 .rhs = undefined, // set by caller2215 .rhs = undefined, // set by caller
...@@ -2246,9 +2232,9 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2246,9 +2232,9 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2246fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2232fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2247 if (eatToken(it, .QuestionMark)) |token| {2233 if (eatToken(it, .QuestionMark)) |token| {
2248 const node = try arena.create(Node.PrefixOp);2234 const node = try arena.create(Node.PrefixOp);
2249 node.* = Node.PrefixOp{2235 node.* = .{
2250 .op_token = token,2236 .op_token = token,
2251 .op = Node.PrefixOp.Op.OptionalType,2237 .op = .OptionalType,
2252 .rhs = undefined, // set by caller2238 .rhs = undefined, // set by caller
2253 };2239 };
2254 return &node.base;2240 return &node.base;
...@@ -2264,7 +2250,7 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -2264,7 +2250,7 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
2264 return null;2250 return null;
2265 };2251 };
2266 const node = try arena.create(Node.AnyFrameType);2252 const node = try arena.create(Node.AnyFrameType);
2267 node.* = Node.AnyFrameType{2253 node.* = .{
2268 .anyframe_token = token,2254 .anyframe_token = token,
2269 .result = Node.AnyFrameType.Result{2255 .result = Node.AnyFrameType.Result{
2270 .arrow_token = arrow,2256 .arrow_token = arrow,
...@@ -2286,18 +2272,18 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -2286,18 +2272,18 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
2286 while (true) {2272 while (true) {
2287 if (eatToken(it, .Keyword_align)) |align_token| {2273 if (eatToken(it, .Keyword_align)) |align_token| {
2288 const lparen = try expectToken(it, tree, .LParen);2274 const lparen = try expectToken(it, tree, .LParen);
2289 const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{2275 const expr_node = try expectNode(arena, it, tree, parseExpr, .{
2290 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },2276 .ExpectedExpr = .{ .token = it.index },
2291 });2277 });
22922278
2293 // Optional bit range2279 // Optional bit range
2294 const bit_range = if (eatToken(it, .Colon)) |_| bit_range_value: {2280 const bit_range = if (eatToken(it, .Colon)) |_| bit_range_value: {
2295 const range_start = try expectNode(arena, it, tree, parseIntegerLiteral, AstError{2281 const range_start = try expectNode(arena, it, tree, parseIntegerLiteral, .{
2296 .ExpectedIntegerLiteral = AstError.ExpectedIntegerLiteral{ .token = it.index },2282 .ExpectedIntegerLiteral = .{ .token = it.index },
2297 });2283 });
2298 _ = try expectToken(it, tree, .Colon);2284 _ = try expectToken(it, tree, .Colon);
2299 const range_end = try expectNode(arena, it, tree, parseIntegerLiteral, AstError{2285 const range_end = try expectNode(arena, it, tree, parseIntegerLiteral, .{
2300 .ExpectedIntegerLiteral = AstError.ExpectedIntegerLiteral{ .token = it.index },2286 .ExpectedIntegerLiteral = .{ .token = it.index },
2301 });2287 });
23022288
2303 break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{2289 break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{
...@@ -2340,8 +2326,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -2340,8 +2326,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
2340 while (true) {2326 while (true) {
2341 if (try parseByteAlign(arena, it, tree)) |align_expr| {2327 if (try parseByteAlign(arena, it, tree)) |align_expr| {
2342 if (slice_type.align_info != null) {2328 if (slice_type.align_info != null) {
2343 try tree.errors.push(AstError{2329 try tree.errors.push(.{
2344 .ExtraAlignQualifier = AstError.ExtraAlignQualifier{ .token = it.index },2330 .ExtraAlignQualifier = .{ .token = it.index },
2345 });2331 });
2346 return error.ParseError;2332 return error.ParseError;
2347 }2333 }
...@@ -2353,8 +2339,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -2353,8 +2339,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
2353 }2339 }
2354 if (eatToken(it, .Keyword_const)) |const_token| {2340 if (eatToken(it, .Keyword_const)) |const_token| {
2355 if (slice_type.const_token != null) {2341 if (slice_type.const_token != null) {
2356 try tree.errors.push(AstError{2342 try tree.errors.push(.{
2357 .ExtraConstQualifier = AstError.ExtraConstQualifier{ .token = it.index },2343 .ExtraConstQualifier = .{ .token = it.index },
2358 });2344 });
2359 return error.ParseError;2345 return error.ParseError;
2360 }2346 }
...@@ -2363,8 +2349,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -2363,8 +2349,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
2363 }2349 }
2364 if (eatToken(it, .Keyword_volatile)) |volatile_token| {2350 if (eatToken(it, .Keyword_volatile)) |volatile_token| {
2365 if (slice_type.volatile_token != null) {2351 if (slice_type.volatile_token != null) {
2366 try tree.errors.push(AstError{2352 try tree.errors.push(.{
2367 .ExtraVolatileQualifier = AstError.ExtraVolatileQualifier{ .token = it.index },2353 .ExtraVolatileQualifier = .{ .token = it.index },
2368 });2354 });
2369 return error.ParseError;2355 return error.ParseError;
2370 }2356 }
...@@ -2373,8 +2359,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -2373,8 +2359,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
2373 }2359 }
2374 if (eatToken(it, .Keyword_allowzero)) |allowzero_token| {2360 if (eatToken(it, .Keyword_allowzero)) |allowzero_token| {
2375 if (slice_type.allowzero_token != null) {2361 if (slice_type.allowzero_token != null) {
2376 try tree.errors.push(AstError{2362 try tree.errors.push(.{
2377 .ExtraAllowZeroQualifier = AstError.ExtraAllowZeroQualifier{ .token = it.index },2363 .ExtraAllowZeroQualifier = .{ .token = it.index },
2378 });2364 });
2379 return error.ParseError;2365 return error.ParseError;
2380 }2366 }
...@@ -2398,15 +2384,14 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -2398,15 +2384,14 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
2398/// / DOTASTERISK2384/// / DOTASTERISK
2399/// / DOTQUESTIONMARK2385/// / DOTQUESTIONMARK
2400fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2386fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2401 const Op = Node.SuffixOp.Op;
2402 const OpAndToken = struct {2387 const OpAndToken = struct {
2403 op: Node.SuffixOp.Op,2388 op: Node.SuffixOp.Op,
2404 token: TokenIndex,2389 token: TokenIndex,
2405 };2390 };
2406 const op_and_token = blk: {2391 const op_and_token: OpAndToken = blk: {
2407 if (eatToken(it, .LBracket)) |_| {2392 if (eatToken(it, .LBracket)) |_| {
2408 const index_expr = try expectNode(arena, it, tree, parseExpr, AstError{2393 const index_expr = try expectNode(arena, it, tree, parseExpr, .{
2409 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },2394 .ExpectedExpr = .{ .token = it.index },
2410 });2395 });
24112396
2412 if (eatToken(it, .Ellipsis2) != null) {2397 if (eatToken(it, .Ellipsis2) != null) {
...@@ -2415,9 +2400,9 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2415,9 +2400,9 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2415 try parseExpr(arena, it, tree)2400 try parseExpr(arena, it, tree)
2416 else2401 else
2417 null;2402 null;
2418 break :blk OpAndToken{2403 break :blk .{
2419 .op = Op{2404 .op = .{
2420 .Slice = Op.Slice{2405 .Slice = .{
2421 .start = index_expr,2406 .start = index_expr,
2422 .end = end_expr,2407 .end = end_expr,
2423 .sentinel = sentinel,2408 .sentinel = sentinel,
...@@ -2427,14 +2412,14 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2427,14 +2412,14 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2427 };2412 };
2428 }2413 }
24292414
2430 break :blk OpAndToken{2415 break :blk .{
2431 .op = Op{ .ArrayAccess = index_expr },2416 .op = .{ .ArrayAccess = index_expr },
2432 .token = try expectToken(it, tree, .RBracket),2417 .token = try expectToken(it, tree, .RBracket),
2433 };2418 };
2434 }2419 }
24352420
2436 if (eatToken(it, .PeriodAsterisk)) |period_asterisk| {2421 if (eatToken(it, .PeriodAsterisk)) |period_asterisk| {
2437 break :blk OpAndToken{ .op = Op{ .Deref = {} }, .token = period_asterisk };2422 break :blk .{ .op = .Deref, .token = period_asterisk };
2438 }2423 }
24392424
2440 if (eatToken(it, .Period)) |period| {2425 if (eatToken(it, .Period)) |period| {
...@@ -2443,19 +2428,19 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2443,19 +2428,19 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2443 // Should there be an ast.Node.SuffixOp.FieldAccess variant? Or should2428 // Should there be an ast.Node.SuffixOp.FieldAccess variant? Or should
2444 // this grammar rule be altered?2429 // this grammar rule be altered?
2445 const node = try arena.create(Node.InfixOp);2430 const node = try arena.create(Node.InfixOp);
2446 node.* = Node.InfixOp{2431 node.* = .{
2447 .op_token = period,2432 .op_token = period,
2448 .lhs = undefined, // set by caller2433 .lhs = undefined, // set by caller
2449 .op = Node.InfixOp.Op.Period,2434 .op = .Period,
2450 .rhs = identifier,2435 .rhs = identifier,
2451 };2436 };
2452 return &node.base;2437 return &node.base;
2453 }2438 }
2454 if (eatToken(it, .QuestionMark)) |question_mark| {2439 if (eatToken(it, .QuestionMark)) |question_mark| {
2455 break :blk OpAndToken{ .op = Op{ .UnwrapOptional = {} }, .token = question_mark };2440 break :blk .{ .op = .UnwrapOptional, .token = question_mark };
2456 }2441 }
2457 try tree.errors.push(AstError{2442 try tree.errors.push(.{
2458 .ExpectedSuffixOp = AstError.ExpectedSuffixOp{ .token = it.index },2443 .ExpectedSuffixOp = .{ .token = it.index },
2459 });2444 });
2460 return null;2445 return null;
2461 }2446 }
...@@ -2464,7 +2449,7 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2464,7 +2449,7 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2464 };2449 };
24652450
2466 const node = try arena.create(Node.SuffixOp);2451 const node = try arena.create(Node.SuffixOp);
2467 node.* = Node.SuffixOp{2452 node.* = .{
2468 .lhs = undefined, // set by caller2453 .lhs = undefined, // set by caller
2469 .op = op_and_token.op,2454 .op = op_and_token.op,
2470 .rtoken = op_and_token.token,2455 .rtoken = op_and_token.token,
...@@ -2491,22 +2476,22 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No...@@ -2491,22 +2476,22 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
2491 const lbracket = eatToken(it, .LBracket) orelse return null;2476 const lbracket = eatToken(it, .LBracket) orelse return null;
2492 const expr = try parseExpr(arena, it, tree);2477 const expr = try parseExpr(arena, it, tree);
2493 const sentinel = if (eatToken(it, .Colon)) |_|2478 const sentinel = if (eatToken(it, .Colon)) |_|
2494 try expectNode(arena, it, tree, parseExpr, AstError{2479 try expectNode(arena, it, tree, parseExpr, .{
2495 .ExpectedExpr = .{ .token = it.index },2480 .ExpectedExpr = .{ .token = it.index },
2496 })2481 })
2497 else2482 else
2498 null;2483 null;
2499 const rbracket = try expectToken(it, tree, .RBracket);2484 const rbracket = try expectToken(it, tree, .RBracket);
25002485
2501 const op = if (expr) |len_expr|2486 const op: Node.PrefixOp.Op = if (expr) |len_expr|
2502 Node.PrefixOp.Op{2487 .{
2503 .ArrayType = .{2488 .ArrayType = .{
2504 .len_expr = len_expr,2489 .len_expr = len_expr,
2505 .sentinel = sentinel,2490 .sentinel = sentinel,
2506 },2491 },
2507 }2492 }
2508 else2493 else
2509 Node.PrefixOp.Op{2494 .{
2510 .SliceType = Node.PrefixOp.PtrInfo{2495 .SliceType = Node.PrefixOp.PtrInfo{
2511 .allowzero_token = null,2496 .allowzero_token = null,
2512 .align_info = null,2497 .align_info = null,
...@@ -2517,7 +2502,7 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No...@@ -2517,7 +2502,7 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
2517 };2502 };
25182503
2519 const node = try arena.create(Node.PrefixOp);2504 const node = try arena.create(Node.PrefixOp);
2520 node.* = Node.PrefixOp{2505 node.* = .{
2521 .op_token = lbracket,2506 .op_token = lbracket,
2522 .op = op,2507 .op = op,
2523 .rhs = undefined, // set by caller2508 .rhs = undefined, // set by caller
...@@ -2533,7 +2518,7 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No...@@ -2533,7 +2518,7 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
2533fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2518fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2534 if (eatToken(it, .Asterisk)) |asterisk| {2519 if (eatToken(it, .Asterisk)) |asterisk| {
2535 const sentinel = if (eatToken(it, .Colon)) |_|2520 const sentinel = if (eatToken(it, .Colon)) |_|
2536 try expectNode(arena, it, tree, parseExpr, AstError{2521 try expectNode(arena, it, tree, parseExpr, .{
2537 .ExpectedExpr = .{ .token = it.index },2522 .ExpectedExpr = .{ .token = it.index },
2538 })2523 })
2539 else2524 else
...@@ -2549,17 +2534,17 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -2549,17 +2534,17 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
25492534
2550 if (eatToken(it, .AsteriskAsterisk)) |double_asterisk| {2535 if (eatToken(it, .AsteriskAsterisk)) |double_asterisk| {
2551 const node = try arena.create(Node.PrefixOp);2536 const node = try arena.create(Node.PrefixOp);
2552 node.* = Node.PrefixOp{2537 node.* = .{
2553 .op_token = double_asterisk,2538 .op_token = double_asterisk,
2554 .op = Node.PrefixOp.Op{ .PtrType = .{} },2539 .op = .{ .PtrType = .{} },
2555 .rhs = undefined, // set by caller2540 .rhs = undefined, // set by caller
2556 };2541 };
25572542
2558 // Special case for **, which is its own token2543 // Special case for **, which is its own token
2559 const child = try arena.create(Node.PrefixOp);2544 const child = try arena.create(Node.PrefixOp);
2560 child.* = Node.PrefixOp{2545 child.* = .{
2561 .op_token = double_asterisk,2546 .op_token = double_asterisk,
2562 .op = Node.PrefixOp.Op{ .PtrType = .{} },2547 .op = .{ .PtrType = .{} },
2563 .rhs = undefined, // set by caller2548 .rhs = undefined, // set by caller
2564 };2549 };
2565 node.rhs = &child.base;2550 node.rhs = &child.base;
...@@ -2586,7 +2571,7 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -2586,7 +2571,7 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
2586 }2571 }
2587 }2572 }
2588 const sentinel = if (eatToken(it, .Colon)) |_|2573 const sentinel = if (eatToken(it, .Colon)) |_|
2589 try expectNode(arena, it, tree, parseExpr, AstError{2574 try expectNode(arena, it, tree, parseExpr, .{
2590 .ExpectedExpr = .{ .token = it.index },2575 .ExpectedExpr = .{ .token = it.index },
2591 })2576 })
2592 else2577 else
...@@ -2629,8 +2614,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?...@@ -2629,8 +2614,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?
2629 .Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} },2614 .Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} },
2630 .Keyword_enum => blk: {2615 .Keyword_enum => blk: {
2631 if (eatToken(it, .LParen) != null) {2616 if (eatToken(it, .LParen) != null) {
2632 const expr = try expectNode(arena, it, tree, parseExpr, AstError{2617 const expr = try expectNode(arena, it, tree, parseExpr, .{
2633 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },2618 .ExpectedExpr = .{ .token = it.index },
2634 });2619 });
2635 _ = try expectToken(it, tree, .RParen);2620 _ = try expectToken(it, tree, .RParen);
2636 break :blk Node.ContainerDecl.InitArg{ .Type = expr };2621 break :blk Node.ContainerDecl.InitArg{ .Type = expr };
...@@ -2641,8 +2626,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?...@@ -2641,8 +2626,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?
2641 if (eatToken(it, .LParen) != null) {2626 if (eatToken(it, .LParen) != null) {
2642 if (eatToken(it, .Keyword_enum) != null) {2627 if (eatToken(it, .Keyword_enum) != null) {
2643 if (eatToken(it, .LParen) != null) {2628 if (eatToken(it, .LParen) != null) {
2644 const expr = try expectNode(arena, it, tree, parseExpr, AstError{2629 const expr = try expectNode(arena, it, tree, parseExpr, .{
2645 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },2630 .ExpectedExpr = .{ .token = it.index },
2646 });2631 });
2647 _ = try expectToken(it, tree, .RParen);2632 _ = try expectToken(it, tree, .RParen);
2648 _ = try expectToken(it, tree, .RParen);2633 _ = try expectToken(it, tree, .RParen);
...@@ -2651,8 +2636,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?...@@ -2651,8 +2636,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?
2651 _ = try expectToken(it, tree, .RParen);2636 _ = try expectToken(it, tree, .RParen);
2652 break :blk Node.ContainerDecl.InitArg{ .Enum = null };2637 break :blk Node.ContainerDecl.InitArg{ .Enum = null };
2653 }2638 }
2654 const expr = try expectNode(arena, it, tree, parseExpr, AstError{2639 const expr = try expectNode(arena, it, tree, parseExpr, .{
2655 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },2640 .ExpectedExpr = .{ .token = it.index },
2656 });2641 });
2657 _ = try expectToken(it, tree, .RParen);2642 _ = try expectToken(it, tree, .RParen);
2658 break :blk Node.ContainerDecl.InitArg{ .Type = expr };2643 break :blk Node.ContainerDecl.InitArg{ .Type = expr };
...@@ -2666,7 +2651,7 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?...@@ -2666,7 +2651,7 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?
2666 };2651 };
26672652
2668 const node = try arena.create(Node.ContainerDecl);2653 const node = try arena.create(Node.ContainerDecl);
2669 node.* = Node.ContainerDecl{2654 node.* = .{
2670 .layout_token = null,2655 .layout_token = null,
2671 .kind_token = kind_token.index,2656 .kind_token = kind_token.index,
2672 .init_arg_expr = init_arg_expr,2657 .init_arg_expr = init_arg_expr,
...@@ -2681,8 +2666,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?...@@ -2681,8 +2666,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?
2681fn parseByteAlign(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2666fn parseByteAlign(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2682 _ = eatToken(it, .Keyword_align) orelse return null;2667 _ = eatToken(it, .Keyword_align) orelse return null;
2683 _ = try expectToken(it, tree, .LParen);2668 _ = try expectToken(it, tree, .LParen);
2684 const expr = try expectNode(arena, it, tree, parseExpr, AstError{2669 const expr = try expectNode(arena, it, tree, parseExpr, .{
2685 .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },2670 .ExpectedExpr = .{ .token = it.index },
2686 });2671 });
2687 _ = try expectToken(it, tree, .RParen);2672 _ = try expectToken(it, tree, .RParen);
2688 return expr;2673 return expr;
...@@ -2738,7 +2723,7 @@ fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) No...@@ -2738,7 +2723,7 @@ fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) No
2738 pub fn parse(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {2723 pub fn parse(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node {
2739 const op_token = eatToken(it, token) orelse return null;2724 const op_token = eatToken(it, token) orelse return null;
2740 const node = try arena.create(Node.InfixOp);2725 const node = try arena.create(Node.InfixOp);
2741 node.* = Node.InfixOp{2726 node.* = .{
2742 .op_token = op_token,2727 .op_token = op_token,
2743 .lhs = undefined, // set by caller2728 .lhs = undefined, // set by caller
2744 .op = op,2729 .op = op,
...@@ -2754,13 +2739,13 @@ fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) No...@@ -2754,13 +2739,13 @@ fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) No
2754fn parseBuiltinCall(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2739fn parseBuiltinCall(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2755 const token = eatToken(it, .Builtin) orelse return null;2740 const token = eatToken(it, .Builtin) orelse return null;
2756 const params = (try parseFnCallArguments(arena, it, tree)) orelse {2741 const params = (try parseFnCallArguments(arena, it, tree)) orelse {
2757 try tree.errors.push(AstError{2742 try tree.errors.push(.{
2758 .ExpectedParamList = AstError.ExpectedParamList{ .token = it.index },2743 .ExpectedParamList = .{ .token = it.index },
2759 });2744 });
2760 return error.ParseError;2745 return error.ParseError;
2761 };2746 };
2762 const node = try arena.create(Node.BuiltinCall);2747 const node = try arena.create(Node.BuiltinCall);
2763 node.* = Node.BuiltinCall{2748 node.* = .{
2764 .builtin_token = token,2749 .builtin_token = token,
2765 .params = params.list,2750 .params = params.list,
2766 .rparen_token = params.rparen,2751 .rparen_token = params.rparen,
...@@ -2773,7 +2758,7 @@ fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2773,7 +2758,7 @@ fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2773 const token = eatToken(it, .Identifier) orelse return null;2758 const token = eatToken(it, .Identifier) orelse return null;
27742759
2775 const node = try arena.create(Node.ErrorTag);2760 const node = try arena.create(Node.ErrorTag);
2776 node.* = Node.ErrorTag{2761 node.* = .{
2777 .doc_comments = doc_comments,2762 .doc_comments = doc_comments,
2778 .name_token = token,2763 .name_token = token,
2779 };2764 };
...@@ -2783,7 +2768,7 @@ fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2783,7 +2768,7 @@ fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2783fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2768fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2784 const token = eatToken(it, .Identifier) orelse return null;2769 const token = eatToken(it, .Identifier) orelse return null;
2785 const node = try arena.create(Node.Identifier);2770 const node = try arena.create(Node.Identifier);
2786 node.* = Node.Identifier{2771 node.* = .{
2787 .token = token,2772 .token = token,
2788 };2773 };
2789 return &node.base;2774 return &node.base;
...@@ -2792,7 +2777,7 @@ fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2792,7 +2777,7 @@ fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2792fn parseVarType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2777fn parseVarType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2793 const token = eatToken(it, .Keyword_var) orelse return null;2778 const token = eatToken(it, .Keyword_var) orelse return null;
2794 const node = try arena.create(Node.VarType);2779 const node = try arena.create(Node.VarType);
2795 node.* = Node.VarType{2780 node.* = .{
2796 .token = token,2781 .token = token,
2797 };2782 };
2798 return &node.base;2783 return &node.base;
...@@ -2810,7 +2795,7 @@ fn createLiteral(arena: *Allocator, comptime T: type, token: TokenIndex) !*Node...@@ -2810,7 +2795,7 @@ fn createLiteral(arena: *Allocator, comptime T: type, token: TokenIndex) !*Node
2810fn parseStringLiteralSingle(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2795fn parseStringLiteralSingle(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2811 if (eatToken(it, .StringLiteral)) |token| {2796 if (eatToken(it, .StringLiteral)) |token| {
2812 const node = try arena.create(Node.StringLiteral);2797 const node = try arena.create(Node.StringLiteral);
2813 node.* = Node.StringLiteral{2798 node.* = .{
2814 .token = token,2799 .token = token,
2815 };2800 };
2816 return &node.base;2801 return &node.base;
...@@ -2824,7 +2809,7 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod...@@ -2824,7 +2809,7 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod
28242809
2825 if (eatToken(it, .MultilineStringLiteralLine)) |first_line| {2810 if (eatToken(it, .MultilineStringLiteralLine)) |first_line| {
2826 const node = try arena.create(Node.MultilineStringLiteral);2811 const node = try arena.create(Node.MultilineStringLiteral);
2827 node.* = Node.MultilineStringLiteral{2812 node.* = .{
2828 .lines = Node.MultilineStringLiteral.LineList.init(arena),2813 .lines = Node.MultilineStringLiteral.LineList.init(arena),
2829 };2814 };
2830 try node.lines.push(first_line);2815 try node.lines.push(first_line);
...@@ -2840,7 +2825,7 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod...@@ -2840,7 +2825,7 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod
2840fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2825fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2841 const token = eatToken(it, .IntegerLiteral) orelse return null;2826 const token = eatToken(it, .IntegerLiteral) orelse return null;
2842 const node = try arena.create(Node.IntegerLiteral);2827 const node = try arena.create(Node.IntegerLiteral);
2843 node.* = Node.IntegerLiteral{2828 node.* = .{
2844 .token = token,2829 .token = token,
2845 };2830 };
2846 return &node.base;2831 return &node.base;
...@@ -2849,7 +2834,7 @@ fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No...@@ -2849,7 +2834,7 @@ fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No
2849fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2834fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2850 const token = eatToken(it, .FloatLiteral) orelse return null;2835 const token = eatToken(it, .FloatLiteral) orelse return null;
2851 const node = try arena.create(Node.FloatLiteral);2836 const node = try arena.create(Node.FloatLiteral);
2852 node.* = Node.FloatLiteral{2837 node.* = .{
2853 .token = token,2838 .token = token,
2854 };2839 };
2855 return &node.base;2840 return &node.base;
...@@ -2858,9 +2843,9 @@ fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node...@@ -2858,9 +2843,9 @@ fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node
2858fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2843fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2859 const token = eatToken(it, .Keyword_try) orelse return null;2844 const token = eatToken(it, .Keyword_try) orelse return null;
2860 const node = try arena.create(Node.PrefixOp);2845 const node = try arena.create(Node.PrefixOp);
2861 node.* = Node.PrefixOp{2846 node.* = .{
2862 .op_token = token,2847 .op_token = token,
2863 .op = Node.PrefixOp.Op.Try,2848 .op = .Try,
2864 .rhs = undefined, // set by caller2849 .rhs = undefined, // set by caller
2865 };2850 };
2866 return &node.base;2851 return &node.base;
...@@ -2869,7 +2854,7 @@ fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {...@@ -2869,7 +2854,7 @@ fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2869fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {2854fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
2870 const token = eatToken(it, .Keyword_usingnamespace) orelse return null;2855 const token = eatToken(it, .Keyword_usingnamespace) orelse return null;
2871 const node = try arena.create(Node.Use);2856 const node = try arena.create(Node.Use);
2872 node.* = Node.Use{2857 node.* = .{
2873 .doc_comments = null,2858 .doc_comments = null,
2874 .visib_token = null,2859 .visib_token = null,
2875 .use_token = token,2860 .use_token = token,
...@@ -2884,17 +2869,17 @@ fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: Node...@@ -2884,17 +2869,17 @@ fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: Node
2884 const node = (try parseIfPrefix(arena, it, tree)) orelse return null;2869 const node = (try parseIfPrefix(arena, it, tree)) orelse return null;
2885 const if_prefix = node.cast(Node.If).?;2870 const if_prefix = node.cast(Node.If).?;
28862871
2887 if_prefix.body = try expectNode(arena, it, tree, bodyParseFn, AstError{2872 if_prefix.body = try expectNode(arena, it, tree, bodyParseFn, .{
2888 .InvalidToken = AstError.InvalidToken{ .token = it.index },2873 .InvalidToken = .{ .token = it.index },
2889 });2874 });
28902875
2891 const else_token = eatToken(it, .Keyword_else) orelse return node;2876 const else_token = eatToken(it, .Keyword_else) orelse return node;
2892 const payload = try parsePayload(arena, it, tree);2877 const payload = try parsePayload(arena, it, tree);
2893 const else_expr = try expectNode(arena, it, tree, bodyParseFn, AstError{2878 const else_expr = try expectNode(arena, it, tree, bodyParseFn, .{
2894 .InvalidToken = AstError.InvalidToken{ .token = it.index },2879 .InvalidToken = .{ .token = it.index },
2895 });2880 });
2896 const else_node = try arena.create(Node.Else);2881 const else_node = try arena.create(Node.Else);
2897 else_node.* = Node.Else{2882 else_node.* = .{
2898 .else_token = else_token,2883 .else_token = else_token,
2899 .payload = payload,2884 .payload = payload,
2900 .body = else_expr,2885 .body = else_expr,
...@@ -2914,7 +2899,7 @@ fn parseDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.D...@@ -2914,7 +2899,7 @@ fn parseDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.D
2914 if (lines.len == 0) return null;2899 if (lines.len == 0) return null;
29152900
2916 const node = try arena.create(Node.DocComment);2901 const node = try arena.create(Node.DocComment);
2917 node.* = Node.DocComment{2902 node.* = .{
2918 .lines = lines,2903 .lines = lines,
2919 };2904 };
2920 return node;2905 return node;
...@@ -2925,7 +2910,7 @@ fn parseAppendedDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree, a...@@ -2925,7 +2910,7 @@ fn parseAppendedDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree, a
2925 const comment_token = eatToken(it, .DocComment) orelse return null;2910 const comment_token = eatToken(it, .DocComment) orelse return null;
2926 if (tree.tokensOnSameLine(after_token, comment_token)) {2911 if (tree.tokensOnSameLine(after_token, comment_token)) {
2927 const node = try arena.create(Node.DocComment);2912 const node = try arena.create(Node.DocComment);
2928 node.* = Node.DocComment{2913 node.* = .{
2929 .lines = Node.DocComment.LineList.init(arena),2914 .lines = Node.DocComment.LineList.init(arena),
2930 };2915 };
2931 try node.lines.push(comment_token);2916 try node.lines.push(comment_token);
...@@ -2974,14 +2959,14 @@ fn parsePrefixOpExpr(...@@ -2974,14 +2959,14 @@ fn parsePrefixOpExpr(
2974 switch (rightmost_op.id) {2959 switch (rightmost_op.id) {
2975 .PrefixOp => {2960 .PrefixOp => {
2976 const prefix_op = rightmost_op.cast(Node.PrefixOp).?;2961 const prefix_op = rightmost_op.cast(Node.PrefixOp).?;
2977 prefix_op.rhs = try expectNode(arena, it, tree, childParseFn, AstError{2962 prefix_op.rhs = try expectNode(arena, it, tree, childParseFn, .{
2978 .InvalidToken = AstError.InvalidToken{ .token = it.index },2963 .InvalidToken = .{ .token = it.index },
2979 });2964 });
2980 },2965 },
2981 .AnyFrameType => {2966 .AnyFrameType => {
2982 const prom = rightmost_op.cast(Node.AnyFrameType).?;2967 const prom = rightmost_op.cast(Node.AnyFrameType).?;
2983 prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, AstError{2968 prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, .{
2984 .InvalidToken = AstError.InvalidToken{ .token = it.index },2969 .InvalidToken = .{ .token = it.index },
2985 });2970 });
2986 },2971 },
2987 else => unreachable,2972 else => unreachable,
...@@ -3010,8 +2995,8 @@ fn parseBinOpExpr(...@@ -3010,8 +2995,8 @@ fn parseBinOpExpr(
3010 var res = (try childParseFn(arena, it, tree)) orelse return null;2995 var res = (try childParseFn(arena, it, tree)) orelse return null;
30112996
3012 while (try opParseFn(arena, it, tree)) |node| {2997 while (try opParseFn(arena, it, tree)) |node| {
3013 const right = try expectNode(arena, it, tree, childParseFn, AstError{2998 const right = try expectNode(arena, it, tree, childParseFn, .{
3014 .InvalidToken = AstError.InvalidToken{ .token = it.index },2999 .InvalidToken = .{ .token = it.index },
3015 });3000 });
3016 const left = res;3001 const left = res;
3017 res = node;3002 res = node;
...@@ -3031,7 +3016,7 @@ fn parseBinOpExpr(...@@ -3031,7 +3016,7 @@ fn parseBinOpExpr(
30313016
3032fn createInfixOp(arena: *Allocator, index: TokenIndex, op: Node.InfixOp.Op) !*Node {3017fn createInfixOp(arena: *Allocator, index: TokenIndex, op: Node.InfixOp.Op) !*Node {
3033 const node = try arena.create(Node.InfixOp);3018 const node = try arena.create(Node.InfixOp);
3034 node.* = Node.InfixOp{3019 node.* = .{
3035 .op_token = index,3020 .op_token = index,
3036 .lhs = undefined, // set by caller3021 .lhs = undefined, // set by caller
3037 .op = op,3022 .op = op,
...@@ -3051,8 +3036,8 @@ fn eatAnnotatedToken(it: *TokenIterator, id: Token.Id) ?AnnotatedToken {...@@ -3051,8 +3036,8 @@ fn eatAnnotatedToken(it: *TokenIterator, id: Token.Id) ?AnnotatedToken {
3051fn expectToken(it: *TokenIterator, tree: *Tree, id: Token.Id) Error!TokenIndex {3036fn expectToken(it: *TokenIterator, tree: *Tree, id: Token.Id) Error!TokenIndex {
3052 const token = nextToken(it);3037 const token = nextToken(it);
3053 if (token.ptr.id != id) {3038 if (token.ptr.id != id) {
3054 try tree.errors.push(AstError{3039 try tree.errors.push(.{
3055 .ExpectedToken = AstError.ExpectedToken{ .token = token.index, .expected_id = id },3040 .ExpectedToken = .{ .token = token.index, .expected_id = id },
3056 });3041 });
3057 return error.ParseError;3042 return error.ParseError;
3058 }3043 }
lib/std/zig/parser_test.zig+2
...@@ -1509,6 +1509,8 @@ test "zig fmt: error set declaration" {...@@ -1509,6 +1509,8 @@ test "zig fmt: error set declaration" {
1509 \\const Error = error{OutOfMemory};1509 \\const Error = error{OutOfMemory};
1510 \\const Error = error{};1510 \\const Error = error{};
1511 \\1511 \\
1512 \\const Error = error{ OutOfMemory, OutOfTime };
1513 \\
1512 );1514 );
1513}1515}
15141516
lib/std/zig/render.zig+41-18
...@@ -583,7 +583,6 @@ fn renderExpression(...@@ -583,7 +583,6 @@ fn renderExpression(
583 },583 },
584584
585 .Try,585 .Try,
586 .Cancel,
587 .Resume,586 .Resume,
588 => {587 => {
589 try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space);588 try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space);
...@@ -1269,25 +1268,51 @@ fn renderExpression(...@@ -1269,25 +1268,51 @@ fn renderExpression(
1269 }1268 }
12701269
1271 try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None); // error1270 try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None); // error
1272 try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // {
1273 const new_indent = indent + indent_delta;
12741271
1275 var it = err_set_decl.decls.iterator(0);1272 const src_has_trailing_comma = blk: {
1276 while (it.next()) |node| {1273 const maybe_comma = tree.prevToken(err_set_decl.rbrace_token);
1277 try stream.writeByteNTimes(' ', new_indent);1274 break :blk tree.tokens.at(maybe_comma).id == .Comma;
1275 };
12781276
1279 if (it.peek()) |next_node| {1277 if (src_has_trailing_comma) {
1280 try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.None);1278 try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // {
1281 try renderToken(tree, stream, tree.nextToken(node.*.lastToken()), new_indent, start_col, Space.Newline); // ,1279 const new_indent = indent + indent_delta;
12821280
1283 try renderExtraNewline(tree, stream, start_col, next_node.*);1281 var it = err_set_decl.decls.iterator(0);
1284 } else {1282 while (it.next()) |node| {
1285 try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.Comma);1283 try stream.writeByteNTimes(' ', new_indent);
1284
1285 if (it.peek()) |next_node| {
1286 try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.None);
1287 try renderToken(tree, stream, tree.nextToken(node.*.lastToken()), new_indent, start_col, Space.Newline); // ,
1288
1289 try renderExtraNewline(tree, stream, start_col, next_node.*);
1290 } else {
1291 try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.Comma);
1292 }
1286 }1293 }
1287 }
12881294
1289 try stream.writeByteNTimes(' ', indent);1295 try stream.writeByteNTimes(' ', indent);
1290 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // }1296 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // }
1297 } else {
1298 try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); // {
1299
1300 var it = err_set_decl.decls.iterator(0);
1301 while (it.next()) |node| {
1302 if (it.peek()) |next_node| {
1303 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None);
1304
1305 const comma_token = tree.nextToken(node.*.lastToken());
1306 assert(tree.tokens.at(comma_token).id == .Comma);
1307 try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // ,
1308 try renderExtraNewline(tree, stream, start_col, next_node.*);
1309 } else {
1310 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Space);
1311 }
1312 }
1313
1314 return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // }
1315 }
1291 },1316 },
12921317
1293 .ErrorTag => {1318 .ErrorTag => {
...@@ -1590,8 +1615,7 @@ fn renderExpression(...@@ -1590,8 +1615,7 @@ fn renderExpression(
1590 }1615 }
1591 } else {1616 } else {
1592 var it = switch_case.items.iterator(0);1617 var it = switch_case.items.iterator(0);
1593 while (true) {1618 while (it.next()) |node| {
1594 const node = it.next().?;
1595 if (it.peek()) |next_node| {1619 if (it.peek()) |next_node| {
1596 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None);1620 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None);
15971621
...@@ -1602,7 +1626,6 @@ fn renderExpression(...@@ -1602,7 +1626,6 @@ fn renderExpression(
1602 } else {1626 } else {
1603 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Comma);1627 try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Comma);
1604 try stream.writeByteNTimes(' ', indent);1628 try stream.writeByteNTimes(' ', indent);
1605 break;
1606 }1629 }
1607 }1630 }
1608 }1631 }
lib/std/zig/system.zig+1-1
...@@ -754,7 +754,7 @@ pub const NativeTargetInfo = struct {...@@ -754,7 +754,7 @@ pub const NativeTargetInfo = struct {
754 const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr));754 const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr));
755 var it = mem.tokenize(rpath_list, ":");755 var it = mem.tokenize(rpath_list, ":");
756 while (it.next()) |rpath| {756 while (it.next()) |rpath| {
757 var dir = fs.cwd().openDirList(rpath) catch |err| switch (err) {757 var dir = fs.cwd().openDir(rpath, .{}) catch |err| switch (err) {
758 error.NameTooLong => unreachable,758 error.NameTooLong => unreachable,
759 error.InvalidUtf8 => unreachable,759 error.InvalidUtf8 => unreachable,
760 error.BadPathName => unreachable,760 error.BadPathName => unreachable,
src-self-hosted/c_int.zig+4-4
...@@ -69,9 +69,9 @@ pub const CInt = struct {...@@ -69,9 +69,9 @@ pub const CInt = struct {
69 };69 };
7070
71 pub fn sizeInBits(cint: CInt, self: Target) u32 {71 pub fn sizeInBits(cint: CInt, self: Target) u32 {
72 const arch = self.getArch();72 const arch = self.cpu.arch;
73 switch (self.os.tag) {73 switch (self.os.tag) {
74 .freestanding, .other => switch (self.getArch()) {74 .freestanding, .other => switch (self.cpu.arch) {
75 .msp430 => switch (cint.id) {75 .msp430 => switch (cint.id) {
76 .Short,76 .Short,
77 .UShort,77 .UShort,
...@@ -94,7 +94,7 @@ pub const CInt = struct {...@@ -94,7 +94,7 @@ pub const CInt = struct {
94 => return 32,94 => return 32,
95 .Long,95 .Long,
96 .ULong,96 .ULong,
97 => return self.getArchPtrBitWidth(),97 => return self.cpu.arch.ptrBitWidth(),
98 .LongLong,98 .LongLong,
99 .ULongLong,99 .ULongLong,
100 => return 64,100 => return 64,
...@@ -114,7 +114,7 @@ pub const CInt = struct {...@@ -114,7 +114,7 @@ pub const CInt = struct {
114 => return 32,114 => return 32,
115 .Long,115 .Long,
116 .ULong,116 .ULong,
117 => return self.getArchPtrBitWidth(),117 => return self.cpu.arch.ptrBitWidth(),
118 .LongLong,118 .LongLong,
119 .ULongLong,119 .ULongLong,
120 => return 64,120 => return 64,
src-self-hosted/compilation.zig+17-13
...@@ -95,7 +95,7 @@ pub const ZigCompiler = struct {...@@ -95,7 +95,7 @@ pub const ZigCompiler = struct {
9595
96 pub fn getNativeLibC(self: *ZigCompiler) !*LibCInstallation {96 pub fn getNativeLibC(self: *ZigCompiler) !*LibCInstallation {
97 if (self.native_libc.start()) |ptr| return ptr;97 if (self.native_libc.start()) |ptr| return ptr;
98 try self.native_libc.data.findNative(self.allocator);98 self.native_libc.data = try LibCInstallation.findNative(.{ .allocator = self.allocator });
99 self.native_libc.resolve();99 self.native_libc.resolve();
100 return &self.native_libc.data;100 return &self.native_libc.data;
101 }101 }
...@@ -126,7 +126,7 @@ pub const Compilation = struct {...@@ -126,7 +126,7 @@ pub const Compilation = struct {
126 name: Buffer,126 name: Buffer,
127 llvm_triple: Buffer,127 llvm_triple: Buffer,
128 root_src_path: ?[]const u8,128 root_src_path: ?[]const u8,
129 target: Target,129 target: std.Target,
130 llvm_target: *llvm.Target,130 llvm_target: *llvm.Target,
131 build_mode: builtin.Mode,131 build_mode: builtin.Mode,
132 zig_lib_dir: []const u8,132 zig_lib_dir: []const u8,
...@@ -338,7 +338,7 @@ pub const Compilation = struct {...@@ -338,7 +338,7 @@ pub const Compilation = struct {
338 zig_compiler: *ZigCompiler,338 zig_compiler: *ZigCompiler,
339 name: []const u8,339 name: []const u8,
340 root_src_path: ?[]const u8,340 root_src_path: ?[]const u8,
341 target: Target,341 target: std.zig.CrossTarget,
342 kind: Kind,342 kind: Kind,
343 build_mode: builtin.Mode,343 build_mode: builtin.Mode,
344 is_static: bool,344 is_static: bool,
...@@ -370,13 +370,18 @@ pub const Compilation = struct {...@@ -370,13 +370,18 @@ pub const Compilation = struct {
370 zig_compiler: *ZigCompiler,370 zig_compiler: *ZigCompiler,
371 name: []const u8,371 name: []const u8,
372 root_src_path: ?[]const u8,372 root_src_path: ?[]const u8,
373 target: Target,373 cross_target: std.zig.CrossTarget,
374 kind: Kind,374 kind: Kind,
375 build_mode: builtin.Mode,375 build_mode: builtin.Mode,
376 is_static: bool,376 is_static: bool,
377 zig_lib_dir: []const u8,377 zig_lib_dir: []const u8,
378 ) !void {378 ) !void {
379 const allocator = zig_compiler.allocator;379 const allocator = zig_compiler.allocator;
380
381 // TODO merge this line with stage2.zig crossTargetToTarget
382 const target_info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator, cross_target);
383 const target = target_info.target;
384
380 var comp = Compilation{385 var comp = Compilation{
381 .arena_allocator = std.heap.ArenaAllocator.init(allocator),386 .arena_allocator = std.heap.ArenaAllocator.init(allocator),
382 .zig_compiler = zig_compiler,387 .zig_compiler = zig_compiler,
...@@ -419,7 +424,7 @@ pub const Compilation = struct {...@@ -419,7 +424,7 @@ pub const Compilation = struct {
419 .target_machine = undefined,424 .target_machine = undefined,
420 .target_data_ref = undefined,425 .target_data_ref = undefined,
421 .target_layout_str = undefined,426 .target_layout_str = undefined,
422 .target_ptr_bits = target.getArchPtrBitWidth(),427 .target_ptr_bits = target.cpu.arch.ptrBitWidth(),
423428
424 .root_package = undefined,429 .root_package = undefined,
425 .std_package = undefined,430 .std_package = undefined,
...@@ -440,7 +445,7 @@ pub const Compilation = struct {...@@ -440,7 +445,7 @@ pub const Compilation = struct {
440 }445 }
441446
442 comp.name = try Buffer.init(comp.arena(), name);447 comp.name = try Buffer.init(comp.arena(), name);
443 comp.llvm_triple = try util.getTriple(comp.arena(), target);448 comp.llvm_triple = try util.getLLVMTriple(comp.arena(), target);
444 comp.llvm_target = try util.llvmTargetFromTriple(comp.llvm_triple);449 comp.llvm_target = try util.llvmTargetFromTriple(comp.llvm_triple);
445 comp.zig_std_dir = try fs.path.join(comp.arena(), &[_][]const u8{ zig_lib_dir, "std" });450 comp.zig_std_dir = try fs.path.join(comp.arena(), &[_][]const u8{ zig_lib_dir, "std" });
446451
...@@ -455,10 +460,8 @@ pub const Compilation = struct {...@@ -455,10 +460,8 @@ pub const Compilation = struct {
455 var target_specific_cpu_features: ?[*:0]u8 = null;460 var target_specific_cpu_features: ?[*:0]u8 = null;
456 defer llvm.DisposeMessage(target_specific_cpu_args);461 defer llvm.DisposeMessage(target_specific_cpu_args);
457 defer llvm.DisposeMessage(target_specific_cpu_features);462 defer llvm.DisposeMessage(target_specific_cpu_features);
458 if (target == Target.Native) {463
459 target_specific_cpu_args = llvm.GetHostCPUName() orelse return error.OutOfMemory;464 // TODO detect native CPU & features here
460 target_specific_cpu_features = llvm.GetNativeFeatures() orelse return error.OutOfMemory;
461 }
462465
463 comp.target_machine = llvm.CreateTargetMachine(466 comp.target_machine = llvm.CreateTargetMachine(
464 comp.llvm_target,467 comp.llvm_target,
...@@ -517,8 +520,7 @@ pub const Compilation = struct {...@@ -517,8 +520,7 @@ pub const Compilation = struct {
517520
518 if (comp.tmp_dir.getOrNull()) |tmp_dir_result|521 if (comp.tmp_dir.getOrNull()) |tmp_dir_result|
519 if (tmp_dir_result.*) |tmp_dir| {522 if (tmp_dir_result.*) |tmp_dir| {
520 // TODO evented I/O?523 fs.cwd().deleteTree(tmp_dir) catch {};
521 fs.deleteTree(tmp_dir) catch {};
522 } else |_| {};524 } else |_| {};
523 }525 }
524526
...@@ -1122,7 +1124,9 @@ pub const Compilation = struct {...@@ -1122,7 +1124,9 @@ pub const Compilation = struct {
1122 self.libc_link_lib = link_lib;1124 self.libc_link_lib = link_lib;
11231125
1124 // get a head start on looking for the native libc1126 // get a head start on looking for the native libc
1125 if (self.target == Target.Native and self.override_libc == null) {1127 // TODO this is missing a bunch of logic related to whether the target is native
1128 // and whether we can build libc
1129 if (self.override_libc == null) {
1126 try self.deinit_group.call(startFindingNativeLibC, .{self});1130 try self.deinit_group.call(startFindingNativeLibC, .{self});
1127 }1131 }
1128 }1132 }
src-self-hosted/errmsg.zig+4-7
...@@ -164,8 +164,7 @@ pub const Msg = struct {...@@ -164,8 +164,7 @@ pub const Msg = struct {
164 const realpath_copy = try mem.dupe(comp.gpa(), u8, tree_scope.root().realpath);164 const realpath_copy = try mem.dupe(comp.gpa(), u8, tree_scope.root().realpath);
165 errdefer comp.gpa().free(realpath_copy);165 errdefer comp.gpa().free(realpath_copy);
166166
167 var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;167 try parse_error.render(&tree_scope.tree.tokens, text_buf.outStream());
168 try parse_error.render(&tree_scope.tree.tokens, out_stream);
169168
170 const msg = try comp.gpa().create(Msg);169 const msg = try comp.gpa().create(Msg);
171 msg.* = Msg{170 msg.* = Msg{
...@@ -204,8 +203,7 @@ pub const Msg = struct {...@@ -204,8 +203,7 @@ pub const Msg = struct {
204 const realpath_copy = try mem.dupe(allocator, u8, realpath);203 const realpath_copy = try mem.dupe(allocator, u8, realpath);
205 errdefer allocator.free(realpath_copy);204 errdefer allocator.free(realpath_copy);
206205
207 var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;206 try parse_error.render(&tree.tokens, text_buf.outStream());
208 try parse_error.render(&tree.tokens, out_stream);
209207
210 const msg = try allocator.create(Msg);208 const msg = try allocator.create(Msg);
211 msg.* = Msg{209 msg.* = Msg{
...@@ -272,7 +270,7 @@ pub const Msg = struct {...@@ -272,7 +270,7 @@ pub const Msg = struct {
272 });270 });
273 try stream.writeByteNTimes(' ', start_loc.column);271 try stream.writeByteNTimes(' ', start_loc.column);
274 try stream.writeByteNTimes('~', last_token.end - first_token.start);272 try stream.writeByteNTimes('~', last_token.end - first_token.start);
275 try stream.write("\n");273 try stream.writeAll("\n");
276 }274 }
277275
278 pub fn printToFile(msg: *const Msg, file: fs.File, color: Color) !void {276 pub fn printToFile(msg: *const Msg, file: fs.File, color: Color) !void {
...@@ -281,7 +279,6 @@ pub const Msg = struct {...@@ -281,7 +279,6 @@ pub const Msg = struct {
281 .On => true,279 .On => true,
282 .Off => false,280 .Off => false,
283 };281 };
284 var stream = &file.outStream().stream;282 return msg.printToStream(file.outStream(), color_on);
285 return msg.printToStream(stream, color_on);
286 }283 }
287};284};
src-self-hosted/ir.zig+1-1
...@@ -1099,7 +1099,6 @@ pub const Builder = struct {...@@ -1099,7 +1099,6 @@ pub const Builder = struct {
1099 .Await => return error.Unimplemented,1099 .Await => return error.Unimplemented,
1100 .BitNot => return error.Unimplemented,1100 .BitNot => return error.Unimplemented,
1101 .BoolNot => return error.Unimplemented,1101 .BoolNot => return error.Unimplemented,
1102 .Cancel => return error.Unimplemented,
1103 .OptionalType => return error.Unimplemented,1102 .OptionalType => return error.Unimplemented,
1104 .Negation => return error.Unimplemented,1103 .Negation => return error.Unimplemented,
1105 .NegationWrap => return error.Unimplemented,1104 .NegationWrap => return error.Unimplemented,
...@@ -1188,6 +1187,7 @@ pub const Builder = struct {...@@ -1188,6 +1187,7 @@ pub const Builder = struct {
1188 .ParamDecl => return error.Unimplemented,1187 .ParamDecl => return error.Unimplemented,
1189 .FieldInitializer => return error.Unimplemented,1188 .FieldInitializer => return error.Unimplemented,
1190 .EnumLiteral => return error.Unimplemented,1189 .EnumLiteral => return error.Unimplemented,
1190 .Noasync => return error.Unimplemented,
1191 }1191 }
1192 }1192 }
11931193
src-self-hosted/libc_installation.zig+5-5
...@@ -280,7 +280,7 @@ pub const LibCInstallation = struct {...@@ -280,7 +280,7 @@ pub const LibCInstallation = struct {
280 // search in reverse order280 // search in reverse order
281 const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1);281 const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1);
282 const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " ");282 const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " ");
283 var search_dir = fs.cwd().openDirList(search_path) catch |err| switch (err) {283 var search_dir = fs.cwd().openDir(search_path, .{}) catch |err| switch (err) {
284 error.FileNotFound,284 error.FileNotFound,
285 error.NotDir,285 error.NotDir,
286 error.NoDevice,286 error.NoDevice,
...@@ -335,7 +335,7 @@ pub const LibCInstallation = struct {...@@ -335,7 +335,7 @@ pub const LibCInstallation = struct {
335 const stream = result_buf.outStream();335 const stream = result_buf.outStream();
336 try stream.print("{}\\Include\\{}\\ucrt", .{ search.path, search.version });336 try stream.print("{}\\Include\\{}\\ucrt", .{ search.path, search.version });
337337
338 var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) {338 var dir = fs.cwd().openDir(result_buf.toSliceConst(), .{}) catch |err| switch (err) {
339 error.FileNotFound,339 error.FileNotFound,
340 error.NotDir,340 error.NotDir,
341 error.NoDevice,341 error.NoDevice,
...@@ -382,7 +382,7 @@ pub const LibCInstallation = struct {...@@ -382,7 +382,7 @@ pub const LibCInstallation = struct {
382 const stream = result_buf.outStream();382 const stream = result_buf.outStream();
383 try stream.print("{}\\Lib\\{}\\ucrt\\{}", .{ search.path, search.version, arch_sub_dir });383 try stream.print("{}\\Lib\\{}\\ucrt\\{}", .{ search.path, search.version, arch_sub_dir });
384384
385 var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) {385 var dir = fs.cwd().openDir(result_buf.toSliceConst(), .{}) catch |err| switch (err) {
386 error.FileNotFound,386 error.FileNotFound,
387 error.NotDir,387 error.NotDir,
388 error.NoDevice,388 error.NoDevice,
...@@ -437,7 +437,7 @@ pub const LibCInstallation = struct {...@@ -437,7 +437,7 @@ pub const LibCInstallation = struct {
437 const stream = result_buf.outStream();437 const stream = result_buf.outStream();
438 try stream.print("{}\\Lib\\{}\\um\\{}", .{ search.path, search.version, arch_sub_dir });438 try stream.print("{}\\Lib\\{}\\um\\{}", .{ search.path, search.version, arch_sub_dir });
439439
440 var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) {440 var dir = fs.cwd().openDir(result_buf.toSliceConst(), .{}) catch |err| switch (err) {
441 error.FileNotFound,441 error.FileNotFound,
442 error.NotDir,442 error.NotDir,
443 error.NoDevice,443 error.NoDevice,
...@@ -475,7 +475,7 @@ pub const LibCInstallation = struct {...@@ -475,7 +475,7 @@ pub const LibCInstallation = struct {
475475
476 try result_buf.append("\\include");476 try result_buf.append("\\include");
477477
478 var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) {478 var dir = fs.cwd().openDir(result_buf.toSliceConst(), .{}) catch |err| switch (err) {
479 error.FileNotFound,479 error.FileNotFound,
480 error.NotDir,480 error.NotDir,
481 error.NoDevice,481 error.NoDevice,
src-self-hosted/link.zig+54-58
...@@ -56,12 +56,13 @@ pub fn link(comp: *Compilation) !void {...@@ -56,12 +56,13 @@ pub fn link(comp: *Compilation) !void {
56 if (comp.haveLibC()) {56 if (comp.haveLibC()) {
57 // TODO https://github.com/ziglang/zig/issues/319057 // TODO https://github.com/ziglang/zig/issues/3190
58 var libc = ctx.comp.override_libc orelse blk: {58 var libc = ctx.comp.override_libc orelse blk: {
59 switch (comp.target) {59 @panic("this code has bitrotted");
60 Target.Native => {60 //switch (comp.target) {
61 break :blk comp.zig_compiler.getNativeLibC() catch return error.LibCRequiredButNotProvidedOrFound;61 // Target.Native => {
62 },62 // break :blk comp.zig_compiler.getNativeLibC() catch return error.LibCRequiredButNotProvidedOrFound;
63 else => return error.LibCRequiredButNotProvidedOrFound,63 // },
64 }64 // else => return error.LibCRequiredButNotProvidedOrFound,
65 //}
65 };66 };
66 ctx.libc = libc;67 ctx.libc = libc;
67 }68 }
...@@ -155,11 +156,11 @@ fn constructLinkerArgsElf(ctx: *Context) !void {...@@ -155,11 +156,11 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
155 //bool shared = !g->is_static && is_lib;156 //bool shared = !g->is_static && is_lib;
156 //Buf *soname = nullptr;157 //Buf *soname = nullptr;
157 if (ctx.comp.is_static) {158 if (ctx.comp.is_static) {
158 if (util.isArmOrThumb(ctx.comp.target)) {159 //if (util.isArmOrThumb(ctx.comp.target)) {
159 try ctx.args.append("-Bstatic");160 // try ctx.args.append("-Bstatic");
160 } else {161 //} else {
161 try ctx.args.append("-static");162 // try ctx.args.append("-static");
162 }163 //}
163 }164 }
164 //} else if (shared) {165 //} else if (shared) {
165 // lj->args.append("-shared");166 // lj->args.append("-shared");
...@@ -176,29 +177,24 @@ fn constructLinkerArgsElf(ctx: *Context) !void {...@@ -176,29 +177,24 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
176177
177 if (ctx.link_in_crt) {178 if (ctx.link_in_crt) {
178 const crt1o = if (ctx.comp.is_static) "crt1.o" else "Scrt1.o";179 const crt1o = if (ctx.comp.is_static) "crt1.o" else "Scrt1.o";
179 const crtbegino = if (ctx.comp.is_static) "crtbeginT.o" else "crtbegin.o";180 try addPathJoin(ctx, ctx.libc.crt_dir.?, crt1o);
180 try addPathJoin(ctx, ctx.libc.lib_dir.?, crt1o);181 try addPathJoin(ctx, ctx.libc.crt_dir.?, "crti.o");
181 try addPathJoin(ctx, ctx.libc.lib_dir.?, "crti.o");
182 try addPathJoin(ctx, ctx.libc.static_lib_dir.?, crtbegino);
183 }182 }
184183
185 if (ctx.comp.haveLibC()) {184 if (ctx.comp.haveLibC()) {
186 try ctx.args.append("-L");185 try ctx.args.append("-L");
187 // TODO addNullByte should probably return [:0]u8186 // TODO addNullByte should probably return [:0]u8
188 try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.lib_dir.?)).ptr));187 try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.crt_dir.?)).ptr));
189188
190 try ctx.args.append("-L");189 //if (!ctx.comp.is_static) {
191 try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.static_lib_dir.?)).ptr));190 // const dl = blk: {
192191 // //if (ctx.libc.dynamic_linker_path) |dl| break :blk dl;
193 if (!ctx.comp.is_static) {192 // //if (util.getDynamicLinkerPath(ctx.comp.target)) |dl| break :blk dl;
194 const dl = blk: {193 // return error.LibCMissingDynamicLinker;
195 if (ctx.libc.dynamic_linker_path) |dl| break :blk dl;194 // };
196 if (util.getDynamicLinkerPath(ctx.comp.target)) |dl| break :blk dl;195 // try ctx.args.append("-dynamic-linker");
197 return error.LibCMissingDynamicLinker;196 // try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr));
198 };197 //}
199 try ctx.args.append("-dynamic-linker");
200 try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr));
201 }
202 }198 }
203199
204 //if (shared) {200 //if (shared) {
...@@ -265,13 +261,12 @@ fn constructLinkerArgsElf(ctx: *Context) !void {...@@ -265,13 +261,12 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
265261
266 // crt end262 // crt end
267 if (ctx.link_in_crt) {263 if (ctx.link_in_crt) {
268 try addPathJoin(ctx, ctx.libc.static_lib_dir.?, "crtend.o");264 try addPathJoin(ctx, ctx.libc.crt_dir.?, "crtn.o");
269 try addPathJoin(ctx, ctx.libc.lib_dir.?, "crtn.o");
270 }265 }
271266
272 if (ctx.comp.target != Target.Native) {267 //if (ctx.comp.target != Target.Native) {
273 try ctx.args.append("--allow-shlib-undefined");268 // try ctx.args.append("--allow-shlib-undefined");
274 }269 //}
275}270}
276271
277fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void {272fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void {
...@@ -287,7 +282,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {...@@ -287,7 +282,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
287 try ctx.args.append("-DEBUG");282 try ctx.args.append("-DEBUG");
288 }283 }
289284
290 switch (ctx.comp.target.getArch()) {285 switch (ctx.comp.target.cpu.arch) {
291 .i386 => try ctx.args.append("-MACHINE:X86"),286 .i386 => try ctx.args.append("-MACHINE:X86"),
292 .x86_64 => try ctx.args.append("-MACHINE:X64"),287 .x86_64 => try ctx.args.append("-MACHINE:X64"),
293 .aarch64 => try ctx.args.append("-MACHINE:ARM"),288 .aarch64 => try ctx.args.append("-MACHINE:ARM"),
...@@ -302,7 +297,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {...@@ -302,7 +297,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
302 if (ctx.comp.haveLibC()) {297 if (ctx.comp.haveLibC()) {
303 try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.msvc_lib_dir.?})).ptr));298 try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.msvc_lib_dir.?})).ptr));
304 try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.kernel32_lib_dir.?})).ptr));299 try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.kernel32_lib_dir.?})).ptr));
305 try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.lib_dir.?})).ptr));300 try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.crt_dir.?})).ptr));
306 }301 }
307302
308 if (ctx.link_in_crt) {303 if (ctx.link_in_crt) {
...@@ -417,7 +412,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {...@@ -417,7 +412,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
417 }412 }
418 },413 },
419 .IPhoneOS => {414 .IPhoneOS => {
420 if (ctx.comp.target.getArch() == .aarch64) {415 if (ctx.comp.target.cpu.arch == .aarch64) {
421 // iOS does not need any crt1 files for arm64416 // iOS does not need any crt1 files for arm64
422 } else if (platform.versionLessThan(3, 1)) {417 } else if (platform.versionLessThan(3, 1)) {
423 try ctx.args.append("-lcrt1.o");418 try ctx.args.append("-lcrt1.o");
...@@ -435,28 +430,29 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {...@@ -435,28 +430,29 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
435 }430 }
436 try addFnObjects(ctx);431 try addFnObjects(ctx);
437432
438 if (ctx.comp.target == Target.Native) {433 // TODO
439 for (ctx.comp.link_libs_list.toSliceConst()) |lib| {434 //if (ctx.comp.target == Target.Native) {
440 if (mem.eql(u8, lib.name, "c")) {435 // for (ctx.comp.link_libs_list.toSliceConst()) |lib| {
441 // on Darwin, libSystem has libc in it, but also you have to use it436 // if (mem.eql(u8, lib.name, "c")) {
442 // to make syscalls because the syscall numbers are not documented437 // // on Darwin, libSystem has libc in it, but also you have to use it
443 // and change between versions.438 // // to make syscalls because the syscall numbers are not documented
444 // so we always link against libSystem439 // // and change between versions.
445 try ctx.args.append("-lSystem");440 // // so we always link against libSystem
446 } else {441 // try ctx.args.append("-lSystem");
447 if (mem.indexOfScalar(u8, lib.name, '/') == null) {442 // } else {
448 const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", .{lib.name});443 // if (mem.indexOfScalar(u8, lib.name, '/') == null) {
449 try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr));444 // const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", .{lib.name});
450 } else {445 // try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr));
451 const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name);446 // } else {
452 try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr));447 // const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name);
453 }448 // try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr));
454 }449 // }
455 }450 // }
456 } else {451 // }
457 try ctx.args.append("-undefined");452 //} else {
458 try ctx.args.append("dynamic_lookup");453 // try ctx.args.append("-undefined");
459 }454 // try ctx.args.append("dynamic_lookup");
455 //}
460456
461 if (platform.kind == .MacOS) {457 if (platform.kind == .MacOS) {
462 if (platform.versionLessThan(10, 5)) {458 if (platform.versionLessThan(10, 5)) {
src-self-hosted/main.zig+56-47
...@@ -18,10 +18,6 @@ const Target = std.Target;...@@ -18,10 +18,6 @@ const Target = std.Target;
18const errmsg = @import("errmsg.zig");18const errmsg = @import("errmsg.zig");
19const LibCInstallation = @import("libc_installation.zig").LibCInstallation;19const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
2020
21var stderr_file: fs.File = undefined;
22var stderr: *io.OutStream(fs.File.WriteError) = undefined;
23var stdout: *io.OutStream(fs.File.WriteError) = undefined;
24
25pub const io_mode = .evented;21pub const io_mode = .evented;
2622
27pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB23pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB
...@@ -51,17 +47,14 @@ const Command = struct {...@@ -51,17 +47,14 @@ const Command = struct {
51pub fn main() !void {47pub fn main() !void {
52 const allocator = std.heap.c_allocator;48 const allocator = std.heap.c_allocator;
5349
54 stdout = &std.io.getStdOut().outStream().stream;50 const stderr = io.getStdErr().outStream();
55
56 stderr_file = std.io.getStdErr();
57 stderr = &stderr_file.outStream().stream;
5851
59 const args = try process.argsAlloc(allocator);52 const args = try process.argsAlloc(allocator);
60 defer process.argsFree(allocator, args);53 defer process.argsFree(allocator, args);
6154
62 if (args.len <= 1) {55 if (args.len <= 1) {
63 try stderr.write("expected command argument\n\n");56 try stderr.writeAll("expected command argument\n\n");
64 try stderr.write(usage);57 try stderr.writeAll(usage);
65 process.exit(1);58 process.exit(1);
66 }59 }
6760
...@@ -78,8 +71,8 @@ pub fn main() !void {...@@ -78,8 +71,8 @@ pub fn main() !void {
78 } else if (mem.eql(u8, cmd, "libc")) {71 } else if (mem.eql(u8, cmd, "libc")) {
79 return cmdLibC(allocator, cmd_args);72 return cmdLibC(allocator, cmd_args);
80 } else if (mem.eql(u8, cmd, "targets")) {73 } else if (mem.eql(u8, cmd, "targets")) {
81 const info = try std.zig.system.NativeTargetInfo.detect(allocator);74 const info = try std.zig.system.NativeTargetInfo.detect(allocator, .{});
82 defer info.deinit(allocator);75 const stdout = io.getStdOut().outStream();
83 return @import("print_targets.zig").cmdTargets(allocator, cmd_args, stdout, info.target);76 return @import("print_targets.zig").cmdTargets(allocator, cmd_args, stdout, info.target);
84 } else if (mem.eql(u8, cmd, "version")) {77 } else if (mem.eql(u8, cmd, "version")) {
85 return cmdVersion(allocator, cmd_args);78 return cmdVersion(allocator, cmd_args);
...@@ -91,7 +84,7 @@ pub fn main() !void {...@@ -91,7 +84,7 @@ pub fn main() !void {
91 return cmdInternal(allocator, cmd_args);84 return cmdInternal(allocator, cmd_args);
92 } else {85 } else {
93 try stderr.print("unknown command: {}\n\n", .{args[1]});86 try stderr.print("unknown command: {}\n\n", .{args[1]});
94 try stderr.write(usage);87 try stderr.writeAll(usage);
95 process.exit(1);88 process.exit(1);
96 }89 }
97}90}
...@@ -156,6 +149,8 @@ const usage_build_generic =...@@ -156,6 +149,8 @@ const usage_build_generic =
156;149;
157150
158fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Compilation.Kind) !void {151fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Compilation.Kind) !void {
152 const stderr = io.getStdErr().outStream();
153
159 var color: errmsg.Color = .Auto;154 var color: errmsg.Color = .Auto;
160 var build_mode: std.builtin.Mode = .Debug;155 var build_mode: std.builtin.Mode = .Debug;
161 var emit_bin = true;156 var emit_bin = true;
...@@ -208,11 +203,11 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -208,11 +203,11 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
208 const arg = args[i];203 const arg = args[i];
209 if (mem.startsWith(u8, arg, "-")) {204 if (mem.startsWith(u8, arg, "-")) {
210 if (mem.eql(u8, arg, "--help")) {205 if (mem.eql(u8, arg, "--help")) {
211 try stdout.write(usage_build_generic);206 try io.getStdOut().writeAll(usage_build_generic);
212 process.exit(0);207 process.exit(0);
213 } else if (mem.eql(u8, arg, "--color")) {208 } else if (mem.eql(u8, arg, "--color")) {
214 if (i + 1 >= args.len) {209 if (i + 1 >= args.len) {
215 try stderr.write("expected [auto|on|off] after --color\n");210 try stderr.writeAll("expected [auto|on|off] after --color\n");
216 process.exit(1);211 process.exit(1);
217 }212 }
218 i += 1;213 i += 1;
...@@ -229,7 +224,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -229,7 +224,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
229 }224 }
230 } else if (mem.eql(u8, arg, "--mode")) {225 } else if (mem.eql(u8, arg, "--mode")) {
231 if (i + 1 >= args.len) {226 if (i + 1 >= args.len) {
232 try stderr.write("expected [Debug|ReleaseSafe|ReleaseFast|ReleaseSmall] after --mode\n");227 try stderr.writeAll("expected [Debug|ReleaseSafe|ReleaseFast|ReleaseSmall] after --mode\n");
233 process.exit(1);228 process.exit(1);
234 }229 }
235 i += 1;230 i += 1;
...@@ -248,49 +243,49 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -248,49 +243,49 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
248 }243 }
249 } else if (mem.eql(u8, arg, "--name")) {244 } else if (mem.eql(u8, arg, "--name")) {
250 if (i + 1 >= args.len) {245 if (i + 1 >= args.len) {
251 try stderr.write("expected parameter after --name\n");246 try stderr.writeAll("expected parameter after --name\n");
252 process.exit(1);247 process.exit(1);
253 }248 }
254 i += 1;249 i += 1;
255 provided_name = args[i];250 provided_name = args[i];
256 } else if (mem.eql(u8, arg, "--ver-major")) {251 } else if (mem.eql(u8, arg, "--ver-major")) {
257 if (i + 1 >= args.len) {252 if (i + 1 >= args.len) {
258 try stderr.write("expected parameter after --ver-major\n");253 try stderr.writeAll("expected parameter after --ver-major\n");
259 process.exit(1);254 process.exit(1);
260 }255 }
261 i += 1;256 i += 1;
262 version.major = try std.fmt.parseInt(u32, args[i], 10);257 version.major = try std.fmt.parseInt(u32, args[i], 10);
263 } else if (mem.eql(u8, arg, "--ver-minor")) {258 } else if (mem.eql(u8, arg, "--ver-minor")) {
264 if (i + 1 >= args.len) {259 if (i + 1 >= args.len) {
265 try stderr.write("expected parameter after --ver-minor\n");260 try stderr.writeAll("expected parameter after --ver-minor\n");
266 process.exit(1);261 process.exit(1);
267 }262 }
268 i += 1;263 i += 1;
269 version.minor = try std.fmt.parseInt(u32, args[i], 10);264 version.minor = try std.fmt.parseInt(u32, args[i], 10);
270 } else if (mem.eql(u8, arg, "--ver-patch")) {265 } else if (mem.eql(u8, arg, "--ver-patch")) {
271 if (i + 1 >= args.len) {266 if (i + 1 >= args.len) {
272 try stderr.write("expected parameter after --ver-patch\n");267 try stderr.writeAll("expected parameter after --ver-patch\n");
273 process.exit(1);268 process.exit(1);
274 }269 }
275 i += 1;270 i += 1;
276 version.patch = try std.fmt.parseInt(u32, args[i], 10);271 version.patch = try std.fmt.parseInt(u32, args[i], 10);
277 } else if (mem.eql(u8, arg, "--linker-script")) {272 } else if (mem.eql(u8, arg, "--linker-script")) {
278 if (i + 1 >= args.len) {273 if (i + 1 >= args.len) {
279 try stderr.write("expected parameter after --linker-script\n");274 try stderr.writeAll("expected parameter after --linker-script\n");
280 process.exit(1);275 process.exit(1);
281 }276 }
282 i += 1;277 i += 1;
283 linker_script = args[i];278 linker_script = args[i];
284 } else if (mem.eql(u8, arg, "--libc")) {279 } else if (mem.eql(u8, arg, "--libc")) {
285 if (i + 1 >= args.len) {280 if (i + 1 >= args.len) {
286 try stderr.write("expected parameter after --libc\n");281 try stderr.writeAll("expected parameter after --libc\n");
287 process.exit(1);282 process.exit(1);
288 }283 }
289 i += 1;284 i += 1;
290 libc_arg = args[i];285 libc_arg = args[i];
291 } else if (mem.eql(u8, arg, "-mllvm")) {286 } else if (mem.eql(u8, arg, "-mllvm")) {
292 if (i + 1 >= args.len) {287 if (i + 1 >= args.len) {
293 try stderr.write("expected parameter after -mllvm\n");288 try stderr.writeAll("expected parameter after -mllvm\n");
294 process.exit(1);289 process.exit(1);
295 }290 }
296 i += 1;291 i += 1;
...@@ -300,14 +295,14 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -300,14 +295,14 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
300 try mllvm_flags.append(args[i]);295 try mllvm_flags.append(args[i]);
301 } else if (mem.eql(u8, arg, "-mmacosx-version-min")) {296 } else if (mem.eql(u8, arg, "-mmacosx-version-min")) {
302 if (i + 1 >= args.len) {297 if (i + 1 >= args.len) {
303 try stderr.write("expected parameter after -mmacosx-version-min\n");298 try stderr.writeAll("expected parameter after -mmacosx-version-min\n");
304 process.exit(1);299 process.exit(1);
305 }300 }
306 i += 1;301 i += 1;
307 macosx_version_min = args[i];302 macosx_version_min = args[i];
308 } else if (mem.eql(u8, arg, "-mios-version-min")) {303 } else if (mem.eql(u8, arg, "-mios-version-min")) {
309 if (i + 1 >= args.len) {304 if (i + 1 >= args.len) {
310 try stderr.write("expected parameter after -mios-version-min\n");305 try stderr.writeAll("expected parameter after -mios-version-min\n");
311 process.exit(1);306 process.exit(1);
312 }307 }
313 i += 1;308 i += 1;
...@@ -348,7 +343,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -348,7 +343,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
348 linker_rdynamic = true;343 linker_rdynamic = true;
349 } else if (mem.eql(u8, arg, "--pkg-begin")) {344 } else if (mem.eql(u8, arg, "--pkg-begin")) {
350 if (i + 2 >= args.len) {345 if (i + 2 >= args.len) {
351 try stderr.write("expected [name] [path] after --pkg-begin\n");346 try stderr.writeAll("expected [name] [path] after --pkg-begin\n");
352 process.exit(1);347 process.exit(1);
353 }348 }
354 i += 1;349 i += 1;
...@@ -363,7 +358,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -363,7 +358,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
363 if (cur_pkg.parent) |parent| {358 if (cur_pkg.parent) |parent| {
364 cur_pkg = parent;359 cur_pkg = parent;
365 } else {360 } else {
366 try stderr.write("encountered --pkg-end with no matching --pkg-begin\n");361 try stderr.writeAll("encountered --pkg-end with no matching --pkg-begin\n");
367 process.exit(1);362 process.exit(1);
368 }363 }
369 } else if (mem.startsWith(u8, arg, "-l")) {364 } else if (mem.startsWith(u8, arg, "-l")) {
...@@ -411,18 +406,18 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -411,18 +406,18 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
411 var it = mem.separate(basename, ".");406 var it = mem.separate(basename, ".");
412 break :blk it.next() orelse basename;407 break :blk it.next() orelse basename;
413 } else {408 } else {
414 try stderr.write("--name [name] not provided and unable to infer\n");409 try stderr.writeAll("--name [name] not provided and unable to infer\n");
415 process.exit(1);410 process.exit(1);
416 }411 }
417 };412 };
418413
419 if (root_src_file == null and link_objects.len == 0 and assembly_files.len == 0) {414 if (root_src_file == null and link_objects.len == 0 and assembly_files.len == 0) {
420 try stderr.write("Expected source file argument or at least one --object or --assembly argument\n");415 try stderr.writeAll("Expected source file argument or at least one --object or --assembly argument\n");
421 process.exit(1);416 process.exit(1);
422 }417 }
423418
424 if (out_type == Compilation.Kind.Obj and link_objects.len != 0) {419 if (out_type == Compilation.Kind.Obj and link_objects.len != 0) {
425 try stderr.write("When building an object file, --object arguments are invalid\n");420 try stderr.writeAll("When building an object file, --object arguments are invalid\n");
426 process.exit(1);421 process.exit(1);
427 }422 }
428423
...@@ -440,7 +435,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -440,7 +435,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
440 &zig_compiler,435 &zig_compiler,
441 root_name,436 root_name,
442 root_src_file,437 root_src_file,
443 Target.Native,438 .{},
444 out_type,439 out_type,
445 build_mode,440 build_mode,
446 !is_dynamic,441 !is_dynamic,
...@@ -478,7 +473,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -478,7 +473,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
478 comp.linker_rdynamic = linker_rdynamic;473 comp.linker_rdynamic = linker_rdynamic;
479474
480 if (macosx_version_min != null and ios_version_min != null) {475 if (macosx_version_min != null and ios_version_min != null) {
481 try stderr.write("-mmacosx-version-min and -mios-version-min options not allowed together\n");476 try stderr.writeAll("-mmacosx-version-min and -mios-version-min options not allowed together\n");
482 process.exit(1);477 process.exit(1);
483 }478 }
484479
...@@ -501,6 +496,8 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -501,6 +496,8 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
501}496}
502497
503fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {498fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {
499 const stderr_file = io.getStdErr();
500 const stderr = stderr_file.outStream();
504 var count: usize = 0;501 var count: usize = 0;
505 while (!comp.cancelled) {502 while (!comp.cancelled) {
506 const build_event = comp.events.get();503 const build_event = comp.events.get();
...@@ -551,7 +548,8 @@ const Fmt = struct {...@@ -551,7 +548,8 @@ const Fmt = struct {
551};548};
552549
553fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_file: []const u8) void {550fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_file: []const u8) void {
554 libc.parse(allocator, libc_paths_file, stderr) catch |err| {551 const stderr = io.getStdErr().outStream();
552 libc.* = LibCInstallation.parse(allocator, libc_paths_file, stderr) catch |err| {
555 stderr.print("Unable to parse libc path file '{}': {}.\n" ++553 stderr.print("Unable to parse libc path file '{}': {}.\n" ++
556 "Try running `zig libc` to see an example for the native target.\n", .{554 "Try running `zig libc` to see an example for the native target.\n", .{
557 libc_paths_file,555 libc_paths_file,
...@@ -562,6 +560,7 @@ fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_fil...@@ -562,6 +560,7 @@ fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_fil
562}560}
563561
564fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {562fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {
563 const stderr = io.getStdErr().outStream();
565 switch (args.len) {564 switch (args.len) {
566 0 => {},565 0 => {},
567 1 => {566 1 => {
...@@ -582,10 +581,12 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {...@@ -582,10 +581,12 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {
582 stderr.print("unable to find libc: {}\n", .{@errorName(err)}) catch {};581 stderr.print("unable to find libc: {}\n", .{@errorName(err)}) catch {};
583 process.exit(1);582 process.exit(1);
584 };583 };
585 libc.render(stdout) catch process.exit(1);584 libc.render(io.getStdOut().outStream()) catch process.exit(1);
586}585}
587586
588fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {587fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
588 const stderr_file = io.getStdErr();
589 const stderr = stderr_file.outStream();
589 var color: errmsg.Color = .Auto;590 var color: errmsg.Color = .Auto;
590 var stdin_flag: bool = false;591 var stdin_flag: bool = false;
591 var check_flag: bool = false;592 var check_flag: bool = false;
...@@ -597,11 +598,12 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -597,11 +598,12 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
597 const arg = args[i];598 const arg = args[i];
598 if (mem.startsWith(u8, arg, "-")) {599 if (mem.startsWith(u8, arg, "-")) {
599 if (mem.eql(u8, arg, "--help")) {600 if (mem.eql(u8, arg, "--help")) {
600 try stdout.write(usage_fmt);601 const stdout = io.getStdOut().outStream();
602 try stdout.writeAll(usage_fmt);
601 process.exit(0);603 process.exit(0);
602 } else if (mem.eql(u8, arg, "--color")) {604 } else if (mem.eql(u8, arg, "--color")) {
603 if (i + 1 >= args.len) {605 if (i + 1 >= args.len) {
604 try stderr.write("expected [auto|on|off] after --color\n");606 try stderr.writeAll("expected [auto|on|off] after --color\n");
605 process.exit(1);607 process.exit(1);
606 }608 }
607 i += 1;609 i += 1;
...@@ -632,14 +634,13 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -632,14 +634,13 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
632634
633 if (stdin_flag) {635 if (stdin_flag) {
634 if (input_files.len != 0) {636 if (input_files.len != 0) {
635 try stderr.write("cannot use --stdin with positional arguments\n");637 try stderr.writeAll("cannot use --stdin with positional arguments\n");
636 process.exit(1);638 process.exit(1);
637 }639 }
638640
639 var stdin_file = io.getStdIn();641 const stdin = io.getStdIn().inStream();
640 var stdin = stdin_file.inStream();
641642
642 const source_code = try stdin.stream.readAllAlloc(allocator, max_src_size);643 const source_code = try stdin.readAllAlloc(allocator, max_src_size);
643 defer allocator.free(source_code);644 defer allocator.free(source_code);
644645
645 const tree = std.zig.parse(allocator, source_code) catch |err| {646 const tree = std.zig.parse(allocator, source_code) catch |err| {
...@@ -653,7 +654,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -653,7 +654,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
653 const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, tree, "<stdin>");654 const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, tree, "<stdin>");
654 defer msg.destroy();655 defer msg.destroy();
655656
656 try msg.printToFile(stderr_file, color);657 try msg.printToFile(io.getStdErr(), color);
657 }658 }
658 if (tree.errors.len != 0) {659 if (tree.errors.len != 0) {
659 process.exit(1);660 process.exit(1);
...@@ -664,12 +665,13 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -664,12 +665,13 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
664 process.exit(code);665 process.exit(code);
665 }666 }
666667
668 const stdout = io.getStdOut().outStream();
667 _ = try std.zig.render(allocator, stdout, tree);669 _ = try std.zig.render(allocator, stdout, tree);
668 return;670 return;
669 }671 }
670672
671 if (input_files.len == 0) {673 if (input_files.len == 0) {
672 try stderr.write("expected at least one source file argument\n");674 try stderr.writeAll("expected at least one source file argument\n");
673 process.exit(1);675 process.exit(1);
674 }676 }
675677
...@@ -713,6 +715,9 @@ const FmtError = error{...@@ -713,6 +715,9 @@ const FmtError = error{
713} || fs.File.OpenError;715} || fs.File.OpenError;
714716
715async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void {717async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void {
718 const stderr_file = io.getStdErr();
719 const stderr = stderr_file.outStream();
720
716 const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref);721 const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref);
717 defer fmt.allocator.free(file_path);722 defer fmt.allocator.free(file_path);
718723
...@@ -729,7 +734,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro...@@ -729,7 +734,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro
729 max_src_size,734 max_src_size,
730 ) catch |err| switch (err) {735 ) catch |err| switch (err) {
731 error.IsDir, error.AccessDenied => {736 error.IsDir, error.AccessDenied => {
732 var dir = try fs.cwd().openDirList(file_path);737 var dir = try fs.cwd().openDir(file_path, .{ .iterate = true });
733 defer dir.close();738 defer dir.close();
734739
735 var group = event.Group(FmtError!void).init(fmt.allocator);740 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...@@ -791,11 +796,13 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro
791}796}
792797
793fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void {798fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void {
799 const stdout = io.getStdOut().outStream();
794 try stdout.print("{}\n", .{c.ZIG_VERSION_STRING});800 try stdout.print("{}\n", .{c.ZIG_VERSION_STRING});
795}801}
796802
797fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void {803fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void {
798 try stdout.write(usage);804 const stdout = io.getStdOut();
805 try stdout.writeAll(usage);
799}806}
800807
801pub const info_zen =808pub const info_zen =
...@@ -816,7 +823,7 @@ pub const info_zen =...@@ -816,7 +823,7 @@ pub const info_zen =
816;823;
817824
818fn cmdZen(allocator: *Allocator, args: []const []const u8) !void {825fn cmdZen(allocator: *Allocator, args: []const []const u8) !void {
819 try stdout.write(info_zen);826 try io.getStdOut().writeAll(info_zen);
820}827}
821828
822const usage_internal =829const usage_internal =
...@@ -829,8 +836,9 @@ const usage_internal =...@@ -829,8 +836,9 @@ const usage_internal =
829;836;
830837
831fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void {838fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void {
839 const stderr = io.getStdErr().outStream();
832 if (args.len == 0) {840 if (args.len == 0) {
833 try stderr.write(usage_internal);841 try stderr.writeAll(usage_internal);
834 process.exit(1);842 process.exit(1);
835 }843 }
836844
...@@ -849,10 +857,11 @@ fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void {...@@ -849,10 +857,11 @@ fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void {
849 }857 }
850858
851 try stderr.print("unknown sub command: {}\n\n", .{args[0]});859 try stderr.print("unknown sub command: {}\n\n", .{args[0]});
852 try stderr.write(usage_internal);860 try stderr.writeAll(usage_internal);
853}861}
854862
855fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void {863fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void {
864 const stdout = io.getStdOut().outStream();
856 try stdout.print(865 try stdout.print(
857 \\ZIG_CMAKE_BINARY_DIR {}866 \\ZIG_CMAKE_BINARY_DIR {}
858 \\ZIG_CXX_COMPILER {}867 \\ZIG_CXX_COMPILER {}
src-self-hosted/print_targets.zig+1-1
...@@ -72,7 +72,7 @@ pub fn cmdTargets(...@@ -72,7 +72,7 @@ pub fn cmdTargets(
72 };72 };
73 defer allocator.free(zig_lib_dir);73 defer allocator.free(zig_lib_dir);
7474
75 var dir = try std.fs.cwd().openDirList(zig_lib_dir);75 var dir = try std.fs.cwd().openDir(zig_lib_dir, .{});
76 defer dir.close();76 defer dir.close();
7777
78 const vers_txt = try dir.readFileAlloc(allocator, "libc/glibc/vers.txt", 10 * 1024);78 const vers_txt = try dir.readFileAlloc(allocator, "libc/glibc/vers.txt", 10 * 1024);
src-self-hosted/stage2.zig+2-2
...@@ -128,7 +128,7 @@ export fn stage2_translate_c(...@@ -128,7 +128,7 @@ export fn stage2_translate_c(
128 args_end: [*]?[*]const u8,128 args_end: [*]?[*]const u8,
129 resources_path: [*:0]const u8,129 resources_path: [*:0]const u8,
130) Error {130) Error {
131 var errors = @as([*]translate_c.ClangErrMsg, undefined)[0..0];131 var errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{};
132 out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) {132 out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) {
133 error.SemanticAnalyzeFail => {133 error.SemanticAnalyzeFail => {
134 out_errors_ptr.* = errors.ptr;134 out_errors_ptr.* = errors.ptr;
...@@ -319,7 +319,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {...@@ -319,7 +319,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void {
319 const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) {319 const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) {
320 error.IsDir, error.AccessDenied => {320 error.IsDir, error.AccessDenied => {
321 // TODO make event based (and dir.next())321 // TODO make event based (and dir.next())
322 var dir = try fs.cwd().openDirList(file_path);322 var dir = try fs.cwd().openDir(file_path, .{ .iterate = true });
323 defer dir.close();323 defer dir.close();
324324
325 var dir_it = dir.iterate();325 var dir_it = dir.iterate();
src-self-hosted/test.zig+2-2
...@@ -57,11 +57,11 @@ pub const TestContext = struct {...@@ -57,11 +57,11 @@ pub const TestContext = struct {
57 errdefer allocator.free(self.zig_lib_dir);57 errdefer allocator.free(self.zig_lib_dir);
5858
59 try std.fs.cwd().makePath(tmp_dir_name);59 try std.fs.cwd().makePath(tmp_dir_name);
60 errdefer std.fs.deleteTree(tmp_dir_name) catch {};60 errdefer std.fs.cwd().deleteTree(tmp_dir_name) catch {};
61 }61 }
6262
63 fn deinit(self: *TestContext) void {63 fn deinit(self: *TestContext) void {
64 std.fs.deleteTree(tmp_dir_name) catch {};64 std.fs.cwd().deleteTree(tmp_dir_name) catch {};
65 allocator.free(self.zig_lib_dir);65 allocator.free(self.zig_lib_dir);
66 self.zig_compiler.deinit();66 self.zig_compiler.deinit();
67 }67 }
src-self-hosted/translate_c.zig+12-14
...@@ -1744,20 +1744,18 @@ fn writeEscapedString(buf: []u8, s: []const u8) void {...@@ -1744,20 +1744,18 @@ fn writeEscapedString(buf: []u8, s: []const u8) void {
1744// Returns either a string literal or a slice of `buf`.1744// Returns either a string literal or a slice of `buf`.
1745fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 {1745fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 {
1746 return switch (c) {1746 return switch (c) {
1747 '\"' => "\\\""[0..],1747 '\"' => "\\\"",
1748 '\'' => "\\'"[0..],1748 '\'' => "\\'",
1749 '\\' => "\\\\"[0..],1749 '\\' => "\\\\",
1750 '\n' => "\\n"[0..],1750 '\n' => "\\n",
1751 '\r' => "\\r"[0..],1751 '\r' => "\\r",
1752 '\t' => "\\t"[0..],1752 '\t' => "\\t",
1753 else => {1753 // Handle the remaining escapes Zig doesn't support by turning them
1754 // Handle the remaining escapes Zig doesn't support by turning them1754 // into their respective hex representation
1755 // into their respective hex representation1755 else => if (std.ascii.isCntrl(c))
1756 if (std.ascii.isCntrl(c))1756 std.fmt.bufPrint(char_buf, "\\x{x:0<2}", .{c}) catch unreachable
1757 return std.fmt.bufPrint(char_buf[0..], "\\x{x:0<2}", .{c}) catch unreachable1757 else
1758 else1758 std.fmt.bufPrint(char_buf, "{c}", .{c}) catch unreachable,
1759 return std.fmt.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable;
1760 },
1761 };1759 };
1762}1760}
17631761
src-self-hosted/util.zig+13-2
...@@ -3,8 +3,7 @@ const Target = std.Target;...@@ -3,8 +3,7 @@ const Target = std.Target;
3const llvm = @import("llvm.zig");3const llvm = @import("llvm.zig");
44
5pub fn getDarwinArchString(self: Target) [:0]const u8 {5pub fn getDarwinArchString(self: Target) [:0]const u8 {
6 const arch = self.getArch();6 switch (self.cpu.arch) {
7 switch (arch) {
8 .aarch64 => return "arm64",7 .aarch64 => return "arm64",
9 .thumb,8 .thumb,
10 .arm,9 .arm,
...@@ -34,3 +33,15 @@ pub fn initializeAllTargets() void {...@@ -34,3 +33,15 @@ pub fn initializeAllTargets() void {
34 llvm.InitializeAllAsmPrinters();33 llvm.InitializeAllAsmPrinters();
35 llvm.InitializeAllAsmParsers();34 llvm.InitializeAllAsmParsers();
36}35}
36
37pub fn getLLVMTriple(allocator: *std.mem.Allocator, target: std.Target) !std.Buffer {
38 var result = try std.Buffer.initSize(allocator, 0);
39 errdefer result.deinit();
40
41 try result.outStream().print(
42 "{}-unknown-{}-{}",
43 .{ @tagName(target.cpu.arch), @tagName(target.os.tag), @tagName(target.abi) },
44 );
45
46 return result;
47}
src/all_types.hpp+6
...@@ -231,6 +231,7 @@ enum ConstPtrSpecial {...@@ -231,6 +231,7 @@ enum ConstPtrSpecial {
231 // The pointer is a reference to a single object.231 // The pointer is a reference to a single object.
232 ConstPtrSpecialRef,232 ConstPtrSpecialRef,
233 // The pointer points to an element in an underlying array.233 // The pointer points to an element in an underlying array.
234 // Not to be confused with ConstPtrSpecialSubArray.
234 ConstPtrSpecialBaseArray,235 ConstPtrSpecialBaseArray,
235 // The pointer points to a field in an underlying struct.236 // The pointer points to a field in an underlying struct.
236 ConstPtrSpecialBaseStruct,237 ConstPtrSpecialBaseStruct,
...@@ -257,6 +258,10 @@ enum ConstPtrSpecial {...@@ -257,6 +258,10 @@ enum ConstPtrSpecial {
257 // types to be the same, so all optionals of pointer types use x_ptr258 // types to be the same, so all optionals of pointer types use x_ptr
258 // instead of x_optional.259 // instead of x_optional.
259 ConstPtrSpecialNull,260 ConstPtrSpecialNull,
261 // The pointer points to a sub-array (not an individual element).
262 // Not to be confused with ConstPtrSpecialBaseArray. However, it uses the same
263 // union payload struct (base_array).
264 ConstPtrSpecialSubArray,
260};265};
261266
262enum ConstPtrMut {267enum ConstPtrMut {
...@@ -3705,6 +3710,7 @@ struct IrInstGenSlice {...@@ -3705,6 +3710,7 @@ struct IrInstGenSlice {
3705 IrInstGen *start;3710 IrInstGen *start;
3706 IrInstGen *end;3711 IrInstGen *end;
3707 IrInstGen *result_loc;3712 IrInstGen *result_loc;
3713 ZigValue *sentinel;
3708 bool safety_check_on;3714 bool safety_check_on;
3709};3715};
37103716
src/analyze.cpp+36-20
...@@ -780,6 +780,8 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa...@@ -780,6 +780,8 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa
780}780}
781781
782ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ZigValue *sentinel) {782ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ZigValue *sentinel) {
783 Error err;
784
783 TypeId type_id = {};785 TypeId type_id = {};
784 type_id.id = ZigTypeIdArray;786 type_id.id = ZigTypeIdArray;
785 type_id.data.array.codegen = g;787 type_id.data.array.codegen = g;
...@@ -791,7 +793,11 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi...@@ -791,7 +793,11 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi
791 return existing_entry->value;793 return existing_entry->value;
792 }794 }
793795
794 assert(type_is_resolved(child_type, ResolveStatusSizeKnown));796 size_t full_array_size = array_size + ((sentinel != nullptr) ? 1 : 0);
797
798 if (full_array_size != 0 && (err = type_resolve(g, child_type, ResolveStatusSizeKnown))) {
799 codegen_report_errors_and_exit(g);
800 }
795801
796 ZigType *entry = new_type_table_entry(ZigTypeIdArray);802 ZigType *entry = new_type_table_entry(ZigTypeIdArray);
797803
...@@ -803,15 +809,8 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi...@@ -803,15 +809,8 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi
803 }809 }
804 buf_appendf(&entry->name, "]%s", buf_ptr(&child_type->name));810 buf_appendf(&entry->name, "]%s", buf_ptr(&child_type->name));
805811
806 size_t full_array_size;
807 if (array_size == 0) {
808 full_array_size = 0;
809 } else {
810 full_array_size = array_size + ((sentinel != nullptr) ? 1 : 0);
811 }
812
813 entry->size_in_bits = child_type->size_in_bits * full_array_size;812 entry->size_in_bits = child_type->size_in_bits * full_array_size;
814 entry->abi_align = child_type->abi_align;813 entry->abi_align = (full_array_size == 0) ? 0 : child_type->abi_align;
815 entry->abi_size = child_type->abi_size * full_array_size;814 entry->abi_size = child_type->abi_size * full_array_size;
816815
817 entry->data.array.child_type = child_type;816 entry->data.array.child_type = child_type;
...@@ -1197,7 +1196,8 @@ Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent...@@ -1197,7 +1196,8 @@ Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent
1197 LazyValueArrayType *lazy_array_type =1196 LazyValueArrayType *lazy_array_type =
1198 reinterpret_cast<LazyValueArrayType *>(type_val->data.x_lazy);1197 reinterpret_cast<LazyValueArrayType *>(type_val->data.x_lazy);
11991198
1200 if (lazy_array_type->length < 1) {1199 // The sentinel counts as an extra element
1200 if (lazy_array_type->length == 0 && lazy_array_type->sentinel == nullptr) {
1201 *is_zero_bits = true;1201 *is_zero_bits = true;
1202 return ErrorNone;1202 return ErrorNone;
1203 }1203 }
...@@ -1452,7 +1452,7 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, ZigV...@@ -1452,7 +1452,7 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, ZigV
1452 case LazyValueIdArrayType: {1452 case LazyValueIdArrayType: {
1453 LazyValueArrayType *lazy_array_type =1453 LazyValueArrayType *lazy_array_type =
1454 reinterpret_cast<LazyValueArrayType *>(type_val->data.x_lazy);1454 reinterpret_cast<LazyValueArrayType *>(type_val->data.x_lazy);
1455 if (lazy_array_type->length < 1)1455 if (lazy_array_type->length == 0)
1456 return OnePossibleValueYes;1456 return OnePossibleValueYes;
1457 return type_val_resolve_has_one_possible_value(g, lazy_array_type->elem_type->value);1457 return type_val_resolve_has_one_possible_value(g, lazy_array_type->elem_type->value);
1458 }1458 }
...@@ -4488,7 +4488,14 @@ static uint32_t get_async_frame_align_bytes(CodeGen *g) {...@@ -4488,7 +4488,14 @@ static uint32_t get_async_frame_align_bytes(CodeGen *g) {
4488}4488}
44894489
4490uint32_t get_ptr_align(CodeGen *g, ZigType *type) {4490uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
4491 ZigType *ptr_type = get_src_ptr_type(type);4491 ZigType *ptr_type;
4492 if (type->id == ZigTypeIdStruct) {
4493 assert(type->data.structure.special == StructSpecialSlice);
4494 TypeStructField *ptr_field = type->data.structure.fields[slice_ptr_index];
4495 ptr_type = resolve_struct_field_type(g, ptr_field);
4496 } else {
4497 ptr_type = get_src_ptr_type(type);
4498 }
4492 if (ptr_type->id == ZigTypeIdPointer) {4499 if (ptr_type->id == ZigTypeIdPointer) {
4493 return (ptr_type->data.pointer.explicit_alignment == 0) ?4500 return (ptr_type->data.pointer.explicit_alignment == 0) ?
4494 get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment;4501 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) {...@@ -4505,8 +4512,15 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
4505 }4512 }
4506}4513}
45074514
4508bool get_ptr_const(ZigType *type) {4515bool get_ptr_const(CodeGen *g, ZigType *type) {
4509 ZigType *ptr_type = get_src_ptr_type(type);4516 ZigType *ptr_type;
4517 if (type->id == ZigTypeIdStruct) {
4518 assert(type->data.structure.special == StructSpecialSlice);
4519 TypeStructField *ptr_field = type->data.structure.fields[slice_ptr_index];
4520 ptr_type = resolve_struct_field_type(g, ptr_field);
4521 } else {
4522 ptr_type = get_src_ptr_type(type);
4523 }
4510 if (ptr_type->id == ZigTypeIdPointer) {4524 if (ptr_type->id == ZigTypeIdPointer) {
4511 return ptr_type->data.pointer.is_const;4525 return ptr_type->data.pointer.is_const;
4512 } else if (ptr_type->id == ZigTypeIdFn) {4526 } else if (ptr_type->id == ZigTypeIdFn) {
...@@ -5282,6 +5296,11 @@ static uint32_t hash_const_val_ptr(ZigValue *const_val) {...@@ -5282,6 +5296,11 @@ static uint32_t hash_const_val_ptr(ZigValue *const_val) {
5282 hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val);5296 hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val);
5283 hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index);5297 hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index);
5284 return hash_val;5298 return hash_val;
5299 case ConstPtrSpecialSubArray:
5300 hash_val += (uint32_t)2643358777;
5301 hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val);
5302 hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index);
5303 return hash_val;
5285 case ConstPtrSpecialBaseStruct:5304 case ConstPtrSpecialBaseStruct:
5286 hash_val += (uint32_t)3518317043;5305 hash_val += (uint32_t)3518317043;
5287 hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val);5306 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) {...@@ -5811,18 +5830,13 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) {
5811 // The elements array cannot be left unpopulated5830 // The elements array cannot be left unpopulated
5812 ZigType *array_type = result->type;5831 ZigType *array_type = result->type;
5813 ZigType *elem_type = array_type->data.array.child_type;5832 ZigType *elem_type = array_type->data.array.child_type;
5814 ZigValue *sentinel_value = array_type->data.array.sentinel;5833 const size_t elem_count = array_type->data.array.len;
5815 const size_t elem_count = array_type->data.array.len + (sentinel_value != nullptr);
58165834
5817 result->data.x_array.data.s_none.elements = g->pass1_arena->allocate<ZigValue>(elem_count);5835 result->data.x_array.data.s_none.elements = g->pass1_arena->allocate<ZigValue>(elem_count);
5818 for (size_t i = 0; i < elem_count; i += 1) {5836 for (size_t i = 0; i < elem_count; i += 1) {
5819 ZigValue *elem_val = &result->data.x_array.data.s_none.elements[i];5837 ZigValue *elem_val = &result->data.x_array.data.s_none.elements[i];
5820 copy_const_val(g, elem_val, get_the_one_possible_value(g, elem_type));5838 copy_const_val(g, elem_val, get_the_one_possible_value(g, elem_type));
5821 }5839 }
5822 if (sentinel_value != nullptr) {
5823 ZigValue *last_elem_val = &result->data.x_array.data.s_none.elements[elem_count - 1];
5824 copy_const_val(g, last_elem_val, sentinel_value);
5825 }
5826 } else if (result->type->id == ZigTypeIdPointer) {5840 } else if (result->type->id == ZigTypeIdPointer) {
5827 result->data.x_ptr.special = ConstPtrSpecialRef;5841 result->data.x_ptr.special = ConstPtrSpecialRef;
5828 result->data.x_ptr.data.ref.pointee = get_the_one_possible_value(g, result->type->data.pointer.child_type);5842 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) {...@@ -6753,6 +6767,7 @@ bool const_values_equal_ptr(ZigValue *a, ZigValue *b) {
6753 return false;6767 return false;
6754 return true;6768 return true;
6755 case ConstPtrSpecialBaseArray:6769 case ConstPtrSpecialBaseArray:
6770 case ConstPtrSpecialSubArray:
6756 if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val) {6771 if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val) {
6757 return false;6772 return false;
6758 }6773 }
...@@ -7010,6 +7025,7 @@ static void render_const_val_ptr(CodeGen *g, Buf *buf, ZigValue *const_val, ZigT...@@ -7010,6 +7025,7 @@ static void render_const_val_ptr(CodeGen *g, Buf *buf, ZigValue *const_val, ZigT
7010 render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr));7025 render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr));
7011 return;7026 return;
7012 case ConstPtrSpecialBaseArray:7027 case ConstPtrSpecialBaseArray:
7028 case ConstPtrSpecialSubArray:
7013 buf_appendf(buf, "*");7029 buf_appendf(buf, "*");
7014 // TODO we need a source node for const_ptr_pointee because it can generate compile errors7030 // TODO we need a source node for const_ptr_pointee because it can generate compile errors
7015 render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr));7031 render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr));
src/analyze.hpp+1-1
...@@ -76,7 +76,7 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool all...@@ -76,7 +76,7 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool all
7676
77ZigType *get_src_ptr_type(ZigType *type);77ZigType *get_src_ptr_type(ZigType *type);
78uint32_t get_ptr_align(CodeGen *g, ZigType *type);78uint32_t get_ptr_align(CodeGen *g, ZigType *type);
79bool get_ptr_const(ZigType *type);79bool get_ptr_const(CodeGen *g, ZigType *type);
80ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry);80ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry);
81ZigType *container_ref_type(ZigType *type_entry);81ZigType *container_ref_type(ZigType *type_entry);
82bool type_is_complete(ZigType *type_entry);82bool type_is_complete(ZigType *type_entry);
src/codegen.cpp+113-52
...@@ -5413,12 +5413,16 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI...@@ -5413,12 +5413,16 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
5413 ZigType *array_type = array_ptr_type->data.pointer.child_type;5413 ZigType *array_type = array_ptr_type->data.pointer.child_type;
5414 LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type);5414 LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type);
54155415
5416 LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
5417
5418 bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base);5416 bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base);
54195417
5420 ZigType *res_slice_ptr_type = instruction->base.value->type->data.structure.fields[slice_ptr_index]->type_entry;5418 ZigType *result_type = instruction->base.value->type;
5421 ZigValue *sentinel = res_slice_ptr_type->data.pointer.sentinel;5419 if (!type_has_bits(g, result_type)) {
5420 return nullptr;
5421 }
5422
5423 // This is not whether the result type has a sentinel, but whether there should be a sentinel check,
5424 // e.g. if they used [a..b :s] syntax.
5425 ZigValue *sentinel = instruction->sentinel;
54225426
5423 if (array_type->id == ZigTypeIdArray ||5427 if (array_type->id == ZigTypeIdArray ||
5424 (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle))5428 (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle))
...@@ -5453,6 +5457,8 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI...@@ -5453,6 +5457,8 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
5453 }5457 }
5454 }5458 }
5455 if (!type_has_bits(g, array_type)) {5459 if (!type_has_bits(g, array_type)) {
5460 LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
5461
5456 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, "");5462 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, "");
54575463
5458 // TODO if runtime safety is on, store 0xaaaaaaa in ptr field5464 // TODO if runtime safety is on, store 0xaaaaaaa in ptr field
...@@ -5461,20 +5467,26 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI...@@ -5461,20 +5467,26 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
5461 return tmp_struct_ptr;5467 return tmp_struct_ptr;
5462 }5468 }
54635469
5464
5465 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, "");
5466 LLVMValueRef indices[] = {5470 LLVMValueRef indices[] = {
5467 LLVMConstNull(g->builtin_types.entry_usize->llvm_type),5471 LLVMConstNull(g->builtin_types.entry_usize->llvm_type),
5468 start_val,5472 start_val,
5469 };5473 };
5470 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");5474 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, "");
5471 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);5475 if (result_type->id == ZigTypeIdPointer) {
5476 ir_assert(instruction->result_loc == nullptr, &instruction->base);
5477 LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type);
5478 return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, "");
5479 } else {
5480 LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
5481 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, "");
5482 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
54725483
5473 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, "");5484 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, "");
5474 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");5485 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
5475 gen_store_untyped(g, len_value, len_field_ptr, 0, false);5486 gen_store_untyped(g, len_value, len_field_ptr, 0, false);
54765487
5477 return tmp_struct_ptr;5488 return tmp_struct_ptr;
5489 }
5478 } else if (array_type->id == ZigTypeIdPointer) {5490 } else if (array_type->id == ZigTypeIdPointer) {
5479 assert(array_type->data.pointer.ptr_len != PtrLenSingle);5491 assert(array_type->data.pointer.ptr_len != PtrLenSingle);
5480 LLVMValueRef start_val = ir_llvm_value(g, instruction->start);5492 LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
...@@ -5488,24 +5500,39 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI...@@ -5488,24 +5500,39 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
5488 }5500 }
5489 }5501 }
54905502
5491 if (type_has_bits(g, array_type)) {5503 if (!type_has_bits(g, array_type)) {
5492 size_t gen_ptr_index = instruction->base.value->type->data.structure.fields[slice_ptr_index]->gen_index;5504 LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
5493 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, "");5505 size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index;
5494 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, "");5506 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, "");
5495 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);5507 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
5508 gen_store_untyped(g, len_value, len_field_ptr, 0, false);
5509 return tmp_struct_ptr;
5496 }5510 }
54975511
5498 size_t gen_len_index = instruction->base.value->type->data.structure.fields[slice_len_index]->gen_index;5512 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, "");
5513 if (result_type->id == ZigTypeIdPointer) {
5514 ir_assert(instruction->result_loc == nullptr, &instruction->base);
5515 LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type);
5516 return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, "");
5517 }
5518
5519 LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
5520
5521 size_t gen_ptr_index = result_type->data.structure.fields[slice_ptr_index]->gen_index;
5522 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, "");
5523 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
5524
5525 size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index;
5499 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, "");5526 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, "");
5500 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");5527 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
5501 gen_store_untyped(g, len_value, len_field_ptr, 0, false);5528 gen_store_untyped(g, len_value, len_field_ptr, 0, false);
55025529
5503 return tmp_struct_ptr;5530 return tmp_struct_ptr;
5531
5504 } else if (array_type->id == ZigTypeIdStruct) {5532 } else if (array_type->id == ZigTypeIdStruct) {
5505 assert(array_type->data.structure.special == StructSpecialSlice);5533 assert(array_type->data.structure.special == StructSpecialSlice);
5506 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);5534 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind);
5507 assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);5535 assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind);
5508 assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(tmp_struct_ptr))) == LLVMStructTypeKind);
55095536
5510 size_t ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index;5537 size_t ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index;
5511 assert(ptr_index != SIZE_MAX);5538 assert(ptr_index != SIZE_MAX);
...@@ -5542,15 +5569,22 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI...@@ -5542,15 +5569,22 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI
5542 }5569 }
5543 }5570 }
55445571
5545 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)ptr_index, "");
5546 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, "");5572 LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, "");
5547 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);5573 if (result_type->id == ZigTypeIdPointer) {
5574 ir_assert(instruction->result_loc == nullptr, &instruction->base);
5575 LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type);
5576 return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, "");
5577 } else {
5578 LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc);
5579 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)ptr_index, "");
5580 gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
55485581
5549 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)len_index, "");5582 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)len_index, "");
5550 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");5583 LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, "");
5551 gen_store_untyped(g, len_value, len_field_ptr, 0, false);5584 gen_store_untyped(g, len_value, len_field_ptr, 0, false);
55525585
5553 return tmp_struct_ptr;5586 return tmp_struct_ptr;
5587 }
5554 } else {5588 } else {
5555 zig_unreachable();5589 zig_unreachable();
5556 }5590 }
...@@ -6635,7 +6669,6 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ZigValue *array_co...@@ -6635,7 +6669,6 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ZigValue *array_co
6635 };6669 };
6636 return LLVMConstInBoundsGEP(base_ptr, indices, 2);6670 return LLVMConstInBoundsGEP(base_ptr, indices, 2);
6637 } else {6671 } else {
6638 assert(parent->id == ConstParentIdScalar);
6639 return base_ptr;6672 return base_ptr;
6640 }6673 }
6641}6674}
...@@ -6785,6 +6818,22 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Zig...@@ -6785,6 +6818,22 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Zig
6785 used_bits += packed_bits_size;6818 used_bits += packed_bits_size;
6786 }6819 }
6787 }6820 }
6821
6822 if (type_entry->data.array.sentinel != nullptr) {
6823 ZigValue *elem_val = type_entry->data.array.sentinel;
6824 LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, elem_val);
6825
6826 if (is_big_endian) {
6827 LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, packed_bits_size, false);
6828 val = LLVMConstShl(val, shift_amt);
6829 val = LLVMConstOr(val, child_val);
6830 } else {
6831 LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false);
6832 LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt);
6833 val = LLVMConstOr(val, child_val_shifted);
6834 used_bits += packed_bits_size;
6835 }
6836 }
6788 return val;6837 return val;
6789 }6838 }
6790 case ZigTypeIdVector:6839 case ZigTypeIdVector:
...@@ -6847,24 +6896,16 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ZigValue *const_val, const cha...@@ -6847,24 +6896,16 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ZigValue *const_val, const cha
6847 return const_val->llvm_value;6896 return const_val->llvm_value;
6848 }6897 }
6849 case ConstPtrSpecialBaseArray:6898 case ConstPtrSpecialBaseArray:
6899 case ConstPtrSpecialSubArray:
6850 {6900 {
6851 ZigValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val;6901 ZigValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val;
6852 assert(array_const_val->type->id == ZigTypeIdArray);6902 assert(array_const_val->type->id == ZigTypeIdArray);
6853 if (!type_has_bits(g, array_const_val->type)) {6903 if (!type_has_bits(g, array_const_val->type)) {
6854 if (array_const_val->type->data.array.sentinel != nullptr) {6904 // make this a null pointer
6855 ZigValue *pointee = array_const_val->type->data.array.sentinel;6905 ZigType *usize = g->builtin_types.entry_usize;
6856 render_const_val(g, pointee, "");6906 const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type),
6857 render_const_val_global(g, pointee, "");6907 get_llvm_type(g, const_val->type));
6858 const_val->llvm_value = LLVMConstBitCast(pointee->llvm_global,6908 return const_val->llvm_value;
6859 get_llvm_type(g, const_val->type));
6860 return const_val->llvm_value;
6861 } else {
6862 // make this a null pointer
6863 ZigType *usize = g->builtin_types.entry_usize;
6864 const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type),
6865 get_llvm_type(g, const_val->type));
6866 return const_val->llvm_value;
6867 }
6868 }6909 }
6869 size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;6910 size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
6870 LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, elem_index);6911 LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, elem_index);
...@@ -9644,6 +9685,21 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose...@@ -9644,6 +9685,21 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose
9644 return ErrorNone;9685 return ErrorNone;
9645}9686}
96469687
9688static bool need_llvm_module(CodeGen *g) {
9689 return buf_len(&g->main_pkg->root_src_path) != 0;
9690}
9691
9692// before gen_c_objects
9693static bool main_output_dir_is_just_one_c_object_pre(CodeGen *g) {
9694 return g->enable_cache && g->c_source_files.length == 1 && !need_llvm_module(g) &&
9695 g->out_type == OutTypeObj && g->link_objects.length == 0;
9696}
9697
9698// after gen_c_objects
9699static bool main_output_dir_is_just_one_c_object_post(CodeGen *g) {
9700 return g->enable_cache && g->link_objects.length == 1 && !need_llvm_module(g) && g->out_type == OutTypeObj;
9701}
9702
9647// returns true if it was a cache miss9703// returns true if it was a cache miss
9648static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {9704static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {
9649 Error err;9705 Error err;
...@@ -9661,7 +9717,12 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {...@@ -9661,7 +9717,12 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) {
9661 buf_len(c_source_basename), 0);9717 buf_len(c_source_basename), 0);
96629718
9663 Buf *final_o_basename = buf_alloc();9719 Buf *final_o_basename = buf_alloc();
9664 os_path_extname(c_source_basename, final_o_basename, nullptr);9720 // We special case when doing build-obj for just one C file
9721 if (main_output_dir_is_just_one_c_object_pre(g)) {
9722 buf_init_from_buf(final_o_basename, g->root_out_name);
9723 } else {
9724 os_path_extname(c_source_basename, final_o_basename, nullptr);
9725 }
9665 buf_append_str(final_o_basename, target_o_file_ext(g->zig_target));9726 buf_append_str(final_o_basename, target_o_file_ext(g->zig_target));
96669727
9667 CacheHash *cache_hash;9728 CacheHash *cache_hash;
...@@ -10461,10 +10522,6 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {...@@ -10461,10 +10522,6 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
10461 return ErrorNone;10522 return ErrorNone;
10462}10523}
1046310524
10464static bool need_llvm_module(CodeGen *g) {
10465 return buf_len(&g->main_pkg->root_src_path) != 0;
10466}
10467
10468static void resolve_out_paths(CodeGen *g) {10525static void resolve_out_paths(CodeGen *g) {
10469 assert(g->output_dir != nullptr);10526 assert(g->output_dir != nullptr);
10470 assert(g->root_out_name != nullptr);10527 assert(g->root_out_name != nullptr);
...@@ -10476,10 +10533,6 @@ static void resolve_out_paths(CodeGen *g) {...@@ -10476,10 +10533,6 @@ static void resolve_out_paths(CodeGen *g) {
10476 case OutTypeUnknown:10533 case OutTypeUnknown:
10477 zig_unreachable();10534 zig_unreachable();
10478 case OutTypeObj:10535 case OutTypeObj:
10479 if (g->enable_cache && g->link_objects.length == 1 && !need_llvm_module(g)) {
10480 buf_init_from_buf(&g->bin_file_output_path, g->link_objects.at(0));
10481 return;
10482 }
10483 if (need_llvm_module(g) && g->link_objects.length != 0 && !g->enable_cache &&10536 if (need_llvm_module(g) && g->link_objects.length != 0 && !g->enable_cache &&
10484 buf_eql_buf(o_basename, out_basename))10537 buf_eql_buf(o_basename, out_basename))
10485 {10538 {
...@@ -10574,6 +10627,16 @@ static void output_type_information(CodeGen *g) {...@@ -10574,6 +10627,16 @@ static void output_type_information(CodeGen *g) {
10574 }10627 }
10575}10628}
1057610629
10630static void init_output_dir(CodeGen *g, Buf *digest) {
10631 if (main_output_dir_is_just_one_c_object_post(g)) {
10632 g->output_dir = buf_alloc();
10633 os_path_dirname(g->link_objects.at(0), g->output_dir);
10634 } else {
10635 g->output_dir = buf_sprintf("%s" OS_SEP CACHE_OUT_SUBDIR OS_SEP "%s",
10636 buf_ptr(g->cache_dir), buf_ptr(digest));
10637 }
10638}
10639
10577void codegen_build_and_link(CodeGen *g) {10640void codegen_build_and_link(CodeGen *g) {
10578 Error err;10641 Error err;
10579 assert(g->out_type != OutTypeUnknown);10642 assert(g->out_type != OutTypeUnknown);
...@@ -10616,8 +10679,7 @@ void codegen_build_and_link(CodeGen *g) {...@@ -10616,8 +10679,7 @@ void codegen_build_and_link(CodeGen *g) {
10616 }10679 }
1061710680
10618 if (g->enable_cache && buf_len(&digest) != 0) {10681 if (g->enable_cache && buf_len(&digest) != 0) {
10619 g->output_dir = buf_sprintf("%s" OS_SEP CACHE_OUT_SUBDIR OS_SEP "%s",10682 init_output_dir(g, &digest);
10620 buf_ptr(g->cache_dir), buf_ptr(&digest));
10621 resolve_out_paths(g);10683 resolve_out_paths(g);
10622 } else {10684 } else {
10623 if (need_llvm_module(g)) {10685 if (need_llvm_module(g)) {
...@@ -10638,8 +10700,7 @@ void codegen_build_and_link(CodeGen *g) {...@@ -10638,8 +10700,7 @@ void codegen_build_and_link(CodeGen *g) {
10638 exit(1);10700 exit(1);
10639 }10701 }
10640 }10702 }
10641 g->output_dir = buf_sprintf("%s" OS_SEP CACHE_OUT_SUBDIR OS_SEP "%s",10703 init_output_dir(g, &digest);
10642 buf_ptr(g->cache_dir), buf_ptr(&digest));
1064310704
10644 if ((err = os_make_path(g->output_dir))) {10705 if ((err = os_make_path(g->output_dir))) {
10645 fprintf(stderr, "Unable to create output directory: %s\n", err_str(err));10706 fprintf(stderr, "Unable to create output directory: %s\n", err_str(err));
src/ir.cpp+327-96
...@@ -784,14 +784,32 @@ static ZigValue *const_ptr_pointee_unchecked_no_isf(CodeGen *g, ZigValue *const_...@@ -784,14 +784,32 @@ static ZigValue *const_ptr_pointee_unchecked_no_isf(CodeGen *g, ZigValue *const_
784 break;784 break;
785 case ConstPtrSpecialBaseArray: {785 case ConstPtrSpecialBaseArray: {
786 ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val;786 ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val;
787 if (const_val->data.x_ptr.data.base_array.elem_index == array_val->type->data.array.len) {787 size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
788 if (elem_index == array_val->type->data.array.len) {
788 result = array_val->type->data.array.sentinel;789 result = array_val->type->data.array.sentinel;
789 } else {790 } else {
790 expand_undef_array(g, array_val);791 expand_undef_array(g, array_val);
791 result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index];792 result = &array_val->data.x_array.data.s_none.elements[elem_index];
792 }793 }
793 break;794 break;
794 }795 }
796 case ConstPtrSpecialSubArray: {
797 ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val;
798 size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index;
799
800 // TODO handle sentinel terminated arrays
801 expand_undef_array(g, array_val);
802 result = g->pass1_arena->create<ZigValue>();
803 result->special = array_val->special;
804 result->type = get_array_type(g, array_val->type->data.array.child_type,
805 array_val->type->data.array.len - elem_index, nullptr);
806 result->data.x_array.special = ConstArraySpecialNone;
807 result->data.x_array.data.s_none.elements = &array_val->data.x_array.data.s_none.elements[elem_index];
808 result->parent.id = ConstParentIdArray;
809 result->parent.data.p_array.array_val = array_val;
810 result->parent.data.p_array.elem_index = elem_index;
811 break;
812 }
795 case ConstPtrSpecialBaseStruct: {813 case ConstPtrSpecialBaseStruct: {
796 ZigValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val;814 ZigValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val;
797 expand_undef_struct(g, struct_val);815 expand_undef_struct(g, struct_val);
...@@ -849,11 +867,6 @@ static bool is_slice(ZigType *type) {...@@ -849,11 +867,6 @@ static bool is_slice(ZigType *type) {
849 return type->id == ZigTypeIdStruct && type->data.structure.special == StructSpecialSlice;867 return type->id == ZigTypeIdStruct && type->data.structure.special == StructSpecialSlice;
850}868}
851869
852static bool slice_is_const(ZigType *type) {
853 assert(is_slice(type));
854 return type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const;
855}
856
857// This function returns true when you can change the type of a ZigValue and the870// This function returns true when you can change the type of a ZigValue and the
858// value remains meaningful.871// value remains meaningful.
859static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expected, ZigType *actual) {872static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expected, ZigType *actual) {
...@@ -3719,7 +3732,8 @@ static IrInstSrc *ir_build_slice_src(IrBuilderSrc *irb, Scope *scope, AstNode *s...@@ -3719,7 +3732,8 @@ static IrInstSrc *ir_build_slice_src(IrBuilderSrc *irb, Scope *scope, AstNode *s
3719}3732}
37203733
3721static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *slice_type,3734static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *slice_type,
3722 IrInstGen *ptr, IrInstGen *start, IrInstGen *end, bool safety_check_on, IrInstGen *result_loc)3735 IrInstGen *ptr, IrInstGen *start, IrInstGen *end, bool safety_check_on, IrInstGen *result_loc,
3736 ZigValue *sentinel)
3723{3737{
3724 IrInstGenSlice *instruction = ir_build_inst_gen<IrInstGenSlice>(3738 IrInstGenSlice *instruction = ir_build_inst_gen<IrInstGenSlice>(
3725 &ira->new_irb, source_instruction->scope, source_instruction->source_node);3739 &ira->new_irb, source_instruction->scope, source_instruction->source_node);
...@@ -3729,11 +3743,12 @@ static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction,...@@ -3729,11 +3743,12 @@ static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction,
3729 instruction->end = end;3743 instruction->end = end;
3730 instruction->safety_check_on = safety_check_on;3744 instruction->safety_check_on = safety_check_on;
3731 instruction->result_loc = result_loc;3745 instruction->result_loc = result_loc;
3746 instruction->sentinel = sentinel;
37323747
3733 ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block);3748 ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block);
3734 ir_ref_inst_gen(start, ira->new_irb.current_basic_block);3749 ir_ref_inst_gen(start, ira->new_irb.current_basic_block);
3735 if (end) ir_ref_inst_gen(end, ira->new_irb.current_basic_block);3750 if (end != nullptr) ir_ref_inst_gen(end, ira->new_irb.current_basic_block);
3736 ir_ref_inst_gen(result_loc, ira->new_irb.current_basic_block);3751 if (result_loc != nullptr) ir_ref_inst_gen(result_loc, ira->new_irb.current_basic_block);
37373752
3738 return &instruction->base;3753 return &instruction->base;
3739}3754}
...@@ -12644,41 +12659,80 @@ static IrInstGen *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInst* sourc...@@ -12644,41 +12659,80 @@ static IrInstGen *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInst* sourc
12644 Error err;12659 Error err;
1264512660
12646 assert(array_ptr->value->type->id == ZigTypeIdPointer);12661 assert(array_ptr->value->type->id == ZigTypeIdPointer);
12662 assert(array_ptr->value->type->data.pointer.child_type->id == ZigTypeIdArray);
12663
12664 ZigType *array_type = array_ptr->value->type->data.pointer.child_type;
12665 size_t array_len = array_type->data.array.len;
12666
12667 // A zero-sized array can be casted regardless of the destination alignment, or
12668 // whether the pointer is undefined, and the result is always comptime known.
12669 // TODO However, this is exposing a result location bug that I failed to solve on the first try.
12670 // If you want to try to fix the bug, uncomment this block and get the tests passing.
12671 //if (array_len == 0 && array_type->data.array.sentinel == nullptr) {
12672 // ZigValue *undef_array = ira->codegen->pass1_arena->create<ZigValue>();
12673 // undef_array->special = ConstValSpecialUndef;
12674 // undef_array->type = array_type;
12675
12676 // IrInstGen *result = ir_const(ira, source_instr, wanted_type);
12677 // init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false);
12678 // result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst;
12679 // result->value->type = wanted_type;
12680 // return result;
12681 //}
1264712682
12648 if ((err = type_resolve(ira->codegen, array_ptr->value->type, ResolveStatusAlignmentKnown))) {12683 if ((err = type_resolve(ira->codegen, array_ptr->value->type, ResolveStatusAlignmentKnown))) {
12649 return ira->codegen->invalid_inst_gen;12684 return ira->codegen->invalid_inst_gen;
12650 }12685 }
1265112686
12652 assert(array_ptr->value->type->data.pointer.child_type->id == ZigTypeIdArray);
12653
12654 const size_t array_len = array_ptr->value->type->data.pointer.child_type->data.array.len;
12655
12656 // A zero-sized array can always be casted irregardless of the destination
12657 // alignment
12658 if (array_len != 0) {12687 if (array_len != 0) {
12659 wanted_type = adjust_slice_align(ira->codegen, wanted_type,12688 wanted_type = adjust_slice_align(ira->codegen, wanted_type,
12660 get_ptr_align(ira->codegen, array_ptr->value->type));12689 get_ptr_align(ira->codegen, array_ptr->value->type));
12661 }12690 }
1266212691
12663 if (instr_is_comptime(array_ptr)) {12692 if (instr_is_comptime(array_ptr)) {
12664 ZigValue *array_ptr_val = ir_resolve_const(ira, array_ptr, UndefBad);12693 UndefAllowed undef_allowed = (array_len == 0) ? UndefOk : UndefBad;
12694 ZigValue *array_ptr_val = ir_resolve_const(ira, array_ptr, undef_allowed);
12665 if (array_ptr_val == nullptr)12695 if (array_ptr_val == nullptr)
12666 return ira->codegen->invalid_inst_gen;12696 return ira->codegen->invalid_inst_gen;
12667 ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, array_ptr_val, source_instr->source_node);12697 ir_assert(is_slice(wanted_type), source_instr);
12668 if (pointee == nullptr)12698 if (array_ptr_val->special == ConstValSpecialUndef) {
12669 return ira->codegen->invalid_inst_gen;12699 ZigValue *undef_array = ira->codegen->pass1_arena->create<ZigValue>();
12670 if (pointee->special != ConstValSpecialRuntime) {12700 undef_array->special = ConstValSpecialUndef;
12671 assert(array_ptr_val->type->id == ZigTypeIdPointer);12701 undef_array->type = array_type;
12672 ZigType *array_type = array_ptr_val->type->data.pointer.child_type;
12673 assert(is_slice(wanted_type));
12674 bool is_const = wanted_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const;
1267512702
12676 IrInstGen *result = ir_const(ira, source_instr, wanted_type);12703 IrInstGen *result = ir_const(ira, source_instr, wanted_type);
12677 init_const_slice(ira->codegen, result->value, pointee, 0, array_type->data.array.len, is_const);12704 init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false);
12678 result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut;12705 result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst;
12679 result->value->type = wanted_type;12706 result->value->type = wanted_type;
12680 return result;12707 return result;
12681 }12708 }
12709 bool wanted_const = wanted_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const;
12710 // Optimization to avoid creating unnecessary ZigValue in const_ptr_pointee
12711 if (array_ptr_val->data.x_ptr.special == ConstPtrSpecialSubArray) {
12712 ZigValue *array_val = array_ptr_val->data.x_ptr.data.base_array.array_val;
12713 if (array_val->special != ConstValSpecialRuntime) {
12714 IrInstGen *result = ir_const(ira, source_instr, wanted_type);
12715 init_const_slice(ira->codegen, result->value, array_val,
12716 array_ptr_val->data.x_ptr.data.base_array.elem_index,
12717 array_type->data.array.len, wanted_const);
12718 result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut;
12719 result->value->type = wanted_type;
12720 return result;
12721 }
12722 } else {
12723 ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, array_ptr_val, source_instr->source_node);
12724 if (pointee == nullptr)
12725 return ira->codegen->invalid_inst_gen;
12726 if (pointee->special != ConstValSpecialRuntime) {
12727 assert(array_ptr_val->type->id == ZigTypeIdPointer);
12728
12729 IrInstGen *result = ir_const(ira, source_instr, wanted_type);
12730 init_const_slice(ira->codegen, result->value, pointee, 0, array_type->data.array.len, wanted_const);
12731 result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut;
12732 result->value->type = wanted_type;
12733 return result;
12734 }
12735 }
12682 }12736 }
1268312737
12684 if (result_loc == nullptr) result_loc = no_result_loc();12738 if (result_loc == nullptr) result_loc = no_result_loc();
...@@ -14548,7 +14602,7 @@ static IrInstGen *ir_analyze_cast(IrAnalyze *ira, IrInst *source_instr,...@@ -14548,7 +14602,7 @@ static IrInstGen *ir_analyze_cast(IrAnalyze *ira, IrInst *source_instr,
14548 return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);14602 return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
14549 }14603 }
1455014604
14551 // *[N]T to ?[]const T14605 // *[N]T to ?[]T
14552 if (wanted_type->id == ZigTypeIdOptional &&14606 if (wanted_type->id == ZigTypeIdOptional &&
14553 is_slice(wanted_type->data.maybe.child_type) &&14607 is_slice(wanted_type->data.maybe.child_type) &&
14554 actual_type->id == ZigTypeIdPointer &&14608 actual_type->id == ZigTypeIdPointer &&
...@@ -19884,6 +19938,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source...@@ -19884,6 +19938,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
19884 buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf), pointee);19938 buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf), pointee);
19885 if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val)))19939 if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val)))
19886 return err;19940 return err;
19941 buf_deinit(&buf);
19887 return ErrorNone;19942 return ErrorNone;
19888 }19943 }
1988919944
...@@ -19903,6 +19958,31 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source...@@ -19903,6 +19958,31 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
19903 dst_size, buf_ptr(&pointee->type->name), src_size));19958 dst_size, buf_ptr(&pointee->type->name), src_size));
19904 return ErrorSemanticAnalyzeFail;19959 return ErrorSemanticAnalyzeFail;
19905 }19960 }
19961 case ConstPtrSpecialSubArray: {
19962 ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val;
19963 assert(array_val->type->id == ZigTypeIdArray);
19964 if (array_val->data.x_array.special != ConstArraySpecialNone)
19965 zig_panic("TODO");
19966 if (dst_size > src_size) {
19967 size_t elem_index = ptr_val->data.x_ptr.data.base_array.elem_index;
19968 opt_ir_add_error_node(ira, codegen, source_node,
19969 buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from %s at index %" ZIG_PRI_usize " which is %" ZIG_PRI_usize " bytes",
19970 dst_size, buf_ptr(&array_val->type->name), elem_index, src_size));
19971 return ErrorSemanticAnalyzeFail;
19972 }
19973 size_t elem_size = src_size;
19974 size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1);
19975 Buf buf = BUF_INIT;
19976 buf_resize(&buf, elem_count * elem_size);
19977 for (size_t i = 0; i < elem_count; i += 1) {
19978 ZigValue *elem_val = &array_val->data.x_array.data.s_none.elements[i];
19979 buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val);
19980 }
19981 if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val)))
19982 return err;
19983 buf_deinit(&buf);
19984 return ErrorNone;
19985 }
19906 case ConstPtrSpecialBaseArray: {19986 case ConstPtrSpecialBaseArray: {
19907 ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val;19987 ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val;
19908 assert(array_val->type->id == ZigTypeIdArray);19988 assert(array_val->type->id == ZigTypeIdArray);
...@@ -19926,6 +20006,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source...@@ -19926,6 +20006,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source
19926 }20006 }
19927 if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val)))20007 if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val)))
19928 return err;20008 return err;
20009 buf_deinit(&buf);
19929 return ErrorNone;20010 return ErrorNone;
19930 }20011 }
19931 case ConstPtrSpecialBaseStruct:20012 case ConstPtrSpecialBaseStruct:
...@@ -20505,6 +20586,44 @@ static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_...@@ -20505,6 +20586,44 @@ static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_
20505 allow_zero);20586 allow_zero);
20506}20587}
2050720588
20589static Error compute_elem_align(IrAnalyze *ira, ZigType *elem_type, uint32_t base_ptr_align,
20590 uint64_t elem_index, uint32_t *result)
20591{
20592 Error err;
20593
20594 if (base_ptr_align == 0) {
20595 *result = 0;
20596 return ErrorNone;
20597 }
20598
20599 // figure out the largest alignment possible
20600 if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown)))
20601 return err;
20602
20603 uint64_t elem_size = type_size(ira->codegen, elem_type);
20604 uint64_t abi_align = get_abi_alignment(ira->codegen, elem_type);
20605 uint64_t ptr_align = base_ptr_align;
20606
20607 uint64_t chosen_align = abi_align;
20608 if (ptr_align >= abi_align) {
20609 while (ptr_align > abi_align) {
20610 if ((elem_index * elem_size) % ptr_align == 0) {
20611 chosen_align = ptr_align;
20612 break;
20613 }
20614 ptr_align >>= 1;
20615 }
20616 } else if (elem_size >= ptr_align && elem_size % ptr_align == 0) {
20617 chosen_align = ptr_align;
20618 } else {
20619 // can't get here because guaranteed elem_size >= abi_align
20620 zig_unreachable();
20621 }
20622
20623 *result = chosen_align;
20624 return ErrorNone;
20625}
20626
20508static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemPtr *elem_ptr_instruction) {20627static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemPtr *elem_ptr_instruction) {
20509 Error err;20628 Error err;
20510 IrInstGen *array_ptr = elem_ptr_instruction->array_ptr->child;20629 IrInstGen *array_ptr = elem_ptr_instruction->array_ptr->child;
...@@ -20545,11 +20664,6 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP...@@ -20545,11 +20664,6 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP
20545 }20664 }
2054620665
20547 if (array_type->id == ZigTypeIdArray) {20666 if (array_type->id == ZigTypeIdArray) {
20548 if (array_type->data.array.len == 0) {
20549 ir_add_error_node(ira, elem_ptr_instruction->base.base.source_node,
20550 buf_sprintf("index 0 outside array of size 0"));
20551 return ira->codegen->invalid_inst_gen;
20552 }
20553 ZigType *child_type = array_type->data.array.child_type;20667 ZigType *child_type = array_type->data.array.child_type;
20554 if (ptr_type->data.pointer.host_int_bytes == 0) {20668 if (ptr_type->data.pointer.host_int_bytes == 0) {
20555 return_type = get_pointer_to_type_extra(ira->codegen, child_type,20669 return_type = get_pointer_to_type_extra(ira->codegen, child_type,
...@@ -20648,29 +20762,11 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP...@@ -20648,29 +20762,11 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP
20648 get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index,20762 get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index,
20649 nullptr, nullptr);20763 nullptr, nullptr);
20650 } else if (return_type->data.pointer.explicit_alignment != 0) {20764 } else if (return_type->data.pointer.explicit_alignment != 0) {
20651 // figure out the largest alignment possible20765 uint32_t chosen_align;
2065220766 if ((err = compute_elem_align(ira, return_type->data.pointer.child_type,
20653 if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown)))20767 return_type->data.pointer.explicit_alignment, index, &chosen_align)))
20768 {
20654 return ira->codegen->invalid_inst_gen;20769 return ira->codegen->invalid_inst_gen;
20655
20656 uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type);
20657 uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type);
20658 uint64_t ptr_align = get_ptr_align(ira->codegen, return_type);
20659
20660 uint64_t chosen_align = abi_align;
20661 if (ptr_align >= abi_align) {
20662 while (ptr_align > abi_align) {
20663 if ((index * elem_size) % ptr_align == 0) {
20664 chosen_align = ptr_align;
20665 break;
20666 }
20667 ptr_align >>= 1;
20668 }
20669 } else if (elem_size >= ptr_align && elem_size % ptr_align == 0) {
20670 chosen_align = ptr_align;
20671 } else {
20672 // can't get here because guaranteed elem_size >= abi_align
20673 zig_unreachable();
20674 }20770 }
20675 return_type = adjust_ptr_align(ira->codegen, return_type, chosen_align);20771 return_type = adjust_ptr_align(ira->codegen, return_type, chosen_align);
20676 }20772 }
...@@ -20791,6 +20887,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP...@@ -20791,6 +20887,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP
20791 }20887 }
20792 break;20888 break;
20793 case ConstPtrSpecialBaseArray:20889 case ConstPtrSpecialBaseArray:
20890 case ConstPtrSpecialSubArray:
20794 {20891 {
20795 size_t offset = array_ptr_val->data.x_ptr.data.base_array.elem_index;20892 size_t offset = array_ptr_val->data.x_ptr.data.base_array.elem_index;
20796 new_index = offset + index;20893 new_index = offset + index;
...@@ -20861,6 +20958,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP...@@ -20861,6 +20958,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP
20861 out_val->data.x_ptr.special = ConstPtrSpecialRef;20958 out_val->data.x_ptr.special = ConstPtrSpecialRef;
20862 out_val->data.x_ptr.data.ref.pointee = ptr_field->data.x_ptr.data.ref.pointee;20959 out_val->data.x_ptr.data.ref.pointee = ptr_field->data.x_ptr.data.ref.pointee;
20863 break;20960 break;
20961 case ConstPtrSpecialSubArray:
20864 case ConstPtrSpecialBaseArray:20962 case ConstPtrSpecialBaseArray:
20865 {20963 {
20866 size_t offset = ptr_field->data.x_ptr.data.base_array.elem_index;20964 size_t offset = ptr_field->data.x_ptr.data.base_array.elem_index;
...@@ -25412,11 +25510,22 @@ static IrInstGen *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstSrcE...@@ -25412,11 +25510,22 @@ static IrInstGen *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstSrcE
25412static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) {25510static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) {
25413 Error err;25511 Error err;
2541425512
25415 ZigType *ptr_type = get_src_ptr_type(ty);25513 ZigType *ptr_type;
25514 if (is_slice(ty)) {
25515 TypeStructField *ptr_field = ty->data.structure.fields[slice_ptr_index];
25516 ptr_type = resolve_struct_field_type(ira->codegen, ptr_field);
25517 } else {
25518 ptr_type = get_src_ptr_type(ty);
25519 }
25416 assert(ptr_type != nullptr);25520 assert(ptr_type != nullptr);
25417 if (ptr_type->id == ZigTypeIdPointer) {25521 if (ptr_type->id == ZigTypeIdPointer) {
25418 if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))25522 if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
25419 return err;25523 return err;
25524 } else if (is_slice(ptr_type)) {
25525 TypeStructField *ptr_field = ptr_type->data.structure.fields[slice_ptr_index];
25526 ZigType *slice_ptr_type = resolve_struct_field_type(ira->codegen, ptr_field);
25527 if ((err = type_resolve(ira->codegen, slice_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
25528 return err;
25420 }25529 }
2542125530
25422 *result_align = get_ptr_align(ira->codegen, ty);25531 *result_align = get_ptr_align(ira->codegen, ty);
...@@ -25871,6 +25980,7 @@ static IrInstGen *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstSrcMemset...@@ -25871,6 +25980,7 @@ static IrInstGen *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstSrcMemset
25871 start = 0;25980 start = 0;
25872 bound_end = 1;25981 bound_end = 1;
25873 break;25982 break;
25983 case ConstPtrSpecialSubArray:
25874 case ConstPtrSpecialBaseArray:25984 case ConstPtrSpecialBaseArray:
25875 {25985 {
25876 ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val;25986 ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val;
...@@ -26004,6 +26114,7 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy...@@ -26004,6 +26114,7 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy
26004 dest_start = 0;26114 dest_start = 0;
26005 dest_end = 1;26115 dest_end = 1;
26006 break;26116 break;
26117 case ConstPtrSpecialSubArray:
26007 case ConstPtrSpecialBaseArray:26118 case ConstPtrSpecialBaseArray:
26008 {26119 {
26009 ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val;26120 ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val;
...@@ -26047,6 +26158,7 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy...@@ -26047,6 +26158,7 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy
26047 src_start = 0;26158 src_start = 0;
26048 src_end = 1;26159 src_end = 1;
26049 break;26160 break;
26161 case ConstPtrSpecialSubArray:
26050 case ConstPtrSpecialBaseArray:26162 case ConstPtrSpecialBaseArray:
26051 {26163 {
26052 ZigValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val;26164 ZigValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val;
...@@ -26090,7 +26202,19 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy...@@ -26090,7 +26202,19 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy
26090 return ir_build_memcpy_gen(ira, &instruction->base.base, casted_dest_ptr, casted_src_ptr, casted_count);26202 return ir_build_memcpy_gen(ira, &instruction->base.base, casted_dest_ptr, casted_src_ptr, casted_count);
26091}26203}
2609226204
26205static ZigType *get_result_loc_type(IrAnalyze *ira, ResultLoc *result_loc) {
26206 if (result_loc == nullptr) return nullptr;
26207
26208 if (result_loc->id == ResultLocIdCast) {
26209 return ir_resolve_type(ira, result_loc->source_instruction->child);
26210 }
26211
26212 return nullptr;
26213}
26214
26093static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *instruction) {26215static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *instruction) {
26216 Error err;
26217
26094 IrInstGen *ptr_ptr = instruction->ptr->child;26218 IrInstGen *ptr_ptr = instruction->ptr->child;
26095 if (type_is_invalid(ptr_ptr->value->type))26219 if (type_is_invalid(ptr_ptr->value->type))
26096 return ira->codegen->invalid_inst_gen;26220 return ira->codegen->invalid_inst_gen;
...@@ -26120,6 +26244,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26120,6 +26244,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26120 end = nullptr;26244 end = nullptr;
26121 }26245 }
2612226246
26247 ZigValue *slice_sentinel_val = nullptr;
26123 ZigType *non_sentinel_slice_ptr_type;26248 ZigType *non_sentinel_slice_ptr_type;
26124 ZigType *elem_type;26249 ZigType *elem_type;
2612526250
...@@ -26170,6 +26295,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26170,6 +26295,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26170 }26295 }
26171 } else if (is_slice(array_type)) {26296 } else if (is_slice(array_type)) {
26172 ZigType *maybe_sentineled_slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry;26297 ZigType *maybe_sentineled_slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry;
26298 slice_sentinel_val = maybe_sentineled_slice_ptr_type->data.pointer.sentinel;
26173 non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr);26299 non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr);
26174 elem_type = non_sentinel_slice_ptr_type->data.pointer.child_type;26300 elem_type = non_sentinel_slice_ptr_type->data.pointer.child_type;
26175 } else {26301 } else {
...@@ -26178,7 +26304,6 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26178,7 +26304,6 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26178 return ira->codegen->invalid_inst_gen;26304 return ira->codegen->invalid_inst_gen;
26179 }26305 }
2618026306
26181 ZigType *return_type;
26182 ZigValue *sentinel_val = nullptr;26307 ZigValue *sentinel_val = nullptr;
26183 if (instruction->sentinel) {26308 if (instruction->sentinel) {
26184 IrInstGen *uncasted_sentinel = instruction->sentinel->child;26309 IrInstGen *uncasted_sentinel = instruction->sentinel->child;
...@@ -26190,11 +26315,76 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26190,11 +26315,76 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26190 sentinel_val = ir_resolve_const(ira, sentinel, UndefBad);26315 sentinel_val = ir_resolve_const(ira, sentinel, UndefBad);
26191 if (sentinel_val == nullptr)26316 if (sentinel_val == nullptr)
26192 return ira->codegen->invalid_inst_gen;26317 return ira->codegen->invalid_inst_gen;
26193 ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, sentinel_val);26318 }
26319
26320 ZigType *child_array_type = (array_type->id == ZigTypeIdPointer &&
26321 array_type->data.pointer.ptr_len == PtrLenSingle) ? array_type->data.pointer.child_type : array_type;
26322
26323 ZigType *return_type;
26324
26325 // If start index and end index are both comptime known, then the result type is a pointer to array
26326 // not a slice. However, if the start or end index is a lazy value, and the result location is a slice,
26327 // then the pointer-to-array would be casted to a slice anyway. So, we preserve the laziness of these
26328 // values by making the return type a slice.
26329 ZigType *res_loc_type = get_result_loc_type(ira, instruction->result_loc);
26330 bool result_loc_is_slice = (res_loc_type != nullptr && is_slice(res_loc_type));
26331 bool end_is_known = !result_loc_is_slice &&
26332 ((end != nullptr && value_is_comptime(end->value)) ||
26333 (end == nullptr && child_array_type->id == ZigTypeIdArray));
26334
26335 ZigValue *array_sentinel = sentinel_val;
26336 if (end_is_known) {
26337 uint64_t end_scalar;
26338 if (end != nullptr) {
26339 ZigValue *end_val = ir_resolve_const(ira, end, UndefBad);
26340 if (!end_val)
26341 return ira->codegen->invalid_inst_gen;
26342 end_scalar = bigint_as_u64(&end_val->data.x_bigint);
26343 } else {
26344 end_scalar = child_array_type->data.array.len;
26345 }
26346 array_sentinel = (child_array_type->id == ZigTypeIdArray && end_scalar == child_array_type->data.array.len)
26347 ? child_array_type->data.array.sentinel : sentinel_val;
26348
26349 if (value_is_comptime(casted_start->value)) {
26350 ZigValue *start_val = ir_resolve_const(ira, casted_start, UndefBad);
26351 if (!start_val)
26352 return ira->codegen->invalid_inst_gen;
26353
26354 uint64_t start_scalar = bigint_as_u64(&start_val->data.x_bigint);
26355
26356 if (start_scalar > end_scalar) {
26357 ir_add_error(ira, &instruction->base.base, buf_sprintf("out of bounds slice"));
26358 return ira->codegen->invalid_inst_gen;
26359 }
26360
26361 uint32_t base_ptr_align = non_sentinel_slice_ptr_type->data.pointer.explicit_alignment;
26362 uint32_t ptr_byte_alignment = 0;
26363 if (end_scalar > start_scalar) {
26364 if ((err = compute_elem_align(ira, elem_type, base_ptr_align, start_scalar, &ptr_byte_alignment)))
26365 return ira->codegen->invalid_inst_gen;
26366 }
26367
26368 ZigType *return_array_type = get_array_type(ira->codegen, elem_type, end_scalar - start_scalar,
26369 array_sentinel);
26370 return_type = get_pointer_to_type_extra(ira->codegen, return_array_type,
26371 non_sentinel_slice_ptr_type->data.pointer.is_const,
26372 non_sentinel_slice_ptr_type->data.pointer.is_volatile,
26373 PtrLenSingle, ptr_byte_alignment, 0, 0, false);
26374 goto done_with_return_type;
26375 }
26376 } else if (array_sentinel == nullptr && end == nullptr) {
26377 array_sentinel = slice_sentinel_val;
26378 }
26379 if (array_sentinel != nullptr) {
26380 // TODO deal with non-abi-alignment here
26381 ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, array_sentinel);
26194 return_type = get_slice_type(ira->codegen, slice_ptr_type);26382 return_type = get_slice_type(ira->codegen, slice_ptr_type);
26195 } else {26383 } else {
26384 // TODO deal with non-abi-alignment here
26196 return_type = get_slice_type(ira->codegen, non_sentinel_slice_ptr_type);26385 return_type = get_slice_type(ira->codegen, non_sentinel_slice_ptr_type);
26197 }26386 }
26387done_with_return_type:
2619826388
26199 if (instr_is_comptime(ptr_ptr) &&26389 if (instr_is_comptime(ptr_ptr) &&
26200 value_is_comptime(casted_start->value) &&26390 value_is_comptime(casted_start->value) &&
...@@ -26205,12 +26395,8 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26205,12 +26395,8 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26205 size_t abs_offset;26395 size_t abs_offset;
26206 size_t rel_end;26396 size_t rel_end;
26207 bool ptr_is_undef = false;26397 bool ptr_is_undef = false;
26208 if (array_type->id == ZigTypeIdArray ||26398 if (child_array_type->id == ZigTypeIdArray) {
26209 (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle))
26210 {
26211 if (array_type->id == ZigTypeIdPointer) {26399 if (array_type->id == ZigTypeIdPointer) {
26212 ZigType *child_array_type = array_type->data.pointer.child_type;
26213 assert(child_array_type->id == ZigTypeIdArray);
26214 parent_ptr = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.base.source_node);26400 parent_ptr = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.base.source_node);
26215 if (parent_ptr == nullptr)26401 if (parent_ptr == nullptr)
26216 return ira->codegen->invalid_inst_gen;26402 return ira->codegen->invalid_inst_gen;
...@@ -26221,6 +26407,10 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26221,6 +26407,10 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26221 abs_offset = 0;26407 abs_offset = 0;
26222 rel_end = SIZE_MAX;26408 rel_end = SIZE_MAX;
26223 ptr_is_undef = true;26409 ptr_is_undef = true;
26410 } else if (parent_ptr->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) {
26411 array_val = nullptr;
26412 abs_offset = 0;
26413 rel_end = SIZE_MAX;
26224 } else {26414 } else {
26225 array_val = const_ptr_pointee(ira, ira->codegen, parent_ptr, instruction->base.base.source_node);26415 array_val = const_ptr_pointee(ira, ira->codegen, parent_ptr, instruction->base.base.source_node);
26226 if (array_val == nullptr)26416 if (array_val == nullptr)
...@@ -26263,6 +26453,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26263,6 +26453,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26263 rel_end = 1;26453 rel_end = 1;
26264 }26454 }
26265 break;26455 break;
26456 case ConstPtrSpecialSubArray:
26266 case ConstPtrSpecialBaseArray:26457 case ConstPtrSpecialBaseArray:
26267 array_val = parent_ptr->data.x_ptr.data.base_array.array_val;26458 array_val = parent_ptr->data.x_ptr.data.base_array.array_val;
26268 abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index;26459 abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index;
...@@ -26313,6 +26504,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26313,6 +26504,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26313 abs_offset = SIZE_MAX;26504 abs_offset = SIZE_MAX;
26314 rel_end = 1;26505 rel_end = 1;
26315 break;26506 break;
26507 case ConstPtrSpecialSubArray:
26316 case ConstPtrSpecialBaseArray:26508 case ConstPtrSpecialBaseArray:
26317 array_val = parent_ptr->data.x_ptr.data.base_array.array_val;26509 array_val = parent_ptr->data.x_ptr.data.base_array.array_val;
26318 abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index;26510 abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index;
...@@ -26373,15 +26565,28 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26373,15 +26565,28 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26373 }26565 }
2637426566
26375 IrInstGen *result = ir_const(ira, &instruction->base.base, return_type);26567 IrInstGen *result = ir_const(ira, &instruction->base.base, return_type);
26376 ZigValue *out_val = result->value;
26377 out_val->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, 2);
2637826568
26379 ZigValue *ptr_val = out_val->data.x_struct.fields[slice_ptr_index];26569 ZigValue *ptr_val;
26570 if (return_type->id == ZigTypeIdPointer) {
26571 // pointer to array
26572 ptr_val = result->value;
26573 } else {
26574 // slice
26575 result->value->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, 2);
26576
26577 ptr_val = result->value->data.x_struct.fields[slice_ptr_index];
2638026578
26579 ZigValue *len_val = result->value->data.x_struct.fields[slice_len_index];
26580 init_const_usize(ira->codegen, len_val, end_scalar - start_scalar);
26581 }
26582
26583 bool return_type_is_const = non_sentinel_slice_ptr_type->data.pointer.is_const;
26381 if (array_val) {26584 if (array_val) {
26382 size_t index = abs_offset + start_scalar;26585 size_t index = abs_offset + start_scalar;
26383 bool is_const = slice_is_const(return_type);26586 init_const_ptr_array(ira->codegen, ptr_val, array_val, index, return_type_is_const, PtrLenUnknown);
26384 init_const_ptr_array(ira->codegen, ptr_val, array_val, index, is_const, PtrLenUnknown);26587 if (return_type->id == ZigTypeIdPointer) {
26588 ptr_val->data.x_ptr.special = ConstPtrSpecialSubArray;
26589 }
26385 if (array_type->id == ZigTypeIdArray) {26590 if (array_type->id == ZigTypeIdArray) {
26386 ptr_val->data.x_ptr.mut = ptr_ptr->value->data.x_ptr.mut;26591 ptr_val->data.x_ptr.mut = ptr_ptr->value->data.x_ptr.mut;
26387 } else if (is_slice(array_type)) {26592 } else if (is_slice(array_type)) {
...@@ -26391,16 +26596,17 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26391,16 +26596,17 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26391 }26596 }
26392 } else if (ptr_is_undef) {26597 } else if (ptr_is_undef) {
26393 ptr_val->type = get_pointer_to_type(ira->codegen, parent_ptr->type->data.pointer.child_type,26598 ptr_val->type = get_pointer_to_type(ira->codegen, parent_ptr->type->data.pointer.child_type,
26394 slice_is_const(return_type));26599 return_type_is_const);
26395 ptr_val->special = ConstValSpecialUndef;26600 ptr_val->special = ConstValSpecialUndef;
26396 } else switch (parent_ptr->data.x_ptr.special) {26601 } else switch (parent_ptr->data.x_ptr.special) {
26397 case ConstPtrSpecialInvalid:26602 case ConstPtrSpecialInvalid:
26398 case ConstPtrSpecialDiscard:26603 case ConstPtrSpecialDiscard:
26399 zig_unreachable();26604 zig_unreachable();
26400 case ConstPtrSpecialRef:26605 case ConstPtrSpecialRef:
26401 init_const_ptr_ref(ira->codegen, ptr_val,26606 init_const_ptr_ref(ira->codegen, ptr_val, parent_ptr->data.x_ptr.data.ref.pointee,
26402 parent_ptr->data.x_ptr.data.ref.pointee, slice_is_const(return_type));26607 return_type_is_const);
26403 break;26608 break;
26609 case ConstPtrSpecialSubArray:
26404 case ConstPtrSpecialBaseArray:26610 case ConstPtrSpecialBaseArray:
26405 zig_unreachable();26611 zig_unreachable();
26406 case ConstPtrSpecialBaseStruct:26612 case ConstPtrSpecialBaseStruct:
...@@ -26415,7 +26621,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26415,7 +26621,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26415 init_const_ptr_hard_coded_addr(ira->codegen, ptr_val,26621 init_const_ptr_hard_coded_addr(ira->codegen, ptr_val,
26416 parent_ptr->type->data.pointer.child_type,26622 parent_ptr->type->data.pointer.child_type,
26417 parent_ptr->data.x_ptr.data.hard_coded_addr.addr + start_scalar,26623 parent_ptr->data.x_ptr.data.hard_coded_addr.addr + start_scalar,
26418 slice_is_const(return_type));26624 return_type_is_const);
26419 break;26625 break;
26420 case ConstPtrSpecialFunction:26626 case ConstPtrSpecialFunction:
26421 zig_panic("TODO");26627 zig_panic("TODO");
...@@ -26423,26 +26629,11 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26423,26 +26629,11 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26423 zig_panic("TODO");26629 zig_panic("TODO");
26424 }26630 }
2642526631
26426 ZigValue *len_val = out_val->data.x_struct.fields[slice_len_index];26632 // In the case of pointer-to-array, we must restore this because above it overwrites ptr_val->type
26427 init_const_usize(ira->codegen, len_val, end_scalar - start_scalar);26633 result->value->type = return_type;
26428
26429 return result;26634 return result;
26430 }26635 }
2643126636
26432 IrInstGen *result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc,
26433 return_type, nullptr, true, true);
26434 if (result_loc != nullptr) {
26435 if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) {
26436 return result_loc;
26437 }
26438 IrInstGen *dummy_value = ir_const(ira, &instruction->base.base, return_type);
26439 dummy_value->value->special = ConstValSpecialRuntime;
26440 IrInstGen *dummy_result = ir_implicit_cast2(ira, &instruction->base.base,
26441 dummy_value, result_loc->value->type->data.pointer.child_type);
26442 if (type_is_invalid(dummy_result->value->type))
26443 return ira->codegen->invalid_inst_gen;
26444 }
26445
26446 if (generate_non_null_assert) {26637 if (generate_non_null_assert) {
26447 IrInstGen *ptr_val = ir_get_deref(ira, &instruction->base.base, ptr_ptr, nullptr);26638 IrInstGen *ptr_val = ir_get_deref(ira, &instruction->base.base, ptr_ptr, nullptr);
2644826639
...@@ -26452,8 +26643,26 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i...@@ -26452,8 +26643,26 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i
26452 ir_build_assert_non_null(ira, &instruction->base.base, ptr_val);26643 ir_build_assert_non_null(ira, &instruction->base.base, ptr_val);
26453 }26644 }
2645426645
26646 IrInstGen *result_loc = nullptr;
26647
26648 if (return_type->id != ZigTypeIdPointer) {
26649 result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc,
26650 return_type, nullptr, true, true);
26651 if (result_loc != nullptr) {
26652 if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) {
26653 return result_loc;
26654 }
26655 IrInstGen *dummy_value = ir_const(ira, &instruction->base.base, return_type);
26656 dummy_value->value->special = ConstValSpecialRuntime;
26657 IrInstGen *dummy_result = ir_implicit_cast2(ira, &instruction->base.base,
26658 dummy_value, result_loc->value->type->data.pointer.child_type);
26659 if (type_is_invalid(dummy_result->value->type))
26660 return ira->codegen->invalid_inst_gen;
26661 }
26662 }
26663
26455 return ir_build_slice_gen(ira, &instruction->base.base, return_type, ptr_ptr,26664 return ir_build_slice_gen(ira, &instruction->base.base, return_type, ptr_ptr,
26456 casted_start, end, instruction->safety_check_on, result_loc);26665 casted_start, end, instruction->safety_check_on, result_loc, sentinel_val);
26457}26666}
2645826667
26459static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasField *instruction) {26668static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasField *instruction) {
...@@ -27479,10 +27688,18 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn...@@ -27479,10 +27688,18 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
27479 // We have a check for zero bits later so we use get_src_ptr_type to27688 // We have a check for zero bits later so we use get_src_ptr_type to
27480 // validate src_type and dest_type.27689 // validate src_type and dest_type.
2748127690
27482 ZigType *src_ptr_type = get_src_ptr_type(src_type);27691 ZigType *if_slice_ptr_type;
27483 if (src_ptr_type == nullptr) {27692 if (is_slice(src_type)) {
27484 ir_add_error(ira, ptr_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name)));27693 TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index];
27485 return ira->codegen->invalid_inst_gen;27694 if_slice_ptr_type = resolve_struct_field_type(ira->codegen, ptr_field);
27695 } else {
27696 if_slice_ptr_type = src_type;
27697
27698 ZigType *src_ptr_type = get_src_ptr_type(src_type);
27699 if (src_ptr_type == nullptr) {
27700 ir_add_error(ira, ptr_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name)));
27701 return ira->codegen->invalid_inst_gen;
27702 }
27486 }27703 }
2748727704
27488 ZigType *dest_ptr_type = get_src_ptr_type(dest_type);27705 ZigType *dest_ptr_type = get_src_ptr_type(dest_type);
...@@ -27492,7 +27709,7 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn...@@ -27492,7 +27709,7 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
27492 return ira->codegen->invalid_inst_gen;27709 return ira->codegen->invalid_inst_gen;
27493 }27710 }
2749427711
27495 if (get_ptr_const(src_type) && !get_ptr_const(dest_type)) {27712 if (get_ptr_const(ira->codegen, src_type) && !get_ptr_const(ira->codegen, dest_type)) {
27496 ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier"));27713 ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier"));
27497 return ira->codegen->invalid_inst_gen;27714 return ira->codegen->invalid_inst_gen;
27498 }27715 }
...@@ -27510,7 +27727,10 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn...@@ -27510,7 +27727,10 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
27510 if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown)))27727 if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown)))
27511 return ira->codegen->invalid_inst_gen;27728 return ira->codegen->invalid_inst_gen;
2751227729
27513 if (type_has_bits(ira->codegen, dest_type) && !type_has_bits(ira->codegen, src_type) && safety_check_on) {27730 if (safety_check_on &&
27731 type_has_bits(ira->codegen, dest_type) &&
27732 !type_has_bits(ira->codegen, if_slice_ptr_type))
27733 {
27514 ErrorMsg *msg = ir_add_error(ira, source_instr,27734 ErrorMsg *msg = ir_add_error(ira, source_instr,
27515 buf_sprintf("'%s' and '%s' do not have the same in-memory representation",27735 buf_sprintf("'%s' and '%s' do not have the same in-memory representation",
27516 buf_ptr(&src_type->name), buf_ptr(&dest_type->name)));27736 buf_ptr(&src_type->name), buf_ptr(&dest_type->name)));
...@@ -27521,6 +27741,14 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn...@@ -27521,6 +27741,14 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
27521 return ira->codegen->invalid_inst_gen;27741 return ira->codegen->invalid_inst_gen;
27522 }27742 }
2752327743
27744 // For slices, follow the `ptr` field.
27745 if (is_slice(src_type)) {
27746 TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index];
27747 IrInstGen *ptr_ref = ir_get_ref(ira, source_instr, ptr, true, false);
27748 IrInstGen *ptr_ptr = ir_analyze_struct_field_ptr(ira, source_instr, ptr_field, ptr_ref, src_type, false);
27749 ptr = ir_get_deref(ira, source_instr, ptr_ptr, nullptr);
27750 }
27751
27524 if (instr_is_comptime(ptr)) {27752 if (instr_is_comptime(ptr)) {
27525 bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type);27753 bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type);
27526 UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad;27754 UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad;
...@@ -27624,6 +27852,9 @@ static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ZigValue...@@ -27624,6 +27852,9 @@ static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ZigValue
27624 buf_write_value_bytes(codegen, &buf[buf_i], elem);27852 buf_write_value_bytes(codegen, &buf[buf_i], elem);
27625 buf_i += type_size(codegen, elem->type);27853 buf_i += type_size(codegen, elem->type);
27626 }27854 }
27855 if (val->type->id == ZigTypeIdArray && val->type->data.array.sentinel != nullptr) {
27856 buf_write_value_bytes(codegen, &buf[buf_i], val->type->data.array.sentinel);
27857 }
27627}27858}
2762827859
27629static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ZigValue *val) {27860static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ZigValue *val) {
src/link.cpp+1
...@@ -566,6 +566,7 @@ static const char *build_libc_object(CodeGen *parent_gen, const char *name, CFil...@@ -566,6 +566,7 @@ static const char *build_libc_object(CodeGen *parent_gen, const char *name, CFil
566 Stage2ProgressNode *progress_node)566 Stage2ProgressNode *progress_node)
567{567{
568 CodeGen *child_gen = create_child_codegen(parent_gen, nullptr, OutTypeObj, nullptr, name, progress_node);568 CodeGen *child_gen = create_child_codegen(parent_gen, nullptr, OutTypeObj, nullptr, name, progress_node);
569 child_gen->root_out_name = buf_create_from_str(name);
569 ZigList<CFile *> c_source_files = {0};570 ZigList<CFile *> c_source_files = {0};
570 c_source_files.append(c_file);571 c_source_files.append(c_file);
571 child_gen->c_source_files = c_source_files;572 child_gen->c_source_files = c_source_files;
src/main.cpp+2-1
...@@ -1291,6 +1291,7 @@ static int main0(int argc, char **argv) {...@@ -1291,6 +1291,7 @@ static int main0(int argc, char **argv) {
1291 if (g->enable_cache) {1291 if (g->enable_cache) {
1292#if defined(ZIG_OS_WINDOWS)1292#if defined(ZIG_OS_WINDOWS)
1293 buf_replace(&g->bin_file_output_path, '/', '\\');1293 buf_replace(&g->bin_file_output_path, '/', '\\');
1294 buf_replace(g->output_dir, '/', '\\');
1294#endif1295#endif
1295 if (final_output_dir_step != nullptr) {1296 if (final_output_dir_step != nullptr) {
1296 Buf *dest_basename = buf_alloc();1297 Buf *dest_basename = buf_alloc();
...@@ -1304,7 +1305,7 @@ static int main0(int argc, char **argv) {...@@ -1304,7 +1305,7 @@ static int main0(int argc, char **argv) {
1304 return main_exit(root_progress_node, EXIT_FAILURE);1305 return main_exit(root_progress_node, EXIT_FAILURE);
1305 }1306 }
1306 } else {1307 } else {
1307 if (printf("%s\n", buf_ptr(&g->bin_file_output_path)) < 0)1308 if (printf("%s\n", buf_ptr(g->output_dir)) < 0)
1308 return main_exit(root_progress_node, EXIT_FAILURE);1309 return main_exit(root_progress_node, EXIT_FAILURE);
1309 }1310 }
1310 }1311 }
test/cli.zig+1-1
...@@ -36,7 +36,7 @@ pub fn main() !void {...@@ -36,7 +36,7 @@ pub fn main() !void {
36 testMissingOutputPath,36 testMissingOutputPath,
37 };37 };
38 for (test_fns) |testFn| {38 for (test_fns) |testFn| {
39 try fs.deleteTree(dir_path);39 try fs.cwd().deleteTree(dir_path);
40 try fs.cwd().makeDir(dir_path);40 try fs.cwd().makeDir(dir_path);
41 try testFn(zig_exe, dir_path);41 try testFn(zig_exe, dir_path);
42 }42 }
test/compare_output.zig+1-1
...@@ -292,7 +292,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -292,7 +292,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
292 \\pub export fn main() c_int {292 \\pub export fn main() c_int {
293 \\ var array = [_]u32{ 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 };293 \\ var array = [_]u32{ 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 };
294 \\294 \\
295 \\ c.qsort(@ptrCast(?*c_void, array[0..].ptr), @intCast(c_ulong, array.len), @sizeOf(i32), compare_fn);295 \\ c.qsort(@ptrCast(?*c_void, &array), @intCast(c_ulong, array.len), @sizeOf(i32), compare_fn);
296 \\296 \\
297 \\ for (array) |item, i| {297 \\ for (array) |item, i| {
298 \\ if (item != i) {298 \\ if (item != i) {
test/compile_errors.zig+2-14
...@@ -103,18 +103,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -103,18 +103,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
103 "tmp.zig:3:23: error: pointer to size 0 type has no address",103 "tmp.zig:3:23: error: pointer to size 0 type has no address",
104 });104 });
105105
106 cases.addTest("slice to pointer conversion mismatch",
107 \\pub fn bytesAsSlice(bytes: var) [*]align(1) const u16 {
108 \\ return @ptrCast([*]align(1) const u16, bytes.ptr)[0..1];
109 \\}
110 \\test "bytesAsSlice" {
111 \\ const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
112 \\ const slice = bytesAsSlice(bytes[0..]);
113 \\}
114 , &[_][]const u8{
115 "tmp.zig:2:54: error: expected type '[*]align(1) const u16', found '[]align(1) const u16'",
116 });
117
118 cases.addTest("access invalid @typeInfo decl",106 cases.addTest("access invalid @typeInfo decl",
119 \\const A = B;107 \\const A = B;
120 \\test "Crash" {108 \\test "Crash" {
...@@ -1918,8 +1906,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1918,8 +1906,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1918 cases.add("reading past end of pointer casted array",1906 cases.add("reading past end of pointer casted array",
1919 \\comptime {1907 \\comptime {
1920 \\ const array: [4]u8 = "aoeu".*;1908 \\ const array: [4]u8 = "aoeu".*;
1921 \\ const slice = array[1..];1909 \\ const sub_array = array[1..];
1922 \\ const int_ptr = @ptrCast(*const u24, slice.ptr);1910 \\ const int_ptr = @ptrCast(*const u24, sub_array);
1923 \\ const deref = int_ptr.*;1911 \\ const deref = int_ptr.*;
1924 \\}1912 \\}
1925 , &[_][]const u8{1913 , &[_][]const u8{
test/runtime_safety.zig+1-1
...@@ -69,7 +69,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {...@@ -69,7 +69,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
69 \\}69 \\}
70 \\pub fn main() void {70 \\pub fn main() void {
71 \\ var buf: [4]u8 = undefined;71 \\ var buf: [4]u8 = undefined;
72 \\ const ptr = buf[0..].ptr;72 \\ const ptr: [*]u8 = &buf;
73 \\ const slice = ptr[0..3 :0];73 \\ const slice = ptr[0..3 :0];
74 \\}74 \\}
75 );75 );
test/stage1/behavior/align.zig+22-14
...@@ -5,10 +5,17 @@ const builtin = @import("builtin");...@@ -5,10 +5,17 @@ const builtin = @import("builtin");
5var foo: u8 align(4) = 100;5var foo: u8 align(4) = 100;
66
7test "global variable alignment" {7test "global variable alignment" {
8 expect(@TypeOf(&foo).alignment == 4);8 comptime expect(@TypeOf(&foo).alignment == 4);
9 expect(@TypeOf(&foo) == *align(4) u8);9 comptime expect(@TypeOf(&foo) == *align(4) u8);
10 const slice = @as(*[1]u8, &foo)[0..];10 {
11 expect(@TypeOf(slice) == []align(4) u8);11 const slice = @as(*[1]u8, &foo)[0..];
12 comptime expect(@TypeOf(slice) == *align(4) [1]u8);
13 }
14 {
15 var runtime_zero: usize = 0;
16 const slice = @as(*[1]u8, &foo)[runtime_zero..];
17 comptime expect(@TypeOf(slice) == []align(4) u8);
18 }
12}19}
1320
14fn derp() align(@sizeOf(usize) * 2) i32 {21fn derp() align(@sizeOf(usize) * 2) i32 {
...@@ -171,18 +178,19 @@ test "runtime known array index has best alignment possible" {...@@ -171,18 +178,19 @@ test "runtime known array index has best alignment possible" {
171178
172 // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2179 // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2
173 var smaller align(2) = [_]u32{ 1, 2, 3, 4 };180 var smaller align(2) = [_]u32{ 1, 2, 3, 4 };
174 comptime expect(@TypeOf(smaller[0..]) == []align(2) u32);181 var runtime_zero: usize = 0;
175 comptime expect(@TypeOf(smaller[0..].ptr) == [*]align(2) u32);182 comptime expect(@TypeOf(smaller[runtime_zero..]) == []align(2) u32);
176 testIndex(smaller[0..].ptr, 0, *align(2) u32);183 comptime expect(@TypeOf(smaller[runtime_zero..].ptr) == [*]align(2) u32);
177 testIndex(smaller[0..].ptr, 1, *align(2) u32);184 testIndex(smaller[runtime_zero..].ptr, 0, *align(2) u32);
178 testIndex(smaller[0..].ptr, 2, *align(2) u32);185 testIndex(smaller[runtime_zero..].ptr, 1, *align(2) u32);
179 testIndex(smaller[0..].ptr, 3, *align(2) u32);186 testIndex(smaller[runtime_zero..].ptr, 2, *align(2) u32);
187 testIndex(smaller[runtime_zero..].ptr, 3, *align(2) u32);
180188
181 // has to use ABI alignment because index known at runtime only189 // has to use ABI alignment because index known at runtime only
182 testIndex2(array[0..].ptr, 0, *u8);190 testIndex2(array[runtime_zero..].ptr, 0, *u8);
183 testIndex2(array[0..].ptr, 1, *u8);191 testIndex2(array[runtime_zero..].ptr, 1, *u8);
184 testIndex2(array[0..].ptr, 2, *u8);192 testIndex2(array[runtime_zero..].ptr, 2, *u8);
185 testIndex2(array[0..].ptr, 3, *u8);193 testIndex2(array[runtime_zero..].ptr, 3, *u8);
186}194}
187fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void {195fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void {
188 comptime expect(@TypeOf(&smaller[index]) == T);196 comptime expect(@TypeOf(&smaller[index]) == T);
test/stage1/behavior/array.zig+38
...@@ -28,6 +28,24 @@ fn getArrayLen(a: []const u32) usize {...@@ -28,6 +28,24 @@ fn getArrayLen(a: []const u32) usize {
28 return a.len;28 return a.len;
29}29}
3030
31test "array with sentinels" {
32 const S = struct {
33 fn doTheTest(is_ct: bool) void {
34 var zero_sized: [0:0xde]u8 = [_:0xde]u8{};
35 expectEqual(@as(u8, 0xde), zero_sized[0]);
36 // Disabled at runtime because of
37 // https://github.com/ziglang/zig/issues/4372
38 if (is_ct) {
39 var reinterpreted = @ptrCast(*[1]u8, &zero_sized);
40 expectEqual(@as(u8, 0xde), reinterpreted[0]);
41 }
42 }
43 };
44
45 S.doTheTest(false);
46 comptime S.doTheTest(true);
47}
48
31test "void arrays" {49test "void arrays" {
32 var array: [4]void = undefined;50 var array: [4]void = undefined;
33 array[0] = void{};51 array[0] = void{};
...@@ -376,3 +394,23 @@ test "type deduction for array subscript expression" {...@@ -376,3 +394,23 @@ test "type deduction for array subscript expression" {
376 S.doTheTest();394 S.doTheTest();
377 comptime S.doTheTest();395 comptime S.doTheTest();
378}396}
397
398test "sentinel element count towards the ABI size calculation" {
399 const S = struct {
400 fn doTheTest() void {
401 const T = packed struct {
402 fill_pre: u8 = 0x55,
403 data: [0:0]u8 = undefined,
404 fill_post: u8 = 0xAA,
405 };
406 var x = T{};
407 var as_slice = mem.asBytes(&x);
408 expectEqual(@as(usize, 3), as_slice.len);
409 expectEqual(@as(u8, 0x55), as_slice[0]);
410 expectEqual(@as(u8, 0xAA), as_slice[2]);
411 }
412 };
413
414 S.doTheTest();
415 comptime S.doTheTest();
416}
test/stage1/behavior/cast.zig+2-1
...@@ -431,7 +431,8 @@ fn incrementVoidPtrValue(value: ?*c_void) void {...@@ -431,7 +431,8 @@ fn incrementVoidPtrValue(value: ?*c_void) void {
431431
432test "implicit cast from [*]T to ?*c_void" {432test "implicit cast from [*]T to ?*c_void" {
433 var a = [_]u8{ 3, 2, 1 };433 var a = [_]u8{ 3, 2, 1 };
434 incrementVoidPtrArray(a[0..].ptr, 3);434 var runtime_zero: usize = 0;
435 incrementVoidPtrArray(a[runtime_zero..].ptr, 3);
435 expect(std.mem.eql(u8, &a, &[_]u8{ 4, 3, 2 }));436 expect(std.mem.eql(u8, &a, &[_]u8{ 4, 3, 2 }));
436}437}
437438
test/stage1/behavior/eval.zig+1-1
...@@ -524,7 +524,7 @@ test "comptime slice of slice preserves comptime var" {...@@ -524,7 +524,7 @@ test "comptime slice of slice preserves comptime var" {
524test "comptime slice of pointer preserves comptime var" {524test "comptime slice of pointer preserves comptime var" {
525 comptime {525 comptime {
526 var buff: [10]u8 = undefined;526 var buff: [10]u8 = undefined;
527 var a = buff[0..].ptr;527 var a = @ptrCast([*]u8, &buff);
528 a[0..1][0] = 1;528 a[0..1][0] = 1;
529 expect(buff[0..][0..][0] == 1);529 expect(buff[0..][0..][0] == 1);
530 }530 }
test/stage1/behavior/misc.zig+9-5
...@@ -102,8 +102,8 @@ test "memcpy and memset intrinsics" {...@@ -102,8 +102,8 @@ test "memcpy and memset intrinsics" {
102 var foo: [20]u8 = undefined;102 var foo: [20]u8 = undefined;
103 var bar: [20]u8 = undefined;103 var bar: [20]u8 = undefined;
104104
105 @memset(foo[0..].ptr, 'A', foo.len);105 @memset(&foo, 'A', foo.len);
106 @memcpy(bar[0..].ptr, foo[0..].ptr, bar.len);106 @memcpy(&bar, &foo, bar.len);
107107
108 if (bar[11] != 'A') unreachable;108 if (bar[11] != 'A') unreachable;
109}109}
...@@ -565,12 +565,16 @@ test "volatile load and store" {...@@ -565,12 +565,16 @@ test "volatile load and store" {
565 expect(ptr.* == 1235);565 expect(ptr.* == 1235);
566}566}
567567
568test "slice string literal has type []const u8" {568test "slice string literal has correct type" {
569 comptime {569 comptime {
570 expect(@TypeOf("aoeu"[0..]) == []const u8);570 expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8);
571 const array = [_]i32{ 1, 2, 3, 4 };571 const array = [_]i32{ 1, 2, 3, 4 };
572 expect(@TypeOf(array[0..]) == []const i32);572 expect(@TypeOf(array[0..]) == *const [4]i32);
573 }573 }
574 var runtime_zero: usize = 0;
575 comptime expect(@TypeOf("aoeu"[runtime_zero..]) == [:0]const u8);
576 const array = [_]i32{ 1, 2, 3, 4 };
577 comptime expect(@TypeOf(array[runtime_zero..]) == []const i32);
574}578}
575579
576test "pointer child field" {580test "pointer child field" {
test/stage1/behavior/pointers.zig+5-4
...@@ -159,12 +159,13 @@ test "allowzero pointer and slice" {...@@ -159,12 +159,13 @@ test "allowzero pointer and slice" {
159 var opt_ptr: ?[*]allowzero i32 = ptr;159 var opt_ptr: ?[*]allowzero i32 = ptr;
160 expect(opt_ptr != null);160 expect(opt_ptr != null);
161 expect(@ptrToInt(ptr) == 0);161 expect(@ptrToInt(ptr) == 0);
162 var slice = ptr[0..10];162 var runtime_zero: usize = 0;
163 expect(@TypeOf(slice) == []allowzero i32);163 var slice = ptr[runtime_zero..10];
164 comptime expect(@TypeOf(slice) == []allowzero i32);
164 expect(@ptrToInt(&slice[5]) == 20);165 expect(@ptrToInt(&slice[5]) == 20);
165166
166 expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero);167 comptime expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero);
167 expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero);168 comptime expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero);
168}169}
169170
170test "assign null directly to C pointer and test null equality" {171test "assign null directly to C pointer and test null equality" {
test/stage1/behavior/ptrcast.zig+1-1
...@@ -13,7 +13,7 @@ fn testReinterpretBytesAsInteger() void {...@@ -13,7 +13,7 @@ fn testReinterpretBytesAsInteger() void {
13 builtin.Endian.Little => 0xab785634,13 builtin.Endian.Little => 0xab785634,
14 builtin.Endian.Big => 0x345678ab,14 builtin.Endian.Big => 0x345678ab,
15 };15 };
16 expect(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected);16 expect(@ptrCast(*align(1) const u32, bytes[1..5]).* == expected);
17}17}
1818
19test "reinterpret bytes of an array into an extern struct" {19test "reinterpret bytes of an array into an extern struct" {
test/stage1/behavior/slice.zig+155-4
...@@ -7,10 +7,10 @@ const mem = std.mem;...@@ -7,10 +7,10 @@ const mem = std.mem;
7const x = @intToPtr([*]i32, 0x1000)[0..0x500];7const x = @intToPtr([*]i32, 0x1000)[0..0x500];
8const y = x[0x100..];8const y = x[0x100..];
9test "compile time slice of pointer to hard coded address" {9test "compile time slice of pointer to hard coded address" {
10 expect(@ptrToInt(x.ptr) == 0x1000);10 expect(@ptrToInt(x) == 0x1000);
11 expect(x.len == 0x500);11 expect(x.len == 0x500);
1212
13 expect(@ptrToInt(y.ptr) == 0x1100);13 expect(@ptrToInt(y) == 0x1100);
14 expect(y.len == 0x400);14 expect(y.len == 0x400);
15}15}
1616
...@@ -47,7 +47,9 @@ test "C pointer slice access" {...@@ -47,7 +47,9 @@ test "C pointer slice access" {
47 var buf: [10]u32 = [1]u32{42} ** 10;47 var buf: [10]u32 = [1]u32{42} ** 10;
48 const c_ptr = @ptrCast([*c]const u32, &buf);48 const c_ptr = @ptrCast([*c]const u32, &buf);
4949
50 comptime expectEqual([]const u32, @TypeOf(c_ptr[0..1]));50 var runtime_zero: usize = 0;
51 comptime expectEqual([]const u32, @TypeOf(c_ptr[runtime_zero..1]));
52 comptime expectEqual(*const [1]u32, @TypeOf(c_ptr[0..1]));
5153
52 for (c_ptr[0..5]) |*cl| {54 for (c_ptr[0..5]) |*cl| {
53 expectEqual(@as(u32, 42), cl.*);55 expectEqual(@as(u32, 42), cl.*);
...@@ -107,7 +109,9 @@ test "obtaining a null terminated slice" {...@@ -107,7 +109,9 @@ test "obtaining a null terminated slice" {
107 const ptr2 = buf[0..runtime_len :0];109 const ptr2 = buf[0..runtime_len :0];
108 // ptr2 is a null-terminated slice110 // ptr2 is a null-terminated slice
109 comptime expect(@TypeOf(ptr2) == [:0]u8);111 comptime expect(@TypeOf(ptr2) == [:0]u8);
110 comptime expect(@TypeOf(ptr2[0..2]) == []u8);112 comptime expect(@TypeOf(ptr2[0..2]) == *[2]u8);
113 var runtime_zero: usize = 0;
114 comptime expect(@TypeOf(ptr2[runtime_zero..2]) == []u8);
111}115}
112116
113test "empty array to slice" {117test "empty array to slice" {
...@@ -126,3 +130,150 @@ test "empty array to slice" {...@@ -126,3 +130,150 @@ test "empty array to slice" {
126 S.doTheTest();130 S.doTheTest();
127 comptime S.doTheTest();131 comptime S.doTheTest();
128}132}
133
134test "@ptrCast slice to pointer" {
135 const S = struct {
136 fn doTheTest() void {
137 var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff };
138 var slice: []u8 = &array;
139 var ptr = @ptrCast(*u16, slice);
140 expect(ptr.* == 65535);
141 }
142 };
143
144 S.doTheTest();
145 comptime S.doTheTest();
146}
147
148test "slice syntax resulting in pointer-to-array" {
149 const S = struct {
150 fn doTheTest() void {
151 testArray();
152 testArrayZ();
153 testArray0();
154 testArrayAlign();
155 testPointer();
156 testPointerZ();
157 testPointer0();
158 testPointerAlign();
159 testSlice();
160 testSliceZ();
161 testSlice0();
162 testSliceAlign();
163 }
164
165 fn testArray() void {
166 var array = [5]u8{ 1, 2, 3, 4, 5 };
167 var slice = array[1..3];
168 comptime expect(@TypeOf(slice) == *[2]u8);
169 expect(slice[0] == 2);
170 expect(slice[1] == 3);
171 }
172
173 fn testArrayZ() void {
174 var array = [5:0]u8{ 1, 2, 3, 4, 5 };
175 comptime expect(@TypeOf(array[1..3]) == *[2]u8);
176 comptime expect(@TypeOf(array[1..5]) == *[4:0]u8);
177 comptime expect(@TypeOf(array[1..]) == *[4:0]u8);
178 comptime expect(@TypeOf(array[1..3 :4]) == *[2:4]u8);
179 }
180
181 fn testArray0() void {
182 {
183 var array = [0]u8{};
184 var slice = array[0..0];
185 comptime expect(@TypeOf(slice) == *[0]u8);
186 }
187 {
188 var array = [0:0]u8{};
189 var slice = array[0..0];
190 comptime expect(@TypeOf(slice) == *[0:0]u8);
191 expect(slice[0] == 0);
192 }
193 }
194
195 fn testArrayAlign() void {
196 var array align(4) = [5]u8{ 1, 2, 3, 4, 5 };
197 var slice = array[4..5];
198 comptime expect(@TypeOf(slice) == *align(4) [1]u8);
199 expect(slice[0] == 5);
200 comptime expect(@TypeOf(array[0..2]) == *align(4) [2]u8);
201 }
202
203 fn testPointer() void {
204 var array = [5]u8{ 1, 2, 3, 4, 5 };
205 var pointer: [*]u8 = &array;
206 var slice = pointer[1..3];
207 comptime expect(@TypeOf(slice) == *[2]u8);
208 expect(slice[0] == 2);
209 expect(slice[1] == 3);
210 }
211
212 fn testPointerZ() void {
213 var array = [5:0]u8{ 1, 2, 3, 4, 5 };
214 var pointer: [*:0]u8 = &array;
215 comptime expect(@TypeOf(pointer[1..3]) == *[2]u8);
216 comptime expect(@TypeOf(pointer[1..3 :4]) == *[2:4]u8);
217 }
218
219 fn testPointer0() void {
220 var pointer: [*]u0 = &[1]u0{0};
221 var slice = pointer[0..1];
222 comptime expect(@TypeOf(slice) == *[1]u0);
223 expect(slice[0] == 0);
224 }
225
226 fn testPointerAlign() void {
227 var array align(4) = [5]u8{ 1, 2, 3, 4, 5 };
228 var pointer: [*]align(4) u8 = &array;
229 var slice = pointer[4..5];
230 comptime expect(@TypeOf(slice) == *align(4) [1]u8);
231 expect(slice[0] == 5);
232 comptime expect(@TypeOf(pointer[0..2]) == *align(4) [2]u8);
233 }
234
235 fn testSlice() void {
236 var array = [5]u8{ 1, 2, 3, 4, 5 };
237 var src_slice: []u8 = &array;
238 var slice = src_slice[1..3];
239 comptime expect(@TypeOf(slice) == *[2]u8);
240 expect(slice[0] == 2);
241 expect(slice[1] == 3);
242 }
243
244 fn testSliceZ() void {
245 var array = [5:0]u8{ 1, 2, 3, 4, 5 };
246 var slice: [:0]u8 = &array;
247 comptime expect(@TypeOf(slice[1..3]) == *[2]u8);
248 comptime expect(@TypeOf(slice[1..]) == [:0]u8);
249 comptime expect(@TypeOf(slice[1..3 :4]) == *[2:4]u8);
250 }
251
252 fn testSlice0() void {
253 {
254 var array = [0]u8{};
255 var src_slice: []u8 = &array;
256 var slice = src_slice[0..0];
257 comptime expect(@TypeOf(slice) == *[0]u8);
258 }
259 {
260 var array = [0:0]u8{};
261 var src_slice: [:0]u8 = &array;
262 var slice = src_slice[0..0];
263 comptime expect(@TypeOf(slice) == *[0]u8);
264 }
265 }
266
267 fn testSliceAlign() void {
268 var array align(4) = [5]u8{ 1, 2, 3, 4, 5 };
269 var src_slice: []align(4) u8 = &array;
270 var slice = src_slice[4..5];
271 comptime expect(@TypeOf(slice) == *align(4) [1]u8);
272 expect(slice[0] == 5);
273 comptime expect(@TypeOf(src_slice[0..2]) == *align(4) [2]u8);
274 }
275 };
276
277 S.doTheTest();
278 comptime S.doTheTest();
279}
test/stage1/behavior/struct.zig+2-2
...@@ -409,8 +409,8 @@ const Bitfields = packed struct {...@@ -409,8 +409,8 @@ const Bitfields = packed struct {
409test "native bit field understands endianness" {409test "native bit field understands endianness" {
410 var all: u64 = 0x7765443322221111;410 var all: u64 = 0x7765443322221111;
411 var bytes: [8]u8 = undefined;411 var bytes: [8]u8 = undefined;
412 @memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8);412 @memcpy(&bytes, @ptrCast([*]u8, &all), 8);
413 var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*;413 var bitfields = @ptrCast(*Bitfields, &bytes).*;
414414
415 expect(bitfields.f1 == 0x1111);415 expect(bitfields.f1 == 0x1111);
416 expect(bitfields.f2 == 0x2222);416 expect(bitfields.f2 == 0x2222);