| author | |
| committer | |
| log | 53b5aa812bd9c0229054121a1c196c9b18994d64 |
| tree | 3c2961c8b70690351a25d3cee22fd52bbb11a60f |
| parent | 75bda408cd69f3d3b0cdb00caa26eb8cbeab5f3e |
| parent | 28a6c136e9dc9bcf3e04ab0aa38edc21918c78b9 |
| signature |
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 | 305 | dependOnLib(b, exe, ctx.llvm); |
| 306 | 306 | |
| 307 | 307 | if (exe.target.getOsTag() == .linux) { |
| 308 | try addCxxKnownPath(b, ctx, exe, "libstdc++.a", | |
| 309 | \\Unable to determine path to libstdc++.a | |
| 310 | \\On Fedora, install libstdc++-static and try again. | |
| 311 | ); | |
| 308 | // First we try to static link against gcc libstdc++. If that doesn't work, | |
| 309 | // we fall back to -lc++ and cross our fingers. | |
| 310 | addCxxKnownPath(b, ctx, exe, "libstdc++.a", "") catch |err| switch (err) { | |
| 311 | error.RequiredLibraryNotFound => { | |
| 312 | exe.linkSystemLibrary("c++"); | |
| 313 | }, | |
| 314 | else => |e| return e, | |
| 315 | }; | |
| 312 | 316 | |
| 313 | 317 | exe.linkSystemLibrary("pthread"); |
| 314 | 318 | } else if (exe.target.isFreeBSD()) { |
| ... | ... | @@ -327,7 +331,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { |
| 327 | 331 | // System compiler, not gcc. |
| 328 | 332 | exe.linkSystemLibrary("c++"); |
| 329 | 333 | }, |
| 330 | else => return err, | |
| 334 | else => |e| return e, | |
| 331 | 335 | } |
| 332 | 336 | } |
| 333 | 337 |
doc/docgen.zig+19-3| ... | ... | @@ -48,7 +48,7 @@ pub fn main() !void { |
| 48 | 48 | var toc = try genToc(allocator, &tokenizer); |
| 49 | 49 | |
| 50 | 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 {}; | |
| 52 | 52 | |
| 53 | 53 | try genHtml(allocator, &tokenizer, &toc, buffered_out_stream.outStream(), zig_exe); |
| 54 | 54 | try buffered_out_stream.flush(); |
| ... | ... | @@ -1096,6 +1096,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var |
| 1096 | 1096 | try build_args.append("-lc"); |
| 1097 | 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 | 1102 | if (code.target_str) |triple| { |
| 1100 | 1103 | try build_args.appendSlice(&[_][]const u8{ "-target", triple }); |
| 1101 | 1104 | if (!code.is_inline) { |
| ... | ... | @@ -1150,7 +1153,15 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var |
| 1150 | 1153 | } |
| 1151 | 1154 | } |
| 1152 | 1155 | |
| 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 | 1165 | const run_args = &[_][]const u8{path_to_exe}; |
| 1155 | 1166 | |
| 1156 | 1167 | var exited_with_signal = false; |
| ... | ... | @@ -1486,7 +1497,12 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var |
| 1486 | 1497 | } |
| 1487 | 1498 | |
| 1488 | 1499 | fn 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 | 1506 | switch (result.term) { |
| 1491 | 1507 | .Exited => |exit_code| { |
| 1492 | 1508 | if (exit_code != 0) { |
doc/langref.html.in+16-20| ... | ... | @@ -2093,8 +2093,9 @@ var foo: u8 align(4) = 100; |
| 2093 | 2093 | test "global variable alignment" { |
| 2094 | 2094 | assert(@TypeOf(&foo).alignment == 4); |
| 2095 | 2095 | assert(@TypeOf(&foo) == *align(4) u8); |
| 2096 | const slice = @as(*[1]u8, &foo)[0..]; | |
| 2097 | assert(@TypeOf(slice) == []align(4) u8); | |
| 2096 | const as_pointer_to_array: *[1]u8 = &foo; | |
| 2097 | const as_slice: []u8 = as_pointer_to_array; | |
| 2098 | assert(@TypeOf(as_slice) == []align(4) u8); | |
| 2098 | 2099 | } |
| 2099 | 2100 | |
| 2100 | 2101 | fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; } |
| ... | ... | @@ -2187,7 +2188,8 @@ test "basic slices" { |
| 2187 | 2188 | // a slice is that the array's length is part of the type and known at |
| 2188 | 2189 | // compile-time, whereas the slice's length is known at runtime. |
| 2189 | 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 | 2193 | assert(&slice[0] == &array[0]); |
| 2192 | 2194 | assert(slice.len == array.len); |
| 2193 | 2195 | |
| ... | ... | @@ -2207,13 +2209,15 @@ test "basic slices" { |
| 2207 | 2209 | {#code_end#} |
| 2208 | 2210 | <p>This is one reason we prefer slices to pointers.</p> |
| 2209 | 2211 | {#code_begin|test|slices#} |
| 2210 | const assert = @import("std").debug.assert; | |
| 2211 | const mem = @import("std").mem; | |
| 2212 | const fmt = @import("std").fmt; | |
| 2212 | const std = @import("std"); | |
| 2213 | const assert = std.debug.assert; | |
| 2214 | const mem = std.mem; | |
| 2215 | const fmt = std.fmt; | |
| 2213 | 2216 | |
| 2214 | 2217 | test "using slices for strings" { |
| 2215 | // Zig has no concept of strings. String literals are arrays of u8, and | |
| 2216 | // in general the string type is []u8 (slice of u8). | |
| 2218 | // Zig has no concept of strings. String literals are const pointers to | |
| 2219 | // arrays of u8, and by convention parameters that are "strings" are | |
| 2220 | // expected to be UTF-8 encoded slices of u8. | |
| 2217 | 2221 | // Here we coerce [5]u8 to []const u8 |
| 2218 | 2222 | const hello: []const u8 = "hello"; |
| 2219 | 2223 | const world: []const u8 = "世界"; |
| ... | ... | @@ -2222,7 +2226,7 @@ test "using slices for strings" { |
| 2222 | 2226 | // You can use slice syntax on an array to convert an array into a slice. |
| 2223 | 2227 | const all_together_slice = all_together[0..]; |
| 2224 | 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 }); | |
| 2226 | 2230 | |
| 2227 | 2231 | // Generally, you can use UTF-8 and not worry about whether something is a |
| 2228 | 2232 | // string. If you don't need to deal with individual characters, no need |
| ... | ... | @@ -2239,23 +2243,15 @@ test "slice pointer" { |
| 2239 | 2243 | slice[2] = 3; |
| 2240 | 2244 | assert(slice[2] == 3); |
| 2241 | 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); | |
| 2243 | 2249 | |
| 2244 | 2250 | // You can also slice a slice: |
| 2245 | 2251 | const slice2 = slice[2..3]; |
| 2246 | 2252 | assert(slice2.len == 1); |
| 2247 | 2253 | assert(slice2[0] == 3); |
| 2248 | 2254 | } |
| 2249 | ||
| 2250 | test "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 | 2255 | {#code_end#} |
| 2260 | 2256 | {#see_also|Pointers|for|Arrays#} |
| 2261 | 2257 |
lib/std/build.zig+26-12| ... | ... | @@ -377,7 +377,7 @@ pub const Builder = struct { |
| 377 | 377 | if (self.verbose) { |
| 378 | 378 | warn("rm {}\n", .{full_path}); |
| 379 | 379 | } |
| 380 | fs.deleteTree(full_path) catch {}; | |
| 380 | fs.cwd().deleteTree(full_path) catch {}; | |
| 381 | 381 | } |
| 382 | 382 | |
| 383 | 383 | // TODO remove empty directories |
| ... | ... | @@ -847,7 +847,8 @@ pub const Builder = struct { |
| 847 | 847 | if (self.verbose) { |
| 848 | 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 | 852 | if (self.verbose) switch (prev_status) { |
| 852 | 853 | .stale => warn("# installed\n", .{}), |
| 853 | 854 | .fresh => warn("# up-to-date\n", .{}), |
| ... | ... | @@ -1157,8 +1158,14 @@ pub const LibExeObjStep = struct { |
| 1157 | 1158 | |
| 1158 | 1159 | valgrind_support: ?bool = null, |
| 1159 | 1160 | |
| 1161 | /// Create a .eh_frame_hdr section and a PT_GNU_EH_FRAME segment in the ELF | |
| 1162 | /// file. | |
| 1160 | 1163 | link_eh_frame_hdr: bool = false, |
| 1161 | 1164 | |
| 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 | 1169 | /// Uses system Wine installation to run cross compiled Windows build artifacts. |
| 1163 | 1170 | enable_wine: bool = false, |
| 1164 | 1171 | |
| ... | ... | @@ -1884,7 +1891,9 @@ pub const LibExeObjStep = struct { |
| 1884 | 1891 | if (self.link_eh_frame_hdr) { |
| 1885 | 1892 | try zig_args.append("--eh-frame-hdr"); |
| 1886 | 1893 | } |
| 1887 | ||
| 1894 | if (self.link_function_sections) { | |
| 1895 | try zig_args.append("-ffunction-sections"); | |
| 1896 | } | |
| 1888 | 1897 | if (self.single_threaded) { |
| 1889 | 1898 | try zig_args.append("--single-threaded"); |
| 1890 | 1899 | } |
| ... | ... | @@ -2144,17 +2153,22 @@ pub const LibExeObjStep = struct { |
| 2144 | 2153 | try zig_args.append("--cache"); |
| 2145 | 2154 | try zig_args.append("on"); |
| 2146 | 2155 | |
| 2147 | const output_path_nl = try builder.execFromStep(zig_args.toSliceConst(), &self.step); | |
| 2148 | const output_path = mem.trimRight(u8, output_path_nl, "\r\n"); | |
| 2156 | const output_dir_nl = try builder.execFromStep(zig_args.toSliceConst(), &self.step); | |
| 2157 | const build_output_dir = mem.trimRight(u8, output_dir_nl, "\r\n"); | |
| 2149 | 2158 | |
| 2150 | 2159 | if (self.output_dir) |output_dir| { |
| 2151 | const full_dest = try fs.path.join(builder.allocator, &[_][]const u8{ | |
| 2152 | output_dir, | |
| 2153 | fs.path.basename(output_path), | |
| 2154 | }); | |
| 2155 | try builder.updateFile(output_path, full_dest); | |
| 2160 | var src_dir = try std.fs.cwd().openDir(build_output_dir, .{ .iterate = true }); | |
| 2161 | defer src_dir.close(); | |
| 2162 | ||
| 2163 | var dest_dir = try std.fs.cwd().openDir(output_dir, .{}); | |
| 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 | 2170 | } else { |
| 2157 | self.output_dir = fs.path.dirname(output_path).?; | |
| 2171 | self.output_dir = build_output_dir; | |
| 2158 | 2172 | } |
| 2159 | 2173 | } |
| 2160 | 2174 | |
| ... | ... | @@ -2352,7 +2366,7 @@ pub const RemoveDirStep = struct { |
| 2352 | 2366 | const self = @fieldParentPtr(RemoveDirStep, "step", step); |
| 2353 | 2367 | |
| 2354 | 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 | 2370 | warn("Unable to remove {}: {}\n", .{ full_path, @errorName(err) }); |
| 2357 | 2371 | return err; |
| 2358 | 2372 | }; |
lib/std/build/run.zig+3-1| ... | ... | @@ -29,6 +29,8 @@ pub const RunStep = struct { |
| 29 | 29 | stdout_action: StdIoAction = .inherit, |
| 30 | 30 | stderr_action: StdIoAction = .inherit, |
| 31 | 31 | |
| 32 | stdin_behavior: std.ChildProcess.StdIo = .Inherit, | |
| 33 | ||
| 32 | 34 | expected_exit_code: u8 = 0, |
| 33 | 35 | |
| 34 | 36 | pub const StdIoAction = union(enum) { |
| ... | ... | @@ -159,7 +161,7 @@ pub const RunStep = struct { |
| 159 | 161 | child.cwd = cwd; |
| 160 | 162 | child.env_map = self.env_map orelse self.builder.env_map; |
| 161 | 163 | |
| 162 | child.stdin_behavior = .Ignore; | |
| 164 | child.stdin_behavior = self.stdin_behavior; | |
| 163 | 165 | child.stdout_behavior = stdIoActionToBehavior(self.stdout_action); |
| 164 | 166 | child.stderr_behavior = stdIoActionToBehavior(self.stderr_action); |
| 165 | 167 |
lib/std/build/write_file.zig+1-1| ... | ... | @@ -78,7 +78,7 @@ pub const WriteFileStep = struct { |
| 78 | 78 | warn("unable to make path {}: {}\n", .{ self.output_dir, @errorName(err) }); |
| 79 | 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 | 82 | defer dir.close(); |
| 83 | 83 | for (self.files.toSliceConst()) |file| { |
| 84 | 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 | 106 | pub extern "c" fn mkdirat(dirfd: fd_t, path: [*:0]const u8, mode: u32) c_int; |
| 107 | 107 | pub extern "c" fn symlink(existing: [*:0]const u8, new: [*:0]const u8) c_int; |
| 108 | 108 | pub extern "c" fn rename(old: [*:0]const u8, new: [*:0]const u8) c_int; |
| 109 | pub extern "c" fn renameat(olddirfd: fd_t, old: [*:0]const u8, newdirfd: fd_t, new: [*:0]const u8) c_int; | |
| 109 | 110 | pub extern "c" fn chdir(path: [*:0]const u8) c_int; |
| 110 | 111 | pub extern "c" fn fchdir(fd: fd_t) c_int; |
| 111 | 112 | pub 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 | 15 | |
| 16 | 16 | // Encrypt one block from src into dst, using the expanded key xk. |
| 17 | 17 | fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { |
| 18 | var s0 = mem.readIntSliceBig(u32, src[0..4]); | |
| 19 | var s1 = mem.readIntSliceBig(u32, src[4..8]); | |
| 20 | var s2 = mem.readIntSliceBig(u32, src[8..12]); | |
| 21 | var s3 = mem.readIntSliceBig(u32, src[12..16]); | |
| 18 | var s0 = mem.readIntBig(u32, src[0..4]); | |
| 19 | var s1 = mem.readIntBig(u32, src[4..8]); | |
| 20 | var s2 = mem.readIntBig(u32, src[8..12]); | |
| 21 | var s3 = mem.readIntBig(u32, src[12..16]); | |
| 22 | 22 | |
| 23 | 23 | // First round just XORs input with key. |
| 24 | 24 | s0 ^= xk[0]; |
| ... | ... | @@ -58,18 +58,18 @@ fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { |
| 58 | 58 | s2 ^= xk[k + 2]; |
| 59 | 59 | s3 ^= xk[k + 3]; |
| 60 | 60 | |
| 61 | mem.writeIntSliceBig(u32, dst[0..4], s0); | |
| 62 | mem.writeIntSliceBig(u32, dst[4..8], s1); | |
| 63 | mem.writeIntSliceBig(u32, dst[8..12], s2); | |
| 64 | mem.writeIntSliceBig(u32, dst[12..16], s3); | |
| 61 | mem.writeIntBig(u32, dst[0..4], s0); | |
| 62 | mem.writeIntBig(u32, dst[4..8], s1); | |
| 63 | mem.writeIntBig(u32, dst[8..12], s2); | |
| 64 | mem.writeIntBig(u32, dst[12..16], s3); | |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | 67 | // Decrypt one block from src into dst, using the expanded key xk. |
| 68 | 68 | pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { |
| 69 | var s0 = mem.readIntSliceBig(u32, src[0..4]); | |
| 70 | var s1 = mem.readIntSliceBig(u32, src[4..8]); | |
| 71 | var s2 = mem.readIntSliceBig(u32, src[8..12]); | |
| 72 | var s3 = mem.readIntSliceBig(u32, src[12..16]); | |
| 69 | var s0 = mem.readIntBig(u32, src[0..4]); | |
| 70 | var s1 = mem.readIntBig(u32, src[4..8]); | |
| 71 | var s2 = mem.readIntBig(u32, src[8..12]); | |
| 72 | var s3 = mem.readIntBig(u32, src[12..16]); | |
| 73 | 73 | |
| 74 | 74 | // First round just XORs input with key. |
| 75 | 75 | s0 ^= xk[0]; |
| ... | ... | @@ -109,10 +109,10 @@ pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { |
| 109 | 109 | s2 ^= xk[k + 2]; |
| 110 | 110 | s3 ^= xk[k + 3]; |
| 111 | 111 | |
| 112 | mem.writeIntSliceBig(u32, dst[0..4], s0); | |
| 113 | mem.writeIntSliceBig(u32, dst[4..8], s1); | |
| 114 | mem.writeIntSliceBig(u32, dst[8..12], s2); | |
| 115 | mem.writeIntSliceBig(u32, dst[12..16], s3); | |
| 112 | mem.writeIntBig(u32, dst[0..4], s0); | |
| 113 | mem.writeIntBig(u32, dst[4..8], s1); | |
| 114 | mem.writeIntBig(u32, dst[8..12], s2); | |
| 115 | mem.writeIntBig(u32, dst[12..16], s3); | |
| 116 | 116 | } |
| 117 | 117 | |
| 118 | 118 | fn xorBytes(dst: []u8, a: []const u8, b: []const u8) usize { |
| ... | ... | @@ -154,8 +154,8 @@ fn AES(comptime keysize: usize) type { |
| 154 | 154 | var n: usize = 0; |
| 155 | 155 | while (n < src.len) { |
| 156 | 156 | ctx.encrypt(keystream[0..], ctrbuf[0..]); |
| 157 | var ctr_i = std.mem.readIntSliceBig(u128, ctrbuf[0..]); | |
| 158 | std.mem.writeIntSliceBig(u128, ctrbuf[0..], ctr_i +% 1); | |
| 157 | var ctr_i = std.mem.readIntBig(u128, ctrbuf[0..]); | |
| 158 | std.mem.writeIntBig(u128, ctrbuf[0..], ctr_i +% 1); | |
| 159 | 159 | |
| 160 | 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 | 251 | var i: usize = 0; |
| 252 | 252 | var nk = key.len / 4; |
| 253 | 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 | 256 | while (i < enc.len) : (i += 1) { |
| 257 | 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 | 123 | const rr = d.h[0 .. out_len / 32]; |
| 124 | 124 | |
| 125 | 125 | for (rr) |s, j| { |
| 126 | // TODO https://github.com/ziglang/zig/issues/863 | |
| 127 | mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s); | |
| 126 | mem.writeIntLittle(u32, out[4 * j ..][0..4], s); | |
| 128 | 127 | } |
| 129 | 128 | } |
| 130 | 129 | |
| ... | ... | @@ -135,8 +134,7 @@ fn Blake2s(comptime out_len: usize) type { |
| 135 | 134 | var v: [16]u32 = undefined; |
| 136 | 135 | |
| 137 | 136 | for (m) |*r, i| { |
| 138 | // TODO https://github.com/ziglang/zig/issues/863 | |
| 139 | r.* = mem.readIntSliceLittle(u32, b[4 * i .. 4 * i + 4]); | |
| 137 | r.* = mem.readIntLittle(u32, b[4 * i ..][0..4]); | |
| 140 | 138 | } |
| 141 | 139 | |
| 142 | 140 | var k: usize = 0; |
| ... | ... | @@ -358,8 +356,7 @@ fn Blake2b(comptime out_len: usize) type { |
| 358 | 356 | const rr = d.h[0 .. out_len / 64]; |
| 359 | 357 | |
| 360 | 358 | for (rr) |s, j| { |
| 361 | // TODO https://github.com/ziglang/zig/issues/863 | |
| 362 | mem.writeIntSliceLittle(u64, out[8 * j .. 8 * j + 8], s); | |
| 359 | mem.writeIntLittle(u64, out[8 * j ..][0..8], s); | |
| 363 | 360 | } |
| 364 | 361 | } |
| 365 | 362 | |
| ... | ... | @@ -370,7 +367,7 @@ fn Blake2b(comptime out_len: usize) type { |
| 370 | 367 | var v: [16]u64 = undefined; |
| 371 | 368 | |
| 372 | 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 | } |
| 375 | 372 | |
| 376 | 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 | 61 | } |
| 62 | 62 | |
| 63 | 63 | for (x) |_, i| { |
| 64 | // TODO https://github.com/ziglang/zig/issues/863 | |
| 65 | mem.writeIntSliceLittle(u32, out[4 * i .. 4 * i + 4], x[i] +% input[i]); | |
| 64 | mem.writeIntLittle(u32, out[4 * i ..][0..4], x[i] +% input[i]); | |
| 66 | 65 | } |
| 67 | 66 | } |
| 68 | 67 | |
| ... | ... | @@ -73,10 +72,10 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo |
| 73 | 72 | |
| 74 | 73 | const c = "expand 32-byte k"; |
| 75 | 74 | const constant_le = [_]u32{ |
| 76 | mem.readIntSliceLittle(u32, c[0..4]), | |
| 77 | mem.readIntSliceLittle(u32, c[4..8]), | |
| 78 | mem.readIntSliceLittle(u32, c[8..12]), | |
| 79 | mem.readIntSliceLittle(u32, c[12..16]), | |
| 75 | mem.readIntLittle(u32, c[0..4]), | |
| 76 | mem.readIntLittle(u32, c[4..8]), | |
| 77 | mem.readIntLittle(u32, c[8..12]), | |
| 78 | mem.readIntLittle(u32, c[12..16]), | |
| 80 | 79 | }; |
| 81 | 80 | |
| 82 | 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 | 119 | var k: [8]u32 = undefined; |
| 121 | 120 | var c: [4]u32 = undefined; |
| 122 | 121 | |
| 123 | k[0] = mem.readIntSliceLittle(u32, key[0..4]); | |
| 124 | k[1] = mem.readIntSliceLittle(u32, key[4..8]); | |
| 125 | k[2] = mem.readIntSliceLittle(u32, key[8..12]); | |
| 126 | k[3] = mem.readIntSliceLittle(u32, key[12..16]); | |
| 127 | k[4] = mem.readIntSliceLittle(u32, key[16..20]); | |
| 128 | k[5] = mem.readIntSliceLittle(u32, key[20..24]); | |
| 129 | k[6] = mem.readIntSliceLittle(u32, key[24..28]); | |
| 130 | k[7] = mem.readIntSliceLittle(u32, key[28..32]); | |
| 122 | k[0] = mem.readIntLittle(u32, key[0..4]); | |
| 123 | k[1] = mem.readIntLittle(u32, key[4..8]); | |
| 124 | k[2] = mem.readIntLittle(u32, key[8..12]); | |
| 125 | k[3] = mem.readIntLittle(u32, key[12..16]); | |
| 126 | k[4] = mem.readIntLittle(u32, key[16..20]); | |
| 127 | k[5] = mem.readIntLittle(u32, key[20..24]); | |
| 128 | k[6] = mem.readIntLittle(u32, key[24..28]); | |
| 129 | k[7] = mem.readIntLittle(u32, key[28..32]); | |
| 131 | 130 | |
| 132 | 131 | c[0] = counter; |
| 133 | c[1] = mem.readIntSliceLittle(u32, nonce[0..4]); | |
| 134 | c[2] = mem.readIntSliceLittle(u32, nonce[4..8]); | |
| 135 | c[3] = mem.readIntSliceLittle(u32, nonce[8..12]); | |
| 132 | c[1] = mem.readIntLittle(u32, nonce[0..4]); | |
| 133 | c[2] = mem.readIntLittle(u32, nonce[4..8]); | |
| 134 | c[3] = mem.readIntLittle(u32, nonce[8..12]); | |
| 136 | 135 | chaCha20_internal(out, in, k, c); |
| 137 | 136 | } |
| 138 | 137 | |
| ... | ... | @@ -147,19 +146,19 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32] |
| 147 | 146 | var k: [8]u32 = undefined; |
| 148 | 147 | var c: [4]u32 = undefined; |
| 149 | 148 | |
| 150 | k[0] = mem.readIntSliceLittle(u32, key[0..4]); | |
| 151 | k[1] = mem.readIntSliceLittle(u32, key[4..8]); | |
| 152 | k[2] = mem.readIntSliceLittle(u32, key[8..12]); | |
| 153 | k[3] = mem.readIntSliceLittle(u32, key[12..16]); | |
| 154 | k[4] = mem.readIntSliceLittle(u32, key[16..20]); | |
| 155 | k[5] = mem.readIntSliceLittle(u32, key[20..24]); | |
| 156 | k[6] = mem.readIntSliceLittle(u32, key[24..28]); | |
| 157 | k[7] = mem.readIntSliceLittle(u32, key[28..32]); | |
| 149 | k[0] = mem.readIntLittle(u32, key[0..4]); | |
| 150 | k[1] = mem.readIntLittle(u32, key[4..8]); | |
| 151 | k[2] = mem.readIntLittle(u32, key[8..12]); | |
| 152 | k[3] = mem.readIntLittle(u32, key[12..16]); | |
| 153 | k[4] = mem.readIntLittle(u32, key[16..20]); | |
| 154 | k[5] = mem.readIntLittle(u32, key[20..24]); | |
| 155 | k[6] = mem.readIntLittle(u32, key[24..28]); | |
| 156 | k[7] = mem.readIntLittle(u32, key[28..32]); | |
| 158 | 157 | |
| 159 | 158 | c[0] = @truncate(u32, counter); |
| 160 | 159 | c[1] = @truncate(u32, counter >> 32); |
| 161 | c[2] = mem.readIntSliceLittle(u32, nonce[0..4]); | |
| 162 | c[3] = mem.readIntSliceLittle(u32, nonce[4..8]); | |
| 160 | c[2] = mem.readIntLittle(u32, nonce[0..4]); | |
| 161 | c[3] = mem.readIntLittle(u32, nonce[4..8]); | |
| 163 | 162 | |
| 164 | 163 | const block_size = (1 << 6); |
| 165 | 164 | // 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 | 462 | mac.update(zeros[0..padding]); |
| 464 | 463 | } |
| 465 | 464 | var lens: [16]u8 = undefined; |
| 466 | mem.writeIntSliceLittle(u64, lens[0..8], data.len); | |
| 467 | mem.writeIntSliceLittle(u64, lens[8..16], plaintext.len); | |
| 465 | mem.writeIntLittle(u64, lens[0..8], data.len); | |
| 466 | mem.writeIntLittle(u64, lens[8..16], plaintext.len); | |
| 468 | 467 | mac.update(lens[0..]); |
| 469 | 468 | mac.final(dst[plaintext.len..]); |
| 470 | 469 | } |
| ... | ... | @@ -500,8 +499,8 @@ pub fn chacha20poly1305Open(dst: []u8, msgAndTag: []const u8, data: []const u8, |
| 500 | 499 | mac.update(zeros[0..padding]); |
| 501 | 500 | } |
| 502 | 501 | var lens: [16]u8 = undefined; |
| 503 | mem.writeIntSliceLittle(u64, lens[0..8], data.len); | |
| 504 | mem.writeIntSliceLittle(u64, lens[8..16], ciphertext.len); | |
| 502 | mem.writeIntLittle(u64, lens[0..8], data.len); | |
| 503 | mem.writeIntLittle(u64, lens[8..16], ciphertext.len); | |
| 505 | 504 | mac.update(lens[0..]); |
| 506 | 505 | var computedTag: [16]u8 = undefined; |
| 507 | 506 | mac.final(computedTag[0..]); |
lib/std/crypto/md5.zig+1-2| ... | ... | @@ -112,8 +112,7 @@ pub const Md5 = struct { |
| 112 | 112 | d.round(d.buf[0..]); |
| 113 | 113 | |
| 114 | 114 | for (d.s) |s, j| { |
| 115 | // TODO https://github.com/ziglang/zig/issues/863 | |
| 116 | mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s); | |
| 115 | mem.writeIntLittle(u32, out[4 * j ..][0..4], s); | |
| 117 | 116 | } |
| 118 | 117 | } |
| 119 | 118 |
lib/std/crypto/poly1305.zig+14-15| ... | ... | @@ -3,11 +3,11 @@ |
| 3 | 3 | // https://monocypher.org/ |
| 4 | 4 | |
| 5 | 5 | const std = @import("../std.zig"); |
| 6 | const builtin = @import("builtin"); | |
| 6 | const builtin = std.builtin; | |
| 7 | 7 | |
| 8 | 8 | const Endian = builtin.Endian; |
| 9 | const readIntSliceLittle = std.mem.readIntSliceLittle; | |
| 10 | const writeIntSliceLittle = std.mem.writeIntSliceLittle; | |
| 9 | const readIntLittle = std.mem.readIntLittle; | |
| 10 | const writeIntLittle = std.mem.writeIntLittle; | |
| 11 | 11 | |
| 12 | 12 | pub const Poly1305 = struct { |
| 13 | 13 | const Self = @This(); |
| ... | ... | @@ -59,19 +59,19 @@ pub const Poly1305 = struct { |
| 59 | 59 | { |
| 60 | 60 | var i: usize = 0; |
| 61 | 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 | 66 | var i: usize = 1; |
| 67 | 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 | 72 | var i: usize = 0; |
| 73 | 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 | } |
| 77 | 77 | |
| ... | ... | @@ -168,10 +168,10 @@ pub const Poly1305 = struct { |
| 168 | 168 | const nb_blocks = nmsg.len >> 4; |
| 169 | 169 | var i: usize = 0; |
| 170 | 170 | while (i < nb_blocks) : (i += 1) { |
| 171 | ctx.c[0] = readIntSliceLittle(u32, nmsg[0..4]); | |
| 172 | ctx.c[1] = readIntSliceLittle(u32, nmsg[4..8]); | |
| 173 | ctx.c[2] = readIntSliceLittle(u32, nmsg[8..12]); | |
| 174 | ctx.c[3] = readIntSliceLittle(u32, nmsg[12..16]); | |
| 171 | ctx.c[0] = readIntLittle(u32, nmsg[0..4]); | |
| 172 | ctx.c[1] = readIntLittle(u32, nmsg[4..8]); | |
| 173 | ctx.c[2] = readIntLittle(u32, nmsg[8..12]); | |
| 174 | ctx.c[3] = readIntLittle(u32, nmsg[12..16]); | |
| 175 | 175 | polyBlock(ctx); |
| 176 | 176 | nmsg = nmsg[16..]; |
| 177 | 177 | } |
| ... | ... | @@ -210,11 +210,10 @@ pub const Poly1305 = struct { |
| 210 | 210 | const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000 |
| 211 | 211 | const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000 |
| 212 | 212 | |
| 213 | // TODO https://github.com/ziglang/zig/issues/863 | |
| 214 | writeIntSliceLittle(u32, out[0..], @truncate(u32, uu0)); | |
| 215 | writeIntSliceLittle(u32, out[4..], @truncate(u32, uu1)); | |
| 216 | writeIntSliceLittle(u32, out[8..], @truncate(u32, uu2)); | |
| 217 | writeIntSliceLittle(u32, out[12..], @truncate(u32, uu3)); | |
| 213 | writeIntLittle(u32, out[0..4], @truncate(u32, uu0)); | |
| 214 | writeIntLittle(u32, out[4..8], @truncate(u32, uu1)); | |
| 215 | writeIntLittle(u32, out[8..12], @truncate(u32, uu2)); | |
| 216 | writeIntLittle(u32, out[12..16], @truncate(u32, uu3)); | |
| 218 | 217 | |
| 219 | 218 | ctx.secureZero(); |
| 220 | 219 | } |
lib/std/crypto/sha1.zig+1-2| ... | ... | @@ -109,8 +109,7 @@ pub const Sha1 = struct { |
| 109 | 109 | d.round(d.buf[0..]); |
| 110 | 110 | |
| 111 | 111 | for (d.s) |s, j| { |
| 112 | // TODO https://github.com/ziglang/zig/issues/863 | |
| 113 | mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s); | |
| 112 | mem.writeIntBig(u32, out[4 * j ..][0..4], s); | |
| 114 | 113 | } |
| 115 | 114 | } |
| 116 | 115 |
lib/std/crypto/sha2.zig+2-4| ... | ... | @@ -167,8 +167,7 @@ fn Sha2_32(comptime params: Sha2Params32) type { |
| 167 | 167 | const rr = d.s[0 .. params.out_len / 32]; |
| 168 | 168 | |
| 169 | 169 | for (rr) |s, j| { |
| 170 | // TODO https://github.com/ziglang/zig/issues/863 | |
| 171 | mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s); | |
| 170 | mem.writeIntBig(u32, out[4 * j ..][0..4], s); | |
| 172 | 171 | } |
| 173 | 172 | } |
| 174 | 173 | |
| ... | ... | @@ -509,8 +508,7 @@ fn Sha2_64(comptime params: Sha2Params64) type { |
| 509 | 508 | const rr = d.s[0 .. params.out_len / 64]; |
| 510 | 509 | |
| 511 | 510 | for (rr) |s, j| { |
| 512 | // TODO https://github.com/ziglang/zig/issues/863 | |
| 513 | mem.writeIntSliceBig(u64, out[8 * j .. 8 * j + 8], s); | |
| 511 | mem.writeIntBig(u64, out[8 * j ..][0..8], s); | |
| 514 | 512 | } |
| 515 | 513 | } |
| 516 | 514 |
lib/std/crypto/sha3.zig+2-3| ... | ... | @@ -120,7 +120,7 @@ fn keccak_f(comptime F: usize, d: []u8) void { |
| 120 | 120 | var c = [_]u64{0} ** 5; |
| 121 | 121 | |
| 122 | 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 | } |
| 125 | 125 | |
| 126 | 126 | comptime var x: usize = 0; |
| ... | ... | @@ -167,8 +167,7 @@ fn keccak_f(comptime F: usize, d: []u8) void { |
| 167 | 167 | } |
| 168 | 168 | |
| 169 | 169 | for (s) |r, i| { |
| 170 | // TODO https://github.com/ziglang/zig/issues/863 | |
| 171 | mem.writeIntSliceLittle(u64, d[8 * i .. 8 * i + 8], r); | |
| 170 | mem.writeIntLittle(u64, d[8 * i ..][0..8], r); | |
| 172 | 171 | } |
| 173 | 172 | } |
| 174 | 173 |
lib/std/crypto/x25519.zig+20-21| ... | ... | @@ -7,8 +7,8 @@ const builtin = @import("builtin"); |
| 7 | 7 | const fmt = std.fmt; |
| 8 | 8 | |
| 9 | 9 | const Endian = builtin.Endian; |
| 10 | const readIntSliceLittle = std.mem.readIntSliceLittle; | |
| 11 | const writeIntSliceLittle = std.mem.writeIntSliceLittle; | |
| 10 | const readIntLittle = std.mem.readIntLittle; | |
| 11 | const writeIntLittle = std.mem.writeIntLittle; | |
| 12 | 12 | |
| 13 | 13 | // Based on Supercop's ref10 implementation. |
| 14 | 14 | pub const X25519 = struct { |
| ... | ... | @@ -255,16 +255,16 @@ const Fe = struct { |
| 255 | 255 | |
| 256 | 256 | var t: [10]i64 = undefined; |
| 257 | 257 | |
| 258 | t[0] = readIntSliceLittle(u32, s[0..4]); | |
| 259 | t[1] = @as(u32, readIntSliceLittle(u24, s[4..7])) << 6; | |
| 260 | t[2] = @as(u32, readIntSliceLittle(u24, s[7..10])) << 5; | |
| 261 | t[3] = @as(u32, readIntSliceLittle(u24, s[10..13])) << 3; | |
| 262 | t[4] = @as(u32, readIntSliceLittle(u24, s[13..16])) << 2; | |
| 263 | t[5] = readIntSliceLittle(u32, s[16..20]); | |
| 264 | t[6] = @as(u32, readIntSliceLittle(u24, s[20..23])) << 7; | |
| 265 | t[7] = @as(u32, readIntSliceLittle(u24, s[23..26])) << 5; | |
| 266 | t[8] = @as(u32, readIntSliceLittle(u24, s[26..29])) << 4; | |
| 267 | t[9] = (@as(u32, readIntSliceLittle(u24, s[29..32])) & 0x7fffff) << 2; | |
| 258 | t[0] = readIntLittle(u32, s[0..4]); | |
| 259 | t[1] = @as(u32, readIntLittle(u24, s[4..7])) << 6; | |
| 260 | t[2] = @as(u32, readIntLittle(u24, s[7..10])) << 5; | |
| 261 | t[3] = @as(u32, readIntLittle(u24, s[10..13])) << 3; | |
| 262 | t[4] = @as(u32, readIntLittle(u24, s[13..16])) << 2; | |
| 263 | t[5] = readIntLittle(u32, s[16..20]); | |
| 264 | t[6] = @as(u32, readIntLittle(u24, s[20..23])) << 7; | |
| 265 | t[7] = @as(u32, readIntLittle(u24, s[23..26])) << 5; | |
| 266 | t[8] = @as(u32, readIntLittle(u24, s[26..29])) << 4; | |
| 267 | t[9] = (@as(u32, readIntLittle(u24, s[29..32])) & 0x7fffff) << 2; | |
| 268 | 268 | |
| 269 | 269 | carry1(h, t[0..]); |
| 270 | 270 | } |
| ... | ... | @@ -544,15 +544,14 @@ const Fe = struct { |
| 544 | 544 | ut[i] = @bitCast(u32, @intCast(i32, t[i])); |
| 545 | 545 | } |
| 546 | 546 | |
| 547 | // TODO https://github.com/ziglang/zig/issues/863 | |
| 548 | writeIntSliceLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26)); | |
| 549 | writeIntSliceLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19)); | |
| 550 | writeIntSliceLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13)); | |
| 551 | writeIntSliceLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6)); | |
| 552 | writeIntSliceLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25)); | |
| 553 | writeIntSliceLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19)); | |
| 554 | writeIntSliceLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12)); | |
| 555 | writeIntSliceLittle(u32, s[28..], (ut[8] >> 20) | (ut[9] << 6)); | |
| 547 | writeIntLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26)); | |
| 548 | writeIntLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19)); | |
| 549 | writeIntLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13)); | |
| 550 | writeIntLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6)); | |
| 551 | writeIntLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25)); | |
| 552 | writeIntLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19)); | |
| 553 | writeIntLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12)); | |
| 554 | writeIntLittle(u32, s[28..32], (ut[8] >> 20) | (ut[9] << 6)); | |
| 556 | 555 | |
| 557 | 556 | std.mem.secureZero(i64, t[0..]); |
| 558 | 557 | } |
lib/std/fmt.zig+2-1| ... | ... | @@ -1223,7 +1223,8 @@ test "slice" { |
| 1223 | 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 | 1228 | try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value}); |
| 1228 | 1229 | } |
| 1229 | 1230 |
lib/std/fs.zig+231-294| ... | ... | @@ -81,134 +81,74 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: |
| 81 | 81 | } |
| 82 | 82 | } |
| 83 | 83 | |
| 84 | // TODO fix enum literal not casting to error union | |
| 85 | const PrevStatus = enum { | |
| 84 | pub const PrevStatus = enum { | |
| 86 | 85 | stale, |
| 87 | 86 | fresh, |
| 88 | 87 | }; |
| 89 | 88 | |
| 90 | pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus { | |
| 91 | return updateFileMode(source_path, dest_path, null); | |
| 92 | } | |
| 89 | pub const CopyFileOptions = struct { | |
| 90 | /// When this is `null` the mode is copied from the source file. | |
| 91 | override_mode: ?File.Mode = null, | |
| 92 | }; | |
| 93 | 93 | |
| 94 | /// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing. | |
| 95 | /// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime, | |
| 96 | /// atime, and mode of the source file so that the next call to `updateFile` will not need a copy. | |
| 97 | /// Returns the previous status of the file before updating. | |
| 98 | /// If any of the directories do not exist for dest_path, they are created. | |
| 99 | /// TODO rework this to integrate with Dir | |
| 100 | pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !PrevStatus { | |
| 94 | /// Same as `Dir.updateFile`, except asserts that both `source_path` and `dest_path` | |
| 95 | /// are absolute. See `Dir.updateFile` for a function that operates on both | |
| 96 | /// absolute and relative paths. | |
| 97 | pub fn updateFileAbsolute( | |
| 98 | source_path: []const u8, | |
| 99 | dest_path: []const u8, | |
| 100 | args: CopyFileOptions, | |
| 101 | ) !PrevStatus { | |
| 102 | assert(path.isAbsolute(source_path)); | |
| 103 | assert(path.isAbsolute(dest_path)); | |
| 101 | 104 | const my_cwd = cwd(); |
| 102 | ||
| 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; | |
| 105 | return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, args); | |
| 138 | 106 | } |
| 139 | 107 | |
| 140 | /// Guaranteed to be atomic. | |
| 141 | /// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available, | |
| 142 | /// there is a possibility of power loss or application termination leaving temporary files present | |
| 143 | /// in the same directory as dest_path. | |
| 144 | /// Destination file will have the same mode as the source file. | |
| 145 | /// TODO rework this to integrate with Dir | |
| 146 | pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void { | |
| 147 | var in_file = try cwd().openFile(source_path, .{}); | |
| 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 | |
| 164 | pub 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(); | |
| 108 | /// Same as `Dir.copyFile`, except asserts that both `source_path` and `dest_path` | |
| 109 | /// are absolute. See `Dir.copyFile` for a function that operates on both | |
| 110 | /// absolute and relative paths. | |
| 111 | pub fn copyFileAbsolute(source_path: []const u8, dest_path: []const u8, args: CopyFileOptions) !void { | |
| 112 | assert(path.isAbsolute(source_path)); | |
| 113 | assert(path.isAbsolute(dest_path)); | |
| 114 | const my_cwd = cwd(); | |
| 115 | return Dir.copyFile(my_cwd, source_path, my_cwd, dest_path, args); | |
| 173 | 116 | } |
| 174 | 117 | |
| 175 | /// TODO update this API to avoid a getrandom syscall for every operation. It | |
| 176 | /// should accept a random interface. | |
| 177 | /// TODO rework this to integrate with Dir | |
| 118 | /// TODO update this API to avoid a getrandom syscall for every operation. | |
| 178 | 119 | pub const AtomicFile = struct { |
| 179 | 120 | file: File, |
| 180 | tmp_path_buf: [MAX_PATH_BYTES]u8, | |
| 121 | tmp_path_buf: [MAX_PATH_BYTES - 1:0]u8, | |
| 181 | 122 | dest_path: []const u8, |
| 182 | finished: bool, | |
| 123 | file_open: bool, | |
| 124 | file_exists: bool, | |
| 125 | dir: Dir, | |
| 183 | 126 | |
| 184 | 127 | const InitError = File.OpenError; |
| 185 | 128 | |
| 186 | /// dest_path must remain valid for the lifetime of AtomicFile | |
| 187 | /// call finish to atomically replace dest_path with contents | |
| 188 | pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile { | |
| 129 | /// TODO rename this. Callers should go through Dir API | |
| 130 | pub fn init2(dest_path: []const u8, mode: File.Mode, dir: Dir) InitError!AtomicFile { | |
| 189 | 131 | const dirname = path.dirname(dest_path); |
| 190 | 132 | var rand_buf: [12]u8 = undefined; |
| 191 | 133 | const dirname_component_len = if (dirname) |d| d.len + 1 else 0; |
| 192 | 134 | const encoded_rand_len = comptime base64.Base64Encoder.calcSize(rand_buf.len); |
| 193 | 135 | const tmp_path_len = dirname_component_len + encoded_rand_len; |
| 194 | var tmp_path_buf: [MAX_PATH_BYTES]u8 = undefined; | |
| 195 | if (tmp_path_len >= tmp_path_buf.len) return error.NameTooLong; | |
| 136 | var tmp_path_buf: [MAX_PATH_BYTES - 1:0]u8 = undefined; | |
| 137 | if (tmp_path_len > tmp_path_buf.len) return error.NameTooLong; | |
| 196 | 138 | |
| 197 | if (dirname) |dir| { | |
| 198 | mem.copy(u8, tmp_path_buf[0..], dir); | |
| 199 | tmp_path_buf[dir.len] = path.sep; | |
| 139 | if (dirname) |dn| { | |
| 140 | mem.copy(u8, tmp_path_buf[0..], dn); | |
| 141 | tmp_path_buf[dn.len] = path.sep; | |
| 200 | 142 | } |
| 201 | 143 | |
| 202 | 144 | tmp_path_buf[tmp_path_len] = 0; |
| 203 | 145 | const tmp_path_slice = tmp_path_buf[0..tmp_path_len :0]; |
| 204 | 146 | |
| 205 | const my_cwd = cwd(); | |
| 206 | ||
| 207 | 147 | while (true) { |
| 208 | 148 | try crypto.randomBytes(rand_buf[0..]); |
| 209 | 149 | base64_encoder.encode(tmp_path_slice[dirname_component_len..tmp_path_len], &rand_buf); |
| 210 | 150 | |
| 211 | const file = my_cwd.createFileC( | |
| 151 | const file = dir.createFileC( | |
| 212 | 152 | tmp_path_slice, |
| 213 | 153 | .{ .mode = mode, .exclusive = true }, |
| 214 | 154 | ) catch |err| switch (err) { |
| ... | ... | @@ -220,33 +160,46 @@ pub const AtomicFile = struct { |
| 220 | 160 | .file = file, |
| 221 | 161 | .tmp_path_buf = tmp_path_buf, |
| 222 | 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 | } |
| 227 | 169 | |
| 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 | 175 | /// always call deinit, even after successful finish() |
| 229 | 176 | pub fn deinit(self: *AtomicFile) void { |
| 230 | if (!self.finished) { | |
| 177 | if (self.file_open) { | |
| 231 | 178 | self.file.close(); |
| 232 | cwd().deleteFileC(@ptrCast([*:0]u8, &self.tmp_path_buf)) catch {}; | |
| 233 | self.finished = true; | |
| 179 | self.file_open = false; | |
| 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 | } |
| 236 | 187 | |
| 237 | 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 | 194 | if (std.Target.current.os.tag == .windows) { |
| 240 | 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)); | |
| 242 | self.file.close(); | |
| 243 | self.finished = true; | |
| 244 | return os.renameW(&tmp_path_w, &dest_path_w); | |
| 196 | const tmp_path_w = try os.windows.cStrToPrefixedFileW(&self.tmp_path_buf); | |
| 197 | try os.renameatW(self.dir.fd, &tmp_path_w, self.dir.fd, &dest_path_w, os.windows.TRUE); | |
| 198 | self.file_exists = false; | |
| 245 | 199 | } else { |
| 246 | 200 | const dest_path_c = try os.toPosixPath(self.dest_path); |
| 247 | self.file.close(); | |
| 248 | self.finished = true; | |
| 249 | return os.renameC(@ptrCast([*:0]u8, &self.tmp_path_buf), &dest_path_c); | |
| 201 | try os.renameatZ(self.dir.fd, &self.tmp_path_buf, self.dir.fd, &dest_path_c); | |
| 202 | self.file_exists = false; | |
| 250 | 203 | } |
| 251 | 204 | } |
| 252 | 205 | }; |
| ... | ... | @@ -274,44 +227,21 @@ pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void { |
| 274 | 227 | os.windows.CloseHandle(handle); |
| 275 | 228 | } |
| 276 | 229 | |
| 277 | /// Returns `error.DirNotEmpty` if the directory is not empty. | |
| 278 | /// To delete a directory recursively, see `deleteTree`. | |
| 230 | /// Deprecated; use `Dir.deleteDir`. | |
| 279 | 231 | pub fn deleteDir(dir_path: []const u8) !void { |
| 280 | 232 | return os.rmdir(dir_path); |
| 281 | 233 | } |
| 282 | 234 | |
| 283 | /// Same as `deleteDir` except the parameter is a null-terminated UTF8-encoded string. | |
| 235 | /// Deprecated; use `Dir.deleteDirC`. | |
| 284 | 236 | pub fn deleteDirC(dir_path: [*:0]const u8) !void { |
| 285 | 237 | return os.rmdirC(dir_path); |
| 286 | 238 | } |
| 287 | 239 | |
| 288 | /// Same as `deleteDir` except the parameter is a null-terminated UTF16LE-encoded string. | |
| 240 | /// Deprecated; use `Dir.deleteDirW`. | |
| 289 | 241 | pub fn deleteDirW(dir_path: [*:0]const u16) !void { |
| 290 | 242 | return os.rmdirW(dir_path); |
| 291 | 243 | } |
| 292 | 244 | |
| 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. | |
| 298 | pub 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 | ||
| 315 | 245 | pub const Dir = struct { |
| 316 | 246 | fd: os.fd_t, |
| 317 | 247 | |
| ... | ... | @@ -368,7 +298,7 @@ pub const Dir = struct { |
| 368 | 298 | if (rc == 0) return null; |
| 369 | 299 | if (rc < 0) { |
| 370 | 300 | switch (os.errno(rc)) { |
| 371 | os.EBADF => unreachable, | |
| 301 | os.EBADF => unreachable, // Dir is invalid or was opened without iteration ability | |
| 372 | 302 | os.EFAULT => unreachable, |
| 373 | 303 | os.ENOTDIR => unreachable, |
| 374 | 304 | os.EINVAL => unreachable, |
| ... | ... | @@ -411,13 +341,13 @@ pub const Dir = struct { |
| 411 | 341 | if (self.index >= self.end_index) { |
| 412 | 342 | const rc = os.system.getdirentries( |
| 413 | 343 | self.dir.fd, |
| 414 | self.buf[0..].ptr, | |
| 344 | &self.buf, | |
| 415 | 345 | self.buf.len, |
| 416 | 346 | &self.seek, |
| 417 | 347 | ); |
| 418 | 348 | switch (os.errno(rc)) { |
| 419 | 349 | 0 => {}, |
| 420 | os.EBADF => unreachable, | |
| 350 | os.EBADF => unreachable, // Dir is invalid or was opened without iteration ability | |
| 421 | 351 | os.EFAULT => unreachable, |
| 422 | 352 | os.ENOTDIR => unreachable, |
| 423 | 353 | os.EINVAL => unreachable, |
| ... | ... | @@ -473,7 +403,7 @@ pub const Dir = struct { |
| 473 | 403 | const rc = os.linux.getdents64(self.dir.fd, &self.buf, self.buf.len); |
| 474 | 404 | switch (os.linux.getErrno(rc)) { |
| 475 | 405 | 0 => {}, |
| 476 | os.EBADF => unreachable, | |
| 406 | os.EBADF => unreachable, // Dir is invalid or was opened without iteration ability | |
| 477 | 407 | os.EFAULT => unreachable, |
| 478 | 408 | os.ENOTDIR => unreachable, |
| 479 | 409 | os.EINVAL => unreachable, |
| ... | ... | @@ -547,7 +477,8 @@ pub const Dir = struct { |
| 547 | 477 | self.end_index = io.Information; |
| 548 | 478 | switch (rc) { |
| 549 | 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 | 482 | else => return w.unexpectedStatus(rc), |
| 552 | 483 | } |
| 553 | 484 | } |
| ... | ... | @@ -625,16 +556,6 @@ pub const Dir = struct { |
| 625 | 556 | DeviceBusy, |
| 626 | 557 | } || os.UnexpectedError; |
| 627 | 558 | |
| 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 | 559 | pub fn close(self: *Dir) void { |
| 639 | 560 | if (need_async_thread) { |
| 640 | 561 | std.event.Loop.instance.?.close(self.fd); |
| ... | ... | @@ -694,7 +615,10 @@ pub const Dir = struct { |
| 694 | 615 | const access_mask = w.SYNCHRONIZE | |
| 695 | 616 | (if (flags.read) @as(u32, w.GENERIC_READ) else 0) | |
| 696 | 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 | } |
| 699 | 623 | |
| 700 | 624 | /// Creates, opens, or overwrites a file with write access. |
| ... | ... | @@ -739,7 +663,10 @@ pub const Dir = struct { |
| 739 | 663 | @as(u32, w.FILE_OVERWRITE_IF) |
| 740 | 664 | else |
| 741 | 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 | } |
| 744 | 671 | |
| 745 | 672 | /// Deprecated; call `openFile` directly. |
| ... | ... | @@ -757,72 +684,6 @@ pub const Dir = struct { |
| 757 | 684 | return self.openFileW(sub_path, .{}); |
| 758 | 685 | } |
| 759 | 686 | |
| 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 | 687 | pub fn makeDir(self: Dir, sub_path: []const u8) !void { |
| 827 | 688 | try os.mkdirat(self.fd, sub_path, default_new_dir_mode); |
| 828 | 689 | } |
| ... | ... | @@ -881,77 +742,61 @@ pub const Dir = struct { |
| 881 | 742 | try os.fchdir(self.fd); |
| 882 | 743 | } |
| 883 | 744 | |
| 884 | /// Deprecated; call `openDirList` directly. | |
| 885 | pub fn openDir(self: Dir, sub_path: []const u8) OpenError!Dir { | |
| 886 | return self.openDirList(sub_path); | |
| 887 | } | |
| 888 | ||
| 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 | } | |
| 745 | pub const OpenDirOptions = struct { | |
| 746 | /// `true` means the opened directory can be used as the `Dir` parameter | |
| 747 | /// for functions which operate based on an open directory handle. When `false`, | |
| 748 | /// such operations are Illegal Behavior. | |
| 749 | access_sub_paths: bool = true, | |
| 893 | 750 | |
| 894 | /// Opens a directory at the given path with the ability to access subpaths | |
| 895 | /// of the result. Calling `iterate` on the result is illegal behavior; to | |
| 896 | /// list the contents of a directory, open it with `openDirList`. | |
| 897 | /// | |
| 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 | } | |
| 751 | /// `true` means the opened directory can be scanned for the files and sub-directories | |
| 752 | /// of the result. It means the `iterate` function can be called. | |
| 753 | iterate: bool = false, | |
| 754 | }; | |
| 910 | 755 | |
| 911 | /// Opens a directory at the given path with the ability to access subpaths and list contents | |
| 912 | /// of the result. If the ability to list contents is unneeded, `openDirTraverse` acts the | |
| 913 | /// same and may be more efficient. | |
| 914 | /// | |
| 915 | /// Call `close` on the result when done. | |
| 756 | /// Opens a directory at the given path. The directory is a system resource that remains | |
| 757 | /// open until `close` is called on the result. | |
| 916 | 758 | /// |
| 917 | 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 | 761 | if (builtin.os.tag == .windows) { |
| 920 | 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 | } |
| 927 | 769 | |
| 928 | /// Same as `openDirTraverse` except the parameter is null-terminated. | |
| 929 | pub fn openDirTraverseC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir { | |
| 770 | /// Same as `openDir` except the parameter is null-terminated. | |
| 771 | pub fn openDirC(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions) OpenError!Dir { | |
| 930 | 772 | if (builtin.os.tag == .windows) { |
| 931 | 773 | const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); |
| 932 | return self.openDirTraverseW(&sub_path_w); | |
| 933 | } else { | |
| 774 | return self.openDirW(&sub_path_w, args); | |
| 775 | } else if (!args.iterate) { | |
| 934 | 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 | } |
| 938 | 782 | |
| 939 | /// Same as `openDirList` except the parameter is null-terminated. | |
| 940 | pub fn openDirListC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir { | |
| 941 | if (builtin.os.tag == .windows) { | |
| 942 | const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); | |
| 943 | return self.openDirListW(&sub_path_w); | |
| 944 | } else { | |
| 945 | return self.openDirFlagsC(sub_path_c, os.O_RDONLY | os.O_CLOEXEC); | |
| 946 | } | |
| 783 | /// Same as `openDir` except the path parameter is WTF-16 encoded, NT-prefixed. | |
| 784 | /// This function asserts the target OS is Windows. | |
| 785 | pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) OpenError!Dir { | |
| 786 | const w = os.windows; | |
| 787 | // TODO remove some of these flags if args.access_sub_paths is false | |
| 788 | const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | | |
| 789 | w.SYNCHRONIZE | w.FILE_TRAVERSE; | |
| 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 | } |
| 948 | 793 | |
| 794 | /// `flags` must contain `os.O_DIRECTORY`. | |
| 949 | 795 | fn openDirFlagsC(self: Dir, sub_path_c: [*:0]const u8, flags: u32) OpenError!Dir { |
| 950 | const os_flags = flags | os.O_DIRECTORY; | |
| 951 | 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 | 798 | else |
| 954 | os.openatC(self.fd, sub_path_c, os_flags, 0); | |
| 799 | os.openatC(self.fd, sub_path_c, flags, 0); | |
| 955 | 800 | const fd = result catch |err| switch (err) { |
| 956 | 801 | error.FileTooBig => unreachable, // can't happen for directories |
| 957 | 802 | error.IsDir => unreachable, // we're providing O_DIRECTORY |
| ... | ... | @@ -962,22 +807,6 @@ pub const Dir = struct { |
| 962 | 807 | return Dir{ .fd = fd }; |
| 963 | 808 | } |
| 964 | 809 | |
| 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 | 810 | fn openDirAccessMaskW(self: Dir, sub_path_w: [*:0]const u16, access_mask: u32) OpenError!Dir { |
| 982 | 811 | const w = os.windows; |
| 983 | 812 | |
| ... | ... | @@ -1198,7 +1027,7 @@ pub const Dir = struct { |
| 1198 | 1027 | error.Unexpected, |
| 1199 | 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 | 1031 | error.NotDir => { |
| 1203 | 1032 | if (got_access_denied) { |
| 1204 | 1033 | return error.AccessDenied; |
| ... | ... | @@ -1231,7 +1060,6 @@ pub const Dir = struct { |
| 1231 | 1060 | |
| 1232 | 1061 | var dir_name_buf: [MAX_PATH_BYTES]u8 = undefined; |
| 1233 | 1062 | var dir_name: []const u8 = sub_path; |
| 1234 | var parent_dir = self; | |
| 1235 | 1063 | |
| 1236 | 1064 | // Here we must avoid recursion, in order to provide O(1) memory guarantee of this function. |
| 1237 | 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 | 1091 | => |e| return e, |
| 1264 | 1092 | } |
| 1265 | 1093 | |
| 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 | 1095 | error.NotDir => { |
| 1268 | 1096 | if (got_access_denied) { |
| 1269 | 1097 | return error.AccessDenied; |
| ... | ... | @@ -1370,9 +1198,96 @@ pub const Dir = struct { |
| 1370 | 1198 | pub fn accessW(self: Dir, sub_path_w: [*:0]const u16, flags: File.OpenFlags) AccessError!void { |
| 1371 | 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 | }; |
| 1374 | 1289 | |
| 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 | 1291 | /// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior. |
| 1377 | 1292 | /// On POSIX targets, this function is comptime-callable. |
| 1378 | 1293 | pub fn cwd() Dir { |
| ... | ... | @@ -1450,6 +1365,25 @@ pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) DeleteFileError!void |
| 1450 | 1365 | return cwd().deleteFileW(absolute_path_w); |
| 1451 | 1366 | } |
| 1452 | 1367 | |
| 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. | |
| 1373 | pub 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 | ||
| 1453 | 1387 | pub const Walker = struct { |
| 1454 | 1388 | stack: std.ArrayList(StackItem), |
| 1455 | 1389 | name_buffer: std.Buffer, |
| ... | ... | @@ -1484,7 +1418,7 @@ pub const Walker = struct { |
| 1484 | 1418 | try self.name_buffer.appendByte(path.sep); |
| 1485 | 1419 | try self.name_buffer.append(base.name); |
| 1486 | 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 | 1422 | error.NameTooLong => unreachable, // no path sep in base.name |
| 1489 | 1423 | else => |e| return e, |
| 1490 | 1424 | }; |
| ... | ... | @@ -1522,7 +1456,7 @@ pub const Walker = struct { |
| 1522 | 1456 | pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { |
| 1523 | 1457 | assert(!mem.endsWith(u8, dir_path, path.sep_str)); |
| 1524 | 1458 | |
| 1525 | var dir = try cwd().openDirList(dir_path); | |
| 1459 | var dir = try cwd().openDir(dir_path, .{ .iterate = true }); | |
| 1526 | 1460 | errdefer dir.close(); |
| 1527 | 1461 | |
| 1528 | 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 | 1475 | return walker; |
| 1542 | 1476 | } |
| 1543 | 1477 | |
| 1544 | /// Read value of a symbolic link. | |
| 1545 | /// The return value is a slice of buffer, from index `0`. | |
| 1478 | /// Deprecated; use `Dir.readLink`. | |
| 1546 | 1479 | pub fn readLink(pathname: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { |
| 1547 | 1480 | return os.readlink(pathname, buffer); |
| 1548 | 1481 | } |
| 1549 | 1482 | |
| 1550 | /// Same as `readLink`, except the parameter is null-terminated. | |
| 1483 | /// Deprecated; use `Dir.readLinkC`. | |
| 1551 | 1484 | pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { |
| 1552 | 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 | 1587 | } |
| 1655 | 1588 | |
| 1656 | 1589 | /// `realpath`, except caller must free the returned memory. |
| 1590 | /// TODO integrate with `Dir` | |
| 1657 | 1591 | pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 { |
| 1658 | 1592 | var buf: [MAX_PATH_BYTES]u8 = undefined; |
| 1659 | 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 | 1596 | test "" { |
| 1663 | 1597 | _ = makeDirAbsolute; |
| 1664 | 1598 | _ = makeDirAbsoluteZ; |
| 1599 | _ = copyFileAbsolute; | |
| 1600 | _ = updateFileAbsolute; | |
| 1601 | _ = Dir.copyFile; | |
| 1665 | 1602 | _ = @import("fs/path.zig"); |
| 1666 | 1603 | _ = @import("fs/file.zig"); |
| 1667 | 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 | 619 | if (true) return error.SkipZigTest; |
| 620 | 620 | |
| 621 | 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 {}; | |
| 623 | 623 | |
| 624 | 624 | const allocator = std.heap.page_allocator; |
| 625 | 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 | 40 | .DeepRecursive => hashArray(hasher, key, .DeepRecursive), |
| 41 | 41 | }, |
| 42 | 42 | |
| 43 | .Many, .C, => switch (strat) { | |
| 43 | .Many, | |
| 44 | .C, | |
| 45 | => switch (strat) { | |
| 44 | 46 | .Shallow => hash(hasher, @ptrToInt(key), .Shallow), |
| 45 | 47 | else => @compileError( |
| 46 | 48 | \\ unknown-length pointers and C pointers cannot be hashed deeply. |
| ... | ... | @@ -236,9 +238,11 @@ test "hash slice shallow" { |
| 236 | 238 | defer std.testing.allocator.destroy(array1); |
| 237 | 239 | array1.* = [_]u32{ 1, 2, 3, 4, 5, 6 }; |
| 238 | 240 | const array2 = [_]u32{ 1, 2, 3, 4, 5, 6 }; |
| 239 | const a = array1[0..]; | |
| 240 | const b = array2[0..]; | |
| 241 | const c = array1[0..3]; | |
| 241 | // TODO audit deep/shallow - maybe it has the wrong behavior with respect to array pointers and slices | |
| 242 | var runtime_zero: usize = 0; | |
| 243 | const a = array1[runtime_zero..]; | |
| 244 | const b = array2[runtime_zero..]; | |
| 245 | const c = array1[runtime_zero..3]; | |
| 242 | 246 | testing.expect(testHashShallow(a) == testHashShallow(a)); |
| 243 | 247 | testing.expect(testHashShallow(a) != testHashShallow(array1)); |
| 244 | 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 | 39 | pub fn init(key: []const u8) Self { |
| 40 | 40 | assert(key.len >= 16); |
| 41 | 41 | |
| 42 | const k0 = mem.readIntSliceLittle(u64, key[0..8]); | |
| 43 | const k1 = mem.readIntSliceLittle(u64, key[8..16]); | |
| 42 | const k0 = mem.readIntLittle(u64, key[0..8]); | |
| 43 | const k1 = mem.readIntLittle(u64, key[8..16]); | |
| 44 | 44 | |
| 45 | 45 | var d = Self{ |
| 46 | 46 | .v0 = k0 ^ 0x736f6d6570736575, |
| ... | ... | @@ -111,7 +111,7 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round |
| 111 | 111 | fn round(self: *Self, b: []const u8) void { |
| 112 | 112 | assert(b.len == 8); |
| 113 | 113 | |
| 114 | const m = mem.readIntSliceLittle(u64, b[0..]); | |
| 114 | const m = mem.readIntLittle(u64, b[0..8]); | |
| 115 | 115 | self.v3 ^= m; |
| 116 | 116 | |
| 117 | 117 | // 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 | 11 | |
| 12 | 12 | fn read_bytes(comptime bytes: u8, data: []const u8) u64 { |
| 13 | 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 | } |
| 16 | 16 | |
| 17 | 17 | fn read_8bytes_swapped(data: []const u8) u64 { |
lib/std/io/serialization.zig+5-1| ... | ... | @@ -1,6 +1,10 @@ |
| 1 | 1 | const std = @import("../std.zig"); |
| 2 | 2 | const builtin = std.builtin; |
| 3 | 3 | const io = std.io; |
| 4 | const assert = std.debug.assert; | |
| 5 | const math = std.math; | |
| 6 | const meta = std.meta; | |
| 7 | const trait = meta.trait; | |
| 4 | 8 | |
| 5 | 9 | pub const Packing = enum { |
| 6 | 10 | /// Pack data to byte alignment |
| ... | ... | @@ -252,7 +256,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co |
| 252 | 256 | byte.* = if (t_bit_count < u8_bit_count) v else @truncate(u8, v); |
| 253 | 257 | } |
| 254 | 258 | |
| 255 | try self.out_stream.write(&buffer); | |
| 259 | try self.out_stream.writeAll(&buffer); | |
| 256 | 260 | } |
| 257 | 261 | |
| 258 | 262 | /// Serializes the passed value into the stream |
lib/std/json.zig+16-7| ... | ... | @@ -2249,11 +2249,16 @@ pub const StringifyOptions = struct { |
| 2249 | 2249 | // TODO: allow picking if []u8 is string or array? |
| 2250 | 2250 | }; |
| 2251 | 2251 | |
| 2252 | pub const StringifyError = error{ | |
| 2253 | TooMuchData, | |
| 2254 | DifferentData, | |
| 2255 | }; | |
| 2256 | ||
| 2252 | 2257 | pub fn stringify( |
| 2253 | 2258 | value: var, |
| 2254 | 2259 | options: StringifyOptions, |
| 2255 | 2260 | out_stream: var, |
| 2256 | ) !void { | |
| 2261 | ) StringifyError!void { | |
| 2257 | 2262 | const T = @TypeOf(value); |
| 2258 | 2263 | switch (@typeInfo(T)) { |
| 2259 | 2264 | .Float, .ComptimeFloat => { |
| ... | ... | @@ -2320,9 +2325,15 @@ pub fn stringify( |
| 2320 | 2325 | return; |
| 2321 | 2326 | }, |
| 2322 | 2327 | .Pointer => |ptr_info| switch (ptr_info.size) { |
| 2323 | .One => { | |
| 2324 | // TODO: avoid loops? | |
| 2325 | return try stringify(value.*, options, out_stream); | |
| 2328 | .One => switch (@typeInfo(ptr_info.child)) { | |
| 2329 | .Array => { | |
| 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 | 2338 | // TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972) |
| 2328 | 2339 | .Slice => { |
| ... | ... | @@ -2381,9 +2392,7 @@ pub fn stringify( |
| 2381 | 2392 | }, |
| 2382 | 2393 | else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"), |
| 2383 | 2394 | }, |
| 2384 | .Array => |info| { | |
| 2385 | return try stringify(value[0..], options, out_stream); | |
| 2386 | }, | |
| 2395 | .Array => return stringify(&value, options, out_stream), | |
| 2387 | 2396 | else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"), |
| 2388 | 2397 | } |
| 2389 | 2398 | unreachable; |
lib/std/math/big/int.zig+2-2| ... | ... | @@ -520,13 +520,13 @@ pub const Int = struct { |
| 520 | 520 | comptime fmt: []const u8, |
| 521 | 521 | options: std.fmt.FormatOptions, |
| 522 | 522 | out_stream: var, |
| 523 | ) FmtError!void { | |
| 523 | ) !void { | |
| 524 | 524 | self.assertWritable(); |
| 525 | 525 | // TODO look at fmt and support other bases |
| 526 | 526 | // TODO support read-only fixed integers |
| 527 | 527 | const str = self.toString(self.allocator.?, 10) catch @panic("TODO make this non allocating"); |
| 528 | 528 | defer self.allocator.?.free(str); |
| 529 | return out_stream.print(str); | |
| 529 | return out_stream.writeAll(str); | |
| 530 | 530 | } |
| 531 | 531 | |
| 532 | 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 | 116 | pub fn allocSentinel(self: *Allocator, comptime Elem: type, n: usize, comptime sentinel: Elem) Error![:sentinel]Elem { |
| 117 | 117 | var ptr = try self.alloc(Elem, n + 1); |
| 118 | 118 | ptr[n] = sentinel; |
| 119 | return ptr[0 .. n :sentinel]; | |
| 119 | return ptr[0..n :sentinel]; | |
| 120 | 120 | } |
| 121 | 121 | |
| 122 | 122 | pub fn alignedAlloc( |
| ... | ... | @@ -496,14 +496,14 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool { |
| 496 | 496 | return true; |
| 497 | 497 | } |
| 498 | 498 | |
| 499 | /// Deprecated. Use `span`. | |
| 499 | /// Deprecated. Use `spanZ`. | |
| 500 | 500 | pub 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 | } |
| 503 | 503 | |
| 504 | /// Deprecated. Use `span`. | |
| 504 | /// Deprecated. Use `spanZ`. | |
| 505 | 505 | pub 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 | } |
| 508 | 508 | |
| 509 | 509 | /// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and |
| ... | ... | @@ -548,6 +548,9 @@ test "Span" { |
| 548 | 548 | /// returns a slice. If there is a sentinel on the input type, there will be a |
| 549 | 549 | /// sentinel on the output type. The constness of the output type matches |
| 550 | 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. | |
| 551 | 554 | pub fn span(ptr: var) Span(@TypeOf(ptr)) { |
| 552 | 555 | const Result = Span(@TypeOf(ptr)); |
| 553 | 556 | const l = len(ptr); |
| ... | ... | @@ -560,20 +563,42 @@ pub fn span(ptr: var) Span(@TypeOf(ptr)) { |
| 560 | 563 | |
| 561 | 564 | test "span" { |
| 562 | 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 | 567 | testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 })); |
| 565 | 568 | testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 })); |
| 566 | 569 | } |
| 567 | 570 | |
| 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. | |
| 574 | pub 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 | ||
| 584 | test "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 | 591 | /// Takes a pointer to an array, an array, a sentinel-terminated pointer, |
| 569 | 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. | |
| 570 | 595 | pub fn len(ptr: var) usize { |
| 571 | 596 | return switch (@typeInfo(@TypeOf(ptr))) { |
| 572 | 597 | .Array => |info| info.len, |
| 573 | 598 | .Pointer => |info| switch (info.size) { |
| 574 | 599 | .One => switch (@typeInfo(info.child)) { |
| 575 | .Array => |x| x.len, | |
| 576 | else => @compileError("invalid type given to std.mem.length"), | |
| 600 | .Array => ptr.len, | |
| 601 | else => @compileError("invalid type given to std.mem.len"), | |
| 577 | 602 | }, |
| 578 | 603 | .Many => if (info.sentinel) |sentinel| |
| 579 | 604 | indexOfSentinel(info.child, sentinel, ptr) |
| ... | ... | @@ -582,7 +607,7 @@ pub fn len(ptr: var) usize { |
| 582 | 607 | .C => indexOfSentinel(info.child, 0, ptr), |
| 583 | 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 | } |
| 588 | 613 | |
| ... | ... | @@ -594,9 +619,67 @@ test "len" { |
| 594 | 619 | testing.expect(len(&array) == 5); |
| 595 | 620 | testing.expect(len(array[0..3]) == 3); |
| 596 | 621 | array[2] = 0; |
| 597 | const ptr = array[0..2 :0].ptr; | |
| 622 | const ptr = @as([*:0]u16, array[0..2 :0]); | |
| 598 | 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. | |
| 638 | pub 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 | ||
| 666 | test "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 | } |
| 601 | 684 | |
| 602 | 685 | pub fn indexOfSentinel(comptime Elem: type, comptime sentinel: Elem, ptr: [*:sentinel]const Elem) usize { |
| ... | ... | @@ -810,8 +893,7 @@ pub const readIntBig = switch (builtin.endian) { |
| 810 | 893 | pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T { |
| 811 | 894 | const n = @divExact(T.bit_count, 8); |
| 812 | 895 | assert(bytes.len >= n); |
| 813 | // TODO https://github.com/ziglang/zig/issues/863 | |
| 814 | return readIntNative(T, @ptrCast(*const [n]u8, bytes.ptr)); | |
| 896 | return readIntNative(T, bytes[0..n]); | |
| 815 | 897 | } |
| 816 | 898 | |
| 817 | 899 | /// 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 | 931 | pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T { |
| 850 | 932 | const n = @divExact(T.bit_count, 8); |
| 851 | 933 | assert(bytes.len >= n); |
| 852 | // TODO https://github.com/ziglang/zig/issues/863 | |
| 853 | return readInt(T, @ptrCast(*const [n]u8, bytes.ptr), endian); | |
| 934 | return readInt(T, bytes[0..n], endian); | |
| 854 | 935 | } |
| 855 | 936 | |
| 856 | 937 | test "comptime read/write int" { |
| ... | ... | @@ -1572,24 +1653,24 @@ pub fn nativeToBig(comptime T: type, x: T) T { |
| 1572 | 1653 | } |
| 1573 | 1654 | |
| 1574 | 1655 | fn AsBytesReturnType(comptime P: type) type { |
| 1575 | if (comptime !trait.isSingleItemPtr(P)) | |
| 1656 | if (!trait.isSingleItemPtr(P)) | |
| 1576 | 1657 | @compileError("expected single item pointer, passed " ++ @typeName(P)); |
| 1577 | 1658 | |
| 1578 | const size = @as(usize, @sizeOf(meta.Child(P))); | |
| 1579 | const alignment = comptime meta.alignment(P); | |
| 1659 | const size = @sizeOf(meta.Child(P)); | |
| 1660 | const alignment = meta.alignment(P); | |
| 1580 | 1661 | |
| 1581 | 1662 | if (alignment == 0) { |
| 1582 | if (comptime trait.isConstPtr(P)) | |
| 1663 | if (trait.isConstPtr(P)) | |
| 1583 | 1664 | return *const [size]u8; |
| 1584 | 1665 | return *[size]u8; |
| 1585 | 1666 | } |
| 1586 | 1667 | |
| 1587 | if (comptime trait.isConstPtr(P)) | |
| 1668 | if (trait.isConstPtr(P)) | |
| 1588 | 1669 | return *align(alignment) const [size]u8; |
| 1589 | 1670 | return *align(alignment) [size]u8; |
| 1590 | 1671 | } |
| 1591 | 1672 | |
| 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. | |
| 1593 | 1674 | pub fn asBytes(ptr: var) AsBytesReturnType(@TypeOf(ptr)) { |
| 1594 | 1675 | const P = @TypeOf(ptr); |
| 1595 | 1676 | return @ptrCast(AsBytesReturnType(P), ptr); |
| ... | ... | @@ -1736,34 +1817,50 @@ fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type { |
| 1736 | 1817 | } |
| 1737 | 1818 | |
| 1738 | 1819 | pub 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 | 1820 | // let's not give an undefined pointer to @ptrCast |
| 1742 | 1821 | // it may be equal to zero and fail a null check |
| 1743 | if (bytesSlice.len == 0) { | |
| 1822 | if (bytes.len == 0) { | |
| 1744 | 1823 | return &[0]T{}; |
| 1745 | 1824 | } |
| 1746 | 1825 | |
| 1747 | const bytesType = @TypeOf(bytesSlice); | |
| 1748 | const alignment = comptime meta.alignment(bytesType); | |
| 1826 | const Bytes = @TypeOf(bytes); | |
| 1827 | const alignment = comptime meta.alignment(Bytes); | |
| 1749 | 1828 | |
| 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; | |
| 1751 | 1830 | |
| 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 | } |
| 1754 | 1833 | |
| 1755 | 1834 | test "bytesAsSlice" { |
| 1756 | const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; | |
| 1757 | const slice = bytesAsSlice(u16, bytes[0..]); | |
| 1758 | testing.expect(slice.len == 2); | |
| 1759 | testing.expect(bigToNative(u16, slice[0]) == 0xDEAD); | |
| 1760 | testing.expect(bigToNative(u16, slice[1]) == 0xBEEF); | |
| 1835 | { | |
| 1836 | const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; | |
| 1837 | const slice = bytesAsSlice(u16, bytes[0..]); | |
| 1838 | testing.expect(slice.len == 2); | |
| 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 | } |
| 1762 | 1851 | |
| 1763 | 1852 | test "bytesAsSlice keeps pointer alignment" { |
| 1764 | var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 }; | |
| 1765 | const numbers = bytesAsSlice(u32, bytes[0..]); | |
| 1766 | comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32); | |
| 1853 | { | |
| 1854 | var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 }; | |
| 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 | } |
| 1768 | 1865 | |
| 1769 | 1866 | test "bytesAsSlice on a packed struct" { |
| ... | ... | @@ -1799,21 +1896,19 @@ fn SliceAsBytesReturnType(comptime sliceType: type) type { |
| 1799 | 1896 | } |
| 1800 | 1897 | |
| 1801 | 1898 | pub fn sliceAsBytes(slice: var) SliceAsBytesReturnType(@TypeOf(slice)) { |
| 1802 | const actualSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(slice))) slice[0..] else slice; | |
| 1803 | const actualSliceTypeInfo = @typeInfo(@TypeOf(actualSlice)).Pointer; | |
| 1899 | const Slice = @TypeOf(slice); | |
| 1804 | 1900 | |
| 1805 | 1901 | // let's not give an undefined pointer to @ptrCast |
| 1806 | 1902 | // 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 | 1904 | return &[0]u8{}; |
| 1809 | 1905 | } |
| 1810 | 1906 | |
| 1811 | const sliceType = @TypeOf(actualSlice); | |
| 1812 | const alignment = comptime meta.alignment(sliceType); | |
| 1907 | const alignment = comptime meta.alignment(Slice); | |
| 1813 | 1908 | |
| 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; | |
| 1815 | 1910 | |
| 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 | } |
| 1818 | 1913 | |
| 1819 | 1914 | test "sliceAsBytes" { |
| ... | ... | @@ -1883,39 +1978,6 @@ test "sliceAsBytes and bytesAsSlice back" { |
| 1883 | 1978 | testing.expect(bytes[11] == math.maxInt(u8)); |
| 1884 | 1979 | } |
| 1885 | 1980 | |
| 1886 | fn 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 | |
| 1894 | pub 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 | ||
| 1906 | test "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 | 1981 | /// Round an address up to the nearest aligned address |
| 1920 | 1982 | /// The alignment must be a power of 2 and greater than 0. |
| 1921 | 1983 | pub 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 | 104 | .Array => |info| info.child, |
| 105 | 105 | .Pointer => |info| info.child, |
| 106 | 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 | } |
| 110 | 110 | |
| ... | ... | @@ -115,30 +115,65 @@ test "std.meta.Child" { |
| 115 | 115 | testing.expect(Child(?u8) == u8); |
| 116 | 116 | } |
| 117 | 117 | |
| 118 | /// Given a type with a sentinel e.g. `[:0]u8`, returns the sentinel | |
| 119 | pub fn Sentinel(comptime T: type) Child(T) { | |
| 120 | // comptime asserts that ptr has a sentinel | |
| 118 | /// Given a "memory span" type, returns the "element type". | |
| 119 | pub fn Elem(comptime T: type) type { | |
| 121 | 120 | switch (@typeInfo(T)) { |
| 122 | .Array => |arrayInfo| { | |
| 123 | return comptime arrayInfo.sentinel.?; | |
| 121 | .Array => |info| return info.child, | |
| 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| { | |
| 126 | switch (ptrInfo.size) { | |
| 127 | .Many, .Slice => { | |
| 128 | return comptime ptrInfo.sentinel.?; | |
| 129 | else => {}, | |
| 130 | } | |
| 131 | @compileError("Expected pointer, slice, or array, found '" ++ @typeName(T) ++ "'"); | |
| 132 | } | |
| 133 | ||
| 134 | test "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. | |
| 144 | pub 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 | 154 | else => {}, |
| 131 | 155 | } |
| 132 | 156 | }, |
| 133 | 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 | } |
| 137 | 161 | |
| 138 | test "std.meta.Sentinel" { | |
| 139 | testing.expectEqual(@as(u8, 0), Sentinel([:0]u8)); | |
| 140 | testing.expectEqual(@as(u8, 0), Sentinel([*:0]u8)); | |
| 141 | testing.expectEqual(@as(u8, 0), Sentinel([5:0]u8)); | |
| 162 | test "std.meta.sentinel" { | |
| 163 | testSentinel(); | |
| 164 | comptime testSentinel(); | |
| 165 | } | |
| 166 | ||
| 167 | fn 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 | } |
| 143 | 178 | |
| 144 | 179 | pub 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 | 230 | |
| 231 | 231 | test "std.meta.trait.isSingleItemPtr" { |
| 232 | 232 | const array = [_]u8{0} ** 10; |
| 233 | testing.expect(isSingleItemPtr(@TypeOf(&array[0]))); | |
| 234 | testing.expect(!isSingleItemPtr(@TypeOf(array))); | |
| 235 | testing.expect(!isSingleItemPtr(@TypeOf(array[0..1]))); | |
| 233 | comptime testing.expect(isSingleItemPtr(@TypeOf(&array[0]))); | |
| 234 | comptime testing.expect(!isSingleItemPtr(@TypeOf(array))); | |
| 235 | var runtime_zero: usize = 0; | |
| 236 | testing.expect(!isSingleItemPtr(@TypeOf(array[runtime_zero..1]))); | |
| 236 | 237 | } |
| 237 | 238 | |
| 238 | 239 | pub fn isManyItemPtr(comptime T: type) bool { |
| ... | ... | @@ -259,7 +260,8 @@ pub fn isSlice(comptime T: type) bool { |
| 259 | 260 | |
| 260 | 261 | test "std.meta.trait.isSlice" { |
| 261 | 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 | 265 | testing.expect(!isSlice(@TypeOf(array))); |
| 264 | 266 | testing.expect(!isSlice(@TypeOf(&array[0]))); |
| 265 | 267 | } |
| ... | ... | @@ -276,7 +278,7 @@ pub fn isIndexable(comptime T: type) bool { |
| 276 | 278 | |
| 277 | 279 | test "std.meta.trait.isIndexable" { |
| 278 | 280 | const array = [_]u8{0} ** 10; |
| 279 | const slice = array[0..]; | |
| 281 | const slice = @as([]const u8, &array); | |
| 280 | 282 | |
| 281 | 283 | testing.expect(isIndexable(@TypeOf(array))); |
| 282 | 284 | testing.expect(isIndexable(@TypeOf(&array))); |
lib/std/net.zig+7-5| ... | ... | @@ -612,8 +612,7 @@ fn linuxLookupName( |
| 612 | 612 | } else { |
| 613 | 613 | mem.copy(u8, &sa6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff"); |
| 614 | 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/863 | |
| 616 | mem.writeIntNative(u32, @ptrCast(*[4]u8, da6.addr[12..].ptr), addr.addr.in.addr); | |
| 615 | mem.writeIntNative(u32, da6.addr[12..], addr.addr.in.addr); | |
| 617 | 616 | da4.addr = addr.addr.in.addr; |
| 618 | 617 | da = @ptrCast(*os.sockaddr, &da4); |
| 619 | 618 | dalen = @sizeOf(os.sockaddr_in); |
| ... | ... | @@ -821,7 +820,7 @@ fn linuxLookupNameFromHosts( |
| 821 | 820 | // Skip to the delimiter in the stream, to fix parsing |
| 822 | 821 | try stream.skipUntilDelimiterOrEof('\n'); |
| 823 | 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 | 825 | else => |e| return e, |
| 827 | 826 | }) |line| { |
| ... | ... | @@ -958,7 +957,10 @@ fn linuxLookupNameFromDns( |
| 958 | 957 | } |
| 959 | 958 | } |
| 960 | 959 | |
| 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 | 964 | try resMSendRc(qp[0..nq], ap[0..nq], apbuf[0..nq], rc); |
| 963 | 965 | |
| 964 | 966 | var i: usize = 0; |
| ... | ... | @@ -1015,7 +1017,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void { |
| 1015 | 1017 | // Skip to the delimiter in the stream, to fix parsing |
| 1016 | 1018 | try stream.skipUntilDelimiterOrEof('\n'); |
| 1017 | 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 | 1022 | else => |e| return e, |
| 1021 | 1023 | }) |line| { |
lib/std/os.zig+143-5| ... | ... | @@ -461,13 +461,11 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void { |
| 461 | 461 | ); |
| 462 | 462 | |
| 463 | 463 | switch (rc) { |
| 464 | .SUCCESS => {}, | |
| 464 | .SUCCESS => return, | |
| 465 | 465 | .INVALID_HANDLE => unreachable, // Handle not open for writing |
| 466 | 466 | .ACCESS_DENIED => return error.CannotTruncate, |
| 467 | 467 | else => return windows.unexpectedStatus(rc), |
| 468 | 468 | } |
| 469 | ||
| 470 | return; | |
| 471 | 469 | } |
| 472 | 470 | |
| 473 | 471 | while (true) { |
| ... | ... | @@ -852,6 +850,7 @@ pub const OpenError = error{ |
| 852 | 850 | |
| 853 | 851 | /// Open and possibly create a file. Keeps trying if it gets interrupted. |
| 854 | 852 | /// See also `openC`. |
| 853 | /// TODO support windows | |
| 855 | 854 | pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t { |
| 856 | 855 | const file_path_c = try toPosixPath(file_path); |
| 857 | 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 | 858 | |
| 860 | 859 | /// Open and possibly create a file. Keeps trying if it gets interrupted. |
| 861 | 860 | /// See also `open`. |
| 861 | /// TODO support windows | |
| 862 | 862 | pub fn openC(file_path: [*:0]const u8, flags: u32, perm: usize) OpenError!fd_t { |
| 863 | 863 | while (true) { |
| 864 | 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 | 892 | /// Open and possibly create a file. Keeps trying if it gets interrupted. |
| 893 | 893 | /// `file_path` is relative to the open directory handle `dir_fd`. |
| 894 | 894 | /// See also `openatC`. |
| 895 | /// TODO support windows | |
| 895 | 896 | pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) OpenError!fd_t { |
| 896 | 897 | const file_path_c = try toPosixPath(file_path); |
| 897 | 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 | 901 | /// Open and possibly create a file. Keeps trying if it gets interrupted. |
| 901 | 902 | /// `file_path` is relative to the open directory handle `dir_fd`. |
| 902 | 903 | /// See also `openat`. |
| 904 | /// TODO support windows | |
| 903 | 905 | pub fn openatC(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t) OpenError!fd_t { |
| 904 | 906 | while (true) { |
| 905 | 907 | const rc = system.openat(dir_fd, file_path, flags, mode); |
| ... | ... | @@ -1527,6 +1529,9 @@ const RenameError = error{ |
| 1527 | 1529 | RenameAcrossMountPoints, |
| 1528 | 1530 | InvalidUtf8, |
| 1529 | 1531 | BadPathName, |
| 1532 | NoDevice, | |
| 1533 | SharingViolation, | |
| 1534 | PipeBusy, | |
| 1530 | 1535 | } || UnexpectedError; |
| 1531 | 1536 | |
| 1532 | 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 | 1585 | return windows.MoveFileExW(old_path, new_path, flags); |
| 1581 | 1586 | } |
| 1582 | 1587 | |
| 1588 | /// Change the name or location of a file based on an open directory handle. | |
| 1589 | pub 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. | |
| 1607 | pub 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. | |
| 1646 | pub 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 | ||
| 1583 | 1695 | pub const MakeDirError = error{ |
| 1584 | 1696 | AccessDenied, |
| 1585 | 1697 | DiskQuota, |
| ... | ... | @@ -2072,7 +2184,7 @@ const ListenError = error{ |
| 2072 | 2184 | OperationNotSupported, |
| 2073 | 2185 | } || UnexpectedError; |
| 2074 | 2186 | |
| 2075 | pub fn listen(sockfd: i32, backlog: u32) ListenError!void { | |
| 2187 | pub fn listen(sockfd: fd_t, backlog: u32) ListenError!void { | |
| 2076 | 2188 | const rc = system.listen(sockfd, backlog); |
| 2077 | 2189 | switch (errno(rc)) { |
| 2078 | 2190 | 0 => return, |
| ... | ... | @@ -2363,7 +2475,7 @@ pub fn connect(sockfd: fd_t, sock_addr: *const sockaddr, len: socklen_t) Connect |
| 2363 | 2475 | } |
| 2364 | 2476 | } |
| 2365 | 2477 | |
| 2366 | pub fn getsockoptError(sockfd: i32) ConnectError!void { | |
| 2478 | pub fn getsockoptError(sockfd: fd_t) ConnectError!void { | |
| 2367 | 2479 | var err_code: u32 = undefined; |
| 2368 | 2480 | var size: u32 = @sizeOf(u32); |
| 2369 | 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 | 3163 | } |
| 3052 | 3164 | } |
| 3053 | 3165 | |
| 3166 | pub const FcntlError = error{ | |
| 3167 | PermissionDenied, | |
| 3168 | FileBusy, | |
| 3169 | ProcessFdQuotaExceeded, | |
| 3170 | Locked, | |
| 3171 | } || UnexpectedError; | |
| 3172 | ||
| 3173 | pub 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 | ||
| 3054 | 3191 | pub const RealPathError = error{ |
| 3055 | 3192 | FileNotFound, |
| 3056 | 3193 | AccessDenied, |
| ... | ... | @@ -3125,6 +3262,7 @@ pub fn realpathC(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealP |
| 3125 | 3262 | } |
| 3126 | 3263 | |
| 3127 | 3264 | /// Same as `realpath` except `pathname` is null-terminated and UTF16LE-encoded. |
| 3265 | /// TODO use ntdll for better semantics | |
| 3128 | 3266 | pub fn realpathW(pathname: [*:0]const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { |
| 3129 | 3267 | const h_file = try windows.CreateFileW( |
| 3130 | 3268 | pathname, |
lib/std/os/bits/dragonfly.zig+2| ... | ... | @@ -283,6 +283,8 @@ pub const F_LOCK = 1; |
| 283 | 283 | pub const F_TLOCK = 2; |
| 284 | 284 | pub const F_TEST = 3; |
| 285 | 285 | |
| 286 | pub const FD_CLOEXEC = 1; | |
| 287 | ||
| 286 | 288 | pub const AT_FDCWD = -328243; |
| 287 | 289 | pub const AT_SYMLINK_NOFOLLOW = 1; |
| 288 | 290 | pub const AT_REMOVEDIR = 2; |
lib/std/os/bits/freebsd.zig+2| ... | ... | @@ -355,6 +355,8 @@ pub const F_GETOWN_EX = 16; |
| 355 | 355 | |
| 356 | 356 | pub const F_GETOWNER_UIDS = 17; |
| 357 | 357 | |
| 358 | pub const FD_CLOEXEC = 1; | |
| 359 | ||
| 358 | 360 | pub const SEEK_SET = 0; |
| 359 | 361 | pub const SEEK_CUR = 1; |
| 360 | 362 | pub const SEEK_END = 2; |
lib/std/os/bits/linux.zig+2| ... | ... | @@ -136,6 +136,8 @@ pub const MAP_FIXED_NOREPLACE = 0x100000; |
| 136 | 136 | /// For anonymous mmap, memory could be uninitialized |
| 137 | 137 | pub const MAP_UNINITIALIZED = 0x4000000; |
| 138 | 138 | |
| 139 | pub const FD_CLOEXEC = 1; | |
| 140 | ||
| 139 | 141 | pub const F_OK = 0; |
| 140 | 142 | pub const X_OK = 1; |
| 141 | 143 | pub const W_OK = 2; |
lib/std/os/bits/netbsd.zig+2| ... | ... | @@ -312,6 +312,8 @@ pub const F_GETLK = 7; |
| 312 | 312 | pub const F_SETLK = 8; |
| 313 | 313 | pub const F_SETLKW = 9; |
| 314 | 314 | |
| 315 | pub const FD_CLOEXEC = 1; | |
| 316 | ||
| 315 | 317 | pub const SEEK_SET = 0; |
| 316 | 318 | pub const SEEK_CUR = 1; |
| 317 | 319 | pub 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 | 465 | return syscall4( |
| 466 | 466 | SYS_renameat, |
| 467 | 467 | @bitCast(usize, @as(isize, oldfd)), |
| 468 | @ptrToInt(old), | |
| 468 | @ptrToInt(oldpath), | |
| 469 | 469 | @bitCast(usize, @as(isize, newfd)), |
| 470 | @ptrToInt(new), | |
| 470 | @ptrToInt(newpath), | |
| 471 | 471 | ); |
| 472 | 472 | } else { |
| 473 | 473 | return syscall5( |
| 474 | 474 | SYS_renameat2, |
| 475 | 475 | @bitCast(usize, @as(isize, oldfd)), |
| 476 | @ptrToInt(old), | |
| 476 | @ptrToInt(oldpath), | |
| 477 | 477 | @bitCast(usize, @as(isize, newfd)), |
| 478 | @ptrToInt(new), | |
| 478 | @ptrToInt(newpath), | |
| 479 | 479 | 0, |
| 480 | 480 | ); |
| 481 | 481 | } |
| ... | ... | @@ -588,6 +588,10 @@ pub fn waitpid(pid: pid_t, status: *u32, flags: u32) usize { |
| 588 | 588 | return syscall4(SYS_wait4, @bitCast(usize, @as(isize, pid)), @ptrToInt(status), flags, 0); |
| 589 | 589 | } |
| 590 | 590 | |
| 591 | pub 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 | ||
| 591 | 595 | var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime); |
| 592 | 596 | |
| 593 | 597 | // 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 | 1 | const std = @import("../std.zig"); |
| 2 | 2 | const os = std.os; |
| 3 | 3 | const testing = std.testing; |
| 4 | const expect = std.testing.expect; | |
| 4 | const expect = testing.expect; | |
| 5 | const expectEqual = testing.expectEqual; | |
| 5 | 6 | const io = std.io; |
| 6 | 7 | const fs = std.fs; |
| 7 | 8 | const mem = std.mem; |
| ... | ... | @@ -19,8 +20,8 @@ test "makePath, put some files in it, deleteTree" { |
| 19 | 20 | try fs.cwd().makePath("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c"); |
| 20 | 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 | 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 | if (fs.cwd().openDirTraverse("os_test_tmp")) |dir| { | |
| 23 | try fs.cwd().deleteTree("os_test_tmp"); | |
| 24 | if (fs.cwd().openDir("os_test_tmp", .{})) |dir| { | |
| 24 | 25 | @panic("expected error"); |
| 25 | 26 | } else |err| { |
| 26 | 27 | expect(err == error.FileNotFound); |
| ... | ... | @@ -37,7 +38,7 @@ test "access file" { |
| 37 | 38 | |
| 38 | 39 | try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", ""); |
| 39 | 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 | } |
| 42 | 43 | |
| 43 | 44 | fn testThreadIdFn(thread_id: *Thread.Id) void { |
| ... | ... | @@ -46,9 +47,9 @@ fn testThreadIdFn(thread_id: *Thread.Id) void { |
| 46 | 47 | |
| 47 | 48 | test "sendfile" { |
| 48 | 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 {}; | |
| 50 | 51 | |
| 51 | var dir = try fs.cwd().openDirList("os_test_tmp"); | |
| 52 | var dir = try fs.cwd().openDir("os_test_tmp", .{}); | |
| 52 | 53 | defer dir.close(); |
| 53 | 54 | |
| 54 | 55 | const line1 = "line1\n"; |
| ... | ... | @@ -112,14 +113,16 @@ test "fs.copyFile" { |
| 112 | 113 | const dest_file = "tmp_test_copy_file2.txt"; |
| 113 | 114 | const dest_file2 = "tmp_test_copy_file3.txt"; |
| 114 | 115 | |
| 115 | try fs.cwd().writeFile(src_file, data); | |
| 116 | defer fs.cwd().deleteFile(src_file) catch {}; | |
| 116 | const cwd = fs.cwd(); | |
| 117 | 117 | |
| 118 | try fs.copyFile(src_file, dest_file); | |
| 119 | defer fs.cwd().deleteFile(dest_file) catch {}; | |
| 118 | try cwd.writeFile(src_file, data); | |
| 119 | defer cwd.deleteFile(src_file) catch {}; | |
| 120 | 120 | |
| 121 | try fs.copyFileMode(src_file, dest_file2, File.default_mode); | |
| 122 | defer fs.cwd().deleteFile(dest_file2) catch {}; | |
| 121 | try cwd.copyFile(src_file, cwd, dest_file, .{}); | |
| 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 {}; | |
| 123 | 126 | |
| 124 | 127 | try expectFileContents(dest_file, data); |
| 125 | 128 | try expectFileContents(dest_file2, data); |
| ... | ... | @@ -446,3 +449,32 @@ test "getenv" { |
| 446 | 449 | expect(os.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null); |
| 447 | 450 | } |
| 448 | 451 | } |
| 452 | ||
| 453 | test "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 | 88 | return result; |
| 89 | 89 | } |
| 90 | 90 | |
| 91 | pub 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 | |
| 105 | pub 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 | ||
| 91 | 167 | pub const CreatePipeError = error{Unexpected}; |
| 92 | 168 | |
| 93 | 169 | pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) CreatePipeError!void { |
| ... | ... | @@ -1200,7 +1276,15 @@ pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError { |
| 1200 | 1276 | // 614 is the length of the longest windows error desciption |
| 1201 | 1277 | var buf_u16: [614]u16 = undefined; |
| 1202 | 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 | 1288 | _ = std.unicode.utf16leToUtf8(&buf_u8, buf_u16[0..len]) catch unreachable; |
| 1205 | 1289 | std.debug.warn("error.Unexpected: GetLastError({}): {}\n", .{ @enumToInt(err), buf_u8[0..len] }); |
| 1206 | 1290 | std.debug.dumpCurrentStackTrace(null); |
lib/std/os/windows/bits.zig+7| ... | ... | @@ -242,6 +242,13 @@ pub const FILE_NAME_INFORMATION = extern struct { |
| 242 | 242 | FileName: [1]WCHAR, |
| 243 | 243 | }; |
| 244 | 244 | |
| 245 | pub const FILE_RENAME_INFORMATION = extern struct { | |
| 246 | ReplaceIfExists: BOOLEAN, | |
| 247 | RootDirectory: ?HANDLE, | |
| 248 | FileNameLength: ULONG, | |
| 249 | FileName: [1]WCHAR, | |
| 250 | }; | |
| 251 | ||
| 245 | 252 | pub const IO_STATUS_BLOCK = extern struct { |
| 246 | 253 | // "DUMMYUNIONNAME" expands to "u" |
| 247 | 254 | u: extern union { |
lib/std/rand.zig+1-1| ... | ... | @@ -5,7 +5,7 @@ |
| 5 | 5 | // ``` |
| 6 | 6 | // var buf: [8]u8 = undefined; |
| 7 | 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 | 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 | const c = std.c; |
| 7 | 7 | const assert = std.debug.assert; |
| 8 | 8 | |
| 9 | const bad_startfn_ret = "expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"; | |
| 10 | ||
| 9 | 11 | pub const Thread = struct { |
| 10 | 12 | data: Data, |
| 11 | 13 | |
| ... | ... | @@ -158,15 +160,34 @@ pub const Thread = struct { |
| 158 | 160 | }; |
| 159 | 161 | fn threadMain(raw_arg: windows.LPVOID) callconv(.C) windows.DWORD { |
| 160 | 162 | const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*; |
| 163 | ||
| 161 | 164 | switch (@typeInfo(@TypeOf(startFn).ReturnType)) { |
| 162 | .Int => { | |
| 163 | return startFn(arg); | |
| 165 | .NoReturn => { | |
| 166 | startFn(arg); | |
| 164 | 167 | }, |
| 165 | 168 | .Void => { |
| 166 | 169 | startFn(arg); |
| 167 | 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 | 223 | const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*; |
| 203 | 224 | |
| 204 | 225 | switch (@typeInfo(@TypeOf(startFn).ReturnType)) { |
| 205 | .Int => { | |
| 206 | return startFn(arg); | |
| 226 | .NoReturn => { | |
| 227 | startFn(arg); | |
| 207 | 228 | }, |
| 208 | 229 | .Void => { |
| 209 | 230 | startFn(arg); |
| 210 | 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 | 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 | 251 | pub fn nextCodepoint(it: *Utf16LeIterator) !?u21 { |
| 252 | 252 | assert(it.i <= it.bytes.len); |
| 253 | 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 | 255 | if (c0 & ~@as(u21, 0x03ff) == 0xd800) { |
| 256 | 256 | // surrogate pair |
| 257 | 257 | it.i += 2; |
| 258 | 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 | 260 | if (c1 & ~@as(u21, 0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf; |
| 261 | 261 | it.i += 2; |
| 262 | 262 | return 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff)); |
| ... | ... | @@ -630,11 +630,11 @@ test "utf8ToUtf16LeWithNull" { |
| 630 | 630 | } |
| 631 | 631 | } |
| 632 | 632 | |
| 633 | /// Converts a UTF-8 string literal into a UTF-16LE string literal. | |
| 634 | pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16LeLen(utf8) :0] u16 { | |
| 633 | /// Converts a UTF-8 string literal into a UTF-16LE string literal. | |
| 634 | pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16LeLen(utf8):0]u16 { | |
| 635 | 635 | comptime { |
| 636 | 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 | 638 | const utf16le_len = utf8ToUtf16Le(&utf16le, utf8[0..]) catch |err| @compileError(err); |
| 639 | 639 | assert(len == utf16le_len); |
| 640 | 640 | return &utf16le; |
| ... | ... | @@ -660,8 +660,8 @@ fn calcUtf16LeLen(utf8: []const u8) usize { |
| 660 | 660 | } |
| 661 | 661 | |
| 662 | 662 | test "utf8ToUtf16LeStringLiteral" { |
| 663 | { | |
| 664 | const bytes = [_:0]u16{ 0x41 }; | |
| 663 | { | |
| 664 | const bytes = [_:0]u16{0x41}; | |
| 665 | 665 | const utf16 = utf8ToUtf16LeStringLiteral("A"); |
| 666 | 666 | testing.expectEqualSlices(u16, &bytes, utf16); |
| 667 | 667 | testing.expect(utf16[1] == 0); |
| ... | ... | @@ -673,19 +673,19 @@ test "utf8ToUtf16LeStringLiteral" { |
| 673 | 673 | testing.expect(utf16[2] == 0); |
| 674 | 674 | } |
| 675 | 675 | { |
| 676 | const bytes = [_:0]u16{ 0x02FF }; | |
| 676 | const bytes = [_:0]u16{0x02FF}; | |
| 677 | 677 | const utf16 = utf8ToUtf16LeStringLiteral("\u{02FF}"); |
| 678 | 678 | testing.expectEqualSlices(u16, &bytes, utf16); |
| 679 | 679 | testing.expect(utf16[1] == 0); |
| 680 | 680 | } |
| 681 | 681 | { |
| 682 | const bytes = [_:0]u16{ 0x7FF }; | |
| 682 | const bytes = [_:0]u16{0x7FF}; | |
| 683 | 683 | const utf16 = utf8ToUtf16LeStringLiteral("\u{7FF}"); |
| 684 | 684 | testing.expectEqualSlices(u16, &bytes, utf16); |
| 685 | 685 | testing.expect(utf16[1] == 0); |
| 686 | 686 | } |
| 687 | 687 | { |
| 688 | const bytes = [_:0]u16{ 0x801 }; | |
| 688 | const bytes = [_:0]u16{0x801}; | |
| 689 | 689 | const utf16 = utf8ToUtf16LeStringLiteral("\u{801}"); |
| 690 | 690 | testing.expectEqualSlices(u16, &bytes, utf16); |
| 691 | 691 | testing.expect(utf16[1] == 0); |
lib/std/zig/ast.zig+66-92| ... | ... | @@ -743,11 +743,11 @@ pub const Node = struct { |
| 743 | 743 | var i = index; |
| 744 | 744 | |
| 745 | 745 | switch (self.init_arg_expr) { |
| 746 | InitArg.Type => |t| { | |
| 746 | .Type => |t| { | |
| 747 | 747 | if (i < 1) return t; |
| 748 | 748 | i -= 1; |
| 749 | 749 | }, |
| 750 | InitArg.None, InitArg.Enum => {}, | |
| 750 | .None, .Enum => {}, | |
| 751 | 751 | } |
| 752 | 752 | |
| 753 | 753 | if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i).*; |
| ... | ... | @@ -907,12 +907,7 @@ pub const Node = struct { |
| 907 | 907 | } |
| 908 | 908 | |
| 909 | 909 | switch (self.return_type) { |
| 910 | // TODO allow this and next prong to share bodies since the types are the same | |
| 911 | ReturnType.Explicit => |node| { | |
| 912 | if (i < 1) return node; | |
| 913 | i -= 1; | |
| 914 | }, | |
| 915 | ReturnType.InferErrorSet => |node| { | |
| 910 | .Explicit, .InferErrorSet => |node| { | |
| 916 | 911 | if (i < 1) return node; |
| 917 | 912 | i -= 1; |
| 918 | 913 | }, |
| ... | ... | @@ -937,9 +932,7 @@ pub const Node = struct { |
| 937 | 932 | pub fn lastToken(self: *const FnProto) TokenIndex { |
| 938 | 933 | if (self.body_node) |body_node| return body_node.lastToken(); |
| 939 | 934 | switch (self.return_type) { |
| 940 | // TODO allow this and next prong to share bodies since the types are the same | |
| 941 | ReturnType.Explicit => |node| return node.lastToken(), | |
| 942 | ReturnType.InferErrorSet => |node| return node.lastToken(), | |
| 935 | .Explicit, .InferErrorSet => |node| return node.lastToken(), | |
| 943 | 936 | } |
| 944 | 937 | } |
| 945 | 938 | }; |
| ... | ... | @@ -1515,55 +1508,55 @@ pub const Node = struct { |
| 1515 | 1508 | i -= 1; |
| 1516 | 1509 | |
| 1517 | 1510 | switch (self.op) { |
| 1518 | Op.Catch => |maybe_payload| { | |
| 1511 | .Catch => |maybe_payload| { | |
| 1519 | 1512 | if (maybe_payload) |payload| { |
| 1520 | 1513 | if (i < 1) return payload; |
| 1521 | 1514 | i -= 1; |
| 1522 | 1515 | } |
| 1523 | 1516 | }, |
| 1524 | 1517 | |
| 1525 | Op.Add, | |
| 1526 | Op.AddWrap, | |
| 1527 | Op.ArrayCat, | |
| 1528 | Op.ArrayMult, | |
| 1529 | Op.Assign, | |
| 1530 | Op.AssignBitAnd, | |
| 1531 | Op.AssignBitOr, | |
| 1532 | Op.AssignBitShiftLeft, | |
| 1533 | Op.AssignBitShiftRight, | |
| 1534 | Op.AssignBitXor, | |
| 1535 | Op.AssignDiv, | |
| 1536 | Op.AssignSub, | |
| 1537 | Op.AssignSubWrap, | |
| 1538 | Op.AssignMod, | |
| 1539 | Op.AssignAdd, | |
| 1540 | Op.AssignAddWrap, | |
| 1541 | Op.AssignMul, | |
| 1542 | Op.AssignMulWrap, | |
| 1543 | Op.BangEqual, | |
| 1544 | Op.BitAnd, | |
| 1545 | Op.BitOr, | |
| 1546 | Op.BitShiftLeft, | |
| 1547 | Op.BitShiftRight, | |
| 1548 | Op.BitXor, | |
| 1549 | Op.BoolAnd, | |
| 1550 | Op.BoolOr, | |
| 1551 | Op.Div, | |
| 1552 | Op.EqualEqual, | |
| 1553 | Op.ErrorUnion, | |
| 1554 | Op.GreaterOrEqual, | |
| 1555 | Op.GreaterThan, | |
| 1556 | Op.LessOrEqual, | |
| 1557 | Op.LessThan, | |
| 1558 | Op.MergeErrorSets, | |
| 1559 | Op.Mod, | |
| 1560 | Op.Mul, | |
| 1561 | Op.MulWrap, | |
| 1562 | Op.Period, | |
| 1563 | Op.Range, | |
| 1564 | Op.Sub, | |
| 1565 | Op.SubWrap, | |
| 1566 | Op.UnwrapOptional, | |
| 1518 | .Add, | |
| 1519 | .AddWrap, | |
| 1520 | .ArrayCat, | |
| 1521 | .ArrayMult, | |
| 1522 | .Assign, | |
| 1523 | .AssignBitAnd, | |
| 1524 | .AssignBitOr, | |
| 1525 | .AssignBitShiftLeft, | |
| 1526 | .AssignBitShiftRight, | |
| 1527 | .AssignBitXor, | |
| 1528 | .AssignDiv, | |
| 1529 | .AssignSub, | |
| 1530 | .AssignSubWrap, | |
| 1531 | .AssignMod, | |
| 1532 | .AssignAdd, | |
| 1533 | .AssignAddWrap, | |
| 1534 | .AssignMul, | |
| 1535 | .AssignMulWrap, | |
| 1536 | .BangEqual, | |
| 1537 | .BitAnd, | |
| 1538 | .BitOr, | |
| 1539 | .BitShiftLeft, | |
| 1540 | .BitShiftRight, | |
| 1541 | .BitXor, | |
| 1542 | .BoolAnd, | |
| 1543 | .BoolOr, | |
| 1544 | .Div, | |
| 1545 | .EqualEqual, | |
| 1546 | .ErrorUnion, | |
| 1547 | .GreaterOrEqual, | |
| 1548 | .GreaterThan, | |
| 1549 | .LessOrEqual, | |
| 1550 | .LessThan, | |
| 1551 | .MergeErrorSets, | |
| 1552 | .Mod, | |
| 1553 | .Mul, | |
| 1554 | .MulWrap, | |
| 1555 | .Period, | |
| 1556 | .Range, | |
| 1557 | .Sub, | |
| 1558 | .SubWrap, | |
| 1559 | .UnwrapOptional, | |
| 1567 | 1560 | => {}, |
| 1568 | 1561 | } |
| 1569 | 1562 | |
| ... | ... | @@ -1594,7 +1587,6 @@ pub const Node = struct { |
| 1594 | 1587 | Await, |
| 1595 | 1588 | BitNot, |
| 1596 | 1589 | BoolNot, |
| 1597 | Cancel, | |
| 1598 | 1590 | OptionalType, |
| 1599 | 1591 | Negation, |
| 1600 | 1592 | NegationWrap, |
| ... | ... | @@ -1631,8 +1623,7 @@ pub const Node = struct { |
| 1631 | 1623 | var i = index; |
| 1632 | 1624 | |
| 1633 | 1625 | switch (self.op) { |
| 1634 | // TODO https://github.com/ziglang/zig/issues/1107 | |
| 1635 | Op.SliceType => |addr_of_info| { | |
| 1626 | .PtrType, .SliceType => |addr_of_info| { | |
| 1636 | 1627 | if (addr_of_info.sentinel) |sentinel| { |
| 1637 | 1628 | if (i < 1) return sentinel; |
| 1638 | 1629 | i -= 1; |
| ... | ... | @@ -1644,14 +1635,7 @@ pub const Node = struct { |
| 1644 | 1635 | } |
| 1645 | 1636 | }, |
| 1646 | 1637 | |
| 1647 | Op.PtrType => |addr_of_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| { | |
| 1638 | .ArrayType => |array_info| { | |
| 1655 | 1639 | if (i < 1) return array_info.len_expr; |
| 1656 | 1640 | i -= 1; |
| 1657 | 1641 | if (array_info.sentinel) |sentinel| { |
| ... | ... | @@ -1660,16 +1644,15 @@ pub const Node = struct { |
| 1660 | 1644 | } |
| 1661 | 1645 | }, |
| 1662 | 1646 | |
| 1663 | Op.AddressOf, | |
| 1664 | Op.Await, | |
| 1665 | Op.BitNot, | |
| 1666 | Op.BoolNot, | |
| 1667 | Op.Cancel, | |
| 1668 | Op.OptionalType, | |
| 1669 | Op.Negation, | |
| 1670 | Op.NegationWrap, | |
| 1671 | Op.Try, | |
| 1672 | Op.Resume, | |
| 1647 | .AddressOf, | |
| 1648 | .Await, | |
| 1649 | .BitNot, | |
| 1650 | .BoolNot, | |
| 1651 | .OptionalType, | |
| 1652 | .Negation, | |
| 1653 | .NegationWrap, | |
| 1654 | .Try, | |
| 1655 | .Resume, | |
| 1673 | 1656 | => {}, |
| 1674 | 1657 | } |
| 1675 | 1658 | |
| ... | ... | @@ -1853,19 +1836,14 @@ pub const Node = struct { |
| 1853 | 1836 | var i = index; |
| 1854 | 1837 | |
| 1855 | 1838 | switch (self.kind) { |
| 1856 | Kind.Break => |maybe_label| { | |
| 1839 | .Break, | |
| 1840 | .Continue => |maybe_label| { | |
| 1857 | 1841 | if (maybe_label) |label| { |
| 1858 | 1842 | if (i < 1) return label; |
| 1859 | 1843 | i -= 1; |
| 1860 | 1844 | } |
| 1861 | 1845 | }, |
| 1862 | Kind.Continue => |maybe_label| { | |
| 1863 | if (maybe_label) |label| { | |
| 1864 | if (i < 1) return label; | |
| 1865 | i -= 1; | |
| 1866 | } | |
| 1867 | }, | |
| 1868 | Kind.Return => {}, | |
| 1846 | .Return => {}, | |
| 1869 | 1847 | } |
| 1870 | 1848 | |
| 1871 | 1849 | if (self.rhs) |rhs| { |
| ... | ... | @@ -1886,17 +1864,13 @@ pub const Node = struct { |
| 1886 | 1864 | } |
| 1887 | 1865 | |
| 1888 | 1866 | switch (self.kind) { |
| 1889 | Kind.Break => |maybe_label| { | |
| 1890 | if (maybe_label) |label| { | |
| 1891 | return label.lastToken(); | |
| 1892 | } | |
| 1893 | }, | |
| 1894 | Kind.Continue => |maybe_label| { | |
| 1867 | .Break, | |
| 1868 | .Continue => |maybe_label| { | |
| 1895 | 1869 | if (maybe_label) |label| { |
| 1896 | 1870 | return label.lastToken(); |
| 1897 | 1871 | } |
| 1898 | 1872 | }, |
| 1899 | Kind.Return => return self.ltoken, | |
| 1873 | .Return => return self.ltoken, | |
| 1900 | 1874 | } |
| 1901 | 1875 | |
| 1902 | 1876 | return self.ltoken; |
| ... | ... | @@ -2137,11 +2111,11 @@ pub const Node = struct { |
| 2137 | 2111 | i -= 1; |
| 2138 | 2112 | |
| 2139 | 2113 | switch (self.kind) { |
| 2140 | Kind.Variable => |variable_name| { | |
| 2114 | .Variable => |variable_name| { | |
| 2141 | 2115 | if (i < 1) return &variable_name.base; |
| 2142 | 2116 | i -= 1; |
| 2143 | 2117 | }, |
| 2144 | Kind.Return => |return_type| { | |
| 2118 | .Return => |return_type| { | |
| 2145 | 2119 | if (i < 1) return return_type; |
| 2146 | 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 | 23 | var arena = std.heap.ArenaAllocator.init(allocator); |
| 24 | 24 | errdefer arena.deinit(); |
| 25 | 25 | const tree = try arena.allocator.create(ast.Tree); |
| 26 | tree.* = ast.Tree{ | |
| 26 | tree.* = .{ | |
| 27 | 27 | .source = source, |
| 28 | 28 | .root_node = undefined, |
| 29 | 29 | .arena_allocator = arena, |
| ... | ... | @@ -66,10 +66,10 @@ pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree { |
| 66 | 66 | /// Root <- skip ContainerMembers eof |
| 67 | 67 | fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!*Node.Root { |
| 68 | 68 | const node = try arena.create(Node.Root); |
| 69 | node.* = Node.Root{ | |
| 69 | node.* = .{ | |
| 70 | 70 | .decls = try parseContainerMembers(arena, it, tree), |
| 71 | 71 | .eof_token = eatToken(it, .Eof) orelse { |
| 72 | try tree.errors.push(AstError{ | |
| 72 | try tree.errors.push(.{ | |
| 73 | 73 | .ExpectedContainerMembers = .{ .token = it.index }, |
| 74 | 74 | }); |
| 75 | 75 | return error.ParseError; |
| ... | ... | @@ -139,8 +139,8 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No |
| 139 | 139 | } |
| 140 | 140 | |
| 141 | 141 | if (visib_token != null) { |
| 142 | try tree.errors.push(AstError{ | |
| 143 | .ExpectedPubItem = AstError.ExpectedPubItem{ .token = it.index }, | |
| 142 | try tree.errors.push(.{ | |
| 143 | .ExpectedPubItem = .{ .token = it.index }, | |
| 144 | 144 | }); |
| 145 | 145 | return error.ParseError; |
| 146 | 146 | } |
| ... | ... | @@ -157,8 +157,8 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No |
| 157 | 157 | |
| 158 | 158 | // Dangling doc comment |
| 159 | 159 | if (doc_comments != null) { |
| 160 | try tree.errors.push(AstError{ | |
| 161 | .UnattachedDocComment = AstError.UnattachedDocComment{ .token = doc_comments.?.firstToken() }, | |
| 160 | try tree.errors.push(.{ | |
| 161 | .UnattachedDocComment = .{ .token = doc_comments.?.firstToken() }, | |
| 162 | 162 | }); |
| 163 | 163 | } |
| 164 | 164 | break; |
| ... | ... | @@ -177,7 +177,7 @@ fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree) |
| 177 | 177 | if (lines.len == 0) return null; |
| 178 | 178 | |
| 179 | 179 | const node = try arena.create(Node.DocComment); |
| 180 | node.* = Node.DocComment{ | |
| 180 | node.* = .{ | |
| 181 | 181 | .lines = lines, |
| 182 | 182 | }; |
| 183 | 183 | return &node.base; |
| ... | ... | @@ -186,15 +186,15 @@ fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree) |
| 186 | 186 | /// TestDecl <- KEYWORD_test STRINGLITERALSINGLE Block |
| 187 | 187 | fn parseTestDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 188 | 188 | const test_token = eatToken(it, .Keyword_test) orelse return null; |
| 189 | const name_node = try expectNode(arena, it, tree, parseStringLiteralSingle, AstError{ | |
| 190 | .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index }, | |
| 189 | const name_node = try expectNode(arena, it, tree, parseStringLiteralSingle, .{ | |
| 190 | .ExpectedStringLiteral = .{ .token = it.index }, | |
| 191 | 191 | }); |
| 192 | const block_node = try expectNode(arena, it, tree, parseBlock, AstError{ | |
| 193 | .ExpectedLBrace = AstError.ExpectedLBrace{ .token = it.index }, | |
| 192 | const block_node = try expectNode(arena, it, tree, parseBlock, .{ | |
| 193 | .ExpectedLBrace = .{ .token = it.index }, | |
| 194 | 194 | }); |
| 195 | 195 | |
| 196 | 196 | const test_node = try arena.create(Node.TestDecl); |
| 197 | test_node.* = Node.TestDecl{ | |
| 197 | test_node.* = .{ | |
| 198 | 198 | .doc_comments = null, |
| 199 | 199 | .test_token = test_token, |
| 200 | 200 | .name = name_node, |
| ... | ... | @@ -211,12 +211,12 @@ fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?* |
| 211 | 211 | return null; |
| 212 | 212 | }; |
| 213 | 213 | putBackToken(it, lbrace); |
| 214 | const block_node = try expectNode(arena, it, tree, parseBlockExpr, AstError{ | |
| 215 | .ExpectedLabelOrLBrace = AstError.ExpectedLabelOrLBrace{ .token = it.index }, | |
| 214 | const block_node = try expectNode(arena, it, tree, parseBlockExpr, .{ | |
| 215 | .ExpectedLabelOrLBrace = .{ .token = it.index }, | |
| 216 | 216 | }); |
| 217 | 217 | |
| 218 | 218 | const comptime_node = try arena.create(Node.Comptime); |
| 219 | comptime_node.* = Node.Comptime{ | |
| 219 | comptime_node.* = .{ | |
| 220 | 220 | .doc_comments = null, |
| 221 | 221 | .comptime_token = tok, |
| 222 | 222 | .expr = block_node, |
| ... | ... | @@ -250,8 +250,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 250 | 250 | fn_node.body_node = body_node; |
| 251 | 251 | return node; |
| 252 | 252 | } |
| 253 | try tree.errors.push(AstError{ | |
| 254 | .ExpectedSemiOrLBrace = AstError.ExpectedSemiOrLBrace{ .token = it.index }, | |
| 253 | try tree.errors.push(.{ | |
| 254 | .ExpectedSemiOrLBrace = .{ .token = it.index }, | |
| 255 | 255 | }); |
| 256 | 256 | return null; |
| 257 | 257 | } |
| ... | ... | @@ -277,8 +277,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 277 | 277 | } |
| 278 | 278 | |
| 279 | 279 | if (thread_local_token != null) { |
| 280 | try tree.errors.push(AstError{ | |
| 281 | .ExpectedVarDecl = AstError.ExpectedVarDecl{ .token = it.index }, | |
| 280 | try tree.errors.push(.{ | |
| 281 | .ExpectedVarDecl = .{ .token = it.index }, | |
| 282 | 282 | }); |
| 283 | 283 | return error.ParseError; |
| 284 | 284 | } |
| ... | ... | @@ -291,8 +291,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 291 | 291 | } |
| 292 | 292 | |
| 293 | 293 | const use_node = (try parseUse(arena, it, tree)) orelse return null; |
| 294 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 295 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 294 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ | |
| 295 | .ExpectedExpr = .{ .token = it.index }, | |
| 296 | 296 | }); |
| 297 | 297 | const semicolon_token = try expectToken(it, tree, .Semicolon); |
| 298 | 298 | const use_node_raw = use_node.cast(Node.Use).?; |
| ... | ... | @@ -310,7 +310,7 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 310 | 310 | if (fnCC == .Extern) { |
| 311 | 311 | putBackToken(it, fnCC.Extern); // 'extern' is also used in ContainerDecl |
| 312 | 312 | } else { |
| 313 | try tree.errors.push(AstError{ | |
| 313 | try tree.errors.push(.{ | |
| 314 | 314 | .ExpectedToken = .{ .token = it.index, .expected_id = .Keyword_fn }, |
| 315 | 315 | }); |
| 316 | 316 | return error.ParseError; |
| ... | ... | @@ -328,16 +328,16 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 328 | 328 | const exclamation_token = eatToken(it, .Bang); |
| 329 | 329 | |
| 330 | 330 | const return_type_expr = (try parseVarType(arena, it, tree)) orelse |
| 331 | try expectNode(arena, it, tree, parseTypeExpr, AstError{ | |
| 332 | .ExpectedReturnType = AstError.ExpectedReturnType{ .token = it.index }, | |
| 331 | try expectNode(arena, it, tree, parseTypeExpr, .{ | |
| 332 | .ExpectedReturnType = .{ .token = it.index }, | |
| 333 | 333 | }); |
| 334 | 334 | |
| 335 | const return_type = if (exclamation_token != null) | |
| 336 | Node.FnProto.ReturnType{ | |
| 335 | const return_type: Node.FnProto.ReturnType = if (exclamation_token != null) | |
| 336 | .{ | |
| 337 | 337 | .InferErrorSet = return_type_expr, |
| 338 | 338 | } |
| 339 | 339 | else |
| 340 | Node.FnProto.ReturnType{ | |
| 340 | .{ | |
| 341 | 341 | .Explicit = return_type_expr, |
| 342 | 342 | }; |
| 343 | 343 | |
| ... | ... | @@ -347,7 +347,7 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 347 | 347 | null; |
| 348 | 348 | |
| 349 | 349 | const fn_proto_node = try arena.create(Node.FnProto); |
| 350 | fn_proto_node.* = Node.FnProto{ | |
| 350 | fn_proto_node.* = .{ | |
| 351 | 351 | .doc_comments = null, |
| 352 | 352 | .visib_token = null, |
| 353 | 353 | .fn_token = fn_token, |
| ... | ... | @@ -382,8 +382,8 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 382 | 382 | |
| 383 | 383 | const name_token = try expectToken(it, tree, .Identifier); |
| 384 | 384 | const type_node = if (eatToken(it, .Colon) != null) |
| 385 | try expectNode(arena, it, tree, parseTypeExpr, AstError{ | |
| 386 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, | |
| 385 | try expectNode(arena, it, tree, parseTypeExpr, .{ | |
| 386 | .ExpectedTypeExpr = .{ .token = it.index }, | |
| 387 | 387 | }) |
| 388 | 388 | else |
| 389 | 389 | null; |
| ... | ... | @@ -391,14 +391,14 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 391 | 391 | const section_node = try parseLinkSection(arena, it, tree); |
| 392 | 392 | const eq_token = eatToken(it, .Equal); |
| 393 | 393 | const init_node = if (eq_token != null) blk: { |
| 394 | break :blk try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 395 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 394 | break :blk try expectNode(arena, it, tree, parseExpr, .{ | |
| 395 | .ExpectedExpr = .{ .token = it.index }, | |
| 396 | 396 | }); |
| 397 | 397 | } else null; |
| 398 | 398 | const semicolon_token = try expectToken(it, tree, .Semicolon); |
| 399 | 399 | |
| 400 | 400 | const node = try arena.create(Node.VarDecl); |
| 401 | node.* = Node.VarDecl{ | |
| 401 | node.* = .{ | |
| 402 | 402 | .doc_comments = null, |
| 403 | 403 | .visib_token = null, |
| 404 | 404 | .thread_local_token = null, |
| ... | ... | @@ -433,22 +433,22 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 433 | 433 | node.* = .{ .token = var_tok }; |
| 434 | 434 | type_expr = &node.base; |
| 435 | 435 | } else { |
| 436 | type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ | |
| 437 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, | |
| 436 | type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ | |
| 437 | .ExpectedTypeExpr = .{ .token = it.index }, | |
| 438 | 438 | }); |
| 439 | 439 | align_expr = try parseByteAlign(arena, it, tree); |
| 440 | 440 | } |
| 441 | 441 | } |
| 442 | 442 | |
| 443 | 443 | const value_expr = if (eatToken(it, .Equal)) |_| |
| 444 | try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 445 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 444 | try expectNode(arena, it, tree, parseExpr, .{ | |
| 445 | .ExpectedExpr = .{ .token = it.index }, | |
| 446 | 446 | }) |
| 447 | 447 | else |
| 448 | 448 | null; |
| 449 | 449 | |
| 450 | 450 | const node = try arena.create(Node.ContainerField); |
| 451 | node.* = Node.ContainerField{ | |
| 451 | node.* = .{ | |
| 452 | 452 | .doc_comments = null, |
| 453 | 453 | .comptime_token = comptime_token, |
| 454 | 454 | .name_token = name_token, |
| ... | ... | @@ -481,12 +481,12 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No |
| 481 | 481 | } |
| 482 | 482 | |
| 483 | 483 | if (comptime_token) |token| { |
| 484 | const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, AstError{ | |
| 485 | .ExpectedBlockOrAssignment = AstError.ExpectedBlockOrAssignment{ .token = it.index }, | |
| 484 | const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, .{ | |
| 485 | .ExpectedBlockOrAssignment = .{ .token = it.index }, | |
| 486 | 486 | }); |
| 487 | 487 | |
| 488 | 488 | const node = try arena.create(Node.Comptime); |
| 489 | node.* = Node.Comptime{ | |
| 489 | node.* = .{ | |
| 490 | 490 | .doc_comments = null, |
| 491 | 491 | .comptime_token = token, |
| 492 | 492 | .expr = block_expr, |
| ... | ... | @@ -511,13 +511,13 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No |
| 511 | 511 | const semicolon = eatToken(it, .Semicolon); |
| 512 | 512 | |
| 513 | 513 | const body_node = if (semicolon == null) blk: { |
| 514 | break :blk try expectNode(arena, it, tree, parseBlockExprStatement, AstError{ | |
| 515 | .ExpectedBlockOrExpression = AstError.ExpectedBlockOrExpression{ .token = it.index }, | |
| 514 | break :blk try expectNode(arena, it, tree, parseBlockExprStatement, .{ | |
| 515 | .ExpectedBlockOrExpression = .{ .token = it.index }, | |
| 516 | 516 | }); |
| 517 | 517 | } else null; |
| 518 | 518 | |
| 519 | 519 | const node = try arena.create(Node.Suspend); |
| 520 | node.* = Node.Suspend{ | |
| 520 | node.* = .{ | |
| 521 | 521 | .suspend_token = suspend_token, |
| 522 | 522 | .body = body_node, |
| 523 | 523 | }; |
| ... | ... | @@ -526,11 +526,11 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No |
| 526 | 526 | |
| 527 | 527 | const defer_token = eatToken(it, .Keyword_defer) orelse eatToken(it, .Keyword_errdefer); |
| 528 | 528 | if (defer_token) |token| { |
| 529 | const expr_node = try expectNode(arena, it, tree, parseBlockExprStatement, AstError{ | |
| 530 | .ExpectedBlockOrExpression = AstError.ExpectedBlockOrExpression{ .token = it.index }, | |
| 529 | const expr_node = try expectNode(arena, it, tree, parseBlockExprStatement, .{ | |
| 530 | .ExpectedBlockOrExpression = .{ .token = it.index }, | |
| 531 | 531 | }); |
| 532 | 532 | const node = try arena.create(Node.Defer); |
| 533 | node.* = Node.Defer{ | |
| 533 | node.* = .{ | |
| 534 | 534 | .defer_token = token, |
| 535 | 535 | .expr = expr_node, |
| 536 | 536 | }; |
| ... | ... | @@ -561,8 +561,8 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 561 | 561 | } else null; |
| 562 | 562 | |
| 563 | 563 | if (block_expr == null and assign_expr == null) { |
| 564 | try tree.errors.push(AstError{ | |
| 565 | .ExpectedBlockOrAssignment = AstError.ExpectedBlockOrAssignment{ .token = it.index }, | |
| 564 | try tree.errors.push(.{ | |
| 565 | .ExpectedBlockOrAssignment = .{ .token = it.index }, | |
| 566 | 566 | }); |
| 567 | 567 | return error.ParseError; |
| 568 | 568 | } |
| ... | ... | @@ -572,12 +572,12 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 572 | 572 | const else_node = if (semicolon == null) blk: { |
| 573 | 573 | const else_token = eatToken(it, .Keyword_else) orelse break :blk null; |
| 574 | 574 | const payload = try parsePayload(arena, it, tree); |
| 575 | const else_body = try expectNode(arena, it, tree, parseStatement, AstError{ | |
| 576 | .InvalidToken = AstError.InvalidToken{ .token = it.index }, | |
| 575 | const else_body = try expectNode(arena, it, tree, parseStatement, .{ | |
| 576 | .InvalidToken = .{ .token = it.index }, | |
| 577 | 577 | }); |
| 578 | 578 | |
| 579 | 579 | const node = try arena.create(Node.Else); |
| 580 | node.* = Node.Else{ | |
| 580 | node.* = .{ | |
| 581 | 581 | .else_token = else_token, |
| 582 | 582 | .payload = payload, |
| 583 | 583 | .body = else_body, |
| ... | ... | @@ -599,8 +599,8 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 599 | 599 | if_prefix.@"else" = else_node; |
| 600 | 600 | return if_node; |
| 601 | 601 | } |
| 602 | try tree.errors.push(AstError{ | |
| 603 | .ExpectedSemiOrElse = AstError.ExpectedSemiOrElse{ .token = it.index }, | |
| 602 | try tree.errors.push(.{ | |
| 603 | .ExpectedSemiOrElse = .{ .token = it.index }, | |
| 604 | 604 | }); |
| 605 | 605 | return error.ParseError; |
| 606 | 606 | } |
| ... | ... | @@ -628,8 +628,8 @@ fn parseLabeledStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?* |
| 628 | 628 | } |
| 629 | 629 | |
| 630 | 630 | if (label_token != null) { |
| 631 | try tree.errors.push(AstError{ | |
| 632 | .ExpectedLabelable = AstError.ExpectedLabelable{ .token = it.index }, | |
| 631 | try tree.errors.push(.{ | |
| 632 | .ExpectedLabelable = .{ .token = it.index }, | |
| 633 | 633 | }); |
| 634 | 634 | return error.ParseError; |
| 635 | 635 | } |
| ... | ... | @@ -665,12 +665,12 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 665 | 665 | for_prefix.body = block_expr_node; |
| 666 | 666 | |
| 667 | 667 | if (eatToken(it, .Keyword_else)) |else_token| { |
| 668 | const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{ | |
| 669 | .InvalidToken = AstError.InvalidToken{ .token = it.index }, | |
| 668 | const statement_node = try expectNode(arena, it, tree, parseStatement, .{ | |
| 669 | .InvalidToken = .{ .token = it.index }, | |
| 670 | 670 | }); |
| 671 | 671 | |
| 672 | 672 | const else_node = try arena.create(Node.Else); |
| 673 | else_node.* = Node.Else{ | |
| 673 | else_node.* = .{ | |
| 674 | 674 | .else_token = else_token, |
| 675 | 675 | .payload = null, |
| 676 | 676 | .body = statement_node, |
| ... | ... | @@ -689,12 +689,12 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 689 | 689 | if (eatToken(it, .Semicolon) != null) return node; |
| 690 | 690 | |
| 691 | 691 | if (eatToken(it, .Keyword_else)) |else_token| { |
| 692 | const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{ | |
| 693 | .ExpectedStatement = AstError.ExpectedStatement{ .token = it.index }, | |
| 692 | const statement_node = try expectNode(arena, it, tree, parseStatement, .{ | |
| 693 | .ExpectedStatement = .{ .token = it.index }, | |
| 694 | 694 | }); |
| 695 | 695 | |
| 696 | 696 | const else_node = try arena.create(Node.Else); |
| 697 | else_node.* = Node.Else{ | |
| 697 | else_node.* = .{ | |
| 698 | 698 | .else_token = else_token, |
| 699 | 699 | .payload = null, |
| 700 | 700 | .body = statement_node, |
| ... | ... | @@ -703,8 +703,8 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 703 | 703 | return node; |
| 704 | 704 | } |
| 705 | 705 | |
| 706 | try tree.errors.push(AstError{ | |
| 707 | .ExpectedSemiOrElse = AstError.ExpectedSemiOrElse{ .token = it.index }, | |
| 706 | try tree.errors.push(.{ | |
| 707 | .ExpectedSemiOrElse = .{ .token = it.index }, | |
| 708 | 708 | }); |
| 709 | 709 | return null; |
| 710 | 710 | } |
| ... | ... | @@ -725,12 +725,12 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 725 | 725 | if (eatToken(it, .Keyword_else)) |else_token| { |
| 726 | 726 | const payload = try parsePayload(arena, it, tree); |
| 727 | 727 | |
| 728 | const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{ | |
| 729 | .InvalidToken = AstError.InvalidToken{ .token = it.index }, | |
| 728 | const statement_node = try expectNode(arena, it, tree, parseStatement, .{ | |
| 729 | .InvalidToken = .{ .token = it.index }, | |
| 730 | 730 | }); |
| 731 | 731 | |
| 732 | 732 | const else_node = try arena.create(Node.Else); |
| 733 | else_node.* = Node.Else{ | |
| 733 | else_node.* = .{ | |
| 734 | 734 | .else_token = else_token, |
| 735 | 735 | .payload = payload, |
| 736 | 736 | .body = statement_node, |
| ... | ... | @@ -751,12 +751,12 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 751 | 751 | if (eatToken(it, .Keyword_else)) |else_token| { |
| 752 | 752 | const payload = try parsePayload(arena, it, tree); |
| 753 | 753 | |
| 754 | const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{ | |
| 755 | .ExpectedStatement = AstError.ExpectedStatement{ .token = it.index }, | |
| 754 | const statement_node = try expectNode(arena, it, tree, parseStatement, .{ | |
| 755 | .ExpectedStatement = .{ .token = it.index }, | |
| 756 | 756 | }); |
| 757 | 757 | |
| 758 | 758 | const else_node = try arena.create(Node.Else); |
| 759 | else_node.* = Node.Else{ | |
| 759 | else_node.* = .{ | |
| 760 | 760 | .else_token = else_token, |
| 761 | 761 | .payload = payload, |
| 762 | 762 | .body = statement_node, |
| ... | ... | @@ -765,8 +765,8 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 765 | 765 | return node; |
| 766 | 766 | } |
| 767 | 767 | |
| 768 | try tree.errors.push(AstError{ | |
| 769 | .ExpectedSemiOrElse = AstError.ExpectedSemiOrElse{ .token = it.index }, | |
| 768 | try tree.errors.push(.{ | |
| 769 | .ExpectedSemiOrElse = .{ .token = it.index }, | |
| 770 | 770 | }); |
| 771 | 771 | return null; |
| 772 | 772 | } |
| ... | ... | @@ -894,8 +894,8 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 894 | 894 | } |
| 895 | 895 | |
| 896 | 896 | if (eatToken(it, .Keyword_comptime)) |token| { |
| 897 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 898 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 897 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ | |
| 898 | .ExpectedExpr = .{ .token = it.index }, | |
| 899 | 899 | }); |
| 900 | 900 | const node = try arena.create(Node.Comptime); |
| 901 | 901 | node.* = .{ |
| ... | ... | @@ -907,8 +907,8 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 907 | 907 | } |
| 908 | 908 | |
| 909 | 909 | if (eatToken(it, .Keyword_noasync)) |token| { |
| 910 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 911 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 910 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ | |
| 911 | .ExpectedExpr = .{ .token = it.index }, | |
| 912 | 912 | }); |
| 913 | 913 | const node = try arena.create(Node.Noasync); |
| 914 | 914 | node.* = .{ |
| ... | ... | @@ -930,13 +930,13 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 930 | 930 | } |
| 931 | 931 | |
| 932 | 932 | if (eatToken(it, .Keyword_resume)) |token| { |
| 933 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 934 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 933 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ | |
| 934 | .ExpectedExpr = .{ .token = it.index }, | |
| 935 | 935 | }); |
| 936 | 936 | const node = try arena.create(Node.PrefixOp); |
| 937 | 937 | node.* = .{ |
| 938 | 938 | .op_token = token, |
| 939 | .op = Node.PrefixOp.Op.Resume, | |
| 939 | .op = .Resume, | |
| 940 | 940 | .rhs = expr_node, |
| 941 | 941 | }; |
| 942 | 942 | return &node.base; |
| ... | ... | @@ -992,7 +992,7 @@ fn parseBlock(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 992 | 992 | const rbrace = try expectToken(it, tree, .RBrace); |
| 993 | 993 | |
| 994 | 994 | const block_node = try arena.create(Node.Block); |
| 995 | block_node.* = Node.Block{ | |
| 995 | block_node.* = .{ | |
| 996 | 996 | .label = null, |
| 997 | 997 | .lbrace = lbrace, |
| 998 | 998 | .statements = statements, |
| ... | ... | @@ -1019,8 +1019,8 @@ fn parseLoopExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1019 | 1019 | if (inline_token == null) return null; |
| 1020 | 1020 | |
| 1021 | 1021 | // If we've seen "inline", there should have been a "for" or "while" |
| 1022 | try tree.errors.push(AstError{ | |
| 1023 | .ExpectedInlinable = AstError.ExpectedInlinable{ .token = it.index }, | |
| 1022 | try tree.errors.push(.{ | |
| 1023 | .ExpectedInlinable = .{ .token = it.index }, | |
| 1024 | 1024 | }); |
| 1025 | 1025 | return error.ParseError; |
| 1026 | 1026 | } |
| ... | ... | @@ -1030,18 +1030,18 @@ fn parseForExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1030 | 1030 | const node = (try parseForPrefix(arena, it, tree)) orelse return null; |
| 1031 | 1031 | const for_prefix = node.cast(Node.For).?; |
| 1032 | 1032 | |
| 1033 | const body_node = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 1034 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 1033 | const body_node = try expectNode(arena, it, tree, parseExpr, .{ | |
| 1034 | .ExpectedExpr = .{ .token = it.index }, | |
| 1035 | 1035 | }); |
| 1036 | 1036 | for_prefix.body = body_node; |
| 1037 | 1037 | |
| 1038 | 1038 | if (eatToken(it, .Keyword_else)) |else_token| { |
| 1039 | const body = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 1040 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 1039 | const body = try expectNode(arena, it, tree, parseExpr, .{ | |
| 1040 | .ExpectedExpr = .{ .token = it.index }, | |
| 1041 | 1041 | }); |
| 1042 | 1042 | |
| 1043 | 1043 | const else_node = try arena.create(Node.Else); |
| 1044 | else_node.* = Node.Else{ | |
| 1044 | else_node.* = .{ | |
| 1045 | 1045 | .else_token = else_token, |
| 1046 | 1046 | .payload = null, |
| 1047 | 1047 | .body = body, |
| ... | ... | @@ -1058,19 +1058,19 @@ fn parseWhileExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1058 | 1058 | const node = (try parseWhilePrefix(arena, it, tree)) orelse return null; |
| 1059 | 1059 | const while_prefix = node.cast(Node.While).?; |
| 1060 | 1060 | |
| 1061 | const body_node = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 1062 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 1061 | const body_node = try expectNode(arena, it, tree, parseExpr, .{ | |
| 1062 | .ExpectedExpr = .{ .token = it.index }, | |
| 1063 | 1063 | }); |
| 1064 | 1064 | while_prefix.body = body_node; |
| 1065 | 1065 | |
| 1066 | 1066 | if (eatToken(it, .Keyword_else)) |else_token| { |
| 1067 | 1067 | const payload = try parsePayload(arena, it, tree); |
| 1068 | const body = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 1069 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 1068 | const body = try expectNode(arena, it, tree, parseExpr, .{ | |
| 1069 | .ExpectedExpr = .{ .token = it.index }, | |
| 1070 | 1070 | }); |
| 1071 | 1071 | |
| 1072 | 1072 | const else_node = try arena.create(Node.Else); |
| 1073 | else_node.* = Node.Else{ | |
| 1073 | else_node.* = .{ | |
| 1074 | 1074 | .else_token = else_token, |
| 1075 | 1075 | .payload = payload, |
| 1076 | 1076 | .body = body, |
| ... | ... | @@ -1098,14 +1098,14 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf |
| 1098 | 1098 | const lbrace = eatToken(it, .LBrace) orelse return null; |
| 1099 | 1099 | var init_list = Node.SuffixOp.Op.InitList.init(arena); |
| 1100 | 1100 | |
| 1101 | const op = blk: { | |
| 1101 | const op: Node.SuffixOp.Op = blk: { | |
| 1102 | 1102 | if (try parseFieldInit(arena, it, tree)) |field_init| { |
| 1103 | 1103 | try init_list.push(field_init); |
| 1104 | 1104 | while (eatToken(it, .Comma)) |_| { |
| 1105 | 1105 | const next = (try parseFieldInit(arena, it, tree)) orelse break; |
| 1106 | 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 | } |
| 1110 | 1110 | |
| 1111 | 1111 | if (try parseExpr(arena, it, tree)) |expr| { |
| ... | ... | @@ -1114,14 +1114,14 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf |
| 1114 | 1114 | const next = (try parseExpr(arena, it, tree)) orelse break; |
| 1115 | 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 | } |
| 1119 | 1119 | |
| 1120 | break :blk Node.SuffixOp.Op{ .StructInitializer = init_list }; | |
| 1120 | break :blk .{ .StructInitializer = init_list }; | |
| 1121 | 1121 | }; |
| 1122 | 1122 | |
| 1123 | 1123 | const node = try arena.create(Node.SuffixOp); |
| 1124 | node.* = Node.SuffixOp{ | |
| 1124 | node.* = .{ | |
| 1125 | 1125 | .lhs = .{ .node = undefined }, // set by caller |
| 1126 | 1126 | .op = op, |
| 1127 | 1127 | .rtoken = try expectToken(it, tree, .RBrace), |
| ... | ... | @@ -1140,8 +1140,8 @@ fn parseErrorUnionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 1140 | 1140 | |
| 1141 | 1141 | if (try SimpleBinOpParseFn(.Bang, Node.InfixOp.Op.ErrorUnion)(arena, it, tree)) |node| { |
| 1142 | 1142 | const error_union = node.cast(Node.InfixOp).?; |
| 1143 | const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ | |
| 1144 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, | |
| 1143 | const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ | |
| 1144 | .ExpectedTypeExpr = .{ .token = it.index }, | |
| 1145 | 1145 | }); |
| 1146 | 1146 | error_union.lhs = suffix_expr; |
| 1147 | 1147 | error_union.rhs = type_expr; |
| ... | ... | @@ -1168,8 +1168,8 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1168 | 1168 | return parsePrimaryTypeExpr(arena, it, tree); |
| 1169 | 1169 | } |
| 1170 | 1170 | // TODO: Implement hack for parsing `async fn ...` in ast_parse_suffix_expr |
| 1171 | var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, AstError{ | |
| 1172 | .ExpectedPrimaryTypeExpr = AstError.ExpectedPrimaryTypeExpr{ .token = it.index }, | |
| 1171 | var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, .{ | |
| 1172 | .ExpectedPrimaryTypeExpr = .{ .token = it.index }, | |
| 1173 | 1173 | }); |
| 1174 | 1174 | |
| 1175 | 1175 | while (try parseSuffixOp(arena, it, tree)) |node| { |
| ... | ... | @@ -1182,16 +1182,16 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1182 | 1182 | } |
| 1183 | 1183 | |
| 1184 | 1184 | const params = (try parseFnCallArguments(arena, it, tree)) orelse { |
| 1185 | try tree.errors.push(AstError{ | |
| 1186 | .ExpectedParamList = AstError.ExpectedParamList{ .token = it.index }, | |
| 1185 | try tree.errors.push(.{ | |
| 1186 | .ExpectedParamList = .{ .token = it.index }, | |
| 1187 | 1187 | }); |
| 1188 | 1188 | return null; |
| 1189 | 1189 | }; |
| 1190 | 1190 | const node = try arena.create(Node.SuffixOp); |
| 1191 | node.* = Node.SuffixOp{ | |
| 1191 | node.* = .{ | |
| 1192 | 1192 | .lhs = .{ .node = res }, |
| 1193 | .op = Node.SuffixOp.Op{ | |
| 1194 | .Call = Node.SuffixOp.Op.Call{ | |
| 1193 | .op = .{ | |
| 1194 | .Call = .{ | |
| 1195 | 1195 | .params = params.list, |
| 1196 | 1196 | .async_token = async_token, |
| 1197 | 1197 | }, |
| ... | ... | @@ -1215,10 +1215,10 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1215 | 1215 | } |
| 1216 | 1216 | if (try parseFnCallArguments(arena, it, tree)) |params| { |
| 1217 | 1217 | const call = try arena.create(Node.SuffixOp); |
| 1218 | call.* = Node.SuffixOp{ | |
| 1218 | call.* = .{ | |
| 1219 | 1219 | .lhs = .{ .node = res }, |
| 1220 | .op = Node.SuffixOp.Op{ | |
| 1221 | .Call = Node.SuffixOp.Op.Call{ | |
| 1220 | .op = .{ | |
| 1221 | .Call = .{ | |
| 1222 | 1222 | .params = params.list, |
| 1223 | 1223 | .async_token = null, |
| 1224 | 1224 | }, |
| ... | ... | @@ -1264,7 +1264,7 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N |
| 1264 | 1264 | if (try parseBuiltinCall(arena, it, tree)) |node| return node; |
| 1265 | 1265 | if (eatToken(it, .CharLiteral)) |token| { |
| 1266 | 1266 | const node = try arena.create(Node.CharLiteral); |
| 1267 | node.* = Node.CharLiteral{ | |
| 1267 | node.* = .{ | |
| 1268 | 1268 | .token = token, |
| 1269 | 1269 | }; |
| 1270 | 1270 | return &node.base; |
| ... | ... | @@ -1300,15 +1300,15 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N |
| 1300 | 1300 | } |
| 1301 | 1301 | if (eatToken(it, .Keyword_error)) |token| { |
| 1302 | 1302 | const period = try expectToken(it, tree, .Period); |
| 1303 | const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{ | |
| 1304 | .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, | |
| 1303 | const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ | |
| 1304 | .ExpectedIdentifier = .{ .token = it.index }, | |
| 1305 | 1305 | }); |
| 1306 | 1306 | const global_error_set = try createLiteral(arena, Node.ErrorType, token); |
| 1307 | 1307 | const node = try arena.create(Node.InfixOp); |
| 1308 | 1308 | node.* = .{ |
| 1309 | 1309 | .op_token = period, |
| 1310 | 1310 | .lhs = global_error_set, |
| 1311 | .op = Node.InfixOp.Op.Period, | |
| 1311 | .op = .Period, | |
| 1312 | 1312 | .rhs = identifier, |
| 1313 | 1313 | }; |
| 1314 | 1314 | return &node.base; |
| ... | ... | @@ -1358,7 +1358,7 @@ fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 1358 | 1358 | const rbrace = try expectToken(it, tree, .RBrace); |
| 1359 | 1359 | |
| 1360 | 1360 | const node = try arena.create(Node.ErrorSetDecl); |
| 1361 | node.* = Node.ErrorSetDecl{ | |
| 1361 | node.* = .{ | |
| 1362 | 1362 | .error_token = error_token, |
| 1363 | 1363 | .decls = decls, |
| 1364 | 1364 | .rbrace_token = rbrace, |
| ... | ... | @@ -1369,13 +1369,13 @@ fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 1369 | 1369 | /// GroupedExpr <- LPAREN Expr RPAREN |
| 1370 | 1370 | fn parseGroupedExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1371 | 1371 | const lparen = eatToken(it, .LParen) orelse return null; |
| 1372 | const expr = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 1373 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 1372 | const expr = try expectNode(arena, it, tree, parseExpr, .{ | |
| 1373 | .ExpectedExpr = .{ .token = it.index }, | |
| 1374 | 1374 | }); |
| 1375 | 1375 | const rparen = try expectToken(it, tree, .RParen); |
| 1376 | 1376 | |
| 1377 | 1377 | const node = try arena.create(Node.GroupedExpression); |
| 1378 | node.* = Node.GroupedExpression{ | |
| 1378 | node.* = .{ | |
| 1379 | 1379 | .lparen = lparen, |
| 1380 | 1380 | .expr = expr, |
| 1381 | 1381 | .rparen = rparen, |
| ... | ... | @@ -1435,8 +1435,8 @@ fn parseLoopTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 1435 | 1435 | if (inline_token == null) return null; |
| 1436 | 1436 | |
| 1437 | 1437 | // If we've seen "inline", there should have been a "for" or "while" |
| 1438 | try tree.errors.push(AstError{ | |
| 1439 | .ExpectedInlinable = AstError.ExpectedInlinable{ .token = it.index }, | |
| 1438 | try tree.errors.push(.{ | |
| 1439 | .ExpectedInlinable = .{ .token = it.index }, | |
| 1440 | 1440 | }); |
| 1441 | 1441 | return error.ParseError; |
| 1442 | 1442 | } |
| ... | ... | @@ -1446,18 +1446,18 @@ fn parseForTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 1446 | 1446 | const node = (try parseForPrefix(arena, it, tree)) orelse return null; |
| 1447 | 1447 | const for_prefix = node.cast(Node.For).?; |
| 1448 | 1448 | |
| 1449 | const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ | |
| 1450 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, | |
| 1449 | const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ | |
| 1450 | .ExpectedTypeExpr = .{ .token = it.index }, | |
| 1451 | 1451 | }); |
| 1452 | 1452 | for_prefix.body = type_expr; |
| 1453 | 1453 | |
| 1454 | 1454 | if (eatToken(it, .Keyword_else)) |else_token| { |
| 1455 | const else_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ | |
| 1456 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, | |
| 1455 | const else_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ | |
| 1456 | .ExpectedTypeExpr = .{ .token = it.index }, | |
| 1457 | 1457 | }); |
| 1458 | 1458 | |
| 1459 | 1459 | const else_node = try arena.create(Node.Else); |
| 1460 | else_node.* = Node.Else{ | |
| 1460 | else_node.* = .{ | |
| 1461 | 1461 | .else_token = else_token, |
| 1462 | 1462 | .payload = null, |
| 1463 | 1463 | .body = else_expr, |
| ... | ... | @@ -1474,20 +1474,20 @@ fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod |
| 1474 | 1474 | const node = (try parseWhilePrefix(arena, it, tree)) orelse return null; |
| 1475 | 1475 | const while_prefix = node.cast(Node.While).?; |
| 1476 | 1476 | |
| 1477 | const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ | |
| 1478 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, | |
| 1477 | const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ | |
| 1478 | .ExpectedTypeExpr = .{ .token = it.index }, | |
| 1479 | 1479 | }); |
| 1480 | 1480 | while_prefix.body = type_expr; |
| 1481 | 1481 | |
| 1482 | 1482 | if (eatToken(it, .Keyword_else)) |else_token| { |
| 1483 | 1483 | const payload = try parsePayload(arena, it, tree); |
| 1484 | 1484 | |
| 1485 | const else_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ | |
| 1486 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, | |
| 1485 | const else_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ | |
| 1486 | .ExpectedTypeExpr = .{ .token = it.index }, | |
| 1487 | 1487 | }); |
| 1488 | 1488 | |
| 1489 | 1489 | const else_node = try arena.create(Node.Else); |
| 1490 | else_node.* = Node.Else{ | |
| 1490 | else_node.* = .{ | |
| 1491 | 1491 | .else_token = else_token, |
| 1492 | 1492 | .payload = null, |
| 1493 | 1493 | .body = else_expr, |
| ... | ... | @@ -1503,8 +1503,8 @@ fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod |
| 1503 | 1503 | fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1504 | 1504 | const switch_token = eatToken(it, .Keyword_switch) orelse return null; |
| 1505 | 1505 | _ = try expectToken(it, tree, .LParen); |
| 1506 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 1507 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 1506 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ | |
| 1507 | .ExpectedExpr = .{ .token = it.index }, | |
| 1508 | 1508 | }); |
| 1509 | 1509 | _ = try expectToken(it, tree, .RParen); |
| 1510 | 1510 | _ = try expectToken(it, tree, .LBrace); |
| ... | ... | @@ -1512,7 +1512,7 @@ fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1512 | 1512 | const rbrace = try expectToken(it, tree, .RBrace); |
| 1513 | 1513 | |
| 1514 | 1514 | const node = try arena.create(Node.Switch); |
| 1515 | node.* = Node.Switch{ | |
| 1515 | node.* = .{ | |
| 1516 | 1516 | .switch_token = switch_token, |
| 1517 | 1517 | .expr = expr_node, |
| 1518 | 1518 | .cases = cases, |
| ... | ... | @@ -1526,12 +1526,12 @@ fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1526 | 1526 | const asm_token = eatToken(it, .Keyword_asm) orelse return null; |
| 1527 | 1527 | const volatile_token = eatToken(it, .Keyword_volatile); |
| 1528 | 1528 | _ = try expectToken(it, tree, .LParen); |
| 1529 | const template = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 1530 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 1529 | const template = try expectNode(arena, it, tree, parseExpr, .{ | |
| 1530 | .ExpectedExpr = .{ .token = it.index }, | |
| 1531 | 1531 | }); |
| 1532 | 1532 | |
| 1533 | 1533 | const node = try arena.create(Node.Asm); |
| 1534 | node.* = Node.Asm{ | |
| 1534 | node.* = .{ | |
| 1535 | 1535 | .asm_token = asm_token, |
| 1536 | 1536 | .volatile_token = volatile_token, |
| 1537 | 1537 | .template = template, |
| ... | ... | @@ -1553,7 +1553,7 @@ fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 1553 | 1553 | // anon enum literal |
| 1554 | 1554 | if (eatToken(it, .Identifier)) |name| { |
| 1555 | 1555 | const node = try arena.create(Node.EnumLiteral); |
| 1556 | node.* = Node.EnumLiteral{ | |
| 1556 | node.* = .{ | |
| 1557 | 1557 | .dot = dot, |
| 1558 | 1558 | .name = name, |
| 1559 | 1559 | }; |
| ... | ... | @@ -1580,32 +1580,32 @@ fn parseAsmOutput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: |
| 1580 | 1580 | /// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN |
| 1581 | 1581 | fn parseAsmOutputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmOutput { |
| 1582 | 1582 | const lbracket = eatToken(it, .LBracket) orelse return null; |
| 1583 | const name = try expectNode(arena, it, tree, parseIdentifier, AstError{ | |
| 1584 | .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, | |
| 1583 | const name = try expectNode(arena, it, tree, parseIdentifier, .{ | |
| 1584 | .ExpectedIdentifier = .{ .token = it.index }, | |
| 1585 | 1585 | }); |
| 1586 | 1586 | _ = try expectToken(it, tree, .RBracket); |
| 1587 | 1587 | |
| 1588 | const constraint = try expectNode(arena, it, tree, parseStringLiteral, AstError{ | |
| 1589 | .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index }, | |
| 1588 | const constraint = try expectNode(arena, it, tree, parseStringLiteral, .{ | |
| 1589 | .ExpectedStringLiteral = .{ .token = it.index }, | |
| 1590 | 1590 | }); |
| 1591 | 1591 | |
| 1592 | 1592 | _ = try expectToken(it, tree, .LParen); |
| 1593 | const kind = blk: { | |
| 1593 | const kind: Node.AsmOutput.Kind = blk: { | |
| 1594 | 1594 | if (eatToken(it, .Arrow) != null) { |
| 1595 | const return_ident = try expectNode(arena, it, tree, parseTypeExpr, AstError{ | |
| 1596 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, | |
| 1595 | const return_ident = try expectNode(arena, it, tree, parseTypeExpr, .{ | |
| 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{ | |
| 1601 | .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, | |
| 1600 | const variable = try expectNode(arena, it, tree, parseIdentifier, .{ | |
| 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 | 1605 | const rparen = try expectToken(it, tree, .RParen); |
| 1606 | 1606 | |
| 1607 | 1607 | const node = try arena.create(Node.AsmOutput); |
| 1608 | node.* = Node.AsmOutput{ | |
| 1608 | node.* = .{ | |
| 1609 | 1609 | .lbracket = lbracket, |
| 1610 | 1610 | .symbolic_name = name, |
| 1611 | 1611 | .constraint = constraint, |
| ... | ... | @@ -1625,23 +1625,23 @@ fn parseAsmInput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: * |
| 1625 | 1625 | /// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN |
| 1626 | 1626 | fn parseAsmInputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmInput { |
| 1627 | 1627 | const lbracket = eatToken(it, .LBracket) orelse return null; |
| 1628 | const name = try expectNode(arena, it, tree, parseIdentifier, AstError{ | |
| 1629 | .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, | |
| 1628 | const name = try expectNode(arena, it, tree, parseIdentifier, .{ | |
| 1629 | .ExpectedIdentifier = .{ .token = it.index }, | |
| 1630 | 1630 | }); |
| 1631 | 1631 | _ = try expectToken(it, tree, .RBracket); |
| 1632 | 1632 | |
| 1633 | const constraint = try expectNode(arena, it, tree, parseStringLiteral, AstError{ | |
| 1634 | .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index }, | |
| 1633 | const constraint = try expectNode(arena, it, tree, parseStringLiteral, .{ | |
| 1634 | .ExpectedStringLiteral = .{ .token = it.index }, | |
| 1635 | 1635 | }); |
| 1636 | 1636 | |
| 1637 | 1637 | _ = try expectToken(it, tree, .LParen); |
| 1638 | const expr = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 1639 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 1638 | const expr = try expectNode(arena, it, tree, parseExpr, .{ | |
| 1639 | .ExpectedExpr = .{ .token = it.index }, | |
| 1640 | 1640 | }); |
| 1641 | 1641 | const rparen = try expectToken(it, tree, .RParen); |
| 1642 | 1642 | |
| 1643 | 1643 | const node = try arena.create(Node.AsmInput); |
| 1644 | node.* = Node.AsmInput{ | |
| 1644 | node.* = .{ | |
| 1645 | 1645 | .lbracket = lbracket, |
| 1646 | 1646 | .symbolic_name = name, |
| 1647 | 1647 | .constraint = constraint, |
| ... | ... | @@ -1664,8 +1664,8 @@ fn parseAsmClobbers(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node |
| 1664 | 1664 | /// BreakLabel <- COLON IDENTIFIER |
| 1665 | 1665 | fn parseBreakLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1666 | 1666 | _ = eatToken(it, .Colon) orelse return null; |
| 1667 | return try expectNode(arena, it, tree, parseIdentifier, AstError{ | |
| 1668 | .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, | |
| 1667 | return try expectNode(arena, it, tree, parseIdentifier, .{ | |
| 1668 | .ExpectedIdentifier = .{ .token = it.index }, | |
| 1669 | 1669 | }); |
| 1670 | 1670 | } |
| 1671 | 1671 | |
| ... | ... | @@ -1694,12 +1694,12 @@ fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1694 | 1694 | putBackToken(it, period_token); |
| 1695 | 1695 | return null; |
| 1696 | 1696 | }; |
| 1697 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 1698 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 1697 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ | |
| 1698 | .ExpectedExpr = .{ .token = it.index }, | |
| 1699 | 1699 | }); |
| 1700 | 1700 | |
| 1701 | 1701 | const node = try arena.create(Node.FieldInitializer); |
| 1702 | node.* = Node.FieldInitializer{ | |
| 1702 | node.* = .{ | |
| 1703 | 1703 | .period_token = period_token, |
| 1704 | 1704 | .name_token = name_token, |
| 1705 | 1705 | .expr = expr_node, |
| ... | ... | @@ -1711,8 +1711,8 @@ fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1711 | 1711 | fn parseWhileContinueExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1712 | 1712 | _ = eatToken(it, .Colon) orelse return null; |
| 1713 | 1713 | _ = try expectToken(it, tree, .LParen); |
| 1714 | const node = try expectNode(arena, it, tree, parseAssignExpr, AstError{ | |
| 1715 | .ExpectedExprOrAssignment = AstError.ExpectedExprOrAssignment{ .token = it.index }, | |
| 1714 | const node = try expectNode(arena, it, tree, parseAssignExpr, .{ | |
| 1715 | .ExpectedExprOrAssignment = .{ .token = it.index }, | |
| 1716 | 1716 | }); |
| 1717 | 1717 | _ = try expectToken(it, tree, .RParen); |
| 1718 | 1718 | return node; |
| ... | ... | @@ -1722,8 +1722,8 @@ fn parseWhileContinueExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? |
| 1722 | 1722 | fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1723 | 1723 | _ = eatToken(it, .Keyword_linksection) orelse return null; |
| 1724 | 1724 | _ = try expectToken(it, tree, .LParen); |
| 1725 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 1726 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 1725 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ | |
| 1726 | .ExpectedExpr = .{ .token = it.index }, | |
| 1727 | 1727 | }); |
| 1728 | 1728 | _ = try expectToken(it, tree, .RParen); |
| 1729 | 1729 | return expr_node; |
| ... | ... | @@ -1733,8 +1733,8 @@ fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 1733 | 1733 | fn parseCallconv(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1734 | 1734 | _ = eatToken(it, .Keyword_callconv) orelse return null; |
| 1735 | 1735 | _ = try expectToken(it, tree, .LParen); |
| 1736 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 1737 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 1736 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ | |
| 1737 | .ExpectedExpr = .{ .token = it.index }, | |
| 1738 | 1738 | }); |
| 1739 | 1739 | _ = try expectToken(it, tree, .RParen); |
| 1740 | 1740 | return expr_node; |
| ... | ... | @@ -1775,14 +1775,14 @@ fn parseParamDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1775 | 1775 | comptime_token == null and |
| 1776 | 1776 | name_token == null and |
| 1777 | 1777 | doc_comments == null) return null; |
| 1778 | try tree.errors.push(AstError{ | |
| 1779 | .ExpectedParamType = AstError.ExpectedParamType{ .token = it.index }, | |
| 1778 | try tree.errors.push(.{ | |
| 1779 | .ExpectedParamType = .{ .token = it.index }, | |
| 1780 | 1780 | }); |
| 1781 | 1781 | return error.ParseError; |
| 1782 | 1782 | }; |
| 1783 | 1783 | |
| 1784 | 1784 | const param_decl = try arena.create(Node.ParamDecl); |
| 1785 | param_decl.* = Node.ParamDecl{ | |
| 1785 | param_decl.* = .{ | |
| 1786 | 1786 | .doc_comments = doc_comments, |
| 1787 | 1787 | .comptime_token = comptime_token, |
| 1788 | 1788 | .noalias_token = noalias_token, |
| ... | ... | @@ -1821,14 +1821,14 @@ const ParamType = union(enum) { |
| 1821 | 1821 | fn parseIfPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1822 | 1822 | const if_token = eatToken(it, .Keyword_if) orelse return null; |
| 1823 | 1823 | _ = try expectToken(it, tree, .LParen); |
| 1824 | const condition = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 1825 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 1824 | const condition = try expectNode(arena, it, tree, parseExpr, .{ | |
| 1825 | .ExpectedExpr = .{ .token = it.index }, | |
| 1826 | 1826 | }); |
| 1827 | 1827 | _ = try expectToken(it, tree, .RParen); |
| 1828 | 1828 | const payload = try parsePtrPayload(arena, it, tree); |
| 1829 | 1829 | |
| 1830 | 1830 | const node = try arena.create(Node.If); |
| 1831 | node.* = Node.If{ | |
| 1831 | node.* = .{ | |
| 1832 | 1832 | .if_token = if_token, |
| 1833 | 1833 | .condition = condition, |
| 1834 | 1834 | .payload = payload, |
| ... | ... | @@ -1843,8 +1843,8 @@ fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 1843 | 1843 | const while_token = eatToken(it, .Keyword_while) orelse return null; |
| 1844 | 1844 | |
| 1845 | 1845 | _ = try expectToken(it, tree, .LParen); |
| 1846 | const condition = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 1847 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 1846 | const condition = try expectNode(arena, it, tree, parseExpr, .{ | |
| 1847 | .ExpectedExpr = .{ .token = it.index }, | |
| 1848 | 1848 | }); |
| 1849 | 1849 | _ = try expectToken(it, tree, .RParen); |
| 1850 | 1850 | |
| ... | ... | @@ -1852,7 +1852,7 @@ fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 1852 | 1852 | const continue_expr = try parseWhileContinueExpr(arena, it, tree); |
| 1853 | 1853 | |
| 1854 | 1854 | const node = try arena.create(Node.While); |
| 1855 | node.* = Node.While{ | |
| 1855 | node.* = .{ | |
| 1856 | 1856 | .label = null, |
| 1857 | 1857 | .inline_token = null, |
| 1858 | 1858 | .while_token = while_token, |
| ... | ... | @@ -1870,17 +1870,17 @@ fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1870 | 1870 | const for_token = eatToken(it, .Keyword_for) orelse return null; |
| 1871 | 1871 | |
| 1872 | 1872 | _ = try expectToken(it, tree, .LParen); |
| 1873 | const array_expr = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 1874 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 1873 | const array_expr = try expectNode(arena, it, tree, parseExpr, .{ | |
| 1874 | .ExpectedExpr = .{ .token = it.index }, | |
| 1875 | 1875 | }); |
| 1876 | 1876 | _ = try expectToken(it, tree, .RParen); |
| 1877 | 1877 | |
| 1878 | const payload = try expectNode(arena, it, tree, parsePtrIndexPayload, AstError{ | |
| 1879 | .ExpectedPayload = AstError.ExpectedPayload{ .token = it.index }, | |
| 1878 | const payload = try expectNode(arena, it, tree, parsePtrIndexPayload, .{ | |
| 1879 | .ExpectedPayload = .{ .token = it.index }, | |
| 1880 | 1880 | }); |
| 1881 | 1881 | |
| 1882 | 1882 | const node = try arena.create(Node.For); |
| 1883 | node.* = Node.For{ | |
| 1883 | node.* = .{ | |
| 1884 | 1884 | .label = null, |
| 1885 | 1885 | .inline_token = null, |
| 1886 | 1886 | .for_token = for_token, |
| ... | ... | @@ -1895,13 +1895,13 @@ fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1895 | 1895 | /// Payload <- PIPE IDENTIFIER PIPE |
| 1896 | 1896 | fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1897 | 1897 | const lpipe = eatToken(it, .Pipe) orelse return null; |
| 1898 | const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{ | |
| 1899 | .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, | |
| 1898 | const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ | |
| 1899 | .ExpectedIdentifier = .{ .token = it.index }, | |
| 1900 | 1900 | }); |
| 1901 | 1901 | const rpipe = try expectToken(it, tree, .Pipe); |
| 1902 | 1902 | |
| 1903 | 1903 | const node = try arena.create(Node.Payload); |
| 1904 | node.* = Node.Payload{ | |
| 1904 | node.* = .{ | |
| 1905 | 1905 | .lpipe = lpipe, |
| 1906 | 1906 | .error_symbol = identifier, |
| 1907 | 1907 | .rpipe = rpipe, |
| ... | ... | @@ -1913,13 +1913,13 @@ fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1913 | 1913 | fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1914 | 1914 | const lpipe = eatToken(it, .Pipe) orelse return null; |
| 1915 | 1915 | const asterisk = eatToken(it, .Asterisk); |
| 1916 | const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{ | |
| 1917 | .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, | |
| 1916 | const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ | |
| 1917 | .ExpectedIdentifier = .{ .token = it.index }, | |
| 1918 | 1918 | }); |
| 1919 | 1919 | const rpipe = try expectToken(it, tree, .Pipe); |
| 1920 | 1920 | |
| 1921 | 1921 | const node = try arena.create(Node.PointerPayload); |
| 1922 | node.* = Node.PointerPayload{ | |
| 1922 | node.* = .{ | |
| 1923 | 1923 | .lpipe = lpipe, |
| 1924 | 1924 | .ptr_token = asterisk, |
| 1925 | 1925 | .value_symbol = identifier, |
| ... | ... | @@ -1932,21 +1932,21 @@ fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1932 | 1932 | fn parsePtrIndexPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1933 | 1933 | const lpipe = eatToken(it, .Pipe) orelse return null; |
| 1934 | 1934 | const asterisk = eatToken(it, .Asterisk); |
| 1935 | const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{ | |
| 1936 | .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, | |
| 1935 | const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ | |
| 1936 | .ExpectedIdentifier = .{ .token = it.index }, | |
| 1937 | 1937 | }); |
| 1938 | 1938 | |
| 1939 | 1939 | const index = if (eatToken(it, .Comma) == null) |
| 1940 | 1940 | null |
| 1941 | 1941 | else |
| 1942 | try expectNode(arena, it, tree, parseIdentifier, AstError{ | |
| 1943 | .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, | |
| 1942 | try expectNode(arena, it, tree, parseIdentifier, .{ | |
| 1943 | .ExpectedIdentifier = .{ .token = it.index }, | |
| 1944 | 1944 | }); |
| 1945 | 1945 | |
| 1946 | 1946 | const rpipe = try expectToken(it, tree, .Pipe); |
| 1947 | 1947 | |
| 1948 | 1948 | const node = try arena.create(Node.PointerIndexPayload); |
| 1949 | node.* = Node.PointerIndexPayload{ | |
| 1949 | node.* = .{ | |
| 1950 | 1950 | .lpipe = lpipe, |
| 1951 | 1951 | .ptr_token = asterisk, |
| 1952 | 1952 | .value_symbol = identifier, |
| ... | ... | @@ -1961,8 +1961,8 @@ fn parseSwitchProng(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 1961 | 1961 | const node = (try parseSwitchCase(arena, it, tree)) orelse return null; |
| 1962 | 1962 | const arrow = try expectToken(it, tree, .EqualAngleBracketRight); |
| 1963 | 1963 | const payload = try parsePtrPayload(arena, it, tree); |
| 1964 | const expr = try expectNode(arena, it, tree, parseAssignExpr, AstError{ | |
| 1965 | .ExpectedExprOrAssignment = AstError.ExpectedExprOrAssignment{ .token = it.index }, | |
| 1964 | const expr = try expectNode(arena, it, tree, parseAssignExpr, .{ | |
| 1965 | .ExpectedExprOrAssignment = .{ .token = it.index }, | |
| 1966 | 1966 | }); |
| 1967 | 1967 | |
| 1968 | 1968 | const switch_case = node.cast(Node.SwitchCase).?; |
| ... | ... | @@ -1987,14 +1987,14 @@ fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1987 | 1987 | } |
| 1988 | 1988 | } else if (eatToken(it, .Keyword_else)) |else_token| { |
| 1989 | 1989 | const else_node = try arena.create(Node.SwitchElse); |
| 1990 | else_node.* = Node.SwitchElse{ | |
| 1990 | else_node.* = .{ | |
| 1991 | 1991 | .token = else_token, |
| 1992 | 1992 | }; |
| 1993 | 1993 | try list.push(&else_node.base); |
| 1994 | 1994 | } else return null; |
| 1995 | 1995 | |
| 1996 | 1996 | const node = try arena.create(Node.SwitchCase); |
| 1997 | node.* = Node.SwitchCase{ | |
| 1997 | node.* = .{ | |
| 1998 | 1998 | .items = list, |
| 1999 | 1999 | .arrow_token = undefined, // set by caller |
| 2000 | 2000 | .payload = null, |
| ... | ... | @@ -2007,15 +2007,15 @@ fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2007 | 2007 | fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2008 | 2008 | const expr = (try parseExpr(arena, it, tree)) orelse return null; |
| 2009 | 2009 | if (eatToken(it, .Ellipsis3)) |token| { |
| 2010 | const range_end = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 2011 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 2010 | const range_end = try expectNode(arena, it, tree, parseExpr, .{ | |
| 2011 | .ExpectedExpr = .{ .token = it.index }, | |
| 2012 | 2012 | }); |
| 2013 | 2013 | |
| 2014 | 2014 | const node = try arena.create(Node.InfixOp); |
| 2015 | node.* = Node.InfixOp{ | |
| 2015 | node.* = .{ | |
| 2016 | 2016 | .op_token = token, |
| 2017 | 2017 | .lhs = expr, |
| 2018 | .op = Node.InfixOp.Op{ .Range = {} }, | |
| 2018 | .op = .Range, | |
| 2019 | 2019 | .rhs = range_end, |
| 2020 | 2020 | }; |
| 2021 | 2021 | return &node.base; |
| ... | ... | @@ -2039,24 +2039,22 @@ fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2039 | 2039 | /// / MINUSPERCENTEQUAL |
| 2040 | 2040 | /// / EQUAL |
| 2041 | 2041 | fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2042 | const Op = Node.InfixOp.Op; | |
| 2043 | ||
| 2044 | 2042 | const token = nextToken(it); |
| 2045 | const op = switch (token.ptr.id) { | |
| 2046 | .AsteriskEqual => Op{ .AssignMul = {} }, | |
| 2047 | .SlashEqual => Op{ .AssignDiv = {} }, | |
| 2048 | .PercentEqual => Op{ .AssignMod = {} }, | |
| 2049 | .PlusEqual => Op{ .AssignAdd = {} }, | |
| 2050 | .MinusEqual => Op{ .AssignSub = {} }, | |
| 2051 | .AngleBracketAngleBracketLeftEqual => Op{ .AssignBitShiftLeft = {} }, | |
| 2052 | .AngleBracketAngleBracketRightEqual => Op{ .AssignBitShiftRight = {} }, | |
| 2053 | .AmpersandEqual => Op{ .AssignBitAnd = {} }, | |
| 2054 | .CaretEqual => Op{ .AssignBitXor = {} }, | |
| 2055 | .PipeEqual => Op{ .AssignBitOr = {} }, | |
| 2056 | .AsteriskPercentEqual => Op{ .AssignMulWrap = {} }, | |
| 2057 | .PlusPercentEqual => Op{ .AssignAddWrap = {} }, | |
| 2058 | .MinusPercentEqual => Op{ .AssignSubWrap = {} }, | |
| 2059 | .Equal => Op{ .Assign = {} }, | |
| 2043 | const op: Node.InfixOp.Op = switch (token.ptr.id) { | |
| 2044 | .AsteriskEqual => .AssignMul, | |
| 2045 | .SlashEqual => .AssignDiv, | |
| 2046 | .PercentEqual => .AssignMod, | |
| 2047 | .PlusEqual => .AssignAdd, | |
| 2048 | .MinusEqual => .AssignSub, | |
| 2049 | .AngleBracketAngleBracketLeftEqual => .AssignBitShiftLeft, | |
| 2050 | .AngleBracketAngleBracketRightEqual => .AssignBitShiftRight, | |
| 2051 | .AmpersandEqual => .AssignBitAnd, | |
| 2052 | .CaretEqual => .AssignBitXor, | |
| 2053 | .PipeEqual => .AssignBitOr, | |
| 2054 | .AsteriskPercentEqual => .AssignMulWrap, | |
| 2055 | .PlusPercentEqual => .AssignAddWrap, | |
| 2056 | .MinusPercentEqual => .AssignSubWrap, | |
| 2057 | .Equal => .Assign, | |
| 2060 | 2058 | else => { |
| 2061 | 2059 | putBackToken(it, token.index); |
| 2062 | 2060 | return null; |
| ... | ... | @@ -2064,7 +2062,7 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2064 | 2062 | }; |
| 2065 | 2063 | |
| 2066 | 2064 | const node = try arena.create(Node.InfixOp); |
| 2067 | node.* = Node.InfixOp{ | |
| 2065 | node.* = .{ | |
| 2068 | 2066 | .op_token = token.index, |
| 2069 | 2067 | .lhs = undefined, // set by caller |
| 2070 | 2068 | .op = op, |
| ... | ... | @@ -2081,16 +2079,14 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2081 | 2079 | /// / LARROWEQUAL |
| 2082 | 2080 | /// / RARROWEQUAL |
| 2083 | 2081 | fn parseCompareOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2084 | const ops = Node.InfixOp.Op; | |
| 2085 | ||
| 2086 | 2082 | const token = nextToken(it); |
| 2087 | const op = switch (token.ptr.id) { | |
| 2088 | .EqualEqual => ops{ .EqualEqual = {} }, | |
| 2089 | .BangEqual => ops{ .BangEqual = {} }, | |
| 2090 | .AngleBracketLeft => ops{ .LessThan = {} }, | |
| 2091 | .AngleBracketRight => ops{ .GreaterThan = {} }, | |
| 2092 | .AngleBracketLeftEqual => ops{ .LessOrEqual = {} }, | |
| 2093 | .AngleBracketRightEqual => ops{ .GreaterOrEqual = {} }, | |
| 2083 | const op: Node.InfixOp.Op = switch (token.ptr.id) { | |
| 2084 | .EqualEqual => .EqualEqual, | |
| 2085 | .BangEqual => .BangEqual, | |
| 2086 | .AngleBracketLeft => .LessThan, | |
| 2087 | .AngleBracketRight => .GreaterThan, | |
| 2088 | .AngleBracketLeftEqual => .LessOrEqual, | |
| 2089 | .AngleBracketRightEqual => .GreaterOrEqual, | |
| 2094 | 2090 | else => { |
| 2095 | 2091 | putBackToken(it, token.index); |
| 2096 | 2092 | return null; |
| ... | ... | @@ -2107,15 +2103,13 @@ fn parseCompareOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2107 | 2103 | /// / KEYWORD_orelse |
| 2108 | 2104 | /// / KEYWORD_catch Payload? |
| 2109 | 2105 | fn parseBitwiseOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2110 | const ops = Node.InfixOp.Op; | |
| 2111 | ||
| 2112 | 2106 | const token = nextToken(it); |
| 2113 | const op = switch (token.ptr.id) { | |
| 2114 | .Ampersand => ops{ .BitAnd = {} }, | |
| 2115 | .Caret => ops{ .BitXor = {} }, | |
| 2116 | .Pipe => ops{ .BitOr = {} }, | |
| 2117 | .Keyword_orelse => ops{ .UnwrapOptional = {} }, | |
| 2118 | .Keyword_catch => ops{ .Catch = try parsePayload(arena, it, tree) }, | |
| 2107 | const op: Node.InfixOp.Op = switch (token.ptr.id) { | |
| 2108 | .Ampersand => .BitAnd, | |
| 2109 | .Caret => .BitXor, | |
| 2110 | .Pipe => .BitOr, | |
| 2111 | .Keyword_orelse => .UnwrapOptional, | |
| 2112 | .Keyword_catch => .{ .Catch = try parsePayload(arena, it, tree) }, | |
| 2119 | 2113 | else => { |
| 2120 | 2114 | putBackToken(it, token.index); |
| 2121 | 2115 | return null; |
| ... | ... | @@ -2129,12 +2123,10 @@ fn parseBitwiseOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2129 | 2123 | /// <- LARROW2 |
| 2130 | 2124 | /// / RARROW2 |
| 2131 | 2125 | fn parseBitShiftOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2132 | const ops = Node.InfixOp.Op; | |
| 2133 | ||
| 2134 | 2126 | const token = nextToken(it); |
| 2135 | const op = switch (token.ptr.id) { | |
| 2136 | .AngleBracketAngleBracketLeft => ops{ .BitShiftLeft = {} }, | |
| 2137 | .AngleBracketAngleBracketRight => ops{ .BitShiftRight = {} }, | |
| 2127 | const op: Node.InfixOp.Op = switch (token.ptr.id) { | |
| 2128 | .AngleBracketAngleBracketLeft => .BitShiftLeft, | |
| 2129 | .AngleBracketAngleBracketRight => .BitShiftRight, | |
| 2138 | 2130 | else => { |
| 2139 | 2131 | putBackToken(it, token.index); |
| 2140 | 2132 | return null; |
| ... | ... | @@ -2151,15 +2143,13 @@ fn parseBitShiftOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2151 | 2143 | /// / PLUSPERCENT |
| 2152 | 2144 | /// / MINUSPERCENT |
| 2153 | 2145 | fn parseAdditionOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2154 | const ops = Node.InfixOp.Op; | |
| 2155 | ||
| 2156 | 2146 | const token = nextToken(it); |
| 2157 | const op = switch (token.ptr.id) { | |
| 2158 | .Plus => ops{ .Add = {} }, | |
| 2159 | .Minus => ops{ .Sub = {} }, | |
| 2160 | .PlusPlus => ops{ .ArrayCat = {} }, | |
| 2161 | .PlusPercent => ops{ .AddWrap = {} }, | |
| 2162 | .MinusPercent => ops{ .SubWrap = {} }, | |
| 2147 | const op: Node.InfixOp.Op = switch (token.ptr.id) { | |
| 2148 | .Plus => .Add, | |
| 2149 | .Minus => .Sub, | |
| 2150 | .PlusPlus => .ArrayCat, | |
| 2151 | .PlusPercent => .AddWrap, | |
| 2152 | .MinusPercent => .SubWrap, | |
| 2163 | 2153 | else => { |
| 2164 | 2154 | putBackToken(it, token.index); |
| 2165 | 2155 | return null; |
| ... | ... | @@ -2177,16 +2167,14 @@ fn parseAdditionOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2177 | 2167 | /// / ASTERISK2 |
| 2178 | 2168 | /// / ASTERISKPERCENT |
| 2179 | 2169 | fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2180 | const ops = Node.InfixOp.Op; | |
| 2181 | ||
| 2182 | 2170 | const token = nextToken(it); |
| 2183 | const op = switch (token.ptr.id) { | |
| 2184 | .PipePipe => ops{ .BoolOr = {} }, | |
| 2185 | .Asterisk => ops{ .Mul = {} }, | |
| 2186 | .Slash => ops{ .Div = {} }, | |
| 2187 | .Percent => ops{ .Mod = {} }, | |
| 2188 | .AsteriskAsterisk => ops{ .ArrayMult = {} }, | |
| 2189 | .AsteriskPercent => ops{ .MulWrap = {} }, | |
| 2171 | const op: Node.InfixOp.Op = switch (token.ptr.id) { | |
| 2172 | .PipePipe => .MergeErrorSets, | |
| 2173 | .Asterisk => .Mul, | |
| 2174 | .Slash => .Div, | |
| 2175 | .Percent => .Mod, | |
| 2176 | .AsteriskAsterisk => .ArrayMult, | |
| 2177 | .AsteriskPercent => .MulWrap, | |
| 2190 | 2178 | else => { |
| 2191 | 2179 | putBackToken(it, token.index); |
| 2192 | 2180 | return null; |
| ... | ... | @@ -2205,17 +2193,15 @@ fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2205 | 2193 | /// / KEYWORD_try |
| 2206 | 2194 | /// / KEYWORD_await |
| 2207 | 2195 | fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2208 | const ops = Node.PrefixOp.Op; | |
| 2209 | ||
| 2210 | 2196 | const token = nextToken(it); |
| 2211 | const op = switch (token.ptr.id) { | |
| 2212 | .Bang => ops{ .BoolNot = {} }, | |
| 2213 | .Minus => ops{ .Negation = {} }, | |
| 2214 | .Tilde => ops{ .BitNot = {} }, | |
| 2215 | .MinusPercent => ops{ .NegationWrap = {} }, | |
| 2216 | .Ampersand => ops{ .AddressOf = {} }, | |
| 2217 | .Keyword_try => ops{ .Try = {} }, | |
| 2218 | .Keyword_await => ops{ .Await = .{} }, | |
| 2197 | const op: Node.PrefixOp.Op = switch (token.ptr.id) { | |
| 2198 | .Bang => .BoolNot, | |
| 2199 | .Minus => .Negation, | |
| 2200 | .Tilde => .BitNot, | |
| 2201 | .MinusPercent => .NegationWrap, | |
| 2202 | .Ampersand => .AddressOf, | |
| 2203 | .Keyword_try => .Try, | |
| 2204 | .Keyword_await => .Await, | |
| 2219 | 2205 | else => { |
| 2220 | 2206 | putBackToken(it, token.index); |
| 2221 | 2207 | return null; |
| ... | ... | @@ -2223,7 +2209,7 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2223 | 2209 | }; |
| 2224 | 2210 | |
| 2225 | 2211 | const node = try arena.create(Node.PrefixOp); |
| 2226 | node.* = Node.PrefixOp{ | |
| 2212 | node.* = .{ | |
| 2227 | 2213 | .op_token = token.index, |
| 2228 | 2214 | .op = op, |
| 2229 | 2215 | .rhs = undefined, // set by caller |
| ... | ... | @@ -2246,9 +2232,9 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2246 | 2232 | fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2247 | 2233 | if (eatToken(it, .QuestionMark)) |token| { |
| 2248 | 2234 | const node = try arena.create(Node.PrefixOp); |
| 2249 | node.* = Node.PrefixOp{ | |
| 2235 | node.* = .{ | |
| 2250 | 2236 | .op_token = token, |
| 2251 | .op = Node.PrefixOp.Op.OptionalType, | |
| 2237 | .op = .OptionalType, | |
| 2252 | 2238 | .rhs = undefined, // set by caller |
| 2253 | 2239 | }; |
| 2254 | 2240 | return &node.base; |
| ... | ... | @@ -2264,7 +2250,7 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2264 | 2250 | return null; |
| 2265 | 2251 | }; |
| 2266 | 2252 | const node = try arena.create(Node.AnyFrameType); |
| 2267 | node.* = Node.AnyFrameType{ | |
| 2253 | node.* = .{ | |
| 2268 | 2254 | .anyframe_token = token, |
| 2269 | 2255 | .result = Node.AnyFrameType.Result{ |
| 2270 | 2256 | .arrow_token = arrow, |
| ... | ... | @@ -2286,18 +2272,18 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2286 | 2272 | while (true) { |
| 2287 | 2273 | if (eatToken(it, .Keyword_align)) |align_token| { |
| 2288 | 2274 | const lparen = try expectToken(it, tree, .LParen); |
| 2289 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 2290 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 2275 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ | |
| 2276 | .ExpectedExpr = .{ .token = it.index }, | |
| 2291 | 2277 | }); |
| 2292 | 2278 | |
| 2293 | 2279 | // Optional bit range |
| 2294 | 2280 | const bit_range = if (eatToken(it, .Colon)) |_| bit_range_value: { |
| 2295 | const range_start = try expectNode(arena, it, tree, parseIntegerLiteral, AstError{ | |
| 2296 | .ExpectedIntegerLiteral = AstError.ExpectedIntegerLiteral{ .token = it.index }, | |
| 2281 | const range_start = try expectNode(arena, it, tree, parseIntegerLiteral, .{ | |
| 2282 | .ExpectedIntegerLiteral = .{ .token = it.index }, | |
| 2297 | 2283 | }); |
| 2298 | 2284 | _ = try expectToken(it, tree, .Colon); |
| 2299 | const range_end = try expectNode(arena, it, tree, parseIntegerLiteral, AstError{ | |
| 2300 | .ExpectedIntegerLiteral = AstError.ExpectedIntegerLiteral{ .token = it.index }, | |
| 2285 | const range_end = try expectNode(arena, it, tree, parseIntegerLiteral, .{ | |
| 2286 | .ExpectedIntegerLiteral = .{ .token = it.index }, | |
| 2301 | 2287 | }); |
| 2302 | 2288 | |
| 2303 | 2289 | break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{ |
| ... | ... | @@ -2340,8 +2326,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2340 | 2326 | while (true) { |
| 2341 | 2327 | if (try parseByteAlign(arena, it, tree)) |align_expr| { |
| 2342 | 2328 | if (slice_type.align_info != null) { |
| 2343 | try tree.errors.push(AstError{ | |
| 2344 | .ExtraAlignQualifier = AstError.ExtraAlignQualifier{ .token = it.index }, | |
| 2329 | try tree.errors.push(.{ | |
| 2330 | .ExtraAlignQualifier = .{ .token = it.index }, | |
| 2345 | 2331 | }); |
| 2346 | 2332 | return error.ParseError; |
| 2347 | 2333 | } |
| ... | ... | @@ -2353,8 +2339,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2353 | 2339 | } |
| 2354 | 2340 | if (eatToken(it, .Keyword_const)) |const_token| { |
| 2355 | 2341 | if (slice_type.const_token != null) { |
| 2356 | try tree.errors.push(AstError{ | |
| 2357 | .ExtraConstQualifier = AstError.ExtraConstQualifier{ .token = it.index }, | |
| 2342 | try tree.errors.push(.{ | |
| 2343 | .ExtraConstQualifier = .{ .token = it.index }, | |
| 2358 | 2344 | }); |
| 2359 | 2345 | return error.ParseError; |
| 2360 | 2346 | } |
| ... | ... | @@ -2363,8 +2349,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2363 | 2349 | } |
| 2364 | 2350 | if (eatToken(it, .Keyword_volatile)) |volatile_token| { |
| 2365 | 2351 | if (slice_type.volatile_token != null) { |
| 2366 | try tree.errors.push(AstError{ | |
| 2367 | .ExtraVolatileQualifier = AstError.ExtraVolatileQualifier{ .token = it.index }, | |
| 2352 | try tree.errors.push(.{ | |
| 2353 | .ExtraVolatileQualifier = .{ .token = it.index }, | |
| 2368 | 2354 | }); |
| 2369 | 2355 | return error.ParseError; |
| 2370 | 2356 | } |
| ... | ... | @@ -2373,8 +2359,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2373 | 2359 | } |
| 2374 | 2360 | if (eatToken(it, .Keyword_allowzero)) |allowzero_token| { |
| 2375 | 2361 | if (slice_type.allowzero_token != null) { |
| 2376 | try tree.errors.push(AstError{ | |
| 2377 | .ExtraAllowZeroQualifier = AstError.ExtraAllowZeroQualifier{ .token = it.index }, | |
| 2362 | try tree.errors.push(.{ | |
| 2363 | .ExtraAllowZeroQualifier = .{ .token = it.index }, | |
| 2378 | 2364 | }); |
| 2379 | 2365 | return error.ParseError; |
| 2380 | 2366 | } |
| ... | ... | @@ -2398,15 +2384,14 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2398 | 2384 | /// / DOTASTERISK |
| 2399 | 2385 | /// / DOTQUESTIONMARK |
| 2400 | 2386 | fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2401 | const Op = Node.SuffixOp.Op; | |
| 2402 | 2387 | const OpAndToken = struct { |
| 2403 | 2388 | op: Node.SuffixOp.Op, |
| 2404 | 2389 | token: TokenIndex, |
| 2405 | 2390 | }; |
| 2406 | const op_and_token = blk: { | |
| 2391 | const op_and_token: OpAndToken = blk: { | |
| 2407 | 2392 | if (eatToken(it, .LBracket)) |_| { |
| 2408 | const index_expr = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 2409 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 2393 | const index_expr = try expectNode(arena, it, tree, parseExpr, .{ | |
| 2394 | .ExpectedExpr = .{ .token = it.index }, | |
| 2410 | 2395 | }); |
| 2411 | 2396 | |
| 2412 | 2397 | if (eatToken(it, .Ellipsis2) != null) { |
| ... | ... | @@ -2415,9 +2400,9 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2415 | 2400 | try parseExpr(arena, it, tree) |
| 2416 | 2401 | else |
| 2417 | 2402 | null; |
| 2418 | break :blk OpAndToken{ | |
| 2419 | .op = Op{ | |
| 2420 | .Slice = Op.Slice{ | |
| 2403 | break :blk .{ | |
| 2404 | .op = .{ | |
| 2405 | .Slice = .{ | |
| 2421 | 2406 | .start = index_expr, |
| 2422 | 2407 | .end = end_expr, |
| 2423 | 2408 | .sentinel = sentinel, |
| ... | ... | @@ -2427,14 +2412,14 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2427 | 2412 | }; |
| 2428 | 2413 | } |
| 2429 | 2414 | |
| 2430 | break :blk OpAndToken{ | |
| 2431 | .op = Op{ .ArrayAccess = index_expr }, | |
| 2415 | break :blk .{ | |
| 2416 | .op = .{ .ArrayAccess = index_expr }, | |
| 2432 | 2417 | .token = try expectToken(it, tree, .RBracket), |
| 2433 | 2418 | }; |
| 2434 | 2419 | } |
| 2435 | 2420 | |
| 2436 | 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 | } |
| 2439 | 2424 | |
| 2440 | 2425 | if (eatToken(it, .Period)) |period| { |
| ... | ... | @@ -2443,19 +2428,19 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2443 | 2428 | // Should there be an ast.Node.SuffixOp.FieldAccess variant? Or should |
| 2444 | 2429 | // this grammar rule be altered? |
| 2445 | 2430 | const node = try arena.create(Node.InfixOp); |
| 2446 | node.* = Node.InfixOp{ | |
| 2431 | node.* = .{ | |
| 2447 | 2432 | .op_token = period, |
| 2448 | 2433 | .lhs = undefined, // set by caller |
| 2449 | .op = Node.InfixOp.Op.Period, | |
| 2434 | .op = .Period, | |
| 2450 | 2435 | .rhs = identifier, |
| 2451 | 2436 | }; |
| 2452 | 2437 | return &node.base; |
| 2453 | 2438 | } |
| 2454 | 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{ | |
| 2458 | .ExpectedSuffixOp = AstError.ExpectedSuffixOp{ .token = it.index }, | |
| 2442 | try tree.errors.push(.{ | |
| 2443 | .ExpectedSuffixOp = .{ .token = it.index }, | |
| 2459 | 2444 | }); |
| 2460 | 2445 | return null; |
| 2461 | 2446 | } |
| ... | ... | @@ -2464,7 +2449,7 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2464 | 2449 | }; |
| 2465 | 2450 | |
| 2466 | 2451 | const node = try arena.create(Node.SuffixOp); |
| 2467 | node.* = Node.SuffixOp{ | |
| 2452 | node.* = .{ | |
| 2468 | 2453 | .lhs = undefined, // set by caller |
| 2469 | 2454 | .op = op_and_token.op, |
| 2470 | 2455 | .rtoken = op_and_token.token, |
| ... | ... | @@ -2491,22 +2476,22 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 2491 | 2476 | const lbracket = eatToken(it, .LBracket) orelse return null; |
| 2492 | 2477 | const expr = try parseExpr(arena, it, tree); |
| 2493 | 2478 | const sentinel = if (eatToken(it, .Colon)) |_| |
| 2494 | try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 2479 | try expectNode(arena, it, tree, parseExpr, .{ | |
| 2495 | 2480 | .ExpectedExpr = .{ .token = it.index }, |
| 2496 | 2481 | }) |
| 2497 | 2482 | else |
| 2498 | 2483 | null; |
| 2499 | 2484 | const rbracket = try expectToken(it, tree, .RBracket); |
| 2500 | 2485 | |
| 2501 | const op = if (expr) |len_expr| | |
| 2502 | Node.PrefixOp.Op{ | |
| 2486 | const op: Node.PrefixOp.Op = if (expr) |len_expr| | |
| 2487 | .{ | |
| 2503 | 2488 | .ArrayType = .{ |
| 2504 | 2489 | .len_expr = len_expr, |
| 2505 | 2490 | .sentinel = sentinel, |
| 2506 | 2491 | }, |
| 2507 | 2492 | } |
| 2508 | 2493 | else |
| 2509 | Node.PrefixOp.Op{ | |
| 2494 | .{ | |
| 2510 | 2495 | .SliceType = Node.PrefixOp.PtrInfo{ |
| 2511 | 2496 | .allowzero_token = null, |
| 2512 | 2497 | .align_info = null, |
| ... | ... | @@ -2517,7 +2502,7 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 2517 | 2502 | }; |
| 2518 | 2503 | |
| 2519 | 2504 | const node = try arena.create(Node.PrefixOp); |
| 2520 | node.* = Node.PrefixOp{ | |
| 2505 | node.* = .{ | |
| 2521 | 2506 | .op_token = lbracket, |
| 2522 | 2507 | .op = op, |
| 2523 | 2508 | .rhs = undefined, // set by caller |
| ... | ... | @@ -2533,7 +2518,7 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 2533 | 2518 | fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2534 | 2519 | if (eatToken(it, .Asterisk)) |asterisk| { |
| 2535 | 2520 | const sentinel = if (eatToken(it, .Colon)) |_| |
| 2536 | try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 2521 | try expectNode(arena, it, tree, parseExpr, .{ | |
| 2537 | 2522 | .ExpectedExpr = .{ .token = it.index }, |
| 2538 | 2523 | }) |
| 2539 | 2524 | else |
| ... | ... | @@ -2549,17 +2534,17 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2549 | 2534 | |
| 2550 | 2535 | if (eatToken(it, .AsteriskAsterisk)) |double_asterisk| { |
| 2551 | 2536 | const node = try arena.create(Node.PrefixOp); |
| 2552 | node.* = Node.PrefixOp{ | |
| 2537 | node.* = .{ | |
| 2553 | 2538 | .op_token = double_asterisk, |
| 2554 | .op = Node.PrefixOp.Op{ .PtrType = .{} }, | |
| 2539 | .op = .{ .PtrType = .{} }, | |
| 2555 | 2540 | .rhs = undefined, // set by caller |
| 2556 | 2541 | }; |
| 2557 | 2542 | |
| 2558 | 2543 | // Special case for **, which is its own token |
| 2559 | 2544 | const child = try arena.create(Node.PrefixOp); |
| 2560 | child.* = Node.PrefixOp{ | |
| 2545 | child.* = .{ | |
| 2561 | 2546 | .op_token = double_asterisk, |
| 2562 | .op = Node.PrefixOp.Op{ .PtrType = .{} }, | |
| 2547 | .op = .{ .PtrType = .{} }, | |
| 2563 | 2548 | .rhs = undefined, // set by caller |
| 2564 | 2549 | }; |
| 2565 | 2550 | node.rhs = &child.base; |
| ... | ... | @@ -2586,7 +2571,7 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2586 | 2571 | } |
| 2587 | 2572 | } |
| 2588 | 2573 | const sentinel = if (eatToken(it, .Colon)) |_| |
| 2589 | try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 2574 | try expectNode(arena, it, tree, parseExpr, .{ | |
| 2590 | 2575 | .ExpectedExpr = .{ .token = it.index }, |
| 2591 | 2576 | }) |
| 2592 | 2577 | else |
| ... | ... | @@ -2629,8 +2614,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? |
| 2629 | 2614 | .Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} }, |
| 2630 | 2615 | .Keyword_enum => blk: { |
| 2631 | 2616 | if (eatToken(it, .LParen) != null) { |
| 2632 | const expr = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 2633 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 2617 | const expr = try expectNode(arena, it, tree, parseExpr, .{ | |
| 2618 | .ExpectedExpr = .{ .token = it.index }, | |
| 2634 | 2619 | }); |
| 2635 | 2620 | _ = try expectToken(it, tree, .RParen); |
| 2636 | 2621 | break :blk Node.ContainerDecl.InitArg{ .Type = expr }; |
| ... | ... | @@ -2641,8 +2626,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? |
| 2641 | 2626 | if (eatToken(it, .LParen) != null) { |
| 2642 | 2627 | if (eatToken(it, .Keyword_enum) != null) { |
| 2643 | 2628 | if (eatToken(it, .LParen) != null) { |
| 2644 | const expr = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 2645 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 2629 | const expr = try expectNode(arena, it, tree, parseExpr, .{ | |
| 2630 | .ExpectedExpr = .{ .token = it.index }, | |
| 2646 | 2631 | }); |
| 2647 | 2632 | _ = try expectToken(it, tree, .RParen); |
| 2648 | 2633 | _ = try expectToken(it, tree, .RParen); |
| ... | ... | @@ -2651,8 +2636,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? |
| 2651 | 2636 | _ = try expectToken(it, tree, .RParen); |
| 2652 | 2637 | break :blk Node.ContainerDecl.InitArg{ .Enum = null }; |
| 2653 | 2638 | } |
| 2654 | const expr = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 2655 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 2639 | const expr = try expectNode(arena, it, tree, parseExpr, .{ | |
| 2640 | .ExpectedExpr = .{ .token = it.index }, | |
| 2656 | 2641 | }); |
| 2657 | 2642 | _ = try expectToken(it, tree, .RParen); |
| 2658 | 2643 | break :blk Node.ContainerDecl.InitArg{ .Type = expr }; |
| ... | ... | @@ -2666,7 +2651,7 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? |
| 2666 | 2651 | }; |
| 2667 | 2652 | |
| 2668 | 2653 | const node = try arena.create(Node.ContainerDecl); |
| 2669 | node.* = Node.ContainerDecl{ | |
| 2654 | node.* = .{ | |
| 2670 | 2655 | .layout_token = null, |
| 2671 | 2656 | .kind_token = kind_token.index, |
| 2672 | 2657 | .init_arg_expr = init_arg_expr, |
| ... | ... | @@ -2681,8 +2666,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? |
| 2681 | 2666 | fn parseByteAlign(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2682 | 2667 | _ = eatToken(it, .Keyword_align) orelse return null; |
| 2683 | 2668 | _ = try expectToken(it, tree, .LParen); |
| 2684 | const expr = try expectNode(arena, it, tree, parseExpr, AstError{ | |
| 2685 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | |
| 2669 | const expr = try expectNode(arena, it, tree, parseExpr, .{ | |
| 2670 | .ExpectedExpr = .{ .token = it.index }, | |
| 2686 | 2671 | }); |
| 2687 | 2672 | _ = try expectToken(it, tree, .RParen); |
| 2688 | 2673 | return expr; |
| ... | ... | @@ -2738,7 +2723,7 @@ fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) No |
| 2738 | 2723 | pub fn parse(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node { |
| 2739 | 2724 | const op_token = eatToken(it, token) orelse return null; |
| 2740 | 2725 | const node = try arena.create(Node.InfixOp); |
| 2741 | node.* = Node.InfixOp{ | |
| 2726 | node.* = .{ | |
| 2742 | 2727 | .op_token = op_token, |
| 2743 | 2728 | .lhs = undefined, // set by caller |
| 2744 | 2729 | .op = op, |
| ... | ... | @@ -2754,13 +2739,13 @@ fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) No |
| 2754 | 2739 | fn parseBuiltinCall(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2755 | 2740 | const token = eatToken(it, .Builtin) orelse return null; |
| 2756 | 2741 | const params = (try parseFnCallArguments(arena, it, tree)) orelse { |
| 2757 | try tree.errors.push(AstError{ | |
| 2758 | .ExpectedParamList = AstError.ExpectedParamList{ .token = it.index }, | |
| 2742 | try tree.errors.push(.{ | |
| 2743 | .ExpectedParamList = .{ .token = it.index }, | |
| 2759 | 2744 | }); |
| 2760 | 2745 | return error.ParseError; |
| 2761 | 2746 | }; |
| 2762 | 2747 | const node = try arena.create(Node.BuiltinCall); |
| 2763 | node.* = Node.BuiltinCall{ | |
| 2748 | node.* = .{ | |
| 2764 | 2749 | .builtin_token = token, |
| 2765 | 2750 | .params = params.list, |
| 2766 | 2751 | .rparen_token = params.rparen, |
| ... | ... | @@ -2773,7 +2758,7 @@ fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2773 | 2758 | const token = eatToken(it, .Identifier) orelse return null; |
| 2774 | 2759 | |
| 2775 | 2760 | const node = try arena.create(Node.ErrorTag); |
| 2776 | node.* = Node.ErrorTag{ | |
| 2761 | node.* = .{ | |
| 2777 | 2762 | .doc_comments = doc_comments, |
| 2778 | 2763 | .name_token = token, |
| 2779 | 2764 | }; |
| ... | ... | @@ -2783,7 +2768,7 @@ fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2783 | 2768 | fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2784 | 2769 | const token = eatToken(it, .Identifier) orelse return null; |
| 2785 | 2770 | const node = try arena.create(Node.Identifier); |
| 2786 | node.* = Node.Identifier{ | |
| 2771 | node.* = .{ | |
| 2787 | 2772 | .token = token, |
| 2788 | 2773 | }; |
| 2789 | 2774 | return &node.base; |
| ... | ... | @@ -2792,7 +2777,7 @@ fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2792 | 2777 | fn parseVarType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2793 | 2778 | const token = eatToken(it, .Keyword_var) orelse return null; |
| 2794 | 2779 | const node = try arena.create(Node.VarType); |
| 2795 | node.* = Node.VarType{ | |
| 2780 | node.* = .{ | |
| 2796 | 2781 | .token = token, |
| 2797 | 2782 | }; |
| 2798 | 2783 | return &node.base; |
| ... | ... | @@ -2810,7 +2795,7 @@ fn createLiteral(arena: *Allocator, comptime T: type, token: TokenIndex) !*Node |
| 2810 | 2795 | fn parseStringLiteralSingle(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2811 | 2796 | if (eatToken(it, .StringLiteral)) |token| { |
| 2812 | 2797 | const node = try arena.create(Node.StringLiteral); |
| 2813 | node.* = Node.StringLiteral{ | |
| 2798 | node.* = .{ | |
| 2814 | 2799 | .token = token, |
| 2815 | 2800 | }; |
| 2816 | 2801 | return &node.base; |
| ... | ... | @@ -2824,7 +2809,7 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod |
| 2824 | 2809 | |
| 2825 | 2810 | if (eatToken(it, .MultilineStringLiteralLine)) |first_line| { |
| 2826 | 2811 | const node = try arena.create(Node.MultilineStringLiteral); |
| 2827 | node.* = Node.MultilineStringLiteral{ | |
| 2812 | node.* = .{ | |
| 2828 | 2813 | .lines = Node.MultilineStringLiteral.LineList.init(arena), |
| 2829 | 2814 | }; |
| 2830 | 2815 | try node.lines.push(first_line); |
| ... | ... | @@ -2840,7 +2825,7 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod |
| 2840 | 2825 | fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2841 | 2826 | const token = eatToken(it, .IntegerLiteral) orelse return null; |
| 2842 | 2827 | const node = try arena.create(Node.IntegerLiteral); |
| 2843 | node.* = Node.IntegerLiteral{ | |
| 2828 | node.* = .{ | |
| 2844 | 2829 | .token = token, |
| 2845 | 2830 | }; |
| 2846 | 2831 | return &node.base; |
| ... | ... | @@ -2849,7 +2834,7 @@ fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 2849 | 2834 | fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2850 | 2835 | const token = eatToken(it, .FloatLiteral) orelse return null; |
| 2851 | 2836 | const node = try arena.create(Node.FloatLiteral); |
| 2852 | node.* = Node.FloatLiteral{ | |
| 2837 | node.* = .{ | |
| 2853 | 2838 | .token = token, |
| 2854 | 2839 | }; |
| 2855 | 2840 | return &node.base; |
| ... | ... | @@ -2858,9 +2843,9 @@ fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2858 | 2843 | fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2859 | 2844 | const token = eatToken(it, .Keyword_try) orelse return null; |
| 2860 | 2845 | const node = try arena.create(Node.PrefixOp); |
| 2861 | node.* = Node.PrefixOp{ | |
| 2846 | node.* = .{ | |
| 2862 | 2847 | .op_token = token, |
| 2863 | .op = Node.PrefixOp.Op.Try, | |
| 2848 | .op = .Try, | |
| 2864 | 2849 | .rhs = undefined, // set by caller |
| 2865 | 2850 | }; |
| 2866 | 2851 | return &node.base; |
| ... | ... | @@ -2869,7 +2854,7 @@ fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2869 | 2854 | fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2870 | 2855 | const token = eatToken(it, .Keyword_usingnamespace) orelse return null; |
| 2871 | 2856 | const node = try arena.create(Node.Use); |
| 2872 | node.* = Node.Use{ | |
| 2857 | node.* = .{ | |
| 2873 | 2858 | .doc_comments = null, |
| 2874 | 2859 | .visib_token = null, |
| 2875 | 2860 | .use_token = token, |
| ... | ... | @@ -2884,17 +2869,17 @@ fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: Node |
| 2884 | 2869 | const node = (try parseIfPrefix(arena, it, tree)) orelse return null; |
| 2885 | 2870 | const if_prefix = node.cast(Node.If).?; |
| 2886 | 2871 | |
| 2887 | if_prefix.body = try expectNode(arena, it, tree, bodyParseFn, AstError{ | |
| 2888 | .InvalidToken = AstError.InvalidToken{ .token = it.index }, | |
| 2872 | if_prefix.body = try expectNode(arena, it, tree, bodyParseFn, .{ | |
| 2873 | .InvalidToken = .{ .token = it.index }, | |
| 2889 | 2874 | }); |
| 2890 | 2875 | |
| 2891 | 2876 | const else_token = eatToken(it, .Keyword_else) orelse return node; |
| 2892 | 2877 | const payload = try parsePayload(arena, it, tree); |
| 2893 | const else_expr = try expectNode(arena, it, tree, bodyParseFn, AstError{ | |
| 2894 | .InvalidToken = AstError.InvalidToken{ .token = it.index }, | |
| 2878 | const else_expr = try expectNode(arena, it, tree, bodyParseFn, .{ | |
| 2879 | .InvalidToken = .{ .token = it.index }, | |
| 2895 | 2880 | }); |
| 2896 | 2881 | const else_node = try arena.create(Node.Else); |
| 2897 | else_node.* = Node.Else{ | |
| 2882 | else_node.* = .{ | |
| 2898 | 2883 | .else_token = else_token, |
| 2899 | 2884 | .payload = payload, |
| 2900 | 2885 | .body = else_expr, |
| ... | ... | @@ -2914,7 +2899,7 @@ fn parseDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.D |
| 2914 | 2899 | if (lines.len == 0) return null; |
| 2915 | 2900 | |
| 2916 | 2901 | const node = try arena.create(Node.DocComment); |
| 2917 | node.* = Node.DocComment{ | |
| 2902 | node.* = .{ | |
| 2918 | 2903 | .lines = lines, |
| 2919 | 2904 | }; |
| 2920 | 2905 | return node; |
| ... | ... | @@ -2925,7 +2910,7 @@ fn parseAppendedDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree, a |
| 2925 | 2910 | const comment_token = eatToken(it, .DocComment) orelse return null; |
| 2926 | 2911 | if (tree.tokensOnSameLine(after_token, comment_token)) { |
| 2927 | 2912 | const node = try arena.create(Node.DocComment); |
| 2928 | node.* = Node.DocComment{ | |
| 2913 | node.* = .{ | |
| 2929 | 2914 | .lines = Node.DocComment.LineList.init(arena), |
| 2930 | 2915 | }; |
| 2931 | 2916 | try node.lines.push(comment_token); |
| ... | ... | @@ -2974,14 +2959,14 @@ fn parsePrefixOpExpr( |
| 2974 | 2959 | switch (rightmost_op.id) { |
| 2975 | 2960 | .PrefixOp => { |
| 2976 | 2961 | const prefix_op = rightmost_op.cast(Node.PrefixOp).?; |
| 2977 | prefix_op.rhs = try expectNode(arena, it, tree, childParseFn, AstError{ | |
| 2978 | .InvalidToken = AstError.InvalidToken{ .token = it.index }, | |
| 2962 | prefix_op.rhs = try expectNode(arena, it, tree, childParseFn, .{ | |
| 2963 | .InvalidToken = .{ .token = it.index }, | |
| 2979 | 2964 | }); |
| 2980 | 2965 | }, |
| 2981 | 2966 | .AnyFrameType => { |
| 2982 | 2967 | const prom = rightmost_op.cast(Node.AnyFrameType).?; |
| 2983 | prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, AstError{ | |
| 2984 | .InvalidToken = AstError.InvalidToken{ .token = it.index }, | |
| 2968 | prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, .{ | |
| 2969 | .InvalidToken = .{ .token = it.index }, | |
| 2985 | 2970 | }); |
| 2986 | 2971 | }, |
| 2987 | 2972 | else => unreachable, |
| ... | ... | @@ -3010,8 +2995,8 @@ fn parseBinOpExpr( |
| 3010 | 2995 | var res = (try childParseFn(arena, it, tree)) orelse return null; |
| 3011 | 2996 | |
| 3012 | 2997 | while (try opParseFn(arena, it, tree)) |node| { |
| 3013 | const right = try expectNode(arena, it, tree, childParseFn, AstError{ | |
| 3014 | .InvalidToken = AstError.InvalidToken{ .token = it.index }, | |
| 2998 | const right = try expectNode(arena, it, tree, childParseFn, .{ | |
| 2999 | .InvalidToken = .{ .token = it.index }, | |
| 3015 | 3000 | }); |
| 3016 | 3001 | const left = res; |
| 3017 | 3002 | res = node; |
| ... | ... | @@ -3031,7 +3016,7 @@ fn parseBinOpExpr( |
| 3031 | 3016 | |
| 3032 | 3017 | fn createInfixOp(arena: *Allocator, index: TokenIndex, op: Node.InfixOp.Op) !*Node { |
| 3033 | 3018 | const node = try arena.create(Node.InfixOp); |
| 3034 | node.* = Node.InfixOp{ | |
| 3019 | node.* = .{ | |
| 3035 | 3020 | .op_token = index, |
| 3036 | 3021 | .lhs = undefined, // set by caller |
| 3037 | 3022 | .op = op, |
| ... | ... | @@ -3051,8 +3036,8 @@ fn eatAnnotatedToken(it: *TokenIterator, id: Token.Id) ?AnnotatedToken { |
| 3051 | 3036 | fn expectToken(it: *TokenIterator, tree: *Tree, id: Token.Id) Error!TokenIndex { |
| 3052 | 3037 | const token = nextToken(it); |
| 3053 | 3038 | if (token.ptr.id != id) { |
| 3054 | try tree.errors.push(AstError{ | |
| 3055 | .ExpectedToken = AstError.ExpectedToken{ .token = token.index, .expected_id = id }, | |
| 3039 | try tree.errors.push(.{ | |
| 3040 | .ExpectedToken = .{ .token = token.index, .expected_id = id }, | |
| 3056 | 3041 | }); |
| 3057 | 3042 | return error.ParseError; |
| 3058 | 3043 | } |
lib/std/zig/parser_test.zig+2| ... | ... | @@ -1509,6 +1509,8 @@ test "zig fmt: error set declaration" { |
| 1509 | 1509 | \\const Error = error{OutOfMemory}; |
| 1510 | 1510 | \\const Error = error{}; |
| 1511 | 1511 | \\ |
| 1512 | \\const Error = error{ OutOfMemory, OutOfTime }; | |
| 1513 | \\ | |
| 1512 | 1514 | ); |
| 1513 | 1515 | } |
| 1514 | 1516 |
lib/std/zig/render.zig+41-18| ... | ... | @@ -583,7 +583,6 @@ fn renderExpression( |
| 583 | 583 | }, |
| 584 | 584 | |
| 585 | 585 | .Try, |
| 586 | .Cancel, | |
| 587 | 586 | .Resume, |
| 588 | 587 | => { |
| 589 | 588 | try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space); |
| ... | ... | @@ -1269,25 +1268,51 @@ fn renderExpression( |
| 1269 | 1268 | } |
| 1270 | 1269 | |
| 1271 | 1270 | 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; | |
| 1274 | 1271 | |
| 1275 | var it = err_set_decl.decls.iterator(0); | |
| 1276 | while (it.next()) |node| { | |
| 1277 | try stream.writeByteNTimes(' ', new_indent); | |
| 1272 | const src_has_trailing_comma = blk: { | |
| 1273 | const maybe_comma = tree.prevToken(err_set_decl.rbrace_token); | |
| 1274 | break :blk tree.tokens.at(maybe_comma).id == .Comma; | |
| 1275 | }; | |
| 1278 | 1276 | |
| 1279 | if (it.peek()) |next_node| { | |
| 1280 | try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.None); | |
| 1281 | try renderToken(tree, stream, tree.nextToken(node.*.lastToken()), new_indent, start_col, Space.Newline); // , | |
| 1277 | if (src_has_trailing_comma) { | |
| 1278 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // { | |
| 1279 | const new_indent = indent + indent_delta; | |
| 1282 | 1280 | |
| 1283 | try renderExtraNewline(tree, stream, start_col, next_node.*); | |
| 1284 | } else { | |
| 1285 | try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.Comma); | |
| 1281 | var it = err_set_decl.decls.iterator(0); | |
| 1282 | while (it.next()) |node| { | |
| 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 | } | |
| 1288 | 1294 | |
| 1289 | try stream.writeByteNTimes(' ', indent); | |
| 1290 | return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // } | |
| 1295 | try stream.writeByteNTimes(' ', indent); | |
| 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 | }, |
| 1292 | 1317 | |
| 1293 | 1318 | .ErrorTag => { |
| ... | ... | @@ -1590,8 +1615,7 @@ fn renderExpression( |
| 1590 | 1615 | } |
| 1591 | 1616 | } else { |
| 1592 | 1617 | var it = switch_case.items.iterator(0); |
| 1593 | while (true) { | |
| 1594 | const node = it.next().?; | |
| 1618 | while (it.next()) |node| { | |
| 1595 | 1619 | if (it.peek()) |next_node| { |
| 1596 | 1620 | try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None); |
| 1597 | 1621 | |
| ... | ... | @@ -1602,7 +1626,6 @@ fn renderExpression( |
| 1602 | 1626 | } else { |
| 1603 | 1627 | try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Comma); |
| 1604 | 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 | 754 | const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr)); |
| 755 | 755 | var it = mem.tokenize(rpath_list, ":"); |
| 756 | 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 | 758 | error.NameTooLong => unreachable, |
| 759 | 759 | error.InvalidUtf8 => unreachable, |
| 760 | 760 | error.BadPathName => unreachable, |
src-self-hosted/c_int.zig+4-4| ... | ... | @@ -69,9 +69,9 @@ pub const CInt = struct { |
| 69 | 69 | }; |
| 70 | 70 | |
| 71 | 71 | pub fn sizeInBits(cint: CInt, self: Target) u32 { |
| 72 | const arch = self.getArch(); | |
| 72 | const arch = self.cpu.arch; | |
| 73 | 73 | switch (self.os.tag) { |
| 74 | .freestanding, .other => switch (self.getArch()) { | |
| 74 | .freestanding, .other => switch (self.cpu.arch) { | |
| 75 | 75 | .msp430 => switch (cint.id) { |
| 76 | 76 | .Short, |
| 77 | 77 | .UShort, |
| ... | ... | @@ -94,7 +94,7 @@ pub const CInt = struct { |
| 94 | 94 | => return 32, |
| 95 | 95 | .Long, |
| 96 | 96 | .ULong, |
| 97 | => return self.getArchPtrBitWidth(), | |
| 97 | => return self.cpu.arch.ptrBitWidth(), | |
| 98 | 98 | .LongLong, |
| 99 | 99 | .ULongLong, |
| 100 | 100 | => return 64, |
| ... | ... | @@ -114,7 +114,7 @@ pub const CInt = struct { |
| 114 | 114 | => return 32, |
| 115 | 115 | .Long, |
| 116 | 116 | .ULong, |
| 117 | => return self.getArchPtrBitWidth(), | |
| 117 | => return self.cpu.arch.ptrBitWidth(), | |
| 118 | 118 | .LongLong, |
| 119 | 119 | .ULongLong, |
| 120 | 120 | => return 64, |
src-self-hosted/compilation.zig+17-13| ... | ... | @@ -95,7 +95,7 @@ pub const ZigCompiler = struct { |
| 95 | 95 | |
| 96 | 96 | pub fn getNativeLibC(self: *ZigCompiler) !*LibCInstallation { |
| 97 | 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 | 99 | self.native_libc.resolve(); |
| 100 | 100 | return &self.native_libc.data; |
| 101 | 101 | } |
| ... | ... | @@ -126,7 +126,7 @@ pub const Compilation = struct { |
| 126 | 126 | name: Buffer, |
| 127 | 127 | llvm_triple: Buffer, |
| 128 | 128 | root_src_path: ?[]const u8, |
| 129 | target: Target, | |
| 129 | target: std.Target, | |
| 130 | 130 | llvm_target: *llvm.Target, |
| 131 | 131 | build_mode: builtin.Mode, |
| 132 | 132 | zig_lib_dir: []const u8, |
| ... | ... | @@ -338,7 +338,7 @@ pub const Compilation = struct { |
| 338 | 338 | zig_compiler: *ZigCompiler, |
| 339 | 339 | name: []const u8, |
| 340 | 340 | root_src_path: ?[]const u8, |
| 341 | target: Target, | |
| 341 | target: std.zig.CrossTarget, | |
| 342 | 342 | kind: Kind, |
| 343 | 343 | build_mode: builtin.Mode, |
| 344 | 344 | is_static: bool, |
| ... | ... | @@ -370,13 +370,18 @@ pub const Compilation = struct { |
| 370 | 370 | zig_compiler: *ZigCompiler, |
| 371 | 371 | name: []const u8, |
| 372 | 372 | root_src_path: ?[]const u8, |
| 373 | target: Target, | |
| 373 | cross_target: std.zig.CrossTarget, | |
| 374 | 374 | kind: Kind, |
| 375 | 375 | build_mode: builtin.Mode, |
| 376 | 376 | is_static: bool, |
| 377 | 377 | zig_lib_dir: []const u8, |
| 378 | 378 | ) !void { |
| 379 | 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 | 385 | var comp = Compilation{ |
| 381 | 386 | .arena_allocator = std.heap.ArenaAllocator.init(allocator), |
| 382 | 387 | .zig_compiler = zig_compiler, |
| ... | ... | @@ -419,7 +424,7 @@ pub const Compilation = struct { |
| 419 | 424 | .target_machine = undefined, |
| 420 | 425 | .target_data_ref = undefined, |
| 421 | 426 | .target_layout_str = undefined, |
| 422 | .target_ptr_bits = target.getArchPtrBitWidth(), | |
| 427 | .target_ptr_bits = target.cpu.arch.ptrBitWidth(), | |
| 423 | 428 | |
| 424 | 429 | .root_package = undefined, |
| 425 | 430 | .std_package = undefined, |
| ... | ... | @@ -440,7 +445,7 @@ pub const Compilation = struct { |
| 440 | 445 | } |
| 441 | 446 | |
| 442 | 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 | 449 | comp.llvm_target = try util.llvmTargetFromTriple(comp.llvm_triple); |
| 445 | 450 | comp.zig_std_dir = try fs.path.join(comp.arena(), &[_][]const u8{ zig_lib_dir, "std" }); |
| 446 | 451 | |
| ... | ... | @@ -455,10 +460,8 @@ pub const Compilation = struct { |
| 455 | 460 | var target_specific_cpu_features: ?[*:0]u8 = null; |
| 456 | 461 | defer llvm.DisposeMessage(target_specific_cpu_args); |
| 457 | 462 | defer llvm.DisposeMessage(target_specific_cpu_features); |
| 458 | if (target == Target.Native) { | |
| 459 | target_specific_cpu_args = llvm.GetHostCPUName() orelse return error.OutOfMemory; | |
| 460 | target_specific_cpu_features = llvm.GetNativeFeatures() orelse return error.OutOfMemory; | |
| 461 | } | |
| 463 | ||
| 464 | // TODO detect native CPU & features here | |
| 462 | 465 | |
| 463 | 466 | comp.target_machine = llvm.CreateTargetMachine( |
| 464 | 467 | comp.llvm_target, |
| ... | ... | @@ -517,8 +520,7 @@ pub const Compilation = struct { |
| 517 | 520 | |
| 518 | 521 | if (comp.tmp_dir.getOrNull()) |tmp_dir_result| |
| 519 | 522 | if (tmp_dir_result.*) |tmp_dir| { |
| 520 | // TODO evented I/O? | |
| 521 | fs.deleteTree(tmp_dir) catch {}; | |
| 523 | fs.cwd().deleteTree(tmp_dir) catch {}; | |
| 522 | 524 | } else |_| {}; |
| 523 | 525 | } |
| 524 | 526 | |
| ... | ... | @@ -1122,7 +1124,9 @@ pub const Compilation = struct { |
| 1122 | 1124 | self.libc_link_lib = link_lib; |
| 1123 | 1125 | |
| 1124 | 1126 | // 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 | 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 | 164 | const realpath_copy = try mem.dupe(comp.gpa(), u8, tree_scope.root().realpath); |
| 165 | 165 | errdefer comp.gpa().free(realpath_copy); |
| 166 | 166 | |
| 167 | var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; | |
| 168 | try parse_error.render(&tree_scope.tree.tokens, out_stream); | |
| 167 | try parse_error.render(&tree_scope.tree.tokens, text_buf.outStream()); | |
| 169 | 168 | |
| 170 | 169 | const msg = try comp.gpa().create(Msg); |
| 171 | 170 | msg.* = Msg{ |
| ... | ... | @@ -204,8 +203,7 @@ pub const Msg = struct { |
| 204 | 203 | const realpath_copy = try mem.dupe(allocator, u8, realpath); |
| 205 | 204 | errdefer allocator.free(realpath_copy); |
| 206 | 205 | |
| 207 | var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; | |
| 208 | try parse_error.render(&tree.tokens, out_stream); | |
| 206 | try parse_error.render(&tree.tokens, text_buf.outStream()); | |
| 209 | 207 | |
| 210 | 208 | const msg = try allocator.create(Msg); |
| 211 | 209 | msg.* = Msg{ |
| ... | ... | @@ -272,7 +270,7 @@ pub const Msg = struct { |
| 272 | 270 | }); |
| 273 | 271 | try stream.writeByteNTimes(' ', start_loc.column); |
| 274 | 272 | try stream.writeByteNTimes('~', last_token.end - first_token.start); |
| 275 | try stream.write("\n"); | |
| 273 | try stream.writeAll("\n"); | |
| 276 | 274 | } |
| 277 | 275 | |
| 278 | 276 | pub fn printToFile(msg: *const Msg, file: fs.File, color: Color) !void { |
| ... | ... | @@ -281,7 +279,6 @@ pub const Msg = struct { |
| 281 | 279 | .On => true, |
| 282 | 280 | .Off => false, |
| 283 | 281 | }; |
| 284 | var stream = &file.outStream().stream; | |
| 285 | return msg.printToStream(stream, color_on); | |
| 282 | return msg.printToStream(file.outStream(), color_on); | |
| 286 | 283 | } |
| 287 | 284 | }; |
src-self-hosted/ir.zig+1-1| ... | ... | @@ -1099,7 +1099,6 @@ pub const Builder = struct { |
| 1099 | 1099 | .Await => return error.Unimplemented, |
| 1100 | 1100 | .BitNot => return error.Unimplemented, |
| 1101 | 1101 | .BoolNot => return error.Unimplemented, |
| 1102 | .Cancel => return error.Unimplemented, | |
| 1103 | 1102 | .OptionalType => return error.Unimplemented, |
| 1104 | 1103 | .Negation => return error.Unimplemented, |
| 1105 | 1104 | .NegationWrap => return error.Unimplemented, |
| ... | ... | @@ -1188,6 +1187,7 @@ pub const Builder = struct { |
| 1188 | 1187 | .ParamDecl => return error.Unimplemented, |
| 1189 | 1188 | .FieldInitializer => return error.Unimplemented, |
| 1190 | 1189 | .EnumLiteral => return error.Unimplemented, |
| 1190 | .Noasync => return error.Unimplemented, | |
| 1191 | 1191 | } |
| 1192 | 1192 | } |
| 1193 | 1193 |
src-self-hosted/libc_installation.zig+5-5| ... | ... | @@ -280,7 +280,7 @@ pub const LibCInstallation = struct { |
| 280 | 280 | // search in reverse order |
| 281 | 281 | const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1); |
| 282 | 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 | 284 | error.FileNotFound, |
| 285 | 285 | error.NotDir, |
| 286 | 286 | error.NoDevice, |
| ... | ... | @@ -335,7 +335,7 @@ pub const LibCInstallation = struct { |
| 335 | 335 | const stream = result_buf.outStream(); |
| 336 | 336 | try stream.print("{}\\Include\\{}\\ucrt", .{ search.path, search.version }); |
| 337 | 337 | |
| 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 | 339 | error.FileNotFound, |
| 340 | 340 | error.NotDir, |
| 341 | 341 | error.NoDevice, |
| ... | ... | @@ -382,7 +382,7 @@ pub const LibCInstallation = struct { |
| 382 | 382 | const stream = result_buf.outStream(); |
| 383 | 383 | try stream.print("{}\\Lib\\{}\\ucrt\\{}", .{ search.path, search.version, arch_sub_dir }); |
| 384 | 384 | |
| 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 | 386 | error.FileNotFound, |
| 387 | 387 | error.NotDir, |
| 388 | 388 | error.NoDevice, |
| ... | ... | @@ -437,7 +437,7 @@ pub const LibCInstallation = struct { |
| 437 | 437 | const stream = result_buf.outStream(); |
| 438 | 438 | try stream.print("{}\\Lib\\{}\\um\\{}", .{ search.path, search.version, arch_sub_dir }); |
| 439 | 439 | |
| 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 | 441 | error.FileNotFound, |
| 442 | 442 | error.NotDir, |
| 443 | 443 | error.NoDevice, |
| ... | ... | @@ -475,7 +475,7 @@ pub const LibCInstallation = struct { |
| 475 | 475 | |
| 476 | 476 | try result_buf.append("\\include"); |
| 477 | 477 | |
| 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 | 479 | error.FileNotFound, |
| 480 | 480 | error.NotDir, |
| 481 | 481 | error.NoDevice, |
src-self-hosted/link.zig+54-58| ... | ... | @@ -56,12 +56,13 @@ pub fn link(comp: *Compilation) !void { |
| 56 | 56 | if (comp.haveLibC()) { |
| 57 | 57 | // TODO https://github.com/ziglang/zig/issues/3190 |
| 58 | 58 | var libc = ctx.comp.override_libc orelse blk: { |
| 59 | switch (comp.target) { | |
| 60 | Target.Native => { | |
| 61 | break :blk comp.zig_compiler.getNativeLibC() catch return error.LibCRequiredButNotProvidedOrFound; | |
| 62 | }, | |
| 63 | else => return error.LibCRequiredButNotProvidedOrFound, | |
| 64 | } | |
| 59 | @panic("this code has bitrotted"); | |
| 60 | //switch (comp.target) { | |
| 61 | // Target.Native => { | |
| 62 | // break :blk comp.zig_compiler.getNativeLibC() catch return error.LibCRequiredButNotProvidedOrFound; | |
| 63 | // }, | |
| 64 | // else => return error.LibCRequiredButNotProvidedOrFound, | |
| 65 | //} | |
| 65 | 66 | }; |
| 66 | 67 | ctx.libc = libc; |
| 67 | 68 | } |
| ... | ... | @@ -155,11 +156,11 @@ fn constructLinkerArgsElf(ctx: *Context) !void { |
| 155 | 156 | //bool shared = !g->is_static && is_lib; |
| 156 | 157 | //Buf *soname = nullptr; |
| 157 | 158 | if (ctx.comp.is_static) { |
| 158 | if (util.isArmOrThumb(ctx.comp.target)) { | |
| 159 | try ctx.args.append("-Bstatic"); | |
| 160 | } else { | |
| 161 | try ctx.args.append("-static"); | |
| 162 | } | |
| 159 | //if (util.isArmOrThumb(ctx.comp.target)) { | |
| 160 | // try ctx.args.append("-Bstatic"); | |
| 161 | //} else { | |
| 162 | // try ctx.args.append("-static"); | |
| 163 | //} | |
| 163 | 164 | } |
| 164 | 165 | //} else if (shared) { |
| 165 | 166 | // lj->args.append("-shared"); |
| ... | ... | @@ -176,29 +177,24 @@ fn constructLinkerArgsElf(ctx: *Context) !void { |
| 176 | 177 | |
| 177 | 178 | if (ctx.link_in_crt) { |
| 178 | 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.lib_dir.?, crt1o); | |
| 181 | try addPathJoin(ctx, ctx.libc.lib_dir.?, "crti.o"); | |
| 182 | try addPathJoin(ctx, ctx.libc.static_lib_dir.?, crtbegino); | |
| 180 | try addPathJoin(ctx, ctx.libc.crt_dir.?, crt1o); | |
| 181 | try addPathJoin(ctx, ctx.libc.crt_dir.?, "crti.o"); | |
| 183 | 182 | } |
| 184 | 183 | |
| 185 | 184 | if (ctx.comp.haveLibC()) { |
| 186 | 185 | try ctx.args.append("-L"); |
| 187 | 186 | // 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)); | |
| 189 | 188 | |
| 190 | try ctx.args.append("-L"); | |
| 191 | try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.static_lib_dir.?)).ptr)); | |
| 192 | ||
| 193 | if (!ctx.comp.is_static) { | |
| 194 | const dl = blk: { | |
| 195 | if (ctx.libc.dynamic_linker_path) |dl| break :blk dl; | |
| 196 | if (util.getDynamicLinkerPath(ctx.comp.target)) |dl| break :blk dl; | |
| 197 | return error.LibCMissingDynamicLinker; | |
| 198 | }; | |
| 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 | } | |
| 189 | //if (!ctx.comp.is_static) { | |
| 190 | // const dl = blk: { | |
| 191 | // //if (ctx.libc.dynamic_linker_path) |dl| break :blk dl; | |
| 192 | // //if (util.getDynamicLinkerPath(ctx.comp.target)) |dl| break :blk dl; | |
| 193 | // return error.LibCMissingDynamicLinker; | |
| 194 | // }; | |
| 195 | // try ctx.args.append("-dynamic-linker"); | |
| 196 | // try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr)); | |
| 197 | //} | |
| 202 | 198 | } |
| 203 | 199 | |
| 204 | 200 | //if (shared) { |
| ... | ... | @@ -265,13 +261,12 @@ fn constructLinkerArgsElf(ctx: *Context) !void { |
| 265 | 261 | |
| 266 | 262 | // crt end |
| 267 | 263 | if (ctx.link_in_crt) { |
| 268 | try addPathJoin(ctx, ctx.libc.static_lib_dir.?, "crtend.o"); | |
| 269 | try addPathJoin(ctx, ctx.libc.lib_dir.?, "crtn.o"); | |
| 264 | try addPathJoin(ctx, ctx.libc.crt_dir.?, "crtn.o"); | |
| 270 | 265 | } |
| 271 | 266 | |
| 272 | if (ctx.comp.target != Target.Native) { | |
| 273 | try ctx.args.append("--allow-shlib-undefined"); | |
| 274 | } | |
| 267 | //if (ctx.comp.target != Target.Native) { | |
| 268 | // try ctx.args.append("--allow-shlib-undefined"); | |
| 269 | //} | |
| 275 | 270 | } |
| 276 | 271 | |
| 277 | 272 | fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void { |
| ... | ... | @@ -287,7 +282,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { |
| 287 | 282 | try ctx.args.append("-DEBUG"); |
| 288 | 283 | } |
| 289 | 284 | |
| 290 | switch (ctx.comp.target.getArch()) { | |
| 285 | switch (ctx.comp.target.cpu.arch) { | |
| 291 | 286 | .i386 => try ctx.args.append("-MACHINE:X86"), |
| 292 | 287 | .x86_64 => try ctx.args.append("-MACHINE:X64"), |
| 293 | 288 | .aarch64 => try ctx.args.append("-MACHINE:ARM"), |
| ... | ... | @@ -302,7 +297,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { |
| 302 | 297 | if (ctx.comp.haveLibC()) { |
| 303 | 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 | 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 | } |
| 307 | 302 | |
| 308 | 303 | if (ctx.link_in_crt) { |
| ... | ... | @@ -417,7 +412,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { |
| 417 | 412 | } |
| 418 | 413 | }, |
| 419 | 414 | .IPhoneOS => { |
| 420 | if (ctx.comp.target.getArch() == .aarch64) { | |
| 415 | if (ctx.comp.target.cpu.arch == .aarch64) { | |
| 421 | 416 | // iOS does not need any crt1 files for arm64 |
| 422 | 417 | } else if (platform.versionLessThan(3, 1)) { |
| 423 | 418 | try ctx.args.append("-lcrt1.o"); |
| ... | ... | @@ -435,28 +430,29 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { |
| 435 | 430 | } |
| 436 | 431 | try addFnObjects(ctx); |
| 437 | 432 | |
| 438 | if (ctx.comp.target == Target.Native) { | |
| 439 | for (ctx.comp.link_libs_list.toSliceConst()) |lib| { | |
| 440 | if (mem.eql(u8, lib.name, "c")) { | |
| 441 | // on Darwin, libSystem has libc in it, but also you have to use it | |
| 442 | // to make syscalls because the syscall numbers are not documented | |
| 443 | // and change between versions. | |
| 444 | // so we always link against libSystem | |
| 445 | try ctx.args.append("-lSystem"); | |
| 446 | } else { | |
| 447 | if (mem.indexOfScalar(u8, lib.name, '/') == null) { | |
| 448 | const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", .{lib.name}); | |
| 449 | try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); | |
| 450 | } else { | |
| 451 | const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name); | |
| 452 | try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); | |
| 453 | } | |
| 454 | } | |
| 455 | } | |
| 456 | } else { | |
| 457 | try ctx.args.append("-undefined"); | |
| 458 | try ctx.args.append("dynamic_lookup"); | |
| 459 | } | |
| 433 | // TODO | |
| 434 | //if (ctx.comp.target == Target.Native) { | |
| 435 | // for (ctx.comp.link_libs_list.toSliceConst()) |lib| { | |
| 436 | // if (mem.eql(u8, lib.name, "c")) { | |
| 437 | // // on Darwin, libSystem has libc in it, but also you have to use it | |
| 438 | // // to make syscalls because the syscall numbers are not documented | |
| 439 | // // and change between versions. | |
| 440 | // // so we always link against libSystem | |
| 441 | // try ctx.args.append("-lSystem"); | |
| 442 | // } else { | |
| 443 | // if (mem.indexOfScalar(u8, lib.name, '/') == null) { | |
| 444 | // const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", .{lib.name}); | |
| 445 | // try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); | |
| 446 | // } else { | |
| 447 | // const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name); | |
| 448 | // try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); | |
| 449 | // } | |
| 450 | // } | |
| 451 | // } | |
| 452 | //} else { | |
| 453 | // try ctx.args.append("-undefined"); | |
| 454 | // try ctx.args.append("dynamic_lookup"); | |
| 455 | //} | |
| 460 | 456 | |
| 461 | 457 | if (platform.kind == .MacOS) { |
| 462 | 458 | if (platform.versionLessThan(10, 5)) { |
src-self-hosted/main.zig+56-47| ... | ... | @@ -18,10 +18,6 @@ const Target = std.Target; |
| 18 | 18 | const errmsg = @import("errmsg.zig"); |
| 19 | 19 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; |
| 20 | 20 | |
| 21 | var stderr_file: fs.File = undefined; | |
| 22 | var stderr: *io.OutStream(fs.File.WriteError) = undefined; | |
| 23 | var stdout: *io.OutStream(fs.File.WriteError) = undefined; | |
| 24 | ||
| 25 | 21 | pub const io_mode = .evented; |
| 26 | 22 | |
| 27 | 23 | pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB |
| ... | ... | @@ -51,17 +47,14 @@ const Command = struct { |
| 51 | 47 | pub fn main() !void { |
| 52 | 48 | const allocator = std.heap.c_allocator; |
| 53 | 49 | |
| 54 | stdout = &std.io.getStdOut().outStream().stream; | |
| 55 | ||
| 56 | stderr_file = std.io.getStdErr(); | |
| 57 | stderr = &stderr_file.outStream().stream; | |
| 50 | const stderr = io.getStdErr().outStream(); | |
| 58 | 51 | |
| 59 | 52 | const args = try process.argsAlloc(allocator); |
| 60 | 53 | defer process.argsFree(allocator, args); |
| 61 | 54 | |
| 62 | 55 | if (args.len <= 1) { |
| 63 | try stderr.write("expected command argument\n\n"); | |
| 64 | try stderr.write(usage); | |
| 56 | try stderr.writeAll("expected command argument\n\n"); | |
| 57 | try stderr.writeAll(usage); | |
| 65 | 58 | process.exit(1); |
| 66 | 59 | } |
| 67 | 60 | |
| ... | ... | @@ -78,8 +71,8 @@ pub fn main() !void { |
| 78 | 71 | } else if (mem.eql(u8, cmd, "libc")) { |
| 79 | 72 | return cmdLibC(allocator, cmd_args); |
| 80 | 73 | } else if (mem.eql(u8, cmd, "targets")) { |
| 81 | const info = try std.zig.system.NativeTargetInfo.detect(allocator); | |
| 82 | defer info.deinit(allocator); | |
| 74 | const info = try std.zig.system.NativeTargetInfo.detect(allocator, .{}); | |
| 75 | const stdout = io.getStdOut().outStream(); | |
| 83 | 76 | return @import("print_targets.zig").cmdTargets(allocator, cmd_args, stdout, info.target); |
| 84 | 77 | } else if (mem.eql(u8, cmd, "version")) { |
| 85 | 78 | return cmdVersion(allocator, cmd_args); |
| ... | ... | @@ -91,7 +84,7 @@ pub fn main() !void { |
| 91 | 84 | return cmdInternal(allocator, cmd_args); |
| 92 | 85 | } else { |
| 93 | 86 | try stderr.print("unknown command: {}\n\n", .{args[1]}); |
| 94 | try stderr.write(usage); | |
| 87 | try stderr.writeAll(usage); | |
| 95 | 88 | process.exit(1); |
| 96 | 89 | } |
| 97 | 90 | } |
| ... | ... | @@ -156,6 +149,8 @@ const usage_build_generic = |
| 156 | 149 | ; |
| 157 | 150 | |
| 158 | 151 | fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Compilation.Kind) !void { |
| 152 | const stderr = io.getStdErr().outStream(); | |
| 153 | ||
| 159 | 154 | var color: errmsg.Color = .Auto; |
| 160 | 155 | var build_mode: std.builtin.Mode = .Debug; |
| 161 | 156 | var emit_bin = true; |
| ... | ... | @@ -208,11 +203,11 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 208 | 203 | const arg = args[i]; |
| 209 | 204 | if (mem.startsWith(u8, arg, "-")) { |
| 210 | 205 | if (mem.eql(u8, arg, "--help")) { |
| 211 | try stdout.write(usage_build_generic); | |
| 206 | try io.getStdOut().writeAll(usage_build_generic); | |
| 212 | 207 | process.exit(0); |
| 213 | 208 | } else if (mem.eql(u8, arg, "--color")) { |
| 214 | 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 | 211 | process.exit(1); |
| 217 | 212 | } |
| 218 | 213 | i += 1; |
| ... | ... | @@ -229,7 +224,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 229 | 224 | } |
| 230 | 225 | } else if (mem.eql(u8, arg, "--mode")) { |
| 231 | 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 | 228 | process.exit(1); |
| 234 | 229 | } |
| 235 | 230 | i += 1; |
| ... | ... | @@ -248,49 +243,49 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 248 | 243 | } |
| 249 | 244 | } else if (mem.eql(u8, arg, "--name")) { |
| 250 | 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 | 247 | process.exit(1); |
| 253 | 248 | } |
| 254 | 249 | i += 1; |
| 255 | 250 | provided_name = args[i]; |
| 256 | 251 | } else if (mem.eql(u8, arg, "--ver-major")) { |
| 257 | 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 | 254 | process.exit(1); |
| 260 | 255 | } |
| 261 | 256 | i += 1; |
| 262 | 257 | version.major = try std.fmt.parseInt(u32, args[i], 10); |
| 263 | 258 | } else if (mem.eql(u8, arg, "--ver-minor")) { |
| 264 | 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 | 261 | process.exit(1); |
| 267 | 262 | } |
| 268 | 263 | i += 1; |
| 269 | 264 | version.minor = try std.fmt.parseInt(u32, args[i], 10); |
| 270 | 265 | } else if (mem.eql(u8, arg, "--ver-patch")) { |
| 271 | 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 | 268 | process.exit(1); |
| 274 | 269 | } |
| 275 | 270 | i += 1; |
| 276 | 271 | version.patch = try std.fmt.parseInt(u32, args[i], 10); |
| 277 | 272 | } else if (mem.eql(u8, arg, "--linker-script")) { |
| 278 | 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 | 275 | process.exit(1); |
| 281 | 276 | } |
| 282 | 277 | i += 1; |
| 283 | 278 | linker_script = args[i]; |
| 284 | 279 | } else if (mem.eql(u8, arg, "--libc")) { |
| 285 | 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 | 282 | process.exit(1); |
| 288 | 283 | } |
| 289 | 284 | i += 1; |
| 290 | 285 | libc_arg = args[i]; |
| 291 | 286 | } else if (mem.eql(u8, arg, "-mllvm")) { |
| 292 | 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 | 289 | process.exit(1); |
| 295 | 290 | } |
| 296 | 291 | i += 1; |
| ... | ... | @@ -300,14 +295,14 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 300 | 295 | try mllvm_flags.append(args[i]); |
| 301 | 296 | } else if (mem.eql(u8, arg, "-mmacosx-version-min")) { |
| 302 | 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 | 299 | process.exit(1); |
| 305 | 300 | } |
| 306 | 301 | i += 1; |
| 307 | 302 | macosx_version_min = args[i]; |
| 308 | 303 | } else if (mem.eql(u8, arg, "-mios-version-min")) { |
| 309 | 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 | 306 | process.exit(1); |
| 312 | 307 | } |
| 313 | 308 | i += 1; |
| ... | ... | @@ -348,7 +343,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 348 | 343 | linker_rdynamic = true; |
| 349 | 344 | } else if (mem.eql(u8, arg, "--pkg-begin")) { |
| 350 | 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 | 347 | process.exit(1); |
| 353 | 348 | } |
| 354 | 349 | i += 1; |
| ... | ... | @@ -363,7 +358,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 363 | 358 | if (cur_pkg.parent) |parent| { |
| 364 | 359 | cur_pkg = parent; |
| 365 | 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 | 362 | process.exit(1); |
| 368 | 363 | } |
| 369 | 364 | } else if (mem.startsWith(u8, arg, "-l")) { |
| ... | ... | @@ -411,18 +406,18 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 411 | 406 | var it = mem.separate(basename, "."); |
| 412 | 407 | break :blk it.next() orelse basename; |
| 413 | 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 | 410 | process.exit(1); |
| 416 | 411 | } |
| 417 | 412 | }; |
| 418 | 413 | |
| 419 | 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 | 416 | process.exit(1); |
| 422 | 417 | } |
| 423 | 418 | |
| 424 | 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 | 421 | process.exit(1); |
| 427 | 422 | } |
| 428 | 423 | |
| ... | ... | @@ -440,7 +435,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 440 | 435 | &zig_compiler, |
| 441 | 436 | root_name, |
| 442 | 437 | root_src_file, |
| 443 | Target.Native, | |
| 438 | .{}, | |
| 444 | 439 | out_type, |
| 445 | 440 | build_mode, |
| 446 | 441 | !is_dynamic, |
| ... | ... | @@ -478,7 +473,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 478 | 473 | comp.linker_rdynamic = linker_rdynamic; |
| 479 | 474 | |
| 480 | 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 | 477 | process.exit(1); |
| 483 | 478 | } |
| 484 | 479 | |
| ... | ... | @@ -501,6 +496,8 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 501 | 496 | } |
| 502 | 497 | |
| 503 | 498 | fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void { |
| 499 | const stderr_file = io.getStdErr(); | |
| 500 | const stderr = stderr_file.outStream(); | |
| 504 | 501 | var count: usize = 0; |
| 505 | 502 | while (!comp.cancelled) { |
| 506 | 503 | const build_event = comp.events.get(); |
| ... | ... | @@ -551,7 +548,8 @@ const Fmt = struct { |
| 551 | 548 | }; |
| 552 | 549 | |
| 553 | 550 | fn 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 | 553 | stderr.print("Unable to parse libc path file '{}': {}.\n" ++ |
| 556 | 554 | "Try running `zig libc` to see an example for the native target.\n", .{ |
| 557 | 555 | libc_paths_file, |
| ... | ... | @@ -562,6 +560,7 @@ fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_fil |
| 562 | 560 | } |
| 563 | 561 | |
| 564 | 562 | fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void { |
| 563 | const stderr = io.getStdErr().outStream(); | |
| 565 | 564 | switch (args.len) { |
| 566 | 565 | 0 => {}, |
| 567 | 566 | 1 => { |
| ... | ... | @@ -582,10 +581,12 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void { |
| 582 | 581 | stderr.print("unable to find libc: {}\n", .{@errorName(err)}) catch {}; |
| 583 | 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 | } |
| 587 | 586 | |
| 588 | 587 | fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { |
| 588 | const stderr_file = io.getStdErr(); | |
| 589 | const stderr = stderr_file.outStream(); | |
| 589 | 590 | var color: errmsg.Color = .Auto; |
| 590 | 591 | var stdin_flag: bool = false; |
| 591 | 592 | var check_flag: bool = false; |
| ... | ... | @@ -597,11 +598,12 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { |
| 597 | 598 | const arg = args[i]; |
| 598 | 599 | if (mem.startsWith(u8, arg, "-")) { |
| 599 | 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 | 603 | process.exit(0); |
| 602 | 604 | } else if (mem.eql(u8, arg, "--color")) { |
| 603 | 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 | 607 | process.exit(1); |
| 606 | 608 | } |
| 607 | 609 | i += 1; |
| ... | ... | @@ -632,14 +634,13 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { |
| 632 | 634 | |
| 633 | 635 | if (stdin_flag) { |
| 634 | 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 | 638 | process.exit(1); |
| 637 | 639 | } |
| 638 | 640 | |
| 639 | var stdin_file = io.getStdIn(); | |
| 640 | var stdin = stdin_file.inStream(); | |
| 641 | const stdin = io.getStdIn().inStream(); | |
| 641 | 642 | |
| 642 | const source_code = try stdin.stream.readAllAlloc(allocator, max_src_size); | |
| 643 | const source_code = try stdin.readAllAlloc(allocator, max_src_size); | |
| 643 | 644 | defer allocator.free(source_code); |
| 644 | 645 | |
| 645 | 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 | 654 | const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, tree, "<stdin>"); |
| 654 | 655 | defer msg.destroy(); |
| 655 | 656 | |
| 656 | try msg.printToFile(stderr_file, color); | |
| 657 | try msg.printToFile(io.getStdErr(), color); | |
| 657 | 658 | } |
| 658 | 659 | if (tree.errors.len != 0) { |
| 659 | 660 | process.exit(1); |
| ... | ... | @@ -664,12 +665,13 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { |
| 664 | 665 | process.exit(code); |
| 665 | 666 | } |
| 666 | 667 | |
| 668 | const stdout = io.getStdOut().outStream(); | |
| 667 | 669 | _ = try std.zig.render(allocator, stdout, tree); |
| 668 | 670 | return; |
| 669 | 671 | } |
| 670 | 672 | |
| 671 | 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 | 675 | process.exit(1); |
| 674 | 676 | } |
| 675 | 677 | |
| ... | ... | @@ -713,6 +715,9 @@ const FmtError = error{ |
| 713 | 715 | } || fs.File.OpenError; |
| 714 | 716 | |
| 715 | 717 | async 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 | 721 | const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref); |
| 717 | 722 | defer fmt.allocator.free(file_path); |
| 718 | 723 | |
| ... | ... | @@ -729,7 +734,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro |
| 729 | 734 | max_src_size, |
| 730 | 735 | ) catch |err| switch (err) { |
| 731 | 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 | 738 | defer dir.close(); |
| 734 | 739 | |
| 735 | 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 | 796 | } |
| 792 | 797 | |
| 793 | 798 | fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void { |
| 799 | const stdout = io.getStdOut().outStream(); | |
| 794 | 800 | try stdout.print("{}\n", .{c.ZIG_VERSION_STRING}); |
| 795 | 801 | } |
| 796 | 802 | |
| 797 | 803 | fn 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 | } |
| 800 | 807 | |
| 801 | 808 | pub const info_zen = |
| ... | ... | @@ -816,7 +823,7 @@ pub const info_zen = |
| 816 | 823 | ; |
| 817 | 824 | |
| 818 | 825 | fn cmdZen(allocator: *Allocator, args: []const []const u8) !void { |
| 819 | try stdout.write(info_zen); | |
| 826 | try io.getStdOut().writeAll(info_zen); | |
| 820 | 827 | } |
| 821 | 828 | |
| 822 | 829 | const usage_internal = |
| ... | ... | @@ -829,8 +836,9 @@ const usage_internal = |
| 829 | 836 | ; |
| 830 | 837 | |
| 831 | 838 | fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void { |
| 839 | const stderr = io.getStdErr().outStream(); | |
| 832 | 840 | if (args.len == 0) { |
| 833 | try stderr.write(usage_internal); | |
| 841 | try stderr.writeAll(usage_internal); | |
| 834 | 842 | process.exit(1); |
| 835 | 843 | } |
| 836 | 844 | |
| ... | ... | @@ -849,10 +857,11 @@ fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void { |
| 849 | 857 | } |
| 850 | 858 | |
| 851 | 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 | } |
| 854 | 862 | |
| 855 | 863 | fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void { |
| 864 | const stdout = io.getStdOut().outStream(); | |
| 856 | 865 | try stdout.print( |
| 857 | 866 | \\ZIG_CMAKE_BINARY_DIR {} |
| 858 | 867 | \\ZIG_CXX_COMPILER {} |
src-self-hosted/print_targets.zig+1-1| ... | ... | @@ -72,7 +72,7 @@ pub fn cmdTargets( |
| 72 | 72 | }; |
| 73 | 73 | defer allocator.free(zig_lib_dir); |
| 74 | 74 | |
| 75 | var dir = try std.fs.cwd().openDirList(zig_lib_dir); | |
| 75 | var dir = try std.fs.cwd().openDir(zig_lib_dir, .{}); | |
| 76 | 76 | defer dir.close(); |
| 77 | 77 | |
| 78 | 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 | 128 | args_end: [*]?[*]const u8, |
| 129 | 129 | resources_path: [*:0]const u8, |
| 130 | 130 | ) Error { |
| 131 | var errors = @as([*]translate_c.ClangErrMsg, undefined)[0..0]; | |
| 131 | var errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{}; | |
| 132 | 132 | out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) { |
| 133 | 133 | error.SemanticAnalyzeFail => { |
| 134 | 134 | out_errors_ptr.* = errors.ptr; |
| ... | ... | @@ -319,7 +319,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { |
| 319 | 319 | const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) { |
| 320 | 320 | error.IsDir, error.AccessDenied => { |
| 321 | 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 | 323 | defer dir.close(); |
| 324 | 324 | |
| 325 | 325 | var dir_it = dir.iterate(); |
src-self-hosted/test.zig+2-2| ... | ... | @@ -57,11 +57,11 @@ pub const TestContext = struct { |
| 57 | 57 | errdefer allocator.free(self.zig_lib_dir); |
| 58 | 58 | |
| 59 | 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 | } |
| 62 | 62 | |
| 63 | 63 | fn deinit(self: *TestContext) void { |
| 64 | std.fs.deleteTree(tmp_dir_name) catch {}; | |
| 64 | std.fs.cwd().deleteTree(tmp_dir_name) catch {}; | |
| 65 | 65 | allocator.free(self.zig_lib_dir); |
| 66 | 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 | 1744 | // Returns either a string literal or a slice of `buf`. |
| 1745 | 1745 | fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 { |
| 1746 | 1746 | return switch (c) { |
| 1747 | '\"' => "\\\""[0..], | |
| 1748 | '\'' => "\\'"[0..], | |
| 1749 | '\\' => "\\\\"[0..], | |
| 1750 | '\n' => "\\n"[0..], | |
| 1751 | '\r' => "\\r"[0..], | |
| 1752 | '\t' => "\\t"[0..], | |
| 1753 | else => { | |
| 1754 | // Handle the remaining escapes Zig doesn't support by turning them | |
| 1755 | // into their respective hex representation | |
| 1756 | if (std.ascii.isCntrl(c)) | |
| 1757 | return std.fmt.bufPrint(char_buf[0..], "\\x{x:0<2}", .{c}) catch unreachable | |
| 1758 | else | |
| 1759 | return std.fmt.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable; | |
| 1760 | }, | |
| 1747 | '\"' => "\\\"", | |
| 1748 | '\'' => "\\'", | |
| 1749 | '\\' => "\\\\", | |
| 1750 | '\n' => "\\n", | |
| 1751 | '\r' => "\\r", | |
| 1752 | '\t' => "\\t", | |
| 1753 | // Handle the remaining escapes Zig doesn't support by turning them | |
| 1754 | // into their respective hex representation | |
| 1755 | else => if (std.ascii.isCntrl(c)) | |
| 1756 | std.fmt.bufPrint(char_buf, "\\x{x:0<2}", .{c}) catch unreachable | |
| 1757 | else | |
| 1758 | std.fmt.bufPrint(char_buf, "{c}", .{c}) catch unreachable, | |
| 1761 | 1759 | }; |
| 1762 | 1760 | } |
| 1763 | 1761 |
src-self-hosted/util.zig+13-2| ... | ... | @@ -3,8 +3,7 @@ const Target = std.Target; |
| 3 | 3 | const llvm = @import("llvm.zig"); |
| 4 | 4 | |
| 5 | 5 | pub fn getDarwinArchString(self: Target) [:0]const u8 { |
| 6 | const arch = self.getArch(); | |
| 7 | switch (arch) { | |
| 6 | switch (self.cpu.arch) { | |
| 8 | 7 | .aarch64 => return "arm64", |
| 9 | 8 | .thumb, |
| 10 | 9 | .arm, |
| ... | ... | @@ -34,3 +33,15 @@ pub fn initializeAllTargets() void { |
| 34 | 33 | llvm.InitializeAllAsmPrinters(); |
| 35 | 34 | llvm.InitializeAllAsmParsers(); |
| 36 | 35 | } |
| 36 | ||
| 37 | pub 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 | 231 | // The pointer is a reference to a single object. |
| 232 | 232 | ConstPtrSpecialRef, |
| 233 | 233 | // The pointer points to an element in an underlying array. |
| 234 | // Not to be confused with ConstPtrSpecialSubArray. | |
| 234 | 235 | ConstPtrSpecialBaseArray, |
| 235 | 236 | // The pointer points to a field in an underlying struct. |
| 236 | 237 | ConstPtrSpecialBaseStruct, |
| ... | ... | @@ -257,6 +258,10 @@ enum ConstPtrSpecial { |
| 257 | 258 | // types to be the same, so all optionals of pointer types use x_ptr |
| 258 | 259 | // instead of x_optional. |
| 259 | 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 | }; |
| 261 | 266 | |
| 262 | 267 | enum ConstPtrMut { |
| ... | ... | @@ -3705,6 +3710,7 @@ struct IrInstGenSlice { |
| 3705 | 3710 | IrInstGen *start; |
| 3706 | 3711 | IrInstGen *end; |
| 3707 | 3712 | IrInstGen *result_loc; |
| 3713 | ZigValue *sentinel; | |
| 3708 | 3714 | bool safety_check_on; |
| 3709 | 3715 | }; |
| 3710 | 3716 |
src/analyze.cpp+36-20| ... | ... | @@ -780,6 +780,8 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa |
| 780 | 780 | } |
| 781 | 781 | |
| 782 | 782 | ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ZigValue *sentinel) { |
| 783 | Error err; | |
| 784 | ||
| 783 | 785 | TypeId type_id = {}; |
| 784 | 786 | type_id.id = ZigTypeIdArray; |
| 785 | 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 | 793 | return existing_entry->value; |
| 792 | 794 | } |
| 793 | 795 | |
| 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 | } | |
| 795 | 801 | |
| 796 | 802 | ZigType *entry = new_type_table_entry(ZigTypeIdArray); |
| 797 | 803 | |
| ... | ... | @@ -803,15 +809,8 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi |
| 803 | 809 | } |
| 804 | 810 | buf_appendf(&entry->name, "]%s", buf_ptr(&child_type->name)); |
| 805 | 811 | |
| 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 | 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 | 814 | entry->abi_size = child_type->abi_size * full_array_size; |
| 816 | 815 | |
| 817 | 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 | 1196 | LazyValueArrayType *lazy_array_type = |
| 1198 | 1197 | reinterpret_cast<LazyValueArrayType *>(type_val->data.x_lazy); |
| 1199 | 1198 | |
| 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 | 1201 | *is_zero_bits = true; |
| 1202 | 1202 | return ErrorNone; |
| 1203 | 1203 | } |
| ... | ... | @@ -1452,7 +1452,7 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, ZigV |
| 1452 | 1452 | case LazyValueIdArrayType: { |
| 1453 | 1453 | LazyValueArrayType *lazy_array_type = |
| 1454 | 1454 | reinterpret_cast<LazyValueArrayType *>(type_val->data.x_lazy); |
| 1455 | if (lazy_array_type->length < 1) | |
| 1455 | if (lazy_array_type->length == 0) | |
| 1456 | 1456 | return OnePossibleValueYes; |
| 1457 | 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 | 4488 | } |
| 4489 | 4489 | |
| 4490 | 4490 | uint32_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 | 4499 | if (ptr_type->id == ZigTypeIdPointer) { |
| 4493 | 4500 | return (ptr_type->data.pointer.explicit_alignment == 0) ? |
| 4494 | 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 | 4512 | } |
| 4506 | 4513 | } |
| 4507 | 4514 | |
| 4508 | bool get_ptr_const(ZigType *type) { | |
| 4509 | ZigType *ptr_type = get_src_ptr_type(type); | |
| 4515 | bool get_ptr_const(CodeGen *g, ZigType *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 | 4524 | if (ptr_type->id == ZigTypeIdPointer) { |
| 4511 | 4525 | return ptr_type->data.pointer.is_const; |
| 4512 | 4526 | } else if (ptr_type->id == ZigTypeIdFn) { |
| ... | ... | @@ -5282,6 +5296,11 @@ static uint32_t hash_const_val_ptr(ZigValue *const_val) { |
| 5282 | 5296 | hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val); |
| 5283 | 5297 | hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index); |
| 5284 | 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 | 5304 | case ConstPtrSpecialBaseStruct: |
| 5286 | 5305 | hash_val += (uint32_t)3518317043; |
| 5287 | 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 | 5830 | // The elements array cannot be left unpopulated |
| 5812 | 5831 | ZigType *array_type = result->type; |
| 5813 | 5832 | ZigType *elem_type = array_type->data.array.child_type; |
| 5814 | ZigValue *sentinel_value = array_type->data.array.sentinel; | |
| 5815 | const size_t elem_count = array_type->data.array.len + (sentinel_value != nullptr); | |
| 5833 | const size_t elem_count = array_type->data.array.len; | |
| 5816 | 5834 | |
| 5817 | 5835 | result->data.x_array.data.s_none.elements = g->pass1_arena->allocate<ZigValue>(elem_count); |
| 5818 | 5836 | for (size_t i = 0; i < elem_count; i += 1) { |
| 5819 | 5837 | ZigValue *elem_val = &result->data.x_array.data.s_none.elements[i]; |
| 5820 | 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 | 5840 | } else if (result->type->id == ZigTypeIdPointer) { |
| 5827 | 5841 | result->data.x_ptr.special = ConstPtrSpecialRef; |
| 5828 | 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 | 6767 | return false; |
| 6754 | 6768 | return true; |
| 6755 | 6769 | case ConstPtrSpecialBaseArray: |
| 6770 | case ConstPtrSpecialSubArray: | |
| 6756 | 6771 | if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val) { |
| 6757 | 6772 | return false; |
| 6758 | 6773 | } |
| ... | ... | @@ -7010,6 +7025,7 @@ static void render_const_val_ptr(CodeGen *g, Buf *buf, ZigValue *const_val, ZigT |
| 7010 | 7025 | render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); |
| 7011 | 7026 | return; |
| 7012 | 7027 | case ConstPtrSpecialBaseArray: |
| 7028 | case ConstPtrSpecialSubArray: | |
| 7013 | 7029 | buf_appendf(buf, "*"); |
| 7014 | 7030 | // TODO we need a source node for const_ptr_pointee because it can generate compile errors |
| 7015 | 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 | 76 | |
| 77 | 77 | ZigType *get_src_ptr_type(ZigType *type); |
| 78 | 78 | uint32_t get_ptr_align(CodeGen *g, ZigType *type); |
| 79 | bool get_ptr_const(ZigType *type); | |
| 79 | bool get_ptr_const(CodeGen *g, ZigType *type); | |
| 80 | 80 | ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry); |
| 81 | 81 | ZigType *container_ref_type(ZigType *type_entry); |
| 82 | 82 | bool 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 | 5413 | ZigType *array_type = array_ptr_type->data.pointer.child_type; |
| 5414 | 5414 | LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); |
| 5415 | 5415 | |
| 5416 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); | |
| 5417 | ||
| 5418 | 5416 | bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); |
| 5419 | 5417 | |
| 5420 | ZigType *res_slice_ptr_type = instruction->base.value->type->data.structure.fields[slice_ptr_index]->type_entry; | |
| 5421 | ZigValue *sentinel = res_slice_ptr_type->data.pointer.sentinel; | |
| 5418 | ZigType *result_type = instruction->base.value->type; | |
| 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; | |
| 5422 | 5426 | |
| 5423 | 5427 | if (array_type->id == ZigTypeIdArray || |
| 5424 | 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 | 5457 | } |
| 5454 | 5458 | } |
| 5455 | 5459 | if (!type_has_bits(g, array_type)) { |
| 5460 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); | |
| 5461 | ||
| 5456 | 5462 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); |
| 5457 | 5463 | |
| 5458 | 5464 | // 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 | 5467 | return tmp_struct_ptr; |
| 5462 | 5468 | } |
| 5463 | 5469 | |
| 5464 | ||
| 5465 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, ""); | |
| 5466 | 5470 | LLVMValueRef indices[] = { |
| 5467 | 5471 | LLVMConstNull(g->builtin_types.entry_usize->llvm_type), |
| 5468 | 5472 | start_val, |
| 5469 | 5473 | }; |
| 5470 | 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); | |
| 5472 | 5483 | |
| 5473 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); | |
| 5474 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); | |
| 5475 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | |
| 5484 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); | |
| 5485 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); | |
| 5486 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | |
| 5476 | 5487 | |
| 5477 | return tmp_struct_ptr; | |
| 5488 | return tmp_struct_ptr; | |
| 5489 | } | |
| 5478 | 5490 | } else if (array_type->id == ZigTypeIdPointer) { |
| 5479 | 5491 | assert(array_type->data.pointer.ptr_len != PtrLenSingle); |
| 5480 | 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 | 5500 | } |
| 5489 | 5501 | } |
| 5490 | 5502 | |
| 5491 | 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; | |
| 5493 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, ""); | |
| 5494 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, ""); | |
| 5495 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); | |
| 5503 | if (!type_has_bits(g, array_type)) { | |
| 5504 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); | |
| 5505 | size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index; | |
| 5506 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, ""); | |
| 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 | } |
| 5497 | 5511 | |
| 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 | 5526 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, ""); |
| 5500 | 5527 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); |
| 5501 | 5528 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); |
| 5502 | 5529 | |
| 5503 | 5530 | return tmp_struct_ptr; |
| 5531 | ||
| 5504 | 5532 | } else if (array_type->id == ZigTypeIdStruct) { |
| 5505 | 5533 | assert(array_type->data.structure.special == StructSpecialSlice); |
| 5506 | 5534 | assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); |
| 5507 | 5535 | assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); |
| 5508 | assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(tmp_struct_ptr))) == LLVMStructTypeKind); | |
| 5509 | 5536 | |
| 5510 | 5537 | size_t ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index; |
| 5511 | 5538 | assert(ptr_index != SIZE_MAX); |
| ... | ... | @@ -5542,15 +5569,22 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI |
| 5542 | 5569 | } |
| 5543 | 5570 | } |
| 5544 | 5571 | |
| 5545 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)ptr_index, ""); | |
| 5546 | 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); | |
| 5548 | 5581 | |
| 5549 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)len_index, ""); | |
| 5550 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); | |
| 5551 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | |
| 5582 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)len_index, ""); | |
| 5583 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); | |
| 5584 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | |
| 5552 | 5585 | |
| 5553 | return tmp_struct_ptr; | |
| 5586 | return tmp_struct_ptr; | |
| 5587 | } | |
| 5554 | 5588 | } else { |
| 5555 | 5589 | zig_unreachable(); |
| 5556 | 5590 | } |
| ... | ... | @@ -6635,7 +6669,6 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ZigValue *array_co |
| 6635 | 6669 | }; |
| 6636 | 6670 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); |
| 6637 | 6671 | } else { |
| 6638 | assert(parent->id == ConstParentIdScalar); | |
| 6639 | 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 | 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 | 6837 | return val; |
| 6789 | 6838 | } |
| 6790 | 6839 | case ZigTypeIdVector: |
| ... | ... | @@ -6847,24 +6896,16 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ZigValue *const_val, const cha |
| 6847 | 6896 | return const_val->llvm_value; |
| 6848 | 6897 | } |
| 6849 | 6898 | case ConstPtrSpecialBaseArray: |
| 6899 | case ConstPtrSpecialSubArray: | |
| 6850 | 6900 | { |
| 6851 | 6901 | ZigValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val; |
| 6852 | 6902 | assert(array_const_val->type->id == ZigTypeIdArray); |
| 6853 | 6903 | if (!type_has_bits(g, array_const_val->type)) { |
| 6854 | if (array_const_val->type->data.array.sentinel != nullptr) { | |
| 6855 | ZigValue *pointee = array_const_val->type->data.array.sentinel; | |
| 6856 | render_const_val(g, pointee, ""); | |
| 6857 | render_const_val_global(g, pointee, ""); | |
| 6858 | const_val->llvm_value = LLVMConstBitCast(pointee->llvm_global, | |
| 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 | } | |
| 6904 | // make this a null pointer | |
| 6905 | ZigType *usize = g->builtin_types.entry_usize; | |
| 6906 | const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), | |
| 6907 | get_llvm_type(g, const_val->type)); | |
| 6908 | return const_val->llvm_value; | |
| 6868 | 6909 | } |
| 6869 | 6910 | size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; |
| 6870 | 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 | 9685 | return ErrorNone; |
| 9645 | 9686 | } |
| 9646 | 9687 | |
| 9688 | static bool need_llvm_module(CodeGen *g) { | |
| 9689 | return buf_len(&g->main_pkg->root_src_path) != 0; | |
| 9690 | } | |
| 9691 | ||
| 9692 | // before gen_c_objects | |
| 9693 | static 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 | |
| 9699 | static 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 | 9703 | // returns true if it was a cache miss |
| 9648 | 9704 | static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { |
| 9649 | 9705 | Error err; |
| ... | ... | @@ -9661,7 +9717,12 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { |
| 9661 | 9717 | buf_len(c_source_basename), 0); |
| 9662 | 9718 | |
| 9663 | 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 | 9726 | buf_append_str(final_o_basename, target_o_file_ext(g->zig_target)); |
| 9666 | 9727 | |
| 9667 | 9728 | CacheHash *cache_hash; |
| ... | ... | @@ -10461,10 +10522,6 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { |
| 10461 | 10522 | return ErrorNone; |
| 10462 | 10523 | } |
| 10463 | 10524 | |
| 10464 | static bool need_llvm_module(CodeGen *g) { | |
| 10465 | return buf_len(&g->main_pkg->root_src_path) != 0; | |
| 10466 | } | |
| 10467 | ||
| 10468 | 10525 | static void resolve_out_paths(CodeGen *g) { |
| 10469 | 10526 | assert(g->output_dir != nullptr); |
| 10470 | 10527 | assert(g->root_out_name != nullptr); |
| ... | ... | @@ -10476,10 +10533,6 @@ static void resolve_out_paths(CodeGen *g) { |
| 10476 | 10533 | case OutTypeUnknown: |
| 10477 | 10534 | zig_unreachable(); |
| 10478 | 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 | 10536 | if (need_llvm_module(g) && g->link_objects.length != 0 && !g->enable_cache && |
| 10484 | 10537 | buf_eql_buf(o_basename, out_basename)) |
| 10485 | 10538 | { |
| ... | ... | @@ -10574,6 +10627,16 @@ static void output_type_information(CodeGen *g) { |
| 10574 | 10627 | } |
| 10575 | 10628 | } |
| 10576 | 10629 | |
| 10630 | static 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 | ||
| 10577 | 10640 | void codegen_build_and_link(CodeGen *g) { |
| 10578 | 10641 | Error err; |
| 10579 | 10642 | assert(g->out_type != OutTypeUnknown); |
| ... | ... | @@ -10616,8 +10679,7 @@ void codegen_build_and_link(CodeGen *g) { |
| 10616 | 10679 | } |
| 10617 | 10680 | |
| 10618 | 10681 | if (g->enable_cache && buf_len(&digest) != 0) { |
| 10619 | g->output_dir = buf_sprintf("%s" OS_SEP CACHE_OUT_SUBDIR OS_SEP "%s", | |
| 10620 | buf_ptr(g->cache_dir), buf_ptr(&digest)); | |
| 10682 | init_output_dir(g, &digest); | |
| 10621 | 10683 | resolve_out_paths(g); |
| 10622 | 10684 | } else { |
| 10623 | 10685 | if (need_llvm_module(g)) { |
| ... | ... | @@ -10638,8 +10700,7 @@ void codegen_build_and_link(CodeGen *g) { |
| 10638 | 10700 | exit(1); |
| 10639 | 10701 | } |
| 10640 | 10702 | } |
| 10641 | g->output_dir = buf_sprintf("%s" OS_SEP CACHE_OUT_SUBDIR OS_SEP "%s", | |
| 10642 | buf_ptr(g->cache_dir), buf_ptr(&digest)); | |
| 10703 | init_output_dir(g, &digest); | |
| 10643 | 10704 | |
| 10644 | 10705 | if ((err = os_make_path(g->output_dir))) { |
| 10645 | 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 | 784 | break; |
| 785 | 785 | case ConstPtrSpecialBaseArray: { |
| 786 | 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 | 789 | result = array_val->type->data.array.sentinel; |
| 789 | 790 | } else { |
| 790 | 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 | 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 | 813 | case ConstPtrSpecialBaseStruct: { |
| 796 | 814 | ZigValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val; |
| 797 | 815 | expand_undef_struct(g, struct_val); |
| ... | ... | @@ -849,11 +867,6 @@ static bool is_slice(ZigType *type) { |
| 849 | 867 | return type->id == ZigTypeIdStruct && type->data.structure.special == StructSpecialSlice; |
| 850 | 868 | } |
| 851 | 869 | |
| 852 | static 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 | 870 | // This function returns true when you can change the type of a ZigValue and the |
| 858 | 871 | // value remains meaningful. |
| 859 | 872 | static 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 | 3732 | } |
| 3720 | 3733 | |
| 3721 | 3734 | static 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 | 3738 | IrInstGenSlice *instruction = ir_build_inst_gen<IrInstGenSlice>( |
| 3725 | 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 | 3743 | instruction->end = end; |
| 3730 | 3744 | instruction->safety_check_on = safety_check_on; |
| 3731 | 3745 | instruction->result_loc = result_loc; |
| 3746 | instruction->sentinel = sentinel; | |
| 3732 | 3747 | |
| 3733 | 3748 | ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block); |
| 3734 | 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); | |
| 3736 | ir_ref_inst_gen(result_loc, ira->new_irb.current_basic_block); | |
| 3750 | if (end != nullptr) ir_ref_inst_gen(end, ira->new_irb.current_basic_block); | |
| 3751 | if (result_loc != nullptr) ir_ref_inst_gen(result_loc, ira->new_irb.current_basic_block); | |
| 3737 | 3752 | |
| 3738 | 3753 | return &instruction->base; |
| 3739 | 3754 | } |
| ... | ... | @@ -12644,41 +12659,80 @@ static IrInstGen *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInst* sourc |
| 12644 | 12659 | Error err; |
| 12645 | 12660 | |
| 12646 | 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 | //} | |
| 12647 | 12682 | |
| 12648 | 12683 | if ((err = type_resolve(ira->codegen, array_ptr->value->type, ResolveStatusAlignmentKnown))) { |
| 12649 | 12684 | return ira->codegen->invalid_inst_gen; |
| 12650 | 12685 | } |
| 12651 | 12686 | |
| 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 | 12687 | if (array_len != 0) { |
| 12659 | 12688 | wanted_type = adjust_slice_align(ira->codegen, wanted_type, |
| 12660 | 12689 | get_ptr_align(ira->codegen, array_ptr->value->type)); |
| 12661 | 12690 | } |
| 12662 | 12691 | |
| 12663 | 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 | 12695 | if (array_ptr_val == nullptr) |
| 12666 | 12696 | return ira->codegen->invalid_inst_gen; |
| 12667 | ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, array_ptr_val, source_instr->source_node); | |
| 12668 | if (pointee == nullptr) | |
| 12669 | return ira->codegen->invalid_inst_gen; | |
| 12670 | if (pointee->special != ConstValSpecialRuntime) { | |
| 12671 | assert(array_ptr_val->type->id == ZigTypeIdPointer); | |
| 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; | |
| 12697 | ir_assert(is_slice(wanted_type), source_instr); | |
| 12698 | if (array_ptr_val->special == ConstValSpecialUndef) { | |
| 12699 | ZigValue *undef_array = ira->codegen->pass1_arena->create<ZigValue>(); | |
| 12700 | undef_array->special = ConstValSpecialUndef; | |
| 12701 | undef_array->type = array_type; | |
| 12675 | 12702 | |
| 12676 | 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); | |
| 12678 | result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut; | |
| 12704 | init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false); | |
| 12705 | result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst; | |
| 12679 | 12706 | result->value->type = wanted_type; |
| 12680 | 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 | } |
| 12683 | 12737 | |
| 12684 | 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 | 14602 | return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); |
| 14549 | 14603 | } |
| 14550 | 14604 | |
| 14551 | // *[N]T to ?[]const T | |
| 14605 | // *[N]T to ?[]T | |
| 14552 | 14606 | if (wanted_type->id == ZigTypeIdOptional && |
| 14553 | 14607 | is_slice(wanted_type->data.maybe.child_type) && |
| 14554 | 14608 | actual_type->id == ZigTypeIdPointer && |
| ... | ... | @@ -19884,6 +19938,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source |
| 19884 | 19938 | buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf), pointee); |
| 19885 | 19939 | if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) |
| 19886 | 19940 | return err; |
| 19941 | buf_deinit(&buf); | |
| 19887 | 19942 | return ErrorNone; |
| 19888 | 19943 | } |
| 19889 | 19944 | |
| ... | ... | @@ -19903,6 +19958,31 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source |
| 19903 | 19958 | dst_size, buf_ptr(&pointee->type->name), src_size)); |
| 19904 | 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 | 19986 | case ConstPtrSpecialBaseArray: { |
| 19907 | 19987 | ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val; |
| 19908 | 19988 | assert(array_val->type->id == ZigTypeIdArray); |
| ... | ... | @@ -19926,6 +20006,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source |
| 19926 | 20006 | } |
| 19927 | 20007 | if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) |
| 19928 | 20008 | return err; |
| 20009 | buf_deinit(&buf); | |
| 19929 | 20010 | return ErrorNone; |
| 19930 | 20011 | } |
| 19931 | 20012 | case ConstPtrSpecialBaseStruct: |
| ... | ... | @@ -20505,6 +20586,44 @@ static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_ |
| 20505 | 20586 | allow_zero); |
| 20506 | 20587 | } |
| 20507 | 20588 | |
| 20589 | static 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 | ||
| 20508 | 20627 | static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemPtr *elem_ptr_instruction) { |
| 20509 | 20628 | Error err; |
| 20510 | 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 | 20664 | } |
| 20546 | 20665 | |
| 20547 | 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 | 20667 | ZigType *child_type = array_type->data.array.child_type; |
| 20554 | 20668 | if (ptr_type->data.pointer.host_int_bytes == 0) { |
| 20555 | 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 | 20762 | get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index, |
| 20649 | 20763 | nullptr, nullptr); |
| 20650 | 20764 | } else if (return_type->data.pointer.explicit_alignment != 0) { |
| 20651 | // figure out the largest alignment possible | |
| 20652 | ||
| 20653 | if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown))) | |
| 20765 | uint32_t chosen_align; | |
| 20766 | if ((err = compute_elem_align(ira, return_type->data.pointer.child_type, | |
| 20767 | return_type->data.pointer.explicit_alignment, index, &chosen_align))) | |
| 20768 | { | |
| 20654 | 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 | 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 | 20887 | } |
| 20792 | 20888 | break; |
| 20793 | 20889 | case ConstPtrSpecialBaseArray: |
| 20890 | case ConstPtrSpecialSubArray: | |
| 20794 | 20891 | { |
| 20795 | 20892 | size_t offset = array_ptr_val->data.x_ptr.data.base_array.elem_index; |
| 20796 | 20893 | new_index = offset + index; |
| ... | ... | @@ -20861,6 +20958,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP |
| 20861 | 20958 | out_val->data.x_ptr.special = ConstPtrSpecialRef; |
| 20862 | 20959 | out_val->data.x_ptr.data.ref.pointee = ptr_field->data.x_ptr.data.ref.pointee; |
| 20863 | 20960 | break; |
| 20961 | case ConstPtrSpecialSubArray: | |
| 20864 | 20962 | case ConstPtrSpecialBaseArray: |
| 20865 | 20963 | { |
| 20866 | 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 | 25510 | static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { |
| 25413 | 25511 | Error err; |
| 25414 | 25512 | |
| 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 | 25520 | assert(ptr_type != nullptr); |
| 25417 | 25521 | if (ptr_type->id == ZigTypeIdPointer) { |
| 25418 | 25522 | if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) |
| 25419 | 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 | } |
| 25421 | 25530 | |
| 25422 | 25531 | *result_align = get_ptr_align(ira->codegen, ty); |
| ... | ... | @@ -25871,6 +25980,7 @@ static IrInstGen *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstSrcMemset |
| 25871 | 25980 | start = 0; |
| 25872 | 25981 | bound_end = 1; |
| 25873 | 25982 | break; |
| 25983 | case ConstPtrSpecialSubArray: | |
| 25874 | 25984 | case ConstPtrSpecialBaseArray: |
| 25875 | 25985 | { |
| 25876 | 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 | 26114 | dest_start = 0; |
| 26005 | 26115 | dest_end = 1; |
| 26006 | 26116 | break; |
| 26117 | case ConstPtrSpecialSubArray: | |
| 26007 | 26118 | case ConstPtrSpecialBaseArray: |
| 26008 | 26119 | { |
| 26009 | 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 | 26158 | src_start = 0; |
| 26048 | 26159 | src_end = 1; |
| 26049 | 26160 | break; |
| 26161 | case ConstPtrSpecialSubArray: | |
| 26050 | 26162 | case ConstPtrSpecialBaseArray: |
| 26051 | 26163 | { |
| 26052 | 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 | 26202 | return ir_build_memcpy_gen(ira, &instruction->base.base, casted_dest_ptr, casted_src_ptr, casted_count); |
| 26091 | 26203 | } |
| 26092 | 26204 | |
| 26205 | static 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 | ||
| 26093 | 26215 | static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *instruction) { |
| 26216 | Error err; | |
| 26217 | ||
| 26094 | 26218 | IrInstGen *ptr_ptr = instruction->ptr->child; |
| 26095 | 26219 | if (type_is_invalid(ptr_ptr->value->type)) |
| 26096 | 26220 | return ira->codegen->invalid_inst_gen; |
| ... | ... | @@ -26120,6 +26244,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26120 | 26244 | end = nullptr; |
| 26121 | 26245 | } |
| 26122 | 26246 | |
| 26247 | ZigValue *slice_sentinel_val = nullptr; | |
| 26123 | 26248 | ZigType *non_sentinel_slice_ptr_type; |
| 26124 | 26249 | ZigType *elem_type; |
| 26125 | 26250 | |
| ... | ... | @@ -26170,6 +26295,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26170 | 26295 | } |
| 26171 | 26296 | } else if (is_slice(array_type)) { |
| 26172 | 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 | 26299 | non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr); |
| 26174 | 26300 | elem_type = non_sentinel_slice_ptr_type->data.pointer.child_type; |
| 26175 | 26301 | } else { |
| ... | ... | @@ -26178,7 +26304,6 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26178 | 26304 | return ira->codegen->invalid_inst_gen; |
| 26179 | 26305 | } |
| 26180 | 26306 | |
| 26181 | ZigType *return_type; | |
| 26182 | 26307 | ZigValue *sentinel_val = nullptr; |
| 26183 | 26308 | if (instruction->sentinel) { |
| 26184 | 26309 | IrInstGen *uncasted_sentinel = instruction->sentinel->child; |
| ... | ... | @@ -26190,11 +26315,76 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26190 | 26315 | sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); |
| 26191 | 26316 | if (sentinel_val == nullptr) |
| 26192 | 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 | 26382 | return_type = get_slice_type(ira->codegen, slice_ptr_type); |
| 26195 | 26383 | } else { |
| 26384 | // TODO deal with non-abi-alignment here | |
| 26196 | 26385 | return_type = get_slice_type(ira->codegen, non_sentinel_slice_ptr_type); |
| 26197 | 26386 | } |
| 26387 | done_with_return_type: | |
| 26198 | 26388 | |
| 26199 | 26389 | if (instr_is_comptime(ptr_ptr) && |
| 26200 | 26390 | value_is_comptime(casted_start->value) && |
| ... | ... | @@ -26205,12 +26395,8 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26205 | 26395 | size_t abs_offset; |
| 26206 | 26396 | size_t rel_end; |
| 26207 | 26397 | bool ptr_is_undef = false; |
| 26208 | if (array_type->id == ZigTypeIdArray || | |
| 26209 | (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) | |
| 26210 | { | |
| 26398 | if (child_array_type->id == ZigTypeIdArray) { | |
| 26211 | 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 | 26400 | parent_ptr = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.base.source_node); |
| 26215 | 26401 | if (parent_ptr == nullptr) |
| 26216 | 26402 | return ira->codegen->invalid_inst_gen; |
| ... | ... | @@ -26221,6 +26407,10 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26221 | 26407 | abs_offset = 0; |
| 26222 | 26408 | rel_end = SIZE_MAX; |
| 26223 | 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 | 26414 | } else { |
| 26225 | 26415 | array_val = const_ptr_pointee(ira, ira->codegen, parent_ptr, instruction->base.base.source_node); |
| 26226 | 26416 | if (array_val == nullptr) |
| ... | ... | @@ -26263,6 +26453,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26263 | 26453 | rel_end = 1; |
| 26264 | 26454 | } |
| 26265 | 26455 | break; |
| 26456 | case ConstPtrSpecialSubArray: | |
| 26266 | 26457 | case ConstPtrSpecialBaseArray: |
| 26267 | 26458 | array_val = parent_ptr->data.x_ptr.data.base_array.array_val; |
| 26268 | 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 | 26504 | abs_offset = SIZE_MAX; |
| 26314 | 26505 | rel_end = 1; |
| 26315 | 26506 | break; |
| 26507 | case ConstPtrSpecialSubArray: | |
| 26316 | 26508 | case ConstPtrSpecialBaseArray: |
| 26317 | 26509 | array_val = parent_ptr->data.x_ptr.data.base_array.array_val; |
| 26318 | 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 | 26565 | } |
| 26374 | 26566 | |
| 26375 | 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); | |
| 26378 | 26568 | |
| 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]; | |
| 26380 | 26578 | |
| 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 | 26584 | if (array_val) { |
| 26382 | 26585 | size_t index = abs_offset + start_scalar; |
| 26383 | bool is_const = slice_is_const(return_type); | |
| 26384 | init_const_ptr_array(ira->codegen, ptr_val, array_val, index, is_const, PtrLenUnknown); | |
| 26586 | init_const_ptr_array(ira->codegen, ptr_val, array_val, index, return_type_is_const, PtrLenUnknown); | |
| 26587 | if (return_type->id == ZigTypeIdPointer) { | |
| 26588 | ptr_val->data.x_ptr.special = ConstPtrSpecialSubArray; | |
| 26589 | } | |
| 26385 | 26590 | if (array_type->id == ZigTypeIdArray) { |
| 26386 | 26591 | ptr_val->data.x_ptr.mut = ptr_ptr->value->data.x_ptr.mut; |
| 26387 | 26592 | } else if (is_slice(array_type)) { |
| ... | ... | @@ -26391,16 +26596,17 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26391 | 26596 | } |
| 26392 | 26597 | } else if (ptr_is_undef) { |
| 26393 | 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 | 26600 | ptr_val->special = ConstValSpecialUndef; |
| 26396 | 26601 | } else switch (parent_ptr->data.x_ptr.special) { |
| 26397 | 26602 | case ConstPtrSpecialInvalid: |
| 26398 | 26603 | case ConstPtrSpecialDiscard: |
| 26399 | 26604 | zig_unreachable(); |
| 26400 | 26605 | case ConstPtrSpecialRef: |
| 26401 | init_const_ptr_ref(ira->codegen, ptr_val, | |
| 26402 | parent_ptr->data.x_ptr.data.ref.pointee, slice_is_const(return_type)); | |
| 26606 | init_const_ptr_ref(ira->codegen, ptr_val, parent_ptr->data.x_ptr.data.ref.pointee, | |
| 26607 | return_type_is_const); | |
| 26403 | 26608 | break; |
| 26609 | case ConstPtrSpecialSubArray: | |
| 26404 | 26610 | case ConstPtrSpecialBaseArray: |
| 26405 | 26611 | zig_unreachable(); |
| 26406 | 26612 | case ConstPtrSpecialBaseStruct: |
| ... | ... | @@ -26415,7 +26621,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26415 | 26621 | init_const_ptr_hard_coded_addr(ira->codegen, ptr_val, |
| 26416 | 26622 | parent_ptr->type->data.pointer.child_type, |
| 26417 | 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 | 26625 | break; |
| 26420 | 26626 | case ConstPtrSpecialFunction: |
| 26421 | 26627 | zig_panic("TODO"); |
| ... | ... | @@ -26423,26 +26629,11 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26423 | 26629 | zig_panic("TODO"); |
| 26424 | 26630 | } |
| 26425 | 26631 | |
| 26426 | ZigValue *len_val = out_val->data.x_struct.fields[slice_len_index]; | |
| 26427 | init_const_usize(ira->codegen, len_val, end_scalar - start_scalar); | |
| 26428 | ||
| 26632 | // In the case of pointer-to-array, we must restore this because above it overwrites ptr_val->type | |
| 26633 | result->value->type = return_type; | |
| 26429 | 26634 | return result; |
| 26430 | 26635 | } |
| 26431 | 26636 | |
| 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 | 26637 | if (generate_non_null_assert) { |
| 26447 | 26638 | IrInstGen *ptr_val = ir_get_deref(ira, &instruction->base.base, ptr_ptr, nullptr); |
| 26448 | 26639 | |
| ... | ... | @@ -26452,8 +26643,26 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26452 | 26643 | ir_build_assert_non_null(ira, &instruction->base.base, ptr_val); |
| 26453 | 26644 | } |
| 26454 | 26645 | |
| 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 | 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 | } |
| 26458 | 26667 | |
| 26459 | 26668 | static 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 | 27688 | // We have a check for zero bits later so we use get_src_ptr_type to |
| 27480 | 27689 | // validate src_type and dest_type. |
| 27481 | 27690 | |
| 27482 | ZigType *src_ptr_type = get_src_ptr_type(src_type); | |
| 27483 | if (src_ptr_type == nullptr) { | |
| 27484 | ir_add_error(ira, ptr_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); | |
| 27485 | return ira->codegen->invalid_inst_gen; | |
| 27691 | ZigType *if_slice_ptr_type; | |
| 27692 | if (is_slice(src_type)) { | |
| 27693 | TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index]; | |
| 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 | } |
| 27487 | 27704 | |
| 27488 | 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 | 27709 | return ira->codegen->invalid_inst_gen; |
| 27493 | 27710 | } |
| 27494 | 27711 | |
| 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 | 27713 | ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier")); |
| 27497 | 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 | 27727 | if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown))) |
| 27511 | 27728 | return ira->codegen->invalid_inst_gen; |
| 27512 | 27729 | |
| 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 | 27734 | ErrorMsg *msg = ir_add_error(ira, source_instr, |
| 27515 | 27735 | buf_sprintf("'%s' and '%s' do not have the same in-memory representation", |
| 27516 | 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 | 27741 | return ira->codegen->invalid_inst_gen; |
| 27522 | 27742 | } |
| 27523 | 27743 | |
| 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 | 27752 | if (instr_is_comptime(ptr)) { |
| 27525 | 27753 | bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type); |
| 27526 | 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 | 27852 | buf_write_value_bytes(codegen, &buf[buf_i], elem); |
| 27625 | 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 | } |
| 27628 | 27859 | |
| 27629 | 27860 | static 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 | 566 | Stage2ProgressNode *progress_node) |
| 567 | 567 | { |
| 568 | 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 | 570 | ZigList<CFile *> c_source_files = {0}; |
| 570 | 571 | c_source_files.append(c_file); |
| 571 | 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 | 1291 | if (g->enable_cache) { |
| 1292 | 1292 | #if defined(ZIG_OS_WINDOWS) |
| 1293 | 1293 | buf_replace(&g->bin_file_output_path, '/', '\\'); |
| 1294 | buf_replace(g->output_dir, '/', '\\'); | |
| 1294 | 1295 | #endif |
| 1295 | 1296 | if (final_output_dir_step != nullptr) { |
| 1296 | 1297 | Buf *dest_basename = buf_alloc(); |
| ... | ... | @@ -1304,7 +1305,7 @@ static int main0(int argc, char **argv) { |
| 1304 | 1305 | return main_exit(root_progress_node, EXIT_FAILURE); |
| 1305 | 1306 | } |
| 1306 | 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 | 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 | 36 | testMissingOutputPath, |
| 37 | 37 | }; |
| 38 | 38 | for (test_fns) |testFn| { |
| 39 | try fs.deleteTree(dir_path); | |
| 39 | try fs.cwd().deleteTree(dir_path); | |
| 40 | 40 | try fs.cwd().makeDir(dir_path); |
| 41 | 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 | 292 | \\pub export fn main() c_int { |
| 293 | 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 | 297 | \\ for (array) |item, i| { |
| 298 | 298 | \\ if (item != i) { |
test/compile_errors.zig+2-14| ... | ... | @@ -103,18 +103,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 103 | 103 | "tmp.zig:3:23: error: pointer to size 0 type has no address", |
| 104 | 104 | }); |
| 105 | 105 | |
| 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 | 106 | cases.addTest("access invalid @typeInfo decl", |
| 119 | 107 | \\const A = B; |
| 120 | 108 | \\test "Crash" { |
| ... | ... | @@ -1918,8 +1906,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1918 | 1906 | cases.add("reading past end of pointer casted array", |
| 1919 | 1907 | \\comptime { |
| 1920 | 1908 | \\ const array: [4]u8 = "aoeu".*; |
| 1921 | \\ const slice = array[1..]; | |
| 1922 | \\ const int_ptr = @ptrCast(*const u24, slice.ptr); | |
| 1909 | \\ const sub_array = array[1..]; | |
| 1910 | \\ const int_ptr = @ptrCast(*const u24, sub_array); | |
| 1923 | 1911 | \\ const deref = int_ptr.*; |
| 1924 | 1912 | \\} |
| 1925 | 1913 | , &[_][]const u8{ |
test/runtime_safety.zig+1-1| ... | ... | @@ -69,7 +69,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 69 | 69 | \\} |
| 70 | 70 | \\pub fn main() void { |
| 71 | 71 | \\ var buf: [4]u8 = undefined; |
| 72 | \\ const ptr = buf[0..].ptr; | |
| 72 | \\ const ptr: [*]u8 = &buf; | |
| 73 | 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 | 5 | var foo: u8 align(4) = 100; |
| 6 | 6 | |
| 7 | 7 | test "global variable alignment" { |
| 8 | expect(@TypeOf(&foo).alignment == 4); | |
| 9 | expect(@TypeOf(&foo) == *align(4) u8); | |
| 10 | const slice = @as(*[1]u8, &foo)[0..]; | |
| 11 | expect(@TypeOf(slice) == []align(4) u8); | |
| 8 | comptime expect(@TypeOf(&foo).alignment == 4); | |
| 9 | comptime expect(@TypeOf(&foo) == *align(4) u8); | |
| 10 | { | |
| 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 | } |
| 13 | 20 | |
| 14 | 21 | fn derp() align(@sizeOf(usize) * 2) i32 { |
| ... | ... | @@ -171,18 +178,19 @@ test "runtime known array index has best alignment possible" { |
| 171 | 178 | |
| 172 | 179 | // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2 |
| 173 | 180 | var smaller align(2) = [_]u32{ 1, 2, 3, 4 }; |
| 174 | comptime expect(@TypeOf(smaller[0..]) == []align(2) u32); | |
| 175 | comptime expect(@TypeOf(smaller[0..].ptr) == [*]align(2) u32); | |
| 176 | testIndex(smaller[0..].ptr, 0, *align(2) u32); | |
| 177 | testIndex(smaller[0..].ptr, 1, *align(2) u32); | |
| 178 | testIndex(smaller[0..].ptr, 2, *align(2) u32); | |
| 179 | testIndex(smaller[0..].ptr, 3, *align(2) u32); | |
| 181 | var runtime_zero: usize = 0; | |
| 182 | comptime expect(@TypeOf(smaller[runtime_zero..]) == []align(2) u32); | |
| 183 | comptime expect(@TypeOf(smaller[runtime_zero..].ptr) == [*]align(2) u32); | |
| 184 | testIndex(smaller[runtime_zero..].ptr, 0, *align(2) u32); | |
| 185 | testIndex(smaller[runtime_zero..].ptr, 1, *align(2) u32); | |
| 186 | testIndex(smaller[runtime_zero..].ptr, 2, *align(2) u32); | |
| 187 | testIndex(smaller[runtime_zero..].ptr, 3, *align(2) u32); | |
| 180 | 188 | |
| 181 | 189 | // has to use ABI alignment because index known at runtime only |
| 182 | testIndex2(array[0..].ptr, 0, *u8); | |
| 183 | testIndex2(array[0..].ptr, 1, *u8); | |
| 184 | testIndex2(array[0..].ptr, 2, *u8); | |
| 185 | testIndex2(array[0..].ptr, 3, *u8); | |
| 190 | testIndex2(array[runtime_zero..].ptr, 0, *u8); | |
| 191 | testIndex2(array[runtime_zero..].ptr, 1, *u8); | |
| 192 | testIndex2(array[runtime_zero..].ptr, 2, *u8); | |
| 193 | testIndex2(array[runtime_zero..].ptr, 3, *u8); | |
| 186 | 194 | } |
| 187 | 195 | fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void { |
| 188 | 196 | comptime expect(@TypeOf(&smaller[index]) == T); |
test/stage1/behavior/array.zig+38| ... | ... | @@ -28,6 +28,24 @@ fn getArrayLen(a: []const u32) usize { |
| 28 | 28 | return a.len; |
| 29 | 29 | } |
| 30 | 30 | |
| 31 | test "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 | ||
| 31 | 49 | test "void arrays" { |
| 32 | 50 | var array: [4]void = undefined; |
| 33 | 51 | array[0] = void{}; |
| ... | ... | @@ -376,3 +394,23 @@ test "type deduction for array subscript expression" { |
| 376 | 394 | S.doTheTest(); |
| 377 | 395 | comptime S.doTheTest(); |
| 378 | 396 | } |
| 397 | ||
| 398 | test "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 | 431 | |
| 432 | 432 | test "implicit cast from [*]T to ?*c_void" { |
| 433 | 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 | 436 | expect(std.mem.eql(u8, &a, &[_]u8{ 4, 3, 2 })); |
| 436 | 437 | } |
| 437 | 438 |
test/stage1/behavior/eval.zig+1-1| ... | ... | @@ -524,7 +524,7 @@ test "comptime slice of slice preserves comptime var" { |
| 524 | 524 | test "comptime slice of pointer preserves comptime var" { |
| 525 | 525 | comptime { |
| 526 | 526 | var buff: [10]u8 = undefined; |
| 527 | var a = buff[0..].ptr; | |
| 527 | var a = @ptrCast([*]u8, &buff); | |
| 528 | 528 | a[0..1][0] = 1; |
| 529 | 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 | 102 | var foo: [20]u8 = undefined; |
| 103 | 103 | var bar: [20]u8 = undefined; |
| 104 | 104 | |
| 105 | @memset(foo[0..].ptr, 'A', foo.len); | |
| 106 | @memcpy(bar[0..].ptr, foo[0..].ptr, bar.len); | |
| 105 | @memset(&foo, 'A', foo.len); | |
| 106 | @memcpy(&bar, &foo, bar.len); | |
| 107 | 107 | |
| 108 | 108 | if (bar[11] != 'A') unreachable; |
| 109 | 109 | } |
| ... | ... | @@ -565,12 +565,16 @@ test "volatile load and store" { |
| 565 | 565 | expect(ptr.* == 1235); |
| 566 | 566 | } |
| 567 | 567 | |
| 568 | test "slice string literal has type []const u8" { | |
| 568 | test "slice string literal has correct type" { | |
| 569 | 569 | comptime { |
| 570 | expect(@TypeOf("aoeu"[0..]) == []const u8); | |
| 570 | expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8); | |
| 571 | 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 | } |
| 575 | 579 | |
| 576 | 580 | test "pointer child field" { |
test/stage1/behavior/pointers.zig+5-4| ... | ... | @@ -159,12 +159,13 @@ test "allowzero pointer and slice" { |
| 159 | 159 | var opt_ptr: ?[*]allowzero i32 = ptr; |
| 160 | 160 | expect(opt_ptr != null); |
| 161 | 161 | expect(@ptrToInt(ptr) == 0); |
| 162 | var slice = ptr[0..10]; | |
| 163 | expect(@TypeOf(slice) == []allowzero i32); | |
| 162 | var runtime_zero: usize = 0; | |
| 163 | var slice = ptr[runtime_zero..10]; | |
| 164 | comptime expect(@TypeOf(slice) == []allowzero i32); | |
| 164 | 165 | expect(@ptrToInt(&slice[5]) == 20); |
| 165 | 166 | |
| 166 | expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero); | |
| 167 | expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero); | |
| 167 | comptime expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero); | |
| 168 | comptime expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero); | |
| 168 | 169 | } |
| 169 | 170 | |
| 170 | 171 | test "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 | 13 | builtin.Endian.Little => 0xab785634, |
| 14 | 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 | } |
| 18 | 18 | |
| 19 | 19 | test "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 | 7 | const x = @intToPtr([*]i32, 0x1000)[0..0x500]; |
| 8 | 8 | const y = x[0x100..]; |
| 9 | 9 | test "compile time slice of pointer to hard coded address" { |
| 10 | expect(@ptrToInt(x.ptr) == 0x1000); | |
| 10 | expect(@ptrToInt(x) == 0x1000); | |
| 11 | 11 | expect(x.len == 0x500); |
| 12 | 12 | |
| 13 | expect(@ptrToInt(y.ptr) == 0x1100); | |
| 13 | expect(@ptrToInt(y) == 0x1100); | |
| 14 | 14 | expect(y.len == 0x400); |
| 15 | 15 | } |
| 16 | 16 | |
| ... | ... | @@ -47,7 +47,9 @@ test "C pointer slice access" { |
| 47 | 47 | var buf: [10]u32 = [1]u32{42} ** 10; |
| 48 | 48 | const c_ptr = @ptrCast([*c]const u32, &buf); |
| 49 | 49 | |
| 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])); | |
| 51 | 53 | |
| 52 | 54 | for (c_ptr[0..5]) |*cl| { |
| 53 | 55 | expectEqual(@as(u32, 42), cl.*); |
| ... | ... | @@ -107,7 +109,9 @@ test "obtaining a null terminated slice" { |
| 107 | 109 | const ptr2 = buf[0..runtime_len :0]; |
| 108 | 110 | // ptr2 is a null-terminated slice |
| 109 | 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 | } |
| 112 | 116 | |
| 113 | 117 | test "empty array to slice" { |
| ... | ... | @@ -126,3 +130,150 @@ test "empty array to slice" { |
| 126 | 130 | S.doTheTest(); |
| 127 | 131 | comptime S.doTheTest(); |
| 128 | 132 | } |
| 133 | ||
| 134 | test "@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 | ||
| 148 | test "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 | 409 | test "native bit field understands endianness" { |
| 410 | 410 | var all: u64 = 0x7765443322221111; |
| 411 | 411 | var bytes: [8]u8 = undefined; |
| 412 | @memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8); | |
| 413 | var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*; | |
| 412 | @memcpy(&bytes, @ptrCast([*]u8, &all), 8); | |
| 413 | var bitfields = @ptrCast(*Bitfields, &bytes).*; | |
| 414 | 414 | |
| 415 | 415 | expect(bitfields.f1 == 0x1111); |
| 416 | 416 | expect(bitfields.f2 == 0x2222); |