| 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,10 +305,14 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { |
| 305 | dependOnLib(b, exe, ctx.llvm); | 305 | dependOnLib(b, exe, ctx.llvm); |
| 306 | 306 | ||
| 307 | if (exe.target.getOsTag() == .linux) { | 307 | if (exe.target.getOsTag() == .linux) { |
| 308 | try addCxxKnownPath(b, ctx, exe, "libstdc++.a", | 308 | // First we try to static link against gcc libstdc++. If that doesn't work, |
| 309 | \\Unable to determine path to libstdc++.a | 309 | // we fall back to -lc++ and cross our fingers. |
| 310 | \\On Fedora, install libstdc++-static and try again. | 310 | addCxxKnownPath(b, ctx, exe, "libstdc++.a", "") catch |err| switch (err) { |
| 311 | ); | 311 | error.RequiredLibraryNotFound => { |
| 312 | exe.linkSystemLibrary("c++"); | ||
| 313 | }, | ||
| 314 | else => |e| return e, | ||
| 315 | }; | ||
| 312 | 316 | ||
| 313 | exe.linkSystemLibrary("pthread"); | 317 | exe.linkSystemLibrary("pthread"); |
| 314 | } else if (exe.target.isFreeBSD()) { | 318 | } else if (exe.target.isFreeBSD()) { |
| ... | @@ -327,7 +331,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { | ... | @@ -327,7 +331,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { |
| 327 | // System compiler, not gcc. | 331 | // System compiler, not gcc. |
| 328 | exe.linkSystemLibrary("c++"); | 332 | exe.linkSystemLibrary("c++"); |
| 329 | }, | 333 | }, |
| 330 | else => return err, | 334 | else => |e| return e, |
| 331 | } | 335 | } |
| 332 | } | 336 | } |
| 333 | 337 |
doc/docgen.zig+19-3| ... | @@ -48,7 +48,7 @@ pub fn main() !void { | ... | @@ -48,7 +48,7 @@ pub fn main() !void { |
| 48 | var toc = try genToc(allocator, &tokenizer); | 48 | var toc = try genToc(allocator, &tokenizer); |
| 49 | 49 | ||
| 50 | try fs.cwd().makePath(tmp_dir_name); | 50 | try fs.cwd().makePath(tmp_dir_name); |
| 51 | defer fs.deleteTree(tmp_dir_name) catch {}; | 51 | defer fs.cwd().deleteTree(tmp_dir_name) catch {}; |
| 52 | 52 | ||
| 53 | try genHtml(allocator, &tokenizer, &toc, buffered_out_stream.outStream(), zig_exe); | 53 | try genHtml(allocator, &tokenizer, &toc, buffered_out_stream.outStream(), zig_exe); |
| 54 | try buffered_out_stream.flush(); | 54 | try buffered_out_stream.flush(); |
| ... | @@ -1096,6 +1096,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var | ... | @@ -1096,6 +1096,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var |
| 1096 | try build_args.append("-lc"); | 1096 | try build_args.append("-lc"); |
| 1097 | try out.print(" -lc", .{}); | 1097 | try out.print(" -lc", .{}); |
| 1098 | } | 1098 | } |
| 1099 | const target = try std.zig.CrossTarget.parse(.{ | ||
| 1100 | .arch_os_abi = code.target_str orelse "native", | ||
| 1101 | }); | ||
| 1099 | if (code.target_str) |triple| { | 1102 | if (code.target_str) |triple| { |
| 1100 | try build_args.appendSlice(&[_][]const u8{ "-target", triple }); | 1103 | try build_args.appendSlice(&[_][]const u8{ "-target", triple }); |
| 1101 | if (!code.is_inline) { | 1104 | if (!code.is_inline) { |
| ... | @@ -1150,7 +1153,15 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var | ... | @@ -1150,7 +1153,15 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var |
| 1150 | } | 1153 | } |
| 1151 | } | 1154 | } |
| 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 | const run_args = &[_][]const u8{path_to_exe}; | 1165 | const run_args = &[_][]const u8{path_to_exe}; |
| 1155 | 1166 | ||
| 1156 | var exited_with_signal = false; | 1167 | var exited_with_signal = false; |
| ... | @@ -1486,7 +1497,12 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var | ... | @@ -1486,7 +1497,12 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var |
| 1486 | } | 1497 | } |
| 1487 | 1498 | ||
| 1488 | fn exec(allocator: *mem.Allocator, env_map: *std.BufMap, args: []const []const u8) !ChildProcess.ExecResult { | 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 | switch (result.term) { | 1506 | switch (result.term) { |
| 1491 | .Exited => |exit_code| { | 1507 | .Exited => |exit_code| { |
| 1492 | if (exit_code != 0) { | 1508 | if (exit_code != 0) { |
doc/langref.html.in+16-20| ... | @@ -2093,8 +2093,9 @@ var foo: u8 align(4) = 100; | ... | @@ -2093,8 +2093,9 @@ var foo: u8 align(4) = 100; |
| 2093 | test "global variable alignment" { | 2093 | test "global variable alignment" { |
| 2094 | assert(@TypeOf(&foo).alignment == 4); | 2094 | assert(@TypeOf(&foo).alignment == 4); |
| 2095 | assert(@TypeOf(&foo) == *align(4) u8); | 2095 | assert(@TypeOf(&foo) == *align(4) u8); |
| 2096 | const slice = @as(*[1]u8, &foo)[0..]; | 2096 | const as_pointer_to_array: *[1]u8 = &foo; |
| 2097 | assert(@TypeOf(slice) == []align(4) u8); | 2097 | const as_slice: []u8 = as_pointer_to_array; |
| 2098 | assert(@TypeOf(as_slice) == []align(4) u8); | ||
| 2098 | } | 2099 | } |
| 2099 | 2100 | ||
| 2100 | fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; } | 2101 | fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; } |
| ... | @@ -2187,7 +2188,8 @@ test "basic slices" { | ... | @@ -2187,7 +2188,8 @@ test "basic slices" { |
| 2187 | // a slice is that the array's length is part of the type and known at | 2188 | // a slice is that the array's length is part of the type and known at |
| 2188 | // compile-time, whereas the slice's length is known at runtime. | 2189 | // compile-time, whereas the slice's length is known at runtime. |
| 2189 | // Both can be accessed with the `len` field. | 2190 | // Both can be accessed with the `len` field. |
| 2190 | const slice = array[0..array.len]; | 2191 | var known_at_runtime_zero: usize = 0; |
| 2192 | const slice = array[known_at_runtime_zero..array.len]; | ||
| 2191 | assert(&slice[0] == &array[0]); | 2193 | assert(&slice[0] == &array[0]); |
| 2192 | assert(slice.len == array.len); | 2194 | assert(slice.len == array.len); |
| 2193 | 2195 | ||
| ... | @@ -2207,13 +2209,15 @@ test "basic slices" { | ... | @@ -2207,13 +2209,15 @@ test "basic slices" { |
| 2207 | {#code_end#} | 2209 | {#code_end#} |
| 2208 | <p>This is one reason we prefer slices to pointers.</p> | 2210 | <p>This is one reason we prefer slices to pointers.</p> |
| 2209 | {#code_begin|test|slices#} | 2211 | {#code_begin|test|slices#} |
| 2210 | const assert = @import("std").debug.assert; | 2212 | const std = @import("std"); |
| 2211 | const mem = @import("std").mem; | 2213 | const assert = std.debug.assert; |
| 2212 | const fmt = @import("std").fmt; | 2214 | const mem = std.mem; |
| 2215 | const fmt = std.fmt; | ||
| 2213 | 2216 | ||
| 2214 | test "using slices for strings" { | 2217 | test "using slices for strings" { |
| 2215 | // Zig has no concept of strings. String literals are arrays of u8, and | 2218 | // Zig has no concept of strings. String literals are const pointers to |
| 2216 | // in general the string type is []u8 (slice of u8). | 2219 | // arrays of u8, and by convention parameters that are "strings" are |
| 2220 | // expected to be UTF-8 encoded slices of u8. | ||
| 2217 | // Here we coerce [5]u8 to []const u8 | 2221 | // Here we coerce [5]u8 to []const u8 |
| 2218 | const hello: []const u8 = "hello"; | 2222 | const hello: []const u8 = "hello"; |
| 2219 | const world: []const u8 = "世界"; | 2223 | const world: []const u8 = "世界"; |
| ... | @@ -2222,7 +2226,7 @@ test "using slices for strings" { | ... | @@ -2222,7 +2226,7 @@ test "using slices for strings" { |
| 2222 | // You can use slice syntax on an array to convert an array into a slice. | 2226 | // You can use slice syntax on an array to convert an array into a slice. |
| 2223 | const all_together_slice = all_together[0..]; | 2227 | const all_together_slice = all_together[0..]; |
| 2224 | // String concatenation example. | 2228 | // String concatenation example. |
| 2225 | const hello_world = try fmt.bufPrint(all_together_slice, "{} {}", .{hello, world}); | 2229 | const hello_world = try fmt.bufPrint(all_together_slice, "{} {}", .{ hello, world }); |
| 2226 | 2230 | ||
| 2227 | // Generally, you can use UTF-8 and not worry about whether something is a | 2231 | // Generally, you can use UTF-8 and not worry about whether something is a |
| 2228 | // string. If you don't need to deal with individual characters, no need | 2232 | // string. If you don't need to deal with individual characters, no need |
| ... | @@ -2239,23 +2243,15 @@ test "slice pointer" { | ... | @@ -2239,23 +2243,15 @@ test "slice pointer" { |
| 2239 | slice[2] = 3; | 2243 | slice[2] = 3; |
| 2240 | assert(slice[2] == 3); | 2244 | assert(slice[2] == 3); |
| 2241 | // The slice is mutable because we sliced a mutable pointer. | 2245 | // The slice is mutable because we sliced a mutable pointer. |
| 2242 | assert(@TypeOf(slice) == []u8); | 2246 | // Furthermore, it is actually a pointer to an array, since the start |
| 2247 | // and end indexes were both comptime-known. | ||
| 2248 | assert(@TypeOf(slice) == *[5]u8); | ||
| 2243 | 2249 | ||
| 2244 | // You can also slice a slice: | 2250 | // You can also slice a slice: |
| 2245 | const slice2 = slice[2..3]; | 2251 | const slice2 = slice[2..3]; |
| 2246 | assert(slice2.len == 1); | 2252 | assert(slice2.len == 1); |
| 2247 | assert(slice2[0] == 3); | 2253 | assert(slice2[0] == 3); |
| 2248 | } | 2254 | } |
| 2249 | |||
| 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 | {#code_end#} | 2255 | {#code_end#} |
| 2260 | {#see_also|Pointers|for|Arrays#} | 2256 | {#see_also|Pointers|for|Arrays#} |
| 2261 | 2257 |
lib/std/build.zig+26-12| ... | @@ -377,7 +377,7 @@ pub const Builder = struct { | ... | @@ -377,7 +377,7 @@ pub const Builder = struct { |
| 377 | if (self.verbose) { | 377 | if (self.verbose) { |
| 378 | warn("rm {}\n", .{full_path}); | 378 | warn("rm {}\n", .{full_path}); |
| 379 | } | 379 | } |
| 380 | fs.deleteTree(full_path) catch {}; | 380 | fs.cwd().deleteTree(full_path) catch {}; |
| 381 | } | 381 | } |
| 382 | 382 | ||
| 383 | // TODO remove empty directories | 383 | // TODO remove empty directories |
| ... | @@ -847,7 +847,8 @@ pub const Builder = struct { | ... | @@ -847,7 +847,8 @@ pub const Builder = struct { |
| 847 | if (self.verbose) { | 847 | if (self.verbose) { |
| 848 | warn("cp {} {} ", .{ source_path, dest_path }); | 848 | warn("cp {} {} ", .{ source_path, dest_path }); |
| 849 | } | 849 | } |
| 850 | const prev_status = try fs.updateFile(source_path, dest_path); | 850 | const cwd = fs.cwd(); |
| 851 | const prev_status = try fs.Dir.updateFile(cwd, source_path, cwd, dest_path, .{}); | ||
| 851 | if (self.verbose) switch (prev_status) { | 852 | if (self.verbose) switch (prev_status) { |
| 852 | .stale => warn("# installed\n", .{}), | 853 | .stale => warn("# installed\n", .{}), |
| 853 | .fresh => warn("# up-to-date\n", .{}), | 854 | .fresh => warn("# up-to-date\n", .{}), |
| ... | @@ -1157,8 +1158,14 @@ pub const LibExeObjStep = struct { | ... | @@ -1157,8 +1158,14 @@ pub const LibExeObjStep = struct { |
| 1157 | 1158 | ||
| 1158 | valgrind_support: ?bool = null, | 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 | link_eh_frame_hdr: bool = false, | 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 | /// Uses system Wine installation to run cross compiled Windows build artifacts. | 1169 | /// Uses system Wine installation to run cross compiled Windows build artifacts. |
| 1163 | enable_wine: bool = false, | 1170 | enable_wine: bool = false, |
| 1164 | 1171 | ||
| ... | @@ -1884,7 +1891,9 @@ pub const LibExeObjStep = struct { | ... | @@ -1884,7 +1891,9 @@ pub const LibExeObjStep = struct { |
| 1884 | if (self.link_eh_frame_hdr) { | 1891 | if (self.link_eh_frame_hdr) { |
| 1885 | try zig_args.append("--eh-frame-hdr"); | 1892 | try zig_args.append("--eh-frame-hdr"); |
| 1886 | } | 1893 | } |
| 1887 | 1894 | if (self.link_function_sections) { | |
| 1895 | try zig_args.append("-ffunction-sections"); | ||
| 1896 | } | ||
| 1888 | if (self.single_threaded) { | 1897 | if (self.single_threaded) { |
| 1889 | try zig_args.append("--single-threaded"); | 1898 | try zig_args.append("--single-threaded"); |
| 1890 | } | 1899 | } |
| ... | @@ -2144,17 +2153,22 @@ pub const LibExeObjStep = struct { | ... | @@ -2144,17 +2153,22 @@ pub const LibExeObjStep = struct { |
| 2144 | try zig_args.append("--cache"); | 2153 | try zig_args.append("--cache"); |
| 2145 | try zig_args.append("on"); | 2154 | try zig_args.append("on"); |
| 2146 | 2155 | ||
| 2147 | const output_path_nl = try builder.execFromStep(zig_args.toSliceConst(), &self.step); | 2156 | const output_dir_nl = try builder.execFromStep(zig_args.toSliceConst(), &self.step); |
| 2148 | const output_path = mem.trimRight(u8, output_path_nl, "\r\n"); | 2157 | const build_output_dir = mem.trimRight(u8, output_dir_nl, "\r\n"); |
| 2149 | 2158 | ||
| 2150 | if (self.output_dir) |output_dir| { | 2159 | if (self.output_dir) |output_dir| { |
| 2151 | const full_dest = try fs.path.join(builder.allocator, &[_][]const u8{ | 2160 | var src_dir = try std.fs.cwd().openDir(build_output_dir, .{ .iterate = true }); |
| 2152 | output_dir, | 2161 | defer src_dir.close(); |
| 2153 | fs.path.basename(output_path), | 2162 | |
| 2154 | }); | 2163 | var dest_dir = try std.fs.cwd().openDir(output_dir, .{}); |
| 2155 | try builder.updateFile(output_path, full_dest); | 2164 | defer dest_dir.close(); |
| 2165 | |||
| 2166 | var it = src_dir.iterate(); | ||
| 2167 | while (try it.next()) |entry| { | ||
| 2168 | _ = try src_dir.updateFile(entry.name, dest_dir, entry.name, .{}); | ||
| 2169 | } | ||
| 2156 | } else { | 2170 | } else { |
| 2157 | self.output_dir = fs.path.dirname(output_path).?; | 2171 | self.output_dir = build_output_dir; |
| 2158 | } | 2172 | } |
| 2159 | } | 2173 | } |
| 2160 | 2174 | ||
| ... | @@ -2352,7 +2366,7 @@ pub const RemoveDirStep = struct { | ... | @@ -2352,7 +2366,7 @@ pub const RemoveDirStep = struct { |
| 2352 | const self = @fieldParentPtr(RemoveDirStep, "step", step); | 2366 | const self = @fieldParentPtr(RemoveDirStep, "step", step); |
| 2353 | 2367 | ||
| 2354 | const full_path = self.builder.pathFromRoot(self.dir_path); | 2368 | const full_path = self.builder.pathFromRoot(self.dir_path); |
| 2355 | fs.deleteTree(full_path) catch |err| { | 2369 | fs.cwd().deleteTree(full_path) catch |err| { |
| 2356 | warn("Unable to remove {}: {}\n", .{ full_path, @errorName(err) }); | 2370 | warn("Unable to remove {}: {}\n", .{ full_path, @errorName(err) }); |
| 2357 | return err; | 2371 | return err; |
| 2358 | }; | 2372 | }; |
lib/std/build/run.zig+3-1| ... | @@ -29,6 +29,8 @@ pub const RunStep = struct { | ... | @@ -29,6 +29,8 @@ pub const RunStep = struct { |
| 29 | stdout_action: StdIoAction = .inherit, | 29 | stdout_action: StdIoAction = .inherit, |
| 30 | stderr_action: StdIoAction = .inherit, | 30 | stderr_action: StdIoAction = .inherit, |
| 31 | 31 | ||
| 32 | stdin_behavior: std.ChildProcess.StdIo = .Inherit, | ||
| 33 | |||
| 32 | expected_exit_code: u8 = 0, | 34 | expected_exit_code: u8 = 0, |
| 33 | 35 | ||
| 34 | pub const StdIoAction = union(enum) { | 36 | pub const StdIoAction = union(enum) { |
| ... | @@ -159,7 +161,7 @@ pub const RunStep = struct { | ... | @@ -159,7 +161,7 @@ pub const RunStep = struct { |
| 159 | child.cwd = cwd; | 161 | child.cwd = cwd; |
| 160 | child.env_map = self.env_map orelse self.builder.env_map; | 162 | child.env_map = self.env_map orelse self.builder.env_map; |
| 161 | 163 | ||
| 162 | child.stdin_behavior = .Ignore; | 164 | child.stdin_behavior = self.stdin_behavior; |
| 163 | child.stdout_behavior = stdIoActionToBehavior(self.stdout_action); | 165 | child.stdout_behavior = stdIoActionToBehavior(self.stdout_action); |
| 164 | child.stderr_behavior = stdIoActionToBehavior(self.stderr_action); | 166 | child.stderr_behavior = stdIoActionToBehavior(self.stderr_action); |
| 165 | 167 |
lib/std/build/write_file.zig+1-1| ... | @@ -78,7 +78,7 @@ pub const WriteFileStep = struct { | ... | @@ -78,7 +78,7 @@ pub const WriteFileStep = struct { |
| 78 | warn("unable to make path {}: {}\n", .{ self.output_dir, @errorName(err) }); | 78 | warn("unable to make path {}: {}\n", .{ self.output_dir, @errorName(err) }); |
| 79 | return err; | 79 | return err; |
| 80 | }; | 80 | }; |
| 81 | var dir = try fs.cwd().openDirTraverse(self.output_dir); | 81 | var dir = try fs.cwd().openDir(self.output_dir, .{}); |
| 82 | defer dir.close(); | 82 | defer dir.close(); |
| 83 | for (self.files.toSliceConst()) |file| { | 83 | for (self.files.toSliceConst()) |file| { |
| 84 | dir.writeFile(file.basename, file.bytes) catch |err| { | 84 | dir.writeFile(file.basename, file.bytes) catch |err| { |
lib/std/c.zig+1| ... | @@ -106,6 +106,7 @@ pub extern "c" fn mkdir(path: [*:0]const u8, mode: c_uint) c_int; | ... | @@ -106,6 +106,7 @@ pub extern "c" fn mkdir(path: [*:0]const u8, mode: c_uint) c_int; |
| 106 | pub extern "c" fn mkdirat(dirfd: fd_t, path: [*:0]const u8, mode: u32) c_int; | 106 | pub extern "c" fn mkdirat(dirfd: fd_t, path: [*:0]const u8, mode: u32) c_int; |
| 107 | pub extern "c" fn symlink(existing: [*:0]const u8, new: [*:0]const u8) c_int; | 107 | pub extern "c" fn symlink(existing: [*:0]const u8, new: [*:0]const u8) c_int; |
| 108 | pub extern "c" fn rename(old: [*:0]const u8, new: [*:0]const u8) c_int; | 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 | pub extern "c" fn chdir(path: [*:0]const u8) c_int; | 110 | pub extern "c" fn chdir(path: [*:0]const u8) c_int; |
| 110 | pub extern "c" fn fchdir(fd: fd_t) c_int; | 111 | pub extern "c" fn fchdir(fd: fd_t) c_int; |
| 111 | pub extern "c" fn execve(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) c_int; | 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,10 +15,10 @@ fn rotw(w: u32) u32 { |
| 15 | 15 | ||
| 16 | // Encrypt one block from src into dst, using the expanded key xk. | 16 | // Encrypt one block from src into dst, using the expanded key xk. |
| 17 | fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { | 17 | fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { |
| 18 | var s0 = mem.readIntSliceBig(u32, src[0..4]); | 18 | var s0 = mem.readIntBig(u32, src[0..4]); |
| 19 | var s1 = mem.readIntSliceBig(u32, src[4..8]); | 19 | var s1 = mem.readIntBig(u32, src[4..8]); |
| 20 | var s2 = mem.readIntSliceBig(u32, src[8..12]); | 20 | var s2 = mem.readIntBig(u32, src[8..12]); |
| 21 | var s3 = mem.readIntSliceBig(u32, src[12..16]); | 21 | var s3 = mem.readIntBig(u32, src[12..16]); |
| 22 | 22 | ||
| 23 | // First round just XORs input with key. | 23 | // First round just XORs input with key. |
| 24 | s0 ^= xk[0]; | 24 | s0 ^= xk[0]; |
| ... | @@ -58,18 +58,18 @@ fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { | ... | @@ -58,18 +58,18 @@ fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { |
| 58 | s2 ^= xk[k + 2]; | 58 | s2 ^= xk[k + 2]; |
| 59 | s3 ^= xk[k + 3]; | 59 | s3 ^= xk[k + 3]; |
| 60 | 60 | ||
| 61 | mem.writeIntSliceBig(u32, dst[0..4], s0); | 61 | mem.writeIntBig(u32, dst[0..4], s0); |
| 62 | mem.writeIntSliceBig(u32, dst[4..8], s1); | 62 | mem.writeIntBig(u32, dst[4..8], s1); |
| 63 | mem.writeIntSliceBig(u32, dst[8..12], s2); | 63 | mem.writeIntBig(u32, dst[8..12], s2); |
| 64 | mem.writeIntSliceBig(u32, dst[12..16], s3); | 64 | mem.writeIntBig(u32, dst[12..16], s3); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | // Decrypt one block from src into dst, using the expanded key xk. | 67 | // Decrypt one block from src into dst, using the expanded key xk. |
| 68 | pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { | 68 | pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { |
| 69 | var s0 = mem.readIntSliceBig(u32, src[0..4]); | 69 | var s0 = mem.readIntBig(u32, src[0..4]); |
| 70 | var s1 = mem.readIntSliceBig(u32, src[4..8]); | 70 | var s1 = mem.readIntBig(u32, src[4..8]); |
| 71 | var s2 = mem.readIntSliceBig(u32, src[8..12]); | 71 | var s2 = mem.readIntBig(u32, src[8..12]); |
| 72 | var s3 = mem.readIntSliceBig(u32, src[12..16]); | 72 | var s3 = mem.readIntBig(u32, src[12..16]); |
| 73 | 73 | ||
| 74 | // First round just XORs input with key. | 74 | // First round just XORs input with key. |
| 75 | s0 ^= xk[0]; | 75 | s0 ^= xk[0]; |
| ... | @@ -109,10 +109,10 @@ pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { | ... | @@ -109,10 +109,10 @@ pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { |
| 109 | s2 ^= xk[k + 2]; | 109 | s2 ^= xk[k + 2]; |
| 110 | s3 ^= xk[k + 3]; | 110 | s3 ^= xk[k + 3]; |
| 111 | 111 | ||
| 112 | mem.writeIntSliceBig(u32, dst[0..4], s0); | 112 | mem.writeIntBig(u32, dst[0..4], s0); |
| 113 | mem.writeIntSliceBig(u32, dst[4..8], s1); | 113 | mem.writeIntBig(u32, dst[4..8], s1); |
| 114 | mem.writeIntSliceBig(u32, dst[8..12], s2); | 114 | mem.writeIntBig(u32, dst[8..12], s2); |
| 115 | mem.writeIntSliceBig(u32, dst[12..16], s3); | 115 | mem.writeIntBig(u32, dst[12..16], s3); |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | fn xorBytes(dst: []u8, a: []const u8, b: []const u8) usize { | 118 | fn xorBytes(dst: []u8, a: []const u8, b: []const u8) usize { |
| ... | @@ -154,8 +154,8 @@ fn AES(comptime keysize: usize) type { | ... | @@ -154,8 +154,8 @@ fn AES(comptime keysize: usize) type { |
| 154 | var n: usize = 0; | 154 | var n: usize = 0; |
| 155 | while (n < src.len) { | 155 | while (n < src.len) { |
| 156 | ctx.encrypt(keystream[0..], ctrbuf[0..]); | 156 | ctx.encrypt(keystream[0..], ctrbuf[0..]); |
| 157 | var ctr_i = std.mem.readIntSliceBig(u128, ctrbuf[0..]); | 157 | var ctr_i = std.mem.readIntBig(u128, ctrbuf[0..]); |
| 158 | std.mem.writeIntSliceBig(u128, ctrbuf[0..], ctr_i +% 1); | 158 | std.mem.writeIntBig(u128, ctrbuf[0..], ctr_i +% 1); |
| 159 | 159 | ||
| 160 | n += xorBytes(dst[n..], src[n..], &keystream); | 160 | n += xorBytes(dst[n..], src[n..], &keystream); |
| 161 | } | 161 | } |
| ... | @@ -251,7 +251,7 @@ fn expandKey(key: []const u8, enc: []u32, dec: []u32) void { | ... | @@ -251,7 +251,7 @@ fn expandKey(key: []const u8, enc: []u32, dec: []u32) void { |
| 251 | var i: usize = 0; | 251 | var i: usize = 0; |
| 252 | var nk = key.len / 4; | 252 | var nk = key.len / 4; |
| 253 | while (i < nk) : (i += 1) { | 253 | while (i < nk) : (i += 1) { |
| 254 | enc[i] = mem.readIntSliceBig(u32, key[4 * i .. 4 * i + 4]); | 254 | enc[i] = mem.readIntBig(u32, key[4 * i ..][0..4]); |
| 255 | } | 255 | } |
| 256 | while (i < enc.len) : (i += 1) { | 256 | while (i < enc.len) : (i += 1) { |
| 257 | var t = enc[i - 1]; | 257 | var t = enc[i - 1]; |
lib/std/crypto/blake2.zig+4-7| ... | @@ -123,8 +123,7 @@ fn Blake2s(comptime out_len: usize) type { | ... | @@ -123,8 +123,7 @@ fn Blake2s(comptime out_len: usize) type { |
| 123 | const rr = d.h[0 .. out_len / 32]; | 123 | const rr = d.h[0 .. out_len / 32]; |
| 124 | 124 | ||
| 125 | for (rr) |s, j| { | 125 | for (rr) |s, j| { |
| 126 | // TODO https://github.com/ziglang/zig/issues/863 | 126 | mem.writeIntLittle(u32, out[4 * j ..][0..4], s); |
| 127 | mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s); | ||
| 128 | } | 127 | } |
| 129 | } | 128 | } |
| 130 | 129 | ||
| ... | @@ -135,8 +134,7 @@ fn Blake2s(comptime out_len: usize) type { | ... | @@ -135,8 +134,7 @@ fn Blake2s(comptime out_len: usize) type { |
| 135 | var v: [16]u32 = undefined; | 134 | var v: [16]u32 = undefined; |
| 136 | 135 | ||
| 137 | for (m) |*r, i| { | 136 | for (m) |*r, i| { |
| 138 | // TODO https://github.com/ziglang/zig/issues/863 | 137 | r.* = mem.readIntLittle(u32, b[4 * i ..][0..4]); |
| 139 | r.* = mem.readIntSliceLittle(u32, b[4 * i .. 4 * i + 4]); | ||
| 140 | } | 138 | } |
| 141 | 139 | ||
| 142 | var k: usize = 0; | 140 | var k: usize = 0; |
| ... | @@ -358,8 +356,7 @@ fn Blake2b(comptime out_len: usize) type { | ... | @@ -358,8 +356,7 @@ fn Blake2b(comptime out_len: usize) type { |
| 358 | const rr = d.h[0 .. out_len / 64]; | 356 | const rr = d.h[0 .. out_len / 64]; |
| 359 | 357 | ||
| 360 | for (rr) |s, j| { | 358 | for (rr) |s, j| { |
| 361 | // TODO https://github.com/ziglang/zig/issues/863 | 359 | mem.writeIntLittle(u64, out[8 * j ..][0..8], s); |
| 362 | mem.writeIntSliceLittle(u64, out[8 * j .. 8 * j + 8], s); | ||
| 363 | } | 360 | } |
| 364 | } | 361 | } |
| 365 | 362 | ||
| ... | @@ -370,7 +367,7 @@ fn Blake2b(comptime out_len: usize) type { | ... | @@ -370,7 +367,7 @@ fn Blake2b(comptime out_len: usize) type { |
| 370 | var v: [16]u64 = undefined; | 367 | var v: [16]u64 = undefined; |
| 371 | 368 | ||
| 372 | for (m) |*r, i| { | 369 | for (m) |*r, i| { |
| 373 | r.* = mem.readIntSliceLittle(u64, b[8 * i .. 8 * i + 8]); | 370 | r.* = mem.readIntLittle(u64, b[8 * i ..][0..8]); |
| 374 | } | 371 | } |
| 375 | 372 | ||
| 376 | var k: usize = 0; | 373 | var k: usize = 0; |
lib/std/crypto/chacha20.zig+30-31| ... | @@ -61,8 +61,7 @@ fn salsa20_wordtobyte(out: []u8, input: [16]u32) void { | ... | @@ -61,8 +61,7 @@ fn salsa20_wordtobyte(out: []u8, input: [16]u32) void { |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | for (x) |_, i| { | 63 | for (x) |_, i| { |
| 64 | // TODO https://github.com/ziglang/zig/issues/863 | 64 | mem.writeIntLittle(u32, out[4 * i ..][0..4], x[i] +% input[i]); |
| 65 | mem.writeIntSliceLittle(u32, out[4 * i .. 4 * i + 4], x[i] +% input[i]); | ||
| 66 | } | 65 | } |
| 67 | } | 66 | } |
| 68 | 67 | ||
| ... | @@ -73,10 +72,10 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo | ... | @@ -73,10 +72,10 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo |
| 73 | 72 | ||
| 74 | const c = "expand 32-byte k"; | 73 | const c = "expand 32-byte k"; |
| 75 | const constant_le = [_]u32{ | 74 | const constant_le = [_]u32{ |
| 76 | mem.readIntSliceLittle(u32, c[0..4]), | 75 | mem.readIntLittle(u32, c[0..4]), |
| 77 | mem.readIntSliceLittle(u32, c[4..8]), | 76 | mem.readIntLittle(u32, c[4..8]), |
| 78 | mem.readIntSliceLittle(u32, c[8..12]), | 77 | mem.readIntLittle(u32, c[8..12]), |
| 79 | mem.readIntSliceLittle(u32, c[12..16]), | 78 | mem.readIntLittle(u32, c[12..16]), |
| 80 | }; | 79 | }; |
| 81 | 80 | ||
| 82 | mem.copy(u32, ctx[0..], constant_le[0..4]); | 81 | mem.copy(u32, ctx[0..], constant_le[0..4]); |
| ... | @@ -120,19 +119,19 @@ pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: | ... | @@ -120,19 +119,19 @@ pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: |
| 120 | var k: [8]u32 = undefined; | 119 | var k: [8]u32 = undefined; |
| 121 | var c: [4]u32 = undefined; | 120 | var c: [4]u32 = undefined; |
| 122 | 121 | ||
| 123 | k[0] = mem.readIntSliceLittle(u32, key[0..4]); | 122 | k[0] = mem.readIntLittle(u32, key[0..4]); |
| 124 | k[1] = mem.readIntSliceLittle(u32, key[4..8]); | 123 | k[1] = mem.readIntLittle(u32, key[4..8]); |
| 125 | k[2] = mem.readIntSliceLittle(u32, key[8..12]); | 124 | k[2] = mem.readIntLittle(u32, key[8..12]); |
| 126 | k[3] = mem.readIntSliceLittle(u32, key[12..16]); | 125 | k[3] = mem.readIntLittle(u32, key[12..16]); |
| 127 | k[4] = mem.readIntSliceLittle(u32, key[16..20]); | 126 | k[4] = mem.readIntLittle(u32, key[16..20]); |
| 128 | k[5] = mem.readIntSliceLittle(u32, key[20..24]); | 127 | k[5] = mem.readIntLittle(u32, key[20..24]); |
| 129 | k[6] = mem.readIntSliceLittle(u32, key[24..28]); | 128 | k[6] = mem.readIntLittle(u32, key[24..28]); |
| 130 | k[7] = mem.readIntSliceLittle(u32, key[28..32]); | 129 | k[7] = mem.readIntLittle(u32, key[28..32]); |
| 131 | 130 | ||
| 132 | c[0] = counter; | 131 | c[0] = counter; |
| 133 | c[1] = mem.readIntSliceLittle(u32, nonce[0..4]); | 132 | c[1] = mem.readIntLittle(u32, nonce[0..4]); |
| 134 | c[2] = mem.readIntSliceLittle(u32, nonce[4..8]); | 133 | c[2] = mem.readIntLittle(u32, nonce[4..8]); |
| 135 | c[3] = mem.readIntSliceLittle(u32, nonce[8..12]); | 134 | c[3] = mem.readIntLittle(u32, nonce[8..12]); |
| 136 | chaCha20_internal(out, in, k, c); | 135 | chaCha20_internal(out, in, k, c); |
| 137 | } | 136 | } |
| 138 | 137 | ||
| ... | @@ -147,19 +146,19 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32] | ... | @@ -147,19 +146,19 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32] |
| 147 | var k: [8]u32 = undefined; | 146 | var k: [8]u32 = undefined; |
| 148 | var c: [4]u32 = undefined; | 147 | var c: [4]u32 = undefined; |
| 149 | 148 | ||
| 150 | k[0] = mem.readIntSliceLittle(u32, key[0..4]); | 149 | k[0] = mem.readIntLittle(u32, key[0..4]); |
| 151 | k[1] = mem.readIntSliceLittle(u32, key[4..8]); | 150 | k[1] = mem.readIntLittle(u32, key[4..8]); |
| 152 | k[2] = mem.readIntSliceLittle(u32, key[8..12]); | 151 | k[2] = mem.readIntLittle(u32, key[8..12]); |
| 153 | k[3] = mem.readIntSliceLittle(u32, key[12..16]); | 152 | k[3] = mem.readIntLittle(u32, key[12..16]); |
| 154 | k[4] = mem.readIntSliceLittle(u32, key[16..20]); | 153 | k[4] = mem.readIntLittle(u32, key[16..20]); |
| 155 | k[5] = mem.readIntSliceLittle(u32, key[20..24]); | 154 | k[5] = mem.readIntLittle(u32, key[20..24]); |
| 156 | k[6] = mem.readIntSliceLittle(u32, key[24..28]); | 155 | k[6] = mem.readIntLittle(u32, key[24..28]); |
| 157 | k[7] = mem.readIntSliceLittle(u32, key[28..32]); | 156 | k[7] = mem.readIntLittle(u32, key[28..32]); |
| 158 | 157 | ||
| 159 | c[0] = @truncate(u32, counter); | 158 | c[0] = @truncate(u32, counter); |
| 160 | c[1] = @truncate(u32, counter >> 32); | 159 | c[1] = @truncate(u32, counter >> 32); |
| 161 | c[2] = mem.readIntSliceLittle(u32, nonce[0..4]); | 160 | c[2] = mem.readIntLittle(u32, nonce[0..4]); |
| 162 | c[3] = mem.readIntSliceLittle(u32, nonce[4..8]); | 161 | c[3] = mem.readIntLittle(u32, nonce[4..8]); |
| 163 | 162 | ||
| 164 | const block_size = (1 << 6); | 163 | const block_size = (1 << 6); |
| 165 | // The full block size is greater than the address space on a 32bit machine | 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,8 +462,8 @@ pub fn chacha20poly1305Seal(dst: []u8, plaintext: []const u8, data: []const u8, |
| 463 | mac.update(zeros[0..padding]); | 462 | mac.update(zeros[0..padding]); |
| 464 | } | 463 | } |
| 465 | var lens: [16]u8 = undefined; | 464 | var lens: [16]u8 = undefined; |
| 466 | mem.writeIntSliceLittle(u64, lens[0..8], data.len); | 465 | mem.writeIntLittle(u64, lens[0..8], data.len); |
| 467 | mem.writeIntSliceLittle(u64, lens[8..16], plaintext.len); | 466 | mem.writeIntLittle(u64, lens[8..16], plaintext.len); |
| 468 | mac.update(lens[0..]); | 467 | mac.update(lens[0..]); |
| 469 | mac.final(dst[plaintext.len..]); | 468 | mac.final(dst[plaintext.len..]); |
| 470 | } | 469 | } |
| ... | @@ -500,8 +499,8 @@ pub fn chacha20poly1305Open(dst: []u8, msgAndTag: []const u8, data: []const u8, | ... | @@ -500,8 +499,8 @@ pub fn chacha20poly1305Open(dst: []u8, msgAndTag: []const u8, data: []const u8, |
| 500 | mac.update(zeros[0..padding]); | 499 | mac.update(zeros[0..padding]); |
| 501 | } | 500 | } |
| 502 | var lens: [16]u8 = undefined; | 501 | var lens: [16]u8 = undefined; |
| 503 | mem.writeIntSliceLittle(u64, lens[0..8], data.len); | 502 | mem.writeIntLittle(u64, lens[0..8], data.len); |
| 504 | mem.writeIntSliceLittle(u64, lens[8..16], ciphertext.len); | 503 | mem.writeIntLittle(u64, lens[8..16], ciphertext.len); |
| 505 | mac.update(lens[0..]); | 504 | mac.update(lens[0..]); |
| 506 | var computedTag: [16]u8 = undefined; | 505 | var computedTag: [16]u8 = undefined; |
| 507 | mac.final(computedTag[0..]); | 506 | mac.final(computedTag[0..]); |
lib/std/crypto/md5.zig+1-2| ... | @@ -112,8 +112,7 @@ pub const Md5 = struct { | ... | @@ -112,8 +112,7 @@ pub const Md5 = struct { |
| 112 | d.round(d.buf[0..]); | 112 | d.round(d.buf[0..]); |
| 113 | 113 | ||
| 114 | for (d.s) |s, j| { | 114 | for (d.s) |s, j| { |
| 115 | // TODO https://github.com/ziglang/zig/issues/863 | 115 | mem.writeIntLittle(u32, out[4 * j ..][0..4], s); |
| 116 | mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s); | ||
| 117 | } | 116 | } |
| 118 | } | 117 | } |
| 119 | 118 |
lib/std/crypto/poly1305.zig+14-15| ... | @@ -3,11 +3,11 @@ | ... | @@ -3,11 +3,11 @@ |
| 3 | // https://monocypher.org/ | 3 | // https://monocypher.org/ |
| 4 | 4 | ||
| 5 | const std = @import("../std.zig"); | 5 | const std = @import("../std.zig"); |
| 6 | const builtin = @import("builtin"); | 6 | const builtin = std.builtin; |
| 7 | 7 | ||
| 8 | const Endian = builtin.Endian; | 8 | const Endian = builtin.Endian; |
| 9 | const readIntSliceLittle = std.mem.readIntSliceLittle; | 9 | const readIntLittle = std.mem.readIntLittle; |
| 10 | const writeIntSliceLittle = std.mem.writeIntSliceLittle; | 10 | const writeIntLittle = std.mem.writeIntLittle; |
| 11 | 11 | ||
| 12 | pub const Poly1305 = struct { | 12 | pub const Poly1305 = struct { |
| 13 | const Self = @This(); | 13 | const Self = @This(); |
| ... | @@ -59,19 +59,19 @@ pub const Poly1305 = struct { | ... | @@ -59,19 +59,19 @@ pub const Poly1305 = struct { |
| 59 | { | 59 | { |
| 60 | var i: usize = 0; | 60 | var i: usize = 0; |
| 61 | while (i < 1) : (i += 1) { | 61 | while (i < 1) : (i += 1) { |
| 62 | ctx.r[0] = readIntSliceLittle(u32, key[0..4]) & 0x0fffffff; | 62 | ctx.r[0] = readIntLittle(u32, key[0..4]) & 0x0fffffff; |
| 63 | } | 63 | } |
| 64 | } | 64 | } |
| 65 | { | 65 | { |
| 66 | var i: usize = 1; | 66 | var i: usize = 1; |
| 67 | while (i < 4) : (i += 1) { | 67 | while (i < 4) : (i += 1) { |
| 68 | ctx.r[i] = readIntSliceLittle(u32, key[i * 4 .. i * 4 + 4]) & 0x0ffffffc; | 68 | ctx.r[i] = readIntLittle(u32, key[i * 4 ..][0..4]) & 0x0ffffffc; |
| 69 | } | 69 | } |
| 70 | } | 70 | } |
| 71 | { | 71 | { |
| 72 | var i: usize = 0; | 72 | var i: usize = 0; |
| 73 | while (i < 4) : (i += 1) { | 73 | while (i < 4) : (i += 1) { |
| 74 | ctx.pad[i] = readIntSliceLittle(u32, key[i * 4 + 16 .. i * 4 + 16 + 4]); | 74 | ctx.pad[i] = readIntLittle(u32, key[i * 4 + 16 ..][0..4]); |
| 75 | } | 75 | } |
| 76 | } | 76 | } |
| 77 | 77 | ||
| ... | @@ -168,10 +168,10 @@ pub const Poly1305 = struct { | ... | @@ -168,10 +168,10 @@ pub const Poly1305 = struct { |
| 168 | const nb_blocks = nmsg.len >> 4; | 168 | const nb_blocks = nmsg.len >> 4; |
| 169 | var i: usize = 0; | 169 | var i: usize = 0; |
| 170 | while (i < nb_blocks) : (i += 1) { | 170 | while (i < nb_blocks) : (i += 1) { |
| 171 | ctx.c[0] = readIntSliceLittle(u32, nmsg[0..4]); | 171 | ctx.c[0] = readIntLittle(u32, nmsg[0..4]); |
| 172 | ctx.c[1] = readIntSliceLittle(u32, nmsg[4..8]); | 172 | ctx.c[1] = readIntLittle(u32, nmsg[4..8]); |
| 173 | ctx.c[2] = readIntSliceLittle(u32, nmsg[8..12]); | 173 | ctx.c[2] = readIntLittle(u32, nmsg[8..12]); |
| 174 | ctx.c[3] = readIntSliceLittle(u32, nmsg[12..16]); | 174 | ctx.c[3] = readIntLittle(u32, nmsg[12..16]); |
| 175 | polyBlock(ctx); | 175 | polyBlock(ctx); |
| 176 | nmsg = nmsg[16..]; | 176 | nmsg = nmsg[16..]; |
| 177 | } | 177 | } |
| ... | @@ -210,11 +210,10 @@ pub const Poly1305 = struct { | ... | @@ -210,11 +210,10 @@ pub const Poly1305 = struct { |
| 210 | const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000 | 210 | const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000 |
| 211 | const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000 | 211 | const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000 |
| 212 | 212 | ||
| 213 | // TODO https://github.com/ziglang/zig/issues/863 | 213 | writeIntLittle(u32, out[0..4], @truncate(u32, uu0)); |
| 214 | writeIntSliceLittle(u32, out[0..], @truncate(u32, uu0)); | 214 | writeIntLittle(u32, out[4..8], @truncate(u32, uu1)); |
| 215 | writeIntSliceLittle(u32, out[4..], @truncate(u32, uu1)); | 215 | writeIntLittle(u32, out[8..12], @truncate(u32, uu2)); |
| 216 | writeIntSliceLittle(u32, out[8..], @truncate(u32, uu2)); | 216 | writeIntLittle(u32, out[12..16], @truncate(u32, uu3)); |
| 217 | writeIntSliceLittle(u32, out[12..], @truncate(u32, uu3)); | ||
| 218 | 217 | ||
| 219 | ctx.secureZero(); | 218 | ctx.secureZero(); |
| 220 | } | 219 | } |
lib/std/crypto/sha1.zig+1-2| ... | @@ -109,8 +109,7 @@ pub const Sha1 = struct { | ... | @@ -109,8 +109,7 @@ pub const Sha1 = struct { |
| 109 | d.round(d.buf[0..]); | 109 | d.round(d.buf[0..]); |
| 110 | 110 | ||
| 111 | for (d.s) |s, j| { | 111 | for (d.s) |s, j| { |
| 112 | // TODO https://github.com/ziglang/zig/issues/863 | 112 | mem.writeIntBig(u32, out[4 * j ..][0..4], s); |
| 113 | mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 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,8 +167,7 @@ fn Sha2_32(comptime params: Sha2Params32) type { |
| 167 | const rr = d.s[0 .. params.out_len / 32]; | 167 | const rr = d.s[0 .. params.out_len / 32]; |
| 168 | 168 | ||
| 169 | for (rr) |s, j| { | 169 | for (rr) |s, j| { |
| 170 | // TODO https://github.com/ziglang/zig/issues/863 | 170 | mem.writeIntBig(u32, out[4 * j ..][0..4], s); |
| 171 | mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s); | ||
| 172 | } | 171 | } |
| 173 | } | 172 | } |
| 174 | 173 | ||
| ... | @@ -509,8 +508,7 @@ fn Sha2_64(comptime params: Sha2Params64) type { | ... | @@ -509,8 +508,7 @@ fn Sha2_64(comptime params: Sha2Params64) type { |
| 509 | const rr = d.s[0 .. params.out_len / 64]; | 508 | const rr = d.s[0 .. params.out_len / 64]; |
| 510 | 509 | ||
| 511 | for (rr) |s, j| { | 510 | for (rr) |s, j| { |
| 512 | // TODO https://github.com/ziglang/zig/issues/863 | 511 | mem.writeIntBig(u64, out[8 * j ..][0..8], s); |
| 513 | mem.writeIntSliceBig(u64, out[8 * j .. 8 * j + 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,7 +120,7 @@ fn keccak_f(comptime F: usize, d: []u8) void { |
| 120 | var c = [_]u64{0} ** 5; | 120 | var c = [_]u64{0} ** 5; |
| 121 | 121 | ||
| 122 | for (s) |*r, i| { | 122 | for (s) |*r, i| { |
| 123 | r.* = mem.readIntSliceLittle(u64, d[8 * i .. 8 * i + 8]); | 123 | r.* = mem.readIntLittle(u64, d[8 * i ..][0..8]); |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | comptime var x: usize = 0; | 126 | comptime var x: usize = 0; |
| ... | @@ -167,8 +167,7 @@ fn keccak_f(comptime F: usize, d: []u8) void { | ... | @@ -167,8 +167,7 @@ fn keccak_f(comptime F: usize, d: []u8) void { |
| 167 | } | 167 | } |
| 168 | 168 | ||
| 169 | for (s) |r, i| { | 169 | for (s) |r, i| { |
| 170 | // TODO https://github.com/ziglang/zig/issues/863 | 170 | mem.writeIntLittle(u64, d[8 * i ..][0..8], r); |
| 171 | mem.writeIntSliceLittle(u64, d[8 * i .. 8 * i + 8], r); | ||
| 172 | } | 171 | } |
| 173 | } | 172 | } |
| 174 | 173 |
lib/std/crypto/x25519.zig+20-21| ... | @@ -7,8 +7,8 @@ const builtin = @import("builtin"); | ... | @@ -7,8 +7,8 @@ const builtin = @import("builtin"); |
| 7 | const fmt = std.fmt; | 7 | const fmt = std.fmt; |
| 8 | 8 | ||
| 9 | const Endian = builtin.Endian; | 9 | const Endian = builtin.Endian; |
| 10 | const readIntSliceLittle = std.mem.readIntSliceLittle; | 10 | const readIntLittle = std.mem.readIntLittle; |
| 11 | const writeIntSliceLittle = std.mem.writeIntSliceLittle; | 11 | const writeIntLittle = std.mem.writeIntLittle; |
| 12 | 12 | ||
| 13 | // Based on Supercop's ref10 implementation. | 13 | // Based on Supercop's ref10 implementation. |
| 14 | pub const X25519 = struct { | 14 | pub const X25519 = struct { |
| ... | @@ -255,16 +255,16 @@ const Fe = struct { | ... | @@ -255,16 +255,16 @@ const Fe = struct { |
| 255 | 255 | ||
| 256 | var t: [10]i64 = undefined; | 256 | var t: [10]i64 = undefined; |
| 257 | 257 | ||
| 258 | t[0] = readIntSliceLittle(u32, s[0..4]); | 258 | t[0] = readIntLittle(u32, s[0..4]); |
| 259 | t[1] = @as(u32, readIntSliceLittle(u24, s[4..7])) << 6; | 259 | t[1] = @as(u32, readIntLittle(u24, s[4..7])) << 6; |
| 260 | t[2] = @as(u32, readIntSliceLittle(u24, s[7..10])) << 5; | 260 | t[2] = @as(u32, readIntLittle(u24, s[7..10])) << 5; |
| 261 | t[3] = @as(u32, readIntSliceLittle(u24, s[10..13])) << 3; | 261 | t[3] = @as(u32, readIntLittle(u24, s[10..13])) << 3; |
| 262 | t[4] = @as(u32, readIntSliceLittle(u24, s[13..16])) << 2; | 262 | t[4] = @as(u32, readIntLittle(u24, s[13..16])) << 2; |
| 263 | t[5] = readIntSliceLittle(u32, s[16..20]); | 263 | t[5] = readIntLittle(u32, s[16..20]); |
| 264 | t[6] = @as(u32, readIntSliceLittle(u24, s[20..23])) << 7; | 264 | t[6] = @as(u32, readIntLittle(u24, s[20..23])) << 7; |
| 265 | t[7] = @as(u32, readIntSliceLittle(u24, s[23..26])) << 5; | 265 | t[7] = @as(u32, readIntLittle(u24, s[23..26])) << 5; |
| 266 | t[8] = @as(u32, readIntSliceLittle(u24, s[26..29])) << 4; | 266 | t[8] = @as(u32, readIntLittle(u24, s[26..29])) << 4; |
| 267 | t[9] = (@as(u32, readIntSliceLittle(u24, s[29..32])) & 0x7fffff) << 2; | 267 | t[9] = (@as(u32, readIntLittle(u24, s[29..32])) & 0x7fffff) << 2; |
| 268 | 268 | ||
| 269 | carry1(h, t[0..]); | 269 | carry1(h, t[0..]); |
| 270 | } | 270 | } |
| ... | @@ -544,15 +544,14 @@ const Fe = struct { | ... | @@ -544,15 +544,14 @@ const Fe = struct { |
| 544 | ut[i] = @bitCast(u32, @intCast(i32, t[i])); | 544 | ut[i] = @bitCast(u32, @intCast(i32, t[i])); |
| 545 | } | 545 | } |
| 546 | 546 | ||
| 547 | // TODO https://github.com/ziglang/zig/issues/863 | 547 | writeIntLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26)); |
| 548 | writeIntSliceLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26)); | 548 | writeIntLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19)); |
| 549 | writeIntSliceLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19)); | 549 | writeIntLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13)); |
| 550 | writeIntSliceLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13)); | 550 | writeIntLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6)); |
| 551 | writeIntSliceLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6)); | 551 | writeIntLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25)); |
| 552 | writeIntSliceLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25)); | 552 | writeIntLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19)); |
| 553 | writeIntSliceLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19)); | 553 | writeIntLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12)); |
| 554 | writeIntSliceLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12)); | 554 | writeIntLittle(u32, s[28..32], (ut[8] >> 20) | (ut[9] << 6)); |
| 555 | writeIntSliceLittle(u32, s[28..], (ut[8] >> 20) | (ut[9] << 6)); | ||
| 556 | 555 | ||
| 557 | std.mem.secureZero(i64, t[0..]); | 556 | std.mem.secureZero(i64, t[0..]); |
| 558 | } | 557 | } |
lib/std/fmt.zig+2-1| ... | @@ -1223,7 +1223,8 @@ test "slice" { | ... | @@ -1223,7 +1223,8 @@ test "slice" { |
| 1223 | try testFmt("slice: abc\n", "slice: {}\n", .{value}); | 1223 | try testFmt("slice: abc\n", "slice: {}\n", .{value}); |
| 1224 | } | 1224 | } |
| 1225 | { | 1225 | { |
| 1226 | const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[0..0]; | 1226 | var runtime_zero: usize = 0; |
| 1227 | const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[runtime_zero..runtime_zero]; | ||
| 1227 | try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value}); | 1228 | try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value}); |
| 1228 | } | 1229 | } |
| 1229 | 1230 |
lib/std/fs.zig+231-294| ... | @@ -81,134 +81,74 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: | ... | @@ -81,134 +81,74 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: |
| 81 | } | 81 | } |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | // TODO fix enum literal not casting to error union | 84 | pub const PrevStatus = enum { |
| 85 | const PrevStatus = enum { | ||
| 86 | stale, | 85 | stale, |
| 87 | fresh, | 86 | fresh, |
| 88 | }; | 87 | }; |
| 89 | 88 | ||
| 90 | pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus { | 89 | pub const CopyFileOptions = struct { |
| 91 | return updateFileMode(source_path, dest_path, null); | 90 | /// When this is `null` the mode is copied from the source file. |
| 92 | } | 91 | override_mode: ?File.Mode = null, |
| 92 | }; | ||
| 93 | 93 | ||
| 94 | /// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing. | 94 | /// Same as `Dir.updateFile`, except asserts that both `source_path` and `dest_path` |
| 95 | /// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime, | 95 | /// are absolute. See `Dir.updateFile` for a function that operates on both |
| 96 | /// atime, and mode of the source file so that the next call to `updateFile` will not need a copy. | 96 | /// absolute and relative paths. |
| 97 | /// Returns the previous status of the file before updating. | 97 | pub fn updateFileAbsolute( |
| 98 | /// If any of the directories do not exist for dest_path, they are created. | 98 | source_path: []const u8, |
| 99 | /// TODO rework this to integrate with Dir | 99 | dest_path: []const u8, |
| 100 | pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !PrevStatus { | 100 | args: CopyFileOptions, |
| 101 | ) !PrevStatus { | ||
| 102 | assert(path.isAbsolute(source_path)); | ||
| 103 | assert(path.isAbsolute(dest_path)); | ||
| 101 | const my_cwd = cwd(); | 104 | const my_cwd = cwd(); |
| 102 | 105 | return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, args); | |
| 103 | var src_file = try my_cwd.openFile(source_path, .{}); | ||
| 104 | defer src_file.close(); | ||
| 105 | |||
| 106 | const src_stat = try src_file.stat(); | ||
| 107 | check_dest_stat: { | ||
| 108 | const dest_stat = blk: { | ||
| 109 | var dest_file = my_cwd.openFile(dest_path, .{}) catch |err| switch (err) { | ||
| 110 | error.FileNotFound => break :check_dest_stat, | ||
| 111 | else => |e| return e, | ||
| 112 | }; | ||
| 113 | defer dest_file.close(); | ||
| 114 | |||
| 115 | break :blk try dest_file.stat(); | ||
| 116 | }; | ||
| 117 | |||
| 118 | if (src_stat.size == dest_stat.size and | ||
| 119 | src_stat.mtime == dest_stat.mtime and | ||
| 120 | src_stat.mode == dest_stat.mode) | ||
| 121 | { | ||
| 122 | return PrevStatus.fresh; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | const actual_mode = mode orelse src_stat.mode; | ||
| 126 | |||
| 127 | if (path.dirname(dest_path)) |dirname| { | ||
| 128 | try cwd().makePath(dirname); | ||
| 129 | } | ||
| 130 | |||
| 131 | var atomic_file = try AtomicFile.init(dest_path, actual_mode); | ||
| 132 | defer atomic_file.deinit(); | ||
| 133 | |||
| 134 | try atomic_file.file.writeFileAll(src_file, .{ .in_len = src_stat.size }); | ||
| 135 | try atomic_file.file.updateTimes(src_stat.atime, src_stat.mtime); | ||
| 136 | try atomic_file.finish(); | ||
| 137 | return PrevStatus.stale; | ||
| 138 | } | 106 | } |
| 139 | 107 | ||
| 140 | /// Guaranteed to be atomic. | 108 | /// Same as `Dir.copyFile`, except asserts that both `source_path` and `dest_path` |
| 141 | /// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available, | 109 | /// are absolute. See `Dir.copyFile` for a function that operates on both |
| 142 | /// there is a possibility of power loss or application termination leaving temporary files present | 110 | /// absolute and relative paths. |
| 143 | /// in the same directory as dest_path. | 111 | pub fn copyFileAbsolute(source_path: []const u8, dest_path: []const u8, args: CopyFileOptions) !void { |
| 144 | /// Destination file will have the same mode as the source file. | 112 | assert(path.isAbsolute(source_path)); |
| 145 | /// TODO rework this to integrate with Dir | 113 | assert(path.isAbsolute(dest_path)); |
| 146 | pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void { | 114 | const my_cwd = cwd(); |
| 147 | var in_file = try cwd().openFile(source_path, .{}); | 115 | return Dir.copyFile(my_cwd, source_path, my_cwd, dest_path, args); |
| 148 | defer in_file.close(); | ||
| 149 | |||
| 150 | const stat = try in_file.stat(); | ||
| 151 | |||
| 152 | var atomic_file = try AtomicFile.init(dest_path, stat.mode); | ||
| 153 | defer atomic_file.deinit(); | ||
| 154 | |||
| 155 | try atomic_file.file.writeFileAll(in_file, .{ .in_len = stat.size }); | ||
| 156 | return atomic_file.finish(); | ||
| 157 | } | ||
| 158 | |||
| 159 | /// Guaranteed to be atomic. | ||
| 160 | /// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available, | ||
| 161 | /// there is a possibility of power loss or application termination leaving temporary files present | ||
| 162 | /// in the same directory as dest_path. | ||
| 163 | /// TODO rework this to integrate with Dir | ||
| 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(); | ||
| 173 | } | 116 | } |
| 174 | 117 | ||
| 175 | /// TODO update this API to avoid a getrandom syscall for every operation. It | 118 | /// TODO update this API to avoid a getrandom syscall for every operation. |
| 176 | /// should accept a random interface. | ||
| 177 | /// TODO rework this to integrate with Dir | ||
| 178 | pub const AtomicFile = struct { | 119 | pub const AtomicFile = struct { |
| 179 | file: File, | 120 | file: File, |
| 180 | tmp_path_buf: [MAX_PATH_BYTES]u8, | 121 | tmp_path_buf: [MAX_PATH_BYTES - 1:0]u8, |
| 181 | dest_path: []const u8, | 122 | dest_path: []const u8, |
| 182 | finished: bool, | 123 | file_open: bool, |
| 124 | file_exists: bool, | ||
| 125 | dir: Dir, | ||
| 183 | 126 | ||
| 184 | const InitError = File.OpenError; | 127 | const InitError = File.OpenError; |
| 185 | 128 | ||
| 186 | /// dest_path must remain valid for the lifetime of AtomicFile | 129 | /// TODO rename this. Callers should go through Dir API |
| 187 | /// call finish to atomically replace dest_path with contents | 130 | pub fn init2(dest_path: []const u8, mode: File.Mode, dir: Dir) InitError!AtomicFile { |
| 188 | pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile { | ||
| 189 | const dirname = path.dirname(dest_path); | 131 | const dirname = path.dirname(dest_path); |
| 190 | var rand_buf: [12]u8 = undefined; | 132 | var rand_buf: [12]u8 = undefined; |
| 191 | const dirname_component_len = if (dirname) |d| d.len + 1 else 0; | 133 | const dirname_component_len = if (dirname) |d| d.len + 1 else 0; |
| 192 | const encoded_rand_len = comptime base64.Base64Encoder.calcSize(rand_buf.len); | 134 | const encoded_rand_len = comptime base64.Base64Encoder.calcSize(rand_buf.len); |
| 193 | const tmp_path_len = dirname_component_len + encoded_rand_len; | 135 | const tmp_path_len = dirname_component_len + encoded_rand_len; |
| 194 | var tmp_path_buf: [MAX_PATH_BYTES]u8 = undefined; | 136 | var tmp_path_buf: [MAX_PATH_BYTES - 1:0]u8 = undefined; |
| 195 | if (tmp_path_len >= tmp_path_buf.len) return error.NameTooLong; | 137 | if (tmp_path_len > tmp_path_buf.len) return error.NameTooLong; |
| 196 | 138 | ||
| 197 | if (dirname) |dir| { | 139 | if (dirname) |dn| { |
| 198 | mem.copy(u8, tmp_path_buf[0..], dir); | 140 | mem.copy(u8, tmp_path_buf[0..], dn); |
| 199 | tmp_path_buf[dir.len] = path.sep; | 141 | tmp_path_buf[dn.len] = path.sep; |
| 200 | } | 142 | } |
| 201 | 143 | ||
| 202 | tmp_path_buf[tmp_path_len] = 0; | 144 | tmp_path_buf[tmp_path_len] = 0; |
| 203 | const tmp_path_slice = tmp_path_buf[0..tmp_path_len :0]; | 145 | const tmp_path_slice = tmp_path_buf[0..tmp_path_len :0]; |
| 204 | 146 | ||
| 205 | const my_cwd = cwd(); | ||
| 206 | |||
| 207 | while (true) { | 147 | while (true) { |
| 208 | try crypto.randomBytes(rand_buf[0..]); | 148 | try crypto.randomBytes(rand_buf[0..]); |
| 209 | base64_encoder.encode(tmp_path_slice[dirname_component_len..tmp_path_len], &rand_buf); | 149 | base64_encoder.encode(tmp_path_slice[dirname_component_len..tmp_path_len], &rand_buf); |
| 210 | 150 | ||
| 211 | const file = my_cwd.createFileC( | 151 | const file = dir.createFileC( |
| 212 | tmp_path_slice, | 152 | tmp_path_slice, |
| 213 | .{ .mode = mode, .exclusive = true }, | 153 | .{ .mode = mode, .exclusive = true }, |
| 214 | ) catch |err| switch (err) { | 154 | ) catch |err| switch (err) { |
| ... | @@ -220,33 +160,46 @@ pub const AtomicFile = struct { | ... | @@ -220,33 +160,46 @@ pub const AtomicFile = struct { |
| 220 | .file = file, | 160 | .file = file, |
| 221 | .tmp_path_buf = tmp_path_buf, | 161 | .tmp_path_buf = tmp_path_buf, |
| 222 | .dest_path = dest_path, | 162 | .dest_path = dest_path, |
| 223 | .finished = false, | 163 | .file_open = true, |
| 164 | .file_exists = true, | ||
| 165 | .dir = dir, | ||
| 224 | }; | 166 | }; |
| 225 | } | 167 | } |
| 226 | } | 168 | } |
| 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 | /// always call deinit, even after successful finish() | 175 | /// always call deinit, even after successful finish() |
| 229 | pub fn deinit(self: *AtomicFile) void { | 176 | pub fn deinit(self: *AtomicFile) void { |
| 230 | if (!self.finished) { | 177 | if (self.file_open) { |
| 231 | self.file.close(); | 178 | self.file.close(); |
| 232 | cwd().deleteFileC(@ptrCast([*:0]u8, &self.tmp_path_buf)) catch {}; | 179 | self.file_open = false; |
| 233 | self.finished = true; | 180 | } |
| 181 | if (self.file_exists) { | ||
| 182 | self.dir.deleteFileC(&self.tmp_path_buf) catch {}; | ||
| 183 | self.file_exists = false; | ||
| 234 | } | 184 | } |
| 185 | self.* = undefined; | ||
| 235 | } | 186 | } |
| 236 | 187 | ||
| 237 | pub fn finish(self: *AtomicFile) !void { | 188 | pub fn finish(self: *AtomicFile) !void { |
| 238 | assert(!self.finished); | 189 | assert(self.file_exists); |
| 190 | if (self.file_open) { | ||
| 191 | self.file.close(); | ||
| 192 | self.file_open = false; | ||
| 193 | } | ||
| 239 | if (std.Target.current.os.tag == .windows) { | 194 | if (std.Target.current.os.tag == .windows) { |
| 240 | const dest_path_w = try os.windows.sliceToPrefixedFileW(self.dest_path); | 195 | const dest_path_w = try os.windows.sliceToPrefixedFileW(self.dest_path); |
| 241 | const tmp_path_w = try os.windows.cStrToPrefixedFileW(@ptrCast([*:0]u8, &self.tmp_path_buf)); | 196 | const tmp_path_w = try os.windows.cStrToPrefixedFileW(&self.tmp_path_buf); |
| 242 | self.file.close(); | 197 | try os.renameatW(self.dir.fd, &tmp_path_w, self.dir.fd, &dest_path_w, os.windows.TRUE); |
| 243 | self.finished = true; | 198 | self.file_exists = false; |
| 244 | return os.renameW(&tmp_path_w, &dest_path_w); | ||
| 245 | } else { | 199 | } else { |
| 246 | const dest_path_c = try os.toPosixPath(self.dest_path); | 200 | const dest_path_c = try os.toPosixPath(self.dest_path); |
| 247 | self.file.close(); | 201 | try os.renameatZ(self.dir.fd, &self.tmp_path_buf, self.dir.fd, &dest_path_c); |
| 248 | self.finished = true; | 202 | self.file_exists = false; |
| 249 | return os.renameC(@ptrCast([*:0]u8, &self.tmp_path_buf), &dest_path_c); | ||
| 250 | } | 203 | } |
| 251 | } | 204 | } |
| 252 | }; | 205 | }; |
| ... | @@ -274,44 +227,21 @@ pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void { | ... | @@ -274,44 +227,21 @@ pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void { |
| 274 | os.windows.CloseHandle(handle); | 227 | os.windows.CloseHandle(handle); |
| 275 | } | 228 | } |
| 276 | 229 | ||
| 277 | /// Returns `error.DirNotEmpty` if the directory is not empty. | 230 | /// Deprecated; use `Dir.deleteDir`. |
| 278 | /// To delete a directory recursively, see `deleteTree`. | ||
| 279 | pub fn deleteDir(dir_path: []const u8) !void { | 231 | pub fn deleteDir(dir_path: []const u8) !void { |
| 280 | return os.rmdir(dir_path); | 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 | pub fn deleteDirC(dir_path: [*:0]const u8) !void { | 236 | pub fn deleteDirC(dir_path: [*:0]const u8) !void { |
| 285 | return os.rmdirC(dir_path); | 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 | pub fn deleteDirW(dir_path: [*:0]const u16) !void { | 241 | pub fn deleteDirW(dir_path: [*:0]const u16) !void { |
| 290 | return os.rmdirW(dir_path); | 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 | pub const Dir = struct { | 245 | pub const Dir = struct { |
| 316 | fd: os.fd_t, | 246 | fd: os.fd_t, |
| 317 | 247 | ||
| ... | @@ -368,7 +298,7 @@ pub const Dir = struct { | ... | @@ -368,7 +298,7 @@ pub const Dir = struct { |
| 368 | if (rc == 0) return null; | 298 | if (rc == 0) return null; |
| 369 | if (rc < 0) { | 299 | if (rc < 0) { |
| 370 | switch (os.errno(rc)) { | 300 | switch (os.errno(rc)) { |
| 371 | os.EBADF => unreachable, | 301 | os.EBADF => unreachable, // Dir is invalid or was opened without iteration ability |
| 372 | os.EFAULT => unreachable, | 302 | os.EFAULT => unreachable, |
| 373 | os.ENOTDIR => unreachable, | 303 | os.ENOTDIR => unreachable, |
| 374 | os.EINVAL => unreachable, | 304 | os.EINVAL => unreachable, |
| ... | @@ -411,13 +341,13 @@ pub const Dir = struct { | ... | @@ -411,13 +341,13 @@ pub const Dir = struct { |
| 411 | if (self.index >= self.end_index) { | 341 | if (self.index >= self.end_index) { |
| 412 | const rc = os.system.getdirentries( | 342 | const rc = os.system.getdirentries( |
| 413 | self.dir.fd, | 343 | self.dir.fd, |
| 414 | self.buf[0..].ptr, | 344 | &self.buf, |
| 415 | self.buf.len, | 345 | self.buf.len, |
| 416 | &self.seek, | 346 | &self.seek, |
| 417 | ); | 347 | ); |
| 418 | switch (os.errno(rc)) { | 348 | switch (os.errno(rc)) { |
| 419 | 0 => {}, | 349 | 0 => {}, |
| 420 | os.EBADF => unreachable, | 350 | os.EBADF => unreachable, // Dir is invalid or was opened without iteration ability |
| 421 | os.EFAULT => unreachable, | 351 | os.EFAULT => unreachable, |
| 422 | os.ENOTDIR => unreachable, | 352 | os.ENOTDIR => unreachable, |
| 423 | os.EINVAL => unreachable, | 353 | os.EINVAL => unreachable, |
| ... | @@ -473,7 +403,7 @@ pub const Dir = struct { | ... | @@ -473,7 +403,7 @@ pub const Dir = struct { |
| 473 | const rc = os.linux.getdents64(self.dir.fd, &self.buf, self.buf.len); | 403 | const rc = os.linux.getdents64(self.dir.fd, &self.buf, self.buf.len); |
| 474 | switch (os.linux.getErrno(rc)) { | 404 | switch (os.linux.getErrno(rc)) { |
| 475 | 0 => {}, | 405 | 0 => {}, |
| 476 | os.EBADF => unreachable, | 406 | os.EBADF => unreachable, // Dir is invalid or was opened without iteration ability |
| 477 | os.EFAULT => unreachable, | 407 | os.EFAULT => unreachable, |
| 478 | os.ENOTDIR => unreachable, | 408 | os.ENOTDIR => unreachable, |
| 479 | os.EINVAL => unreachable, | 409 | os.EINVAL => unreachable, |
| ... | @@ -547,7 +477,8 @@ pub const Dir = struct { | ... | @@ -547,7 +477,8 @@ pub const Dir = struct { |
| 547 | self.end_index = io.Information; | 477 | self.end_index = io.Information; |
| 548 | switch (rc) { | 478 | switch (rc) { |
| 549 | .SUCCESS => {}, | 479 | .SUCCESS => {}, |
| 550 | .ACCESS_DENIED => return error.AccessDenied, | 480 | .ACCESS_DENIED => return error.AccessDenied, // Double-check that the Dir was opened with iteration ability |
| 481 | |||
| 551 | else => return w.unexpectedStatus(rc), | 482 | else => return w.unexpectedStatus(rc), |
| 552 | } | 483 | } |
| 553 | } | 484 | } |
| ... | @@ -625,16 +556,6 @@ pub const Dir = struct { | ... | @@ -625,16 +556,6 @@ pub const Dir = struct { |
| 625 | DeviceBusy, | 556 | DeviceBusy, |
| 626 | } || os.UnexpectedError; | 557 | } || os.UnexpectedError; |
| 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 | pub fn close(self: *Dir) void { | 559 | pub fn close(self: *Dir) void { |
| 639 | if (need_async_thread) { | 560 | if (need_async_thread) { |
| 640 | std.event.Loop.instance.?.close(self.fd); | 561 | std.event.Loop.instance.?.close(self.fd); |
| ... | @@ -694,7 +615,10 @@ pub const Dir = struct { | ... | @@ -694,7 +615,10 @@ pub const Dir = struct { |
| 694 | const access_mask = w.SYNCHRONIZE | | 615 | const access_mask = w.SYNCHRONIZE | |
| 695 | (if (flags.read) @as(u32, w.GENERIC_READ) else 0) | | 616 | (if (flags.read) @as(u32, w.GENERIC_READ) else 0) | |
| 696 | (if (flags.write) @as(u32, w.GENERIC_WRITE) else 0); | 617 | (if (flags.write) @as(u32, w.GENERIC_WRITE) else 0); |
| 697 | return self.openFileWindows(sub_path_w, access_mask, w.FILE_OPEN); | 618 | return @as(File, .{ |
| 619 | .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, w.FILE_OPEN), | ||
| 620 | .io_mode = .blocking, | ||
| 621 | }); | ||
| 698 | } | 622 | } |
| 699 | 623 | ||
| 700 | /// Creates, opens, or overwrites a file with write access. | 624 | /// Creates, opens, or overwrites a file with write access. |
| ... | @@ -739,7 +663,10 @@ pub const Dir = struct { | ... | @@ -739,7 +663,10 @@ pub const Dir = struct { |
| 739 | @as(u32, w.FILE_OVERWRITE_IF) | 663 | @as(u32, w.FILE_OVERWRITE_IF) |
| 740 | else | 664 | else |
| 741 | @as(u32, w.FILE_OPEN_IF); | 665 | @as(u32, w.FILE_OPEN_IF); |
| 742 | return self.openFileWindows(sub_path_w, access_mask, creation); | 666 | return @as(File, .{ |
| 667 | .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, creation), | ||
| 668 | .io_mode = .blocking, | ||
| 669 | }); | ||
| 743 | } | 670 | } |
| 744 | 671 | ||
| 745 | /// Deprecated; call `openFile` directly. | 672 | /// Deprecated; call `openFile` directly. |
| ... | @@ -757,72 +684,6 @@ pub const Dir = struct { | ... | @@ -757,72 +684,6 @@ pub const Dir = struct { |
| 757 | return self.openFileW(sub_path, .{}); | 684 | return self.openFileW(sub_path, .{}); |
| 758 | } | 685 | } |
| 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 | pub fn makeDir(self: Dir, sub_path: []const u8) !void { | 687 | pub fn makeDir(self: Dir, sub_path: []const u8) !void { |
| 827 | try os.mkdirat(self.fd, sub_path, default_new_dir_mode); | 688 | try os.mkdirat(self.fd, sub_path, default_new_dir_mode); |
| 828 | } | 689 | } |
| ... | @@ -881,77 +742,61 @@ pub const Dir = struct { | ... | @@ -881,77 +742,61 @@ pub const Dir = struct { |
| 881 | try os.fchdir(self.fd); | 742 | try os.fchdir(self.fd); |
| 882 | } | 743 | } |
| 883 | 744 | ||
| 884 | /// Deprecated; call `openDirList` directly. | 745 | pub const OpenDirOptions = struct { |
| 885 | pub fn openDir(self: Dir, sub_path: []const u8) OpenError!Dir { | 746 | /// `true` means the opened directory can be used as the `Dir` parameter |
| 886 | return self.openDirList(sub_path); | 747 | /// for functions which operate based on an open directory handle. When `false`, |
| 887 | } | 748 | /// such operations are Illegal Behavior. |
| 888 | 749 | access_sub_paths: bool = true, | |
| 889 | /// Deprecated; call `openDirListC` directly. | ||
| 890 | pub fn openDirC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir { | ||
| 891 | return self.openDirListC(sub_path_c); | ||
| 892 | } | ||
| 893 | 750 | ||
| 894 | /// Opens a directory at the given path with the ability to access subpaths | 751 | /// `true` means the opened directory can be scanned for the files and sub-directories |
| 895 | /// of the result. Calling `iterate` on the result is illegal behavior; to | 752 | /// of the result. It means the `iterate` function can be called. |
| 896 | /// list the contents of a directory, open it with `openDirList`. | 753 | iterate: bool = false, |
| 897 | /// | 754 | }; |
| 898 | /// Call `close` on the result when done. | ||
| 899 | /// | ||
| 900 | /// Asserts that the path parameter has no null bytes. | ||
| 901 | pub fn openDirTraverse(self: Dir, sub_path: []const u8) OpenError!Dir { | ||
| 902 | if (builtin.os.tag == .windows) { | ||
| 903 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); | ||
| 904 | return self.openDirTraverseW(&sub_path_w); | ||
| 905 | } | ||
| 906 | |||
| 907 | const sub_path_c = try os.toPosixPath(sub_path); | ||
| 908 | return self.openDirTraverseC(&sub_path_c); | ||
| 909 | } | ||
| 910 | 755 | ||
| 911 | /// Opens a directory at the given path with the ability to access subpaths and list contents | 756 | /// Opens a directory at the given path. The directory is a system resource that remains |
| 912 | /// of the result. If the ability to list contents is unneeded, `openDirTraverse` acts the | 757 | /// open until `close` is called on the result. |
| 913 | /// same and may be more efficient. | ||
| 914 | /// | ||
| 915 | /// Call `close` on the result when done. | ||
| 916 | /// | 758 | /// |
| 917 | /// Asserts that the path parameter has no null bytes. | 759 | /// Asserts that the path parameter has no null bytes. |
| 918 | pub fn openDirList(self: Dir, sub_path: []const u8) OpenError!Dir { | 760 | pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir { |
| 919 | if (builtin.os.tag == .windows) { | 761 | if (builtin.os.tag == .windows) { |
| 920 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); | 762 | const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); |
| 921 | return self.openDirListW(&sub_path_w); | 763 | return self.openDirW(&sub_path_w, args); |
| 764 | } else { | ||
| 765 | const sub_path_c = try os.toPosixPath(sub_path); | ||
| 766 | return self.openDirC(&sub_path_c, args); | ||
| 922 | } | 767 | } |
| 923 | |||
| 924 | const sub_path_c = try os.toPosixPath(sub_path); | ||
| 925 | return self.openDirListC(&sub_path_c); | ||
| 926 | } | 768 | } |
| 927 | 769 | ||
| 928 | /// Same as `openDirTraverse` except the parameter is null-terminated. | 770 | /// Same as `openDir` except the parameter is null-terminated. |
| 929 | pub fn openDirTraverseC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir { | 771 | pub fn openDirC(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions) OpenError!Dir { |
| 930 | if (builtin.os.tag == .windows) { | 772 | if (builtin.os.tag == .windows) { |
| 931 | const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); | 773 | const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); |
| 932 | return self.openDirTraverseW(&sub_path_w); | 774 | return self.openDirW(&sub_path_w, args); |
| 933 | } else { | 775 | } else if (!args.iterate) { |
| 934 | const O_PATH = if (@hasDecl(os, "O_PATH")) os.O_PATH else 0; | 776 | const O_PATH = if (@hasDecl(os, "O_PATH")) os.O_PATH else 0; |
| 935 | return self.openDirFlagsC(sub_path_c, os.O_RDONLY | os.O_CLOEXEC | O_PATH); | 777 | return self.openDirFlagsC(sub_path_c, os.O_DIRECTORY | os.O_RDONLY | os.O_CLOEXEC | O_PATH); |
| 778 | } else { | ||
| 779 | return self.openDirFlagsC(sub_path_c, os.O_DIRECTORY | os.O_RDONLY | os.O_CLOEXEC); | ||
| 936 | } | 780 | } |
| 937 | } | 781 | } |
| 938 | 782 | ||
| 939 | /// Same as `openDirList` except the parameter is null-terminated. | 783 | /// Same as `openDir` except the path parameter is WTF-16 encoded, NT-prefixed. |
| 940 | pub fn openDirListC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir { | 784 | /// This function asserts the target OS is Windows. |
| 941 | if (builtin.os.tag == .windows) { | 785 | pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) OpenError!Dir { |
| 942 | const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); | 786 | const w = os.windows; |
| 943 | return self.openDirListW(&sub_path_w); | 787 | // TODO remove some of these flags if args.access_sub_paths is false |
| 944 | } else { | 788 | const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | |
| 945 | return self.openDirFlagsC(sub_path_c, os.O_RDONLY | os.O_CLOEXEC); | 789 | w.SYNCHRONIZE | w.FILE_TRAVERSE; |
| 946 | } | 790 | const flags: u32 = if (args.iterate) base_flags | w.FILE_LIST_DIRECTORY else base_flags; |
| 791 | return self.openDirAccessMaskW(sub_path_w, flags); | ||
| 947 | } | 792 | } |
| 948 | 793 | ||
| 794 | /// `flags` must contain `os.O_DIRECTORY`. | ||
| 949 | fn openDirFlagsC(self: Dir, sub_path_c: [*:0]const u8, flags: u32) OpenError!Dir { | 795 | fn openDirFlagsC(self: Dir, sub_path_c: [*:0]const u8, flags: u32) OpenError!Dir { |
| 950 | const os_flags = flags | os.O_DIRECTORY; | ||
| 951 | const result = if (need_async_thread) | 796 | const result = if (need_async_thread) |
| 952 | std.event.Loop.instance.?.openatZ(self.fd, sub_path_c, os_flags, 0) | 797 | std.event.Loop.instance.?.openatZ(self.fd, sub_path_c, flags, 0) |
| 953 | else | 798 | else |
| 954 | os.openatC(self.fd, sub_path_c, os_flags, 0); | 799 | os.openatC(self.fd, sub_path_c, flags, 0); |
| 955 | const fd = result catch |err| switch (err) { | 800 | const fd = result catch |err| switch (err) { |
| 956 | error.FileTooBig => unreachable, // can't happen for directories | 801 | error.FileTooBig => unreachable, // can't happen for directories |
| 957 | error.IsDir => unreachable, // we're providing O_DIRECTORY | 802 | error.IsDir => unreachable, // we're providing O_DIRECTORY |
| ... | @@ -962,22 +807,6 @@ pub const Dir = struct { | ... | @@ -962,22 +807,6 @@ pub const Dir = struct { |
| 962 | return Dir{ .fd = fd }; | 807 | return Dir{ .fd = fd }; |
| 963 | } | 808 | } |
| 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 | fn openDirAccessMaskW(self: Dir, sub_path_w: [*:0]const u16, access_mask: u32) OpenError!Dir { | 810 | fn openDirAccessMaskW(self: Dir, sub_path_w: [*:0]const u16, access_mask: u32) OpenError!Dir { |
| 982 | const w = os.windows; | 811 | const w = os.windows; |
| 983 | 812 | ||
| ... | @@ -1198,7 +1027,7 @@ pub const Dir = struct { | ... | @@ -1198,7 +1027,7 @@ pub const Dir = struct { |
| 1198 | error.Unexpected, | 1027 | error.Unexpected, |
| 1199 | => |e| return e, | 1028 | => |e| return e, |
| 1200 | } | 1029 | } |
| 1201 | var dir = self.openDirList(sub_path) catch |err| switch (err) { | 1030 | var dir = self.openDir(sub_path, .{ .iterate = true }) catch |err| switch (err) { |
| 1202 | error.NotDir => { | 1031 | error.NotDir => { |
| 1203 | if (got_access_denied) { | 1032 | if (got_access_denied) { |
| 1204 | return error.AccessDenied; | 1033 | return error.AccessDenied; |
| ... | @@ -1231,7 +1060,6 @@ pub const Dir = struct { | ... | @@ -1231,7 +1060,6 @@ pub const Dir = struct { |
| 1231 | 1060 | ||
| 1232 | var dir_name_buf: [MAX_PATH_BYTES]u8 = undefined; | 1061 | var dir_name_buf: [MAX_PATH_BYTES]u8 = undefined; |
| 1233 | var dir_name: []const u8 = sub_path; | 1062 | var dir_name: []const u8 = sub_path; |
| 1234 | var parent_dir = self; | ||
| 1235 | 1063 | ||
| 1236 | // Here we must avoid recursion, in order to provide O(1) memory guarantee of this function. | 1064 | // Here we must avoid recursion, in order to provide O(1) memory guarantee of this function. |
| 1237 | // Go through each entry and if it is not a directory, delete it. If it is a directory, | 1065 | // Go through each entry and if it is not a directory, delete it. If it is a directory, |
| ... | @@ -1263,7 +1091,7 @@ pub const Dir = struct { | ... | @@ -1263,7 +1091,7 @@ pub const Dir = struct { |
| 1263 | => |e| return e, | 1091 | => |e| return e, |
| 1264 | } | 1092 | } |
| 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 | error.NotDir => { | 1095 | error.NotDir => { |
| 1268 | if (got_access_denied) { | 1096 | if (got_access_denied) { |
| 1269 | return error.AccessDenied; | 1097 | return error.AccessDenied; |
| ... | @@ -1370,9 +1198,96 @@ pub const Dir = struct { | ... | @@ -1370,9 +1198,96 @@ pub const Dir = struct { |
| 1370 | pub fn accessW(self: Dir, sub_path_w: [*:0]const u16, flags: File.OpenFlags) AccessError!void { | 1198 | pub fn accessW(self: Dir, sub_path_w: [*:0]const u16, flags: File.OpenFlags) AccessError!void { |
| 1371 | return os.faccessatW(self.fd, sub_path_w, 0, 0); | 1199 | return os.faccessatW(self.fd, sub_path_w, 0, 0); |
| 1372 | } | 1200 | } |
| 1201 | |||
| 1202 | /// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing. | ||
| 1203 | /// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime, | ||
| 1204 | /// atime, and mode of the source file so that the next call to `updateFile` will not need a copy. | ||
| 1205 | /// Returns the previous status of the file before updating. | ||
| 1206 | /// If any of the directories do not exist for dest_path, they are created. | ||
| 1207 | pub fn updateFile( | ||
| 1208 | source_dir: Dir, | ||
| 1209 | source_path: []const u8, | ||
| 1210 | dest_dir: Dir, | ||
| 1211 | dest_path: []const u8, | ||
| 1212 | options: CopyFileOptions, | ||
| 1213 | ) !PrevStatus { | ||
| 1214 | var src_file = try source_dir.openFile(source_path, .{}); | ||
| 1215 | defer src_file.close(); | ||
| 1216 | |||
| 1217 | const src_stat = try src_file.stat(); | ||
| 1218 | const actual_mode = options.override_mode orelse src_stat.mode; | ||
| 1219 | check_dest_stat: { | ||
| 1220 | const dest_stat = blk: { | ||
| 1221 | var dest_file = dest_dir.openFile(dest_path, .{}) catch |err| switch (err) { | ||
| 1222 | error.FileNotFound => break :check_dest_stat, | ||
| 1223 | else => |e| return e, | ||
| 1224 | }; | ||
| 1225 | defer dest_file.close(); | ||
| 1226 | |||
| 1227 | break :blk try dest_file.stat(); | ||
| 1228 | }; | ||
| 1229 | |||
| 1230 | if (src_stat.size == dest_stat.size and | ||
| 1231 | src_stat.mtime == dest_stat.mtime and | ||
| 1232 | actual_mode == dest_stat.mode) | ||
| 1233 | { | ||
| 1234 | return PrevStatus.fresh; | ||
| 1235 | } | ||
| 1236 | } | ||
| 1237 | |||
| 1238 | if (path.dirname(dest_path)) |dirname| { | ||
| 1239 | try dest_dir.makePath(dirname); | ||
| 1240 | } | ||
| 1241 | |||
| 1242 | var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = actual_mode }); | ||
| 1243 | defer atomic_file.deinit(); | ||
| 1244 | |||
| 1245 | try atomic_file.file.writeFileAll(src_file, .{ .in_len = src_stat.size }); | ||
| 1246 | try atomic_file.file.updateTimes(src_stat.atime, src_stat.mtime); | ||
| 1247 | try atomic_file.finish(); | ||
| 1248 | return PrevStatus.stale; | ||
| 1249 | } | ||
| 1250 | |||
| 1251 | /// Guaranteed to be atomic. | ||
| 1252 | /// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available, | ||
| 1253 | /// there is a possibility of power loss or application termination leaving temporary files present | ||
| 1254 | /// in the same directory as dest_path. | ||
| 1255 | pub fn copyFile( | ||
| 1256 | source_dir: Dir, | ||
| 1257 | source_path: []const u8, | ||
| 1258 | dest_dir: Dir, | ||
| 1259 | dest_path: []const u8, | ||
| 1260 | options: CopyFileOptions, | ||
| 1261 | ) !void { | ||
| 1262 | var in_file = try source_dir.openFile(source_path, .{}); | ||
| 1263 | defer in_file.close(); | ||
| 1264 | |||
| 1265 | var size: ?u64 = null; | ||
| 1266 | const mode = options.override_mode orelse blk: { | ||
| 1267 | const stat = try in_file.stat(); | ||
| 1268 | size = stat.size; | ||
| 1269 | break :blk stat.mode; | ||
| 1270 | }; | ||
| 1271 | |||
| 1272 | var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = mode }); | ||
| 1273 | defer atomic_file.deinit(); | ||
| 1274 | |||
| 1275 | try atomic_file.file.writeFileAll(in_file, .{ .in_len = size }); | ||
| 1276 | return atomic_file.finish(); | ||
| 1277 | } | ||
| 1278 | |||
| 1279 | pub const AtomicFileOptions = struct { | ||
| 1280 | mode: File.Mode = File.default_mode, | ||
| 1281 | }; | ||
| 1282 | |||
| 1283 | /// `dest_path` must remain valid for the lifetime of `AtomicFile`. | ||
| 1284 | /// Call `AtomicFile.finish` to atomically replace `dest_path` with contents. | ||
| 1285 | pub fn atomicFile(self: Dir, dest_path: []const u8, options: AtomicFileOptions) !AtomicFile { | ||
| 1286 | return AtomicFile.init2(dest_path, options.mode, self); | ||
| 1287 | } | ||
| 1373 | }; | 1288 | }; |
| 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 | /// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior. | 1291 | /// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior. |
| 1377 | /// On POSIX targets, this function is comptime-callable. | 1292 | /// On POSIX targets, this function is comptime-callable. |
| 1378 | pub fn cwd() Dir { | 1293 | pub fn cwd() Dir { |
| ... | @@ -1450,6 +1365,25 @@ pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) DeleteFileError!void | ... | @@ -1450,6 +1365,25 @@ pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) DeleteFileError!void |
| 1450 | return cwd().deleteFileW(absolute_path_w); | 1365 | return cwd().deleteFileW(absolute_path_w); |
| 1451 | } | 1366 | } |
| 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 | pub const Walker = struct { | 1387 | pub const Walker = struct { |
| 1454 | stack: std.ArrayList(StackItem), | 1388 | stack: std.ArrayList(StackItem), |
| 1455 | name_buffer: std.Buffer, | 1389 | name_buffer: std.Buffer, |
| ... | @@ -1484,7 +1418,7 @@ pub const Walker = struct { | ... | @@ -1484,7 +1418,7 @@ pub const Walker = struct { |
| 1484 | try self.name_buffer.appendByte(path.sep); | 1418 | try self.name_buffer.appendByte(path.sep); |
| 1485 | try self.name_buffer.append(base.name); | 1419 | try self.name_buffer.append(base.name); |
| 1486 | if (base.kind == .Directory) { | 1420 | if (base.kind == .Directory) { |
| 1487 | var new_dir = top.dir_it.dir.openDirList(base.name) catch |err| switch (err) { | 1421 | var new_dir = top.dir_it.dir.openDir(base.name, .{ .iterate = true }) catch |err| switch (err) { |
| 1488 | error.NameTooLong => unreachable, // no path sep in base.name | 1422 | error.NameTooLong => unreachable, // no path sep in base.name |
| 1489 | else => |e| return e, | 1423 | else => |e| return e, |
| 1490 | }; | 1424 | }; |
| ... | @@ -1522,7 +1456,7 @@ pub const Walker = struct { | ... | @@ -1522,7 +1456,7 @@ pub const Walker = struct { |
| 1522 | pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { | 1456 | pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { |
| 1523 | assert(!mem.endsWith(u8, dir_path, path.sep_str)); | 1457 | assert(!mem.endsWith(u8, dir_path, path.sep_str)); |
| 1524 | 1458 | ||
| 1525 | var dir = try cwd().openDirList(dir_path); | 1459 | var dir = try cwd().openDir(dir_path, .{ .iterate = true }); |
| 1526 | errdefer dir.close(); | 1460 | errdefer dir.close(); |
| 1527 | 1461 | ||
| 1528 | var name_buffer = try std.Buffer.init(allocator, dir_path); | 1462 | var name_buffer = try std.Buffer.init(allocator, dir_path); |
| ... | @@ -1541,13 +1475,12 @@ pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { | ... | @@ -1541,13 +1475,12 @@ pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { |
| 1541 | return walker; | 1475 | return walker; |
| 1542 | } | 1476 | } |
| 1543 | 1477 | ||
| 1544 | /// Read value of a symbolic link. | 1478 | /// Deprecated; use `Dir.readLink`. |
| 1545 | /// The return value is a slice of buffer, from index `0`. | ||
| 1546 | pub fn readLink(pathname: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { | 1479 | pub fn readLink(pathname: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { |
| 1547 | return os.readlink(pathname, buffer); | 1480 | return os.readlink(pathname, buffer); |
| 1548 | } | 1481 | } |
| 1549 | 1482 | ||
| 1550 | /// Same as `readLink`, except the parameter is null-terminated. | 1483 | /// Deprecated; use `Dir.readLinkC`. |
| 1551 | pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { | 1484 | pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { |
| 1552 | return os.readlinkC(pathname_c, buffer); | 1485 | return os.readlinkC(pathname_c, buffer); |
| 1553 | } | 1486 | } |
| ... | @@ -1654,6 +1587,7 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const | ... | @@ -1654,6 +1587,7 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const |
| 1654 | } | 1587 | } |
| 1655 | 1588 | ||
| 1656 | /// `realpath`, except caller must free the returned memory. | 1589 | /// `realpath`, except caller must free the returned memory. |
| 1590 | /// TODO integrate with `Dir` | ||
| 1657 | pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 { | 1591 | pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 { |
| 1658 | var buf: [MAX_PATH_BYTES]u8 = undefined; | 1592 | var buf: [MAX_PATH_BYTES]u8 = undefined; |
| 1659 | return mem.dupe(allocator, u8, try os.realpath(pathname, &buf)); | 1593 | return mem.dupe(allocator, u8, try os.realpath(pathname, &buf)); |
| ... | @@ -1662,6 +1596,9 @@ pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 { | ... | @@ -1662,6 +1596,9 @@ pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 { |
| 1662 | test "" { | 1596 | test "" { |
| 1663 | _ = makeDirAbsolute; | 1597 | _ = makeDirAbsolute; |
| 1664 | _ = makeDirAbsoluteZ; | 1598 | _ = makeDirAbsoluteZ; |
| 1599 | _ = copyFileAbsolute; | ||
| 1600 | _ = updateFileAbsolute; | ||
| 1601 | _ = Dir.copyFile; | ||
| 1665 | _ = @import("fs/path.zig"); | 1602 | _ = @import("fs/path.zig"); |
| 1666 | _ = @import("fs/file.zig"); | 1603 | _ = @import("fs/file.zig"); |
| 1667 | _ = @import("fs/get_app_data_dir.zig"); | 1604 | _ = @import("fs/get_app_data_dir.zig"); |
lib/std/fs/watch.zig+1-1| ... | @@ -619,7 +619,7 @@ test "write a file, watch it, write it again" { | ... | @@ -619,7 +619,7 @@ test "write a file, watch it, write it again" { |
| 619 | if (true) return error.SkipZigTest; | 619 | if (true) return error.SkipZigTest; |
| 620 | 620 | ||
| 621 | try fs.cwd().makePath(test_tmp_dir); | 621 | try fs.cwd().makePath(test_tmp_dir); |
| 622 | defer os.deleteTree(test_tmp_dir) catch {}; | 622 | defer fs.cwd().deleteTree(test_tmp_dir) catch {}; |
| 623 | 623 | ||
| 624 | const allocator = std.heap.page_allocator; | 624 | const allocator = std.heap.page_allocator; |
| 625 | return testFsWatch(&allocator); | 625 | return testFsWatch(&allocator); |
lib/std/hash/auto_hash.zig+8-4| ... | @@ -40,7 +40,9 @@ pub fn hashPointer(hasher: var, key: var, comptime strat: HashStrategy) void { | ... | @@ -40,7 +40,9 @@ pub fn hashPointer(hasher: var, key: var, comptime strat: HashStrategy) void { |
| 40 | .DeepRecursive => hashArray(hasher, key, .DeepRecursive), | 40 | .DeepRecursive => hashArray(hasher, key, .DeepRecursive), |
| 41 | }, | 41 | }, |
| 42 | 42 | ||
| 43 | .Many, .C, => switch (strat) { | 43 | .Many, |
| 44 | .C, | ||
| 45 | => switch (strat) { | ||
| 44 | .Shallow => hash(hasher, @ptrToInt(key), .Shallow), | 46 | .Shallow => hash(hasher, @ptrToInt(key), .Shallow), |
| 45 | else => @compileError( | 47 | else => @compileError( |
| 46 | \\ unknown-length pointers and C pointers cannot be hashed deeply. | 48 | \\ unknown-length pointers and C pointers cannot be hashed deeply. |
| ... | @@ -236,9 +238,11 @@ test "hash slice shallow" { | ... | @@ -236,9 +238,11 @@ test "hash slice shallow" { |
| 236 | defer std.testing.allocator.destroy(array1); | 238 | defer std.testing.allocator.destroy(array1); |
| 237 | array1.* = [_]u32{ 1, 2, 3, 4, 5, 6 }; | 239 | array1.* = [_]u32{ 1, 2, 3, 4, 5, 6 }; |
| 238 | const array2 = [_]u32{ 1, 2, 3, 4, 5, 6 }; | 240 | const array2 = [_]u32{ 1, 2, 3, 4, 5, 6 }; |
| 239 | const a = array1[0..]; | 241 | // TODO audit deep/shallow - maybe it has the wrong behavior with respect to array pointers and slices |
| 240 | const b = array2[0..]; | 242 | var runtime_zero: usize = 0; |
| 241 | const c = array1[0..3]; | 243 | const a = array1[runtime_zero..]; |
| 244 | const b = array2[runtime_zero..]; | ||
| 245 | const c = array1[runtime_zero..3]; | ||
| 242 | testing.expect(testHashShallow(a) == testHashShallow(a)); | 246 | testing.expect(testHashShallow(a) == testHashShallow(a)); |
| 243 | testing.expect(testHashShallow(a) != testHashShallow(array1)); | 247 | testing.expect(testHashShallow(a) != testHashShallow(array1)); |
| 244 | testing.expect(testHashShallow(a) != testHashShallow(b)); | 248 | testing.expect(testHashShallow(a) != testHashShallow(b)); |
lib/std/hash/siphash.zig+3-3| ... | @@ -39,8 +39,8 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round | ... | @@ -39,8 +39,8 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round |
| 39 | pub fn init(key: []const u8) Self { | 39 | pub fn init(key: []const u8) Self { |
| 40 | assert(key.len >= 16); | 40 | assert(key.len >= 16); |
| 41 | 41 | ||
| 42 | const k0 = mem.readIntSliceLittle(u64, key[0..8]); | 42 | const k0 = mem.readIntLittle(u64, key[0..8]); |
| 43 | const k1 = mem.readIntSliceLittle(u64, key[8..16]); | 43 | const k1 = mem.readIntLittle(u64, key[8..16]); |
| 44 | 44 | ||
| 45 | var d = Self{ | 45 | var d = Self{ |
| 46 | .v0 = k0 ^ 0x736f6d6570736575, | 46 | .v0 = k0 ^ 0x736f6d6570736575, |
| ... | @@ -111,7 +111,7 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round | ... | @@ -111,7 +111,7 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round |
| 111 | fn round(self: *Self, b: []const u8) void { | 111 | fn round(self: *Self, b: []const u8) void { |
| 112 | assert(b.len == 8); | 112 | assert(b.len == 8); |
| 113 | 113 | ||
| 114 | const m = mem.readIntSliceLittle(u64, b[0..]); | 114 | const m = mem.readIntLittle(u64, b[0..8]); |
| 115 | self.v3 ^= m; | 115 | self.v3 ^= m; |
| 116 | 116 | ||
| 117 | // TODO this is a workaround, should be able to supply the value without a separate variable | 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,7 +11,7 @@ const primes = [_]u64{ |
| 11 | 11 | ||
| 12 | fn read_bytes(comptime bytes: u8, data: []const u8) u64 { | 12 | fn read_bytes(comptime bytes: u8, data: []const u8) u64 { |
| 13 | const T = std.meta.IntType(false, 8 * bytes); | 13 | const T = std.meta.IntType(false, 8 * bytes); |
| 14 | return mem.readIntSliceLittle(T, data[0..bytes]); | 14 | return mem.readIntLittle(T, data[0..bytes]); |
| 15 | } | 15 | } |
| 16 | 16 | ||
| 17 | fn read_8bytes_swapped(data: []const u8) u64 { | 17 | fn read_8bytes_swapped(data: []const u8) u64 { |
lib/std/io/serialization.zig+5-1| ... | @@ -1,6 +1,10 @@ | ... | @@ -1,6 +1,10 @@ |
| 1 | const std = @import("../std.zig"); | 1 | const std = @import("../std.zig"); |
| 2 | const builtin = std.builtin; | 2 | const builtin = std.builtin; |
| 3 | const io = std.io; | 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 | pub const Packing = enum { | 9 | pub const Packing = enum { |
| 6 | /// Pack data to byte alignment | 10 | /// Pack data to byte alignment |
| ... | @@ -252,7 +256,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co | ... | @@ -252,7 +256,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co |
| 252 | byte.* = if (t_bit_count < u8_bit_count) v else @truncate(u8, v); | 256 | byte.* = if (t_bit_count < u8_bit_count) v else @truncate(u8, v); |
| 253 | } | 257 | } |
| 254 | 258 | ||
| 255 | try self.out_stream.write(&buffer); | 259 | try self.out_stream.writeAll(&buffer); |
| 256 | } | 260 | } |
| 257 | 261 | ||
| 258 | /// Serializes the passed value into the stream | 262 | /// Serializes the passed value into the stream |
lib/std/json.zig+16-7| ... | @@ -2249,11 +2249,16 @@ pub const StringifyOptions = struct { | ... | @@ -2249,11 +2249,16 @@ pub const StringifyOptions = struct { |
| 2249 | // TODO: allow picking if []u8 is string or array? | 2249 | // TODO: allow picking if []u8 is string or array? |
| 2250 | }; | 2250 | }; |
| 2251 | 2251 | ||
| 2252 | pub const StringifyError = error{ | ||
| 2253 | TooMuchData, | ||
| 2254 | DifferentData, | ||
| 2255 | }; | ||
| 2256 | |||
| 2252 | pub fn stringify( | 2257 | pub fn stringify( |
| 2253 | value: var, | 2258 | value: var, |
| 2254 | options: StringifyOptions, | 2259 | options: StringifyOptions, |
| 2255 | out_stream: var, | 2260 | out_stream: var, |
| 2256 | ) !void { | 2261 | ) StringifyError!void { |
| 2257 | const T = @TypeOf(value); | 2262 | const T = @TypeOf(value); |
| 2258 | switch (@typeInfo(T)) { | 2263 | switch (@typeInfo(T)) { |
| 2259 | .Float, .ComptimeFloat => { | 2264 | .Float, .ComptimeFloat => { |
| ... | @@ -2320,9 +2325,15 @@ pub fn stringify( | ... | @@ -2320,9 +2325,15 @@ pub fn stringify( |
| 2320 | return; | 2325 | return; |
| 2321 | }, | 2326 | }, |
| 2322 | .Pointer => |ptr_info| switch (ptr_info.size) { | 2327 | .Pointer => |ptr_info| switch (ptr_info.size) { |
| 2323 | .One => { | 2328 | .One => switch (@typeInfo(ptr_info.child)) { |
| 2324 | // TODO: avoid loops? | 2329 | .Array => { |
| 2325 | return try stringify(value.*, options, out_stream); | 2330 | const Slice = []const std.meta.Elem(ptr_info.child); |
| 2331 | return stringify(@as(Slice, value), options, out_stream); | ||
| 2332 | }, | ||
| 2333 | else => { | ||
| 2334 | // TODO: avoid loops? | ||
| 2335 | return stringify(value.*, options, out_stream); | ||
| 2336 | }, | ||
| 2326 | }, | 2337 | }, |
| 2327 | // TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972) | 2338 | // TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972) |
| 2328 | .Slice => { | 2339 | .Slice => { |
| ... | @@ -2381,9 +2392,7 @@ pub fn stringify( | ... | @@ -2381,9 +2392,7 @@ pub fn stringify( |
| 2381 | }, | 2392 | }, |
| 2382 | else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"), | 2393 | else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"), |
| 2383 | }, | 2394 | }, |
| 2384 | .Array => |info| { | 2395 | .Array => return stringify(&value, options, out_stream), |
| 2385 | return try stringify(value[0..], options, out_stream); | ||
| 2386 | }, | ||
| 2387 | else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"), | 2396 | else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"), |
| 2388 | } | 2397 | } |
| 2389 | unreachable; | 2398 | unreachable; |
lib/std/math/big/int.zig+2-2| ... | @@ -520,13 +520,13 @@ pub const Int = struct { | ... | @@ -520,13 +520,13 @@ pub const Int = struct { |
| 520 | comptime fmt: []const u8, | 520 | comptime fmt: []const u8, |
| 521 | options: std.fmt.FormatOptions, | 521 | options: std.fmt.FormatOptions, |
| 522 | out_stream: var, | 522 | out_stream: var, |
| 523 | ) FmtError!void { | 523 | ) !void { |
| 524 | self.assertWritable(); | 524 | self.assertWritable(); |
| 525 | // TODO look at fmt and support other bases | 525 | // TODO look at fmt and support other bases |
| 526 | // TODO support read-only fixed integers | 526 | // TODO support read-only fixed integers |
| 527 | const str = self.toString(self.allocator.?, 10) catch @panic("TODO make this non allocating"); | 527 | const str = self.toString(self.allocator.?, 10) catch @panic("TODO make this non allocating"); |
| 528 | defer self.allocator.?.free(str); | 528 | defer self.allocator.?.free(str); |
| 529 | return out_stream.print(str); | 529 | return out_stream.writeAll(str); |
| 530 | } | 530 | } |
| 531 | 531 | ||
| 532 | /// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively. | 532 | /// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively. |
lib/std/mem.zig+137-75| ... | @@ -116,7 +116,7 @@ pub const Allocator = struct { | ... | @@ -116,7 +116,7 @@ pub const Allocator = struct { |
| 116 | pub fn allocSentinel(self: *Allocator, comptime Elem: type, n: usize, comptime sentinel: Elem) Error![:sentinel]Elem { | 116 | pub fn allocSentinel(self: *Allocator, comptime Elem: type, n: usize, comptime sentinel: Elem) Error![:sentinel]Elem { |
| 117 | var ptr = try self.alloc(Elem, n + 1); | 117 | var ptr = try self.alloc(Elem, n + 1); |
| 118 | ptr[n] = sentinel; | 118 | ptr[n] = sentinel; |
| 119 | return ptr[0 .. n :sentinel]; | 119 | return ptr[0..n :sentinel]; |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | pub fn alignedAlloc( | 122 | pub fn alignedAlloc( |
| ... | @@ -496,14 +496,14 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool { | ... | @@ -496,14 +496,14 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool { |
| 496 | return true; | 496 | return true; |
| 497 | } | 497 | } |
| 498 | 498 | ||
| 499 | /// Deprecated. Use `span`. | 499 | /// Deprecated. Use `spanZ`. |
| 500 | pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T { | 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 | pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T { | 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 | /// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and | 509 | /// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and |
| ... | @@ -548,6 +548,9 @@ test "Span" { | ... | @@ -548,6 +548,9 @@ test "Span" { |
| 548 | /// returns a slice. If there is a sentinel on the input type, there will be a | 548 | /// returns a slice. If there is a sentinel on the input type, there will be a |
| 549 | /// sentinel on the output type. The constness of the output type matches | 549 | /// sentinel on the output type. The constness of the output type matches |
| 550 | /// the constness of the input type. | 550 | /// the constness of the input type. |
| 551 | /// | ||
| 552 | /// When there is both a sentinel and an array length or slice length, the | ||
| 553 | /// length value is used instead of the sentinel. | ||
| 551 | pub fn span(ptr: var) Span(@TypeOf(ptr)) { | 554 | pub fn span(ptr: var) Span(@TypeOf(ptr)) { |
| 552 | const Result = Span(@TypeOf(ptr)); | 555 | const Result = Span(@TypeOf(ptr)); |
| 553 | const l = len(ptr); | 556 | const l = len(ptr); |
| ... | @@ -560,20 +563,42 @@ pub fn span(ptr: var) Span(@TypeOf(ptr)) { | ... | @@ -560,20 +563,42 @@ pub fn span(ptr: var) Span(@TypeOf(ptr)) { |
| 560 | 563 | ||
| 561 | test "span" { | 564 | test "span" { |
| 562 | var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; | 565 | var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; |
| 563 | const ptr = array[0..2 :3].ptr; | 566 | const ptr = @as([*:3]u16, array[0..2 :3]); |
| 564 | testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 })); | 567 | testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 })); |
| 565 | testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 })); | 568 | testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 })); |
| 566 | } | 569 | } |
| 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 | /// Takes a pointer to an array, an array, a sentinel-terminated pointer, | 591 | /// Takes a pointer to an array, an array, a sentinel-terminated pointer, |
| 569 | /// or a slice, and returns the length. | 592 | /// or a slice, and returns the length. |
| 593 | /// In the case of a sentinel-terminated array, it uses the array length. | ||
| 594 | /// For C pointers it assumes it is a pointer-to-many with a 0 sentinel. | ||
| 570 | pub fn len(ptr: var) usize { | 595 | pub fn len(ptr: var) usize { |
| 571 | return switch (@typeInfo(@TypeOf(ptr))) { | 596 | return switch (@typeInfo(@TypeOf(ptr))) { |
| 572 | .Array => |info| info.len, | 597 | .Array => |info| info.len, |
| 573 | .Pointer => |info| switch (info.size) { | 598 | .Pointer => |info| switch (info.size) { |
| 574 | .One => switch (@typeInfo(info.child)) { | 599 | .One => switch (@typeInfo(info.child)) { |
| 575 | .Array => |x| x.len, | 600 | .Array => ptr.len, |
| 576 | else => @compileError("invalid type given to std.mem.length"), | 601 | else => @compileError("invalid type given to std.mem.len"), |
| 577 | }, | 602 | }, |
| 578 | .Many => if (info.sentinel) |sentinel| | 603 | .Many => if (info.sentinel) |sentinel| |
| 579 | indexOfSentinel(info.child, sentinel, ptr) | 604 | indexOfSentinel(info.child, sentinel, ptr) |
| ... | @@ -582,7 +607,7 @@ pub fn len(ptr: var) usize { | ... | @@ -582,7 +607,7 @@ pub fn len(ptr: var) usize { |
| 582 | .C => indexOfSentinel(info.child, 0, ptr), | 607 | .C => indexOfSentinel(info.child, 0, ptr), |
| 583 | .Slice => ptr.len, | 608 | .Slice => ptr.len, |
| 584 | }, | 609 | }, |
| 585 | else => @compileError("invalid type given to std.mem.length"), | 610 | else => @compileError("invalid type given to std.mem.len"), |
| 586 | }; | 611 | }; |
| 587 | } | 612 | } |
| 588 | 613 | ||
| ... | @@ -594,9 +619,67 @@ test "len" { | ... | @@ -594,9 +619,67 @@ test "len" { |
| 594 | testing.expect(len(&array) == 5); | 619 | testing.expect(len(&array) == 5); |
| 595 | testing.expect(len(array[0..3]) == 3); | 620 | testing.expect(len(array[0..3]) == 3); |
| 596 | array[2] = 0; | 621 | array[2] = 0; |
| 597 | const ptr = array[0..2 :0].ptr; | 622 | const ptr = @as([*:0]u16, array[0..2 :0]); |
| 598 | testing.expect(len(ptr) == 2); | 623 | testing.expect(len(ptr) == 2); |
| 599 | } | 624 | } |
| 625 | { | ||
| 626 | var array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 }; | ||
| 627 | testing.expect(len(&array) == 5); | ||
| 628 | array[2] = 0; | ||
| 629 | testing.expect(len(&array) == 5); | ||
| 630 | } | ||
| 631 | } | ||
| 632 | |||
| 633 | /// Takes a pointer to an array, an array, a sentinel-terminated pointer, | ||
| 634 | /// or a slice, and returns the length. | ||
| 635 | /// In the case of a sentinel-terminated array, it scans the array | ||
| 636 | /// for a sentinel and uses that for the length, rather than using the array length. | ||
| 637 | /// For C pointers it assumes it is a pointer-to-many with a 0 sentinel. | ||
| 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 | pub fn indexOfSentinel(comptime Elem: type, comptime sentinel: Elem, ptr: [*:sentinel]const Elem) usize { | 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,8 +893,7 @@ pub const readIntBig = switch (builtin.endian) { |
| 810 | pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T { | 893 | pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T { |
| 811 | const n = @divExact(T.bit_count, 8); | 894 | const n = @divExact(T.bit_count, 8); |
| 812 | assert(bytes.len >= n); | 895 | assert(bytes.len >= n); |
| 813 | // TODO https://github.com/ziglang/zig/issues/863 | 896 | return readIntNative(T, bytes[0..n]); |
| 814 | return readIntNative(T, @ptrCast(*const [n]u8, bytes.ptr)); | ||
| 815 | } | 897 | } |
| 816 | 898 | ||
| 817 | /// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0 | 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,8 +931,7 @@ pub fn readInt(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8, en |
| 849 | pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T { | 931 | pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T { |
| 850 | const n = @divExact(T.bit_count, 8); | 932 | const n = @divExact(T.bit_count, 8); |
| 851 | assert(bytes.len >= n); | 933 | assert(bytes.len >= n); |
| 852 | // TODO https://github.com/ziglang/zig/issues/863 | 934 | return readInt(T, bytes[0..n], endian); |
| 853 | return readInt(T, @ptrCast(*const [n]u8, bytes.ptr), endian); | ||
| 854 | } | 935 | } |
| 855 | 936 | ||
| 856 | test "comptime read/write int" { | 937 | test "comptime read/write int" { |
| ... | @@ -1572,24 +1653,24 @@ pub fn nativeToBig(comptime T: type, x: T) T { | ... | @@ -1572,24 +1653,24 @@ pub fn nativeToBig(comptime T: type, x: T) T { |
| 1572 | } | 1653 | } |
| 1573 | 1654 | ||
| 1574 | fn AsBytesReturnType(comptime P: type) type { | 1655 | fn AsBytesReturnType(comptime P: type) type { |
| 1575 | if (comptime !trait.isSingleItemPtr(P)) | 1656 | if (!trait.isSingleItemPtr(P)) |
| 1576 | @compileError("expected single item pointer, passed " ++ @typeName(P)); | 1657 | @compileError("expected single item pointer, passed " ++ @typeName(P)); |
| 1577 | 1658 | ||
| 1578 | const size = @as(usize, @sizeOf(meta.Child(P))); | 1659 | const size = @sizeOf(meta.Child(P)); |
| 1579 | const alignment = comptime meta.alignment(P); | 1660 | const alignment = meta.alignment(P); |
| 1580 | 1661 | ||
| 1581 | if (alignment == 0) { | 1662 | if (alignment == 0) { |
| 1582 | if (comptime trait.isConstPtr(P)) | 1663 | if (trait.isConstPtr(P)) |
| 1583 | return *const [size]u8; | 1664 | return *const [size]u8; |
| 1584 | return *[size]u8; | 1665 | return *[size]u8; |
| 1585 | } | 1666 | } |
| 1586 | 1667 | ||
| 1587 | if (comptime trait.isConstPtr(P)) | 1668 | if (trait.isConstPtr(P)) |
| 1588 | return *align(alignment) const [size]u8; | 1669 | return *align(alignment) const [size]u8; |
| 1589 | return *align(alignment) [size]u8; | 1670 | return *align(alignment) [size]u8; |
| 1590 | } | 1671 | } |
| 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 | pub fn asBytes(ptr: var) AsBytesReturnType(@TypeOf(ptr)) { | 1674 | pub fn asBytes(ptr: var) AsBytesReturnType(@TypeOf(ptr)) { |
| 1594 | const P = @TypeOf(ptr); | 1675 | const P = @TypeOf(ptr); |
| 1595 | return @ptrCast(AsBytesReturnType(P), ptr); | 1676 | return @ptrCast(AsBytesReturnType(P), ptr); |
| ... | @@ -1736,34 +1817,50 @@ fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type { | ... | @@ -1736,34 +1817,50 @@ fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type { |
| 1736 | } | 1817 | } |
| 1737 | 1818 | ||
| 1738 | pub fn bytesAsSlice(comptime T: type, bytes: var) BytesAsSliceReturnType(T, @TypeOf(bytes)) { | 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 | // let's not give an undefined pointer to @ptrCast | 1820 | // let's not give an undefined pointer to @ptrCast |
| 1742 | // it may be equal to zero and fail a null check | 1821 | // it may be equal to zero and fail a null check |
| 1743 | if (bytesSlice.len == 0) { | 1822 | if (bytes.len == 0) { |
| 1744 | return &[0]T{}; | 1823 | return &[0]T{}; |
| 1745 | } | 1824 | } |
| 1746 | 1825 | ||
| 1747 | const bytesType = @TypeOf(bytesSlice); | 1826 | const Bytes = @TypeOf(bytes); |
| 1748 | const alignment = comptime meta.alignment(bytesType); | 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 | test "bytesAsSlice" { | 1834 | test "bytesAsSlice" { |
| 1756 | const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; | 1835 | { |
| 1757 | const slice = bytesAsSlice(u16, bytes[0..]); | 1836 | const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; |
| 1758 | testing.expect(slice.len == 2); | 1837 | const slice = bytesAsSlice(u16, bytes[0..]); |
| 1759 | testing.expect(bigToNative(u16, slice[0]) == 0xDEAD); | 1838 | testing.expect(slice.len == 2); |
| 1760 | testing.expect(bigToNative(u16, slice[1]) == 0xBEEF); | 1839 | testing.expect(bigToNative(u16, slice[0]) == 0xDEAD); |
| 1840 | testing.expect(bigToNative(u16, slice[1]) == 0xBEEF); | ||
| 1841 | } | ||
| 1842 | { | ||
| 1843 | const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; | ||
| 1844 | var runtime_zero: usize = 0; | ||
| 1845 | const slice = bytesAsSlice(u16, bytes[runtime_zero..]); | ||
| 1846 | testing.expect(slice.len == 2); | ||
| 1847 | testing.expect(bigToNative(u16, slice[0]) == 0xDEAD); | ||
| 1848 | testing.expect(bigToNative(u16, slice[1]) == 0xBEEF); | ||
| 1849 | } | ||
| 1761 | } | 1850 | } |
| 1762 | 1851 | ||
| 1763 | test "bytesAsSlice keeps pointer alignment" { | 1852 | test "bytesAsSlice keeps pointer alignment" { |
| 1764 | var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 }; | 1853 | { |
| 1765 | const numbers = bytesAsSlice(u32, bytes[0..]); | 1854 | var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 }; |
| 1766 | comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32); | 1855 | const numbers = bytesAsSlice(u32, bytes[0..]); |
| 1856 | comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32); | ||
| 1857 | } | ||
| 1858 | { | ||
| 1859 | var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 }; | ||
| 1860 | var runtime_zero: usize = 0; | ||
| 1861 | const numbers = bytesAsSlice(u32, bytes[runtime_zero..]); | ||
| 1862 | comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32); | ||
| 1863 | } | ||
| 1767 | } | 1864 | } |
| 1768 | 1865 | ||
| 1769 | test "bytesAsSlice on a packed struct" { | 1866 | test "bytesAsSlice on a packed struct" { |
| ... | @@ -1799,21 +1896,19 @@ fn SliceAsBytesReturnType(comptime sliceType: type) type { | ... | @@ -1799,21 +1896,19 @@ fn SliceAsBytesReturnType(comptime sliceType: type) type { |
| 1799 | } | 1896 | } |
| 1800 | 1897 | ||
| 1801 | pub fn sliceAsBytes(slice: var) SliceAsBytesReturnType(@TypeOf(slice)) { | 1898 | pub fn sliceAsBytes(slice: var) SliceAsBytesReturnType(@TypeOf(slice)) { |
| 1802 | const actualSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(slice))) slice[0..] else slice; | 1899 | const Slice = @TypeOf(slice); |
| 1803 | const actualSliceTypeInfo = @typeInfo(@TypeOf(actualSlice)).Pointer; | ||
| 1804 | 1900 | ||
| 1805 | // let's not give an undefined pointer to @ptrCast | 1901 | // let's not give an undefined pointer to @ptrCast |
| 1806 | // it may be equal to zero and fail a null check | 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 | return &[0]u8{}; | 1904 | return &[0]u8{}; |
| 1809 | } | 1905 | } |
| 1810 | 1906 | ||
| 1811 | const sliceType = @TypeOf(actualSlice); | 1907 | const alignment = comptime meta.alignment(Slice); |
| 1812 | const alignment = comptime meta.alignment(sliceType); | ||
| 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 | test "sliceAsBytes" { | 1914 | test "sliceAsBytes" { |
| ... | @@ -1883,39 +1978,6 @@ test "sliceAsBytes and bytesAsSlice back" { | ... | @@ -1883,39 +1978,6 @@ test "sliceAsBytes and bytesAsSlice back" { |
| 1883 | testing.expect(bytes[11] == math.maxInt(u8)); | 1978 | testing.expect(bytes[11] == math.maxInt(u8)); |
| 1884 | } | 1979 | } |
| 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 | /// Round an address up to the nearest aligned address | 1981 | /// Round an address up to the nearest aligned address |
| 1920 | /// The alignment must be a power of 2 and greater than 0. | 1982 | /// The alignment must be a power of 2 and greater than 0. |
| 1921 | pub fn alignForward(addr: usize, alignment: usize) usize { | 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,7 +104,7 @@ pub fn Child(comptime T: type) type { |
| 104 | .Array => |info| info.child, | 104 | .Array => |info| info.child, |
| 105 | .Pointer => |info| info.child, | 105 | .Pointer => |info| info.child, |
| 106 | .Optional => |info| info.child, | 106 | .Optional => |info| info.child, |
| 107 | else => @compileError("Expected pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"), | 107 | else => @compileError("Expected pointer, optional, or array type, found '" ++ @typeName(T) ++ "'"), |
| 108 | }; | 108 | }; |
| 109 | } | 109 | } |
| 110 | 110 | ||
| ... | @@ -115,30 +115,65 @@ test "std.meta.Child" { | ... | @@ -115,30 +115,65 @@ test "std.meta.Child" { |
| 115 | testing.expect(Child(?u8) == u8); | 115 | testing.expect(Child(?u8) == u8); |
| 116 | } | 116 | } |
| 117 | 117 | ||
| 118 | /// Given a type with a sentinel e.g. `[:0]u8`, returns the sentinel | 118 | /// Given a "memory span" type, returns the "element type". |
| 119 | pub fn Sentinel(comptime T: type) Child(T) { | 119 | pub fn Elem(comptime T: type) type { |
| 120 | // comptime asserts that ptr has a sentinel | ||
| 121 | switch (@typeInfo(T)) { | 120 | switch (@typeInfo(T)) { |
| 122 | .Array => |arrayInfo| { | 121 | .Array => |info| return info.child, |
| 123 | return comptime arrayInfo.sentinel.?; | 122 | .Pointer => |info| switch (info.size) { |
| 123 | .One => switch (@typeInfo(info.child)) { | ||
| 124 | .Array => |array_info| return array_info.child, | ||
| 125 | else => {}, | ||
| 126 | }, | ||
| 127 | .Many, .C, .Slice => return info.child, | ||
| 124 | }, | 128 | }, |
| 125 | .Pointer => |ptrInfo| { | 129 | else => {}, |
| 126 | switch (ptrInfo.size) { | 130 | } |
| 127 | .Many, .Slice => { | 131 | @compileError("Expected pointer, slice, or array, found '" ++ @typeName(T) ++ "'"); |
| 128 | return comptime ptrInfo.sentinel.?; | 132 | } |
| 133 | |||
| 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 | else => {}, | 154 | else => {}, |
| 131 | } | 155 | } |
| 132 | }, | 156 | }, |
| 133 | else => {}, | 157 | else => {}, |
| 134 | } | 158 | } |
| 135 | @compileError("not a sentinel type, found '" ++ @typeName(T) ++ "'"); | 159 | @compileError("type '" ++ @typeName(T) ++ "' cannot possibly have a sentinel"); |
| 136 | } | 160 | } |
| 137 | 161 | ||
| 138 | test "std.meta.Sentinel" { | 162 | test "std.meta.sentinel" { |
| 139 | testing.expectEqual(@as(u8, 0), Sentinel([:0]u8)); | 163 | testSentinel(); |
| 140 | testing.expectEqual(@as(u8, 0), Sentinel([*:0]u8)); | 164 | comptime testSentinel(); |
| 141 | testing.expectEqual(@as(u8, 0), Sentinel([5:0]u8)); | 165 | } |
| 166 | |||
| 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 | pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout { | 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,9 +230,10 @@ pub fn isSingleItemPtr(comptime T: type) bool { |
| 230 | 230 | ||
| 231 | test "std.meta.trait.isSingleItemPtr" { | 231 | test "std.meta.trait.isSingleItemPtr" { |
| 232 | const array = [_]u8{0} ** 10; | 232 | const array = [_]u8{0} ** 10; |
| 233 | testing.expect(isSingleItemPtr(@TypeOf(&array[0]))); | 233 | comptime testing.expect(isSingleItemPtr(@TypeOf(&array[0]))); |
| 234 | testing.expect(!isSingleItemPtr(@TypeOf(array))); | 234 | comptime testing.expect(!isSingleItemPtr(@TypeOf(array))); |
| 235 | testing.expect(!isSingleItemPtr(@TypeOf(array[0..1]))); | 235 | var runtime_zero: usize = 0; |
| 236 | testing.expect(!isSingleItemPtr(@TypeOf(array[runtime_zero..1]))); | ||
| 236 | } | 237 | } |
| 237 | 238 | ||
| 238 | pub fn isManyItemPtr(comptime T: type) bool { | 239 | pub fn isManyItemPtr(comptime T: type) bool { |
| ... | @@ -259,7 +260,8 @@ pub fn isSlice(comptime T: type) bool { | ... | @@ -259,7 +260,8 @@ pub fn isSlice(comptime T: type) bool { |
| 259 | 260 | ||
| 260 | test "std.meta.trait.isSlice" { | 261 | test "std.meta.trait.isSlice" { |
| 261 | const array = [_]u8{0} ** 10; | 262 | const array = [_]u8{0} ** 10; |
| 262 | testing.expect(isSlice(@TypeOf(array[0..]))); | 263 | var runtime_zero: usize = 0; |
| 264 | testing.expect(isSlice(@TypeOf(array[runtime_zero..]))); | ||
| 263 | testing.expect(!isSlice(@TypeOf(array))); | 265 | testing.expect(!isSlice(@TypeOf(array))); |
| 264 | testing.expect(!isSlice(@TypeOf(&array[0]))); | 266 | testing.expect(!isSlice(@TypeOf(&array[0]))); |
| 265 | } | 267 | } |
| ... | @@ -276,7 +278,7 @@ pub fn isIndexable(comptime T: type) bool { | ... | @@ -276,7 +278,7 @@ pub fn isIndexable(comptime T: type) bool { |
| 276 | 278 | ||
| 277 | test "std.meta.trait.isIndexable" { | 279 | test "std.meta.trait.isIndexable" { |
| 278 | const array = [_]u8{0} ** 10; | 280 | const array = [_]u8{0} ** 10; |
| 279 | const slice = array[0..]; | 281 | const slice = @as([]const u8, &array); |
| 280 | 282 | ||
| 281 | testing.expect(isIndexable(@TypeOf(array))); | 283 | testing.expect(isIndexable(@TypeOf(array))); |
| 282 | testing.expect(isIndexable(@TypeOf(&array))); | 284 | testing.expect(isIndexable(@TypeOf(&array))); |
lib/std/net.zig+7-5| ... | @@ -612,8 +612,7 @@ fn linuxLookupName( | ... | @@ -612,8 +612,7 @@ fn linuxLookupName( |
| 612 | } else { | 612 | } else { |
| 613 | mem.copy(u8, &sa6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff"); | 613 | mem.copy(u8, &sa6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff"); |
| 614 | mem.copy(u8, &da6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff"); | 614 | mem.copy(u8, &da6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff"); |
| 615 | // TODO https://github.com/ziglang/zig/issues/863 | 615 | mem.writeIntNative(u32, da6.addr[12..], addr.addr.in.addr); |
| 616 | mem.writeIntNative(u32, @ptrCast(*[4]u8, da6.addr[12..].ptr), addr.addr.in.addr); | ||
| 617 | da4.addr = addr.addr.in.addr; | 616 | da4.addr = addr.addr.in.addr; |
| 618 | da = @ptrCast(*os.sockaddr, &da4); | 617 | da = @ptrCast(*os.sockaddr, &da4); |
| 619 | dalen = @sizeOf(os.sockaddr_in); | 618 | dalen = @sizeOf(os.sockaddr_in); |
| ... | @@ -821,7 +820,7 @@ fn linuxLookupNameFromHosts( | ... | @@ -821,7 +820,7 @@ fn linuxLookupNameFromHosts( |
| 821 | // Skip to the delimiter in the stream, to fix parsing | 820 | // Skip to the delimiter in the stream, to fix parsing |
| 822 | try stream.skipUntilDelimiterOrEof('\n'); | 821 | try stream.skipUntilDelimiterOrEof('\n'); |
| 823 | // Use the truncated line. A truncated comment or hostname will be handled correctly. | 822 | // Use the truncated line. A truncated comment or hostname will be handled correctly. |
| 824 | break :blk line_buf[0..]; | 823 | break :blk @as([]u8, &line_buf); // TODO the cast should not be necessary |
| 825 | }, | 824 | }, |
| 826 | else => |e| return e, | 825 | else => |e| return e, |
| 827 | }) |line| { | 826 | }) |line| { |
| ... | @@ -958,7 +957,10 @@ fn linuxLookupNameFromDns( | ... | @@ -958,7 +957,10 @@ fn linuxLookupNameFromDns( |
| 958 | } | 957 | } |
| 959 | } | 958 | } |
| 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 | try resMSendRc(qp[0..nq], ap[0..nq], apbuf[0..nq], rc); | 964 | try resMSendRc(qp[0..nq], ap[0..nq], apbuf[0..nq], rc); |
| 963 | 965 | ||
| 964 | var i: usize = 0; | 966 | var i: usize = 0; |
| ... | @@ -1015,7 +1017,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void { | ... | @@ -1015,7 +1017,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void { |
| 1015 | // Skip to the delimiter in the stream, to fix parsing | 1017 | // Skip to the delimiter in the stream, to fix parsing |
| 1016 | try stream.skipUntilDelimiterOrEof('\n'); | 1018 | try stream.skipUntilDelimiterOrEof('\n'); |
| 1017 | // Give an empty line to the while loop, which will be skipped. | 1019 | // Give an empty line to the while loop, which will be skipped. |
| 1018 | break :blk line_buf[0..0]; | 1020 | break :blk @as([]u8, line_buf[0..0]); // TODO the cast should not be necessary |
| 1019 | }, | 1021 | }, |
| 1020 | else => |e| return e, | 1022 | else => |e| return e, |
| 1021 | }) |line| { | 1023 | }) |line| { |
lib/std/os.zig+143-5| ... | @@ -461,13 +461,11 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void { | ... | @@ -461,13 +461,11 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void { |
| 461 | ); | 461 | ); |
| 462 | 462 | ||
| 463 | switch (rc) { | 463 | switch (rc) { |
| 464 | .SUCCESS => {}, | 464 | .SUCCESS => return, |
| 465 | .INVALID_HANDLE => unreachable, // Handle not open for writing | 465 | .INVALID_HANDLE => unreachable, // Handle not open for writing |
| 466 | .ACCESS_DENIED => return error.CannotTruncate, | 466 | .ACCESS_DENIED => return error.CannotTruncate, |
| 467 | else => return windows.unexpectedStatus(rc), | 467 | else => return windows.unexpectedStatus(rc), |
| 468 | } | 468 | } |
| 469 | |||
| 470 | return; | ||
| 471 | } | 469 | } |
| 472 | 470 | ||
| 473 | while (true) { | 471 | while (true) { |
| ... | @@ -852,6 +850,7 @@ pub const OpenError = error{ | ... | @@ -852,6 +850,7 @@ pub const OpenError = error{ |
| 852 | 850 | ||
| 853 | /// Open and possibly create a file. Keeps trying if it gets interrupted. | 851 | /// Open and possibly create a file. Keeps trying if it gets interrupted. |
| 854 | /// See also `openC`. | 852 | /// See also `openC`. |
| 853 | /// TODO support windows | ||
| 855 | pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t { | 854 | pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t { |
| 856 | const file_path_c = try toPosixPath(file_path); | 855 | const file_path_c = try toPosixPath(file_path); |
| 857 | return openC(&file_path_c, flags, perm); | 856 | return openC(&file_path_c, flags, perm); |
| ... | @@ -859,6 +858,7 @@ pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t { | ... | @@ -859,6 +858,7 @@ pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t { |
| 859 | 858 | ||
| 860 | /// Open and possibly create a file. Keeps trying if it gets interrupted. | 859 | /// Open and possibly create a file. Keeps trying if it gets interrupted. |
| 861 | /// See also `open`. | 860 | /// See also `open`. |
| 861 | /// TODO support windows | ||
| 862 | pub fn openC(file_path: [*:0]const u8, flags: u32, perm: usize) OpenError!fd_t { | 862 | pub fn openC(file_path: [*:0]const u8, flags: u32, perm: usize) OpenError!fd_t { |
| 863 | while (true) { | 863 | while (true) { |
| 864 | const rc = system.open(file_path, flags, perm); | 864 | const rc = system.open(file_path, flags, perm); |
| ... | @@ -892,6 +892,7 @@ pub fn openC(file_path: [*:0]const u8, flags: u32, perm: usize) OpenError!fd_t { | ... | @@ -892,6 +892,7 @@ pub fn openC(file_path: [*:0]const u8, flags: u32, perm: usize) OpenError!fd_t { |
| 892 | /// Open and possibly create a file. Keeps trying if it gets interrupted. | 892 | /// Open and possibly create a file. Keeps trying if it gets interrupted. |
| 893 | /// `file_path` is relative to the open directory handle `dir_fd`. | 893 | /// `file_path` is relative to the open directory handle `dir_fd`. |
| 894 | /// See also `openatC`. | 894 | /// See also `openatC`. |
| 895 | /// TODO support windows | ||
| 895 | pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) OpenError!fd_t { | 896 | pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) OpenError!fd_t { |
| 896 | const file_path_c = try toPosixPath(file_path); | 897 | const file_path_c = try toPosixPath(file_path); |
| 897 | return openatC(dir_fd, &file_path_c, flags, mode); | 898 | return openatC(dir_fd, &file_path_c, flags, mode); |
| ... | @@ -900,6 +901,7 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope | ... | @@ -900,6 +901,7 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope |
| 900 | /// Open and possibly create a file. Keeps trying if it gets interrupted. | 901 | /// Open and possibly create a file. Keeps trying if it gets interrupted. |
| 901 | /// `file_path` is relative to the open directory handle `dir_fd`. | 902 | /// `file_path` is relative to the open directory handle `dir_fd`. |
| 902 | /// See also `openat`. | 903 | /// See also `openat`. |
| 904 | /// TODO support windows | ||
| 903 | pub fn openatC(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t) OpenError!fd_t { | 905 | pub fn openatC(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t) OpenError!fd_t { |
| 904 | while (true) { | 906 | while (true) { |
| 905 | const rc = system.openat(dir_fd, file_path, flags, mode); | 907 | const rc = system.openat(dir_fd, file_path, flags, mode); |
| ... | @@ -1527,6 +1529,9 @@ const RenameError = error{ | ... | @@ -1527,6 +1529,9 @@ const RenameError = error{ |
| 1527 | RenameAcrossMountPoints, | 1529 | RenameAcrossMountPoints, |
| 1528 | InvalidUtf8, | 1530 | InvalidUtf8, |
| 1529 | BadPathName, | 1531 | BadPathName, |
| 1532 | NoDevice, | ||
| 1533 | SharingViolation, | ||
| 1534 | PipeBusy, | ||
| 1530 | } || UnexpectedError; | 1535 | } || UnexpectedError; |
| 1531 | 1536 | ||
| 1532 | /// Change the name or location of a file. | 1537 | /// Change the name or location of a file. |
| ... | @@ -1580,6 +1585,113 @@ pub fn renameW(old_path: [*:0]const u16, new_path: [*:0]const u16) RenameError!v | ... | @@ -1580,6 +1585,113 @@ pub fn renameW(old_path: [*:0]const u16, new_path: [*:0]const u16) RenameError!v |
| 1580 | return windows.MoveFileExW(old_path, new_path, flags); | 1585 | return windows.MoveFileExW(old_path, new_path, flags); |
| 1581 | } | 1586 | } |
| 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 | pub const MakeDirError = error{ | 1695 | pub const MakeDirError = error{ |
| 1584 | AccessDenied, | 1696 | AccessDenied, |
| 1585 | DiskQuota, | 1697 | DiskQuota, |
| ... | @@ -2072,7 +2184,7 @@ const ListenError = error{ | ... | @@ -2072,7 +2184,7 @@ const ListenError = error{ |
| 2072 | OperationNotSupported, | 2184 | OperationNotSupported, |
| 2073 | } || UnexpectedError; | 2185 | } || UnexpectedError; |
| 2074 | 2186 | ||
| 2075 | pub fn listen(sockfd: i32, backlog: u32) ListenError!void { | 2187 | pub fn listen(sockfd: fd_t, backlog: u32) ListenError!void { |
| 2076 | const rc = system.listen(sockfd, backlog); | 2188 | const rc = system.listen(sockfd, backlog); |
| 2077 | switch (errno(rc)) { | 2189 | switch (errno(rc)) { |
| 2078 | 0 => return, | 2190 | 0 => return, |
| ... | @@ -2363,7 +2475,7 @@ pub fn connect(sockfd: fd_t, sock_addr: *const sockaddr, len: socklen_t) Connect | ... | @@ -2363,7 +2475,7 @@ pub fn connect(sockfd: fd_t, sock_addr: *const sockaddr, len: socklen_t) Connect |
| 2363 | } | 2475 | } |
| 2364 | } | 2476 | } |
| 2365 | 2477 | ||
| 2366 | pub fn getsockoptError(sockfd: i32) ConnectError!void { | 2478 | pub fn getsockoptError(sockfd: fd_t) ConnectError!void { |
| 2367 | var err_code: u32 = undefined; | 2479 | var err_code: u32 = undefined; |
| 2368 | var size: u32 = @sizeOf(u32); | 2480 | var size: u32 = @sizeOf(u32); |
| 2369 | const rc = system.getsockopt(sockfd, SOL_SOCKET, SO_ERROR, @ptrCast([*]u8, &err_code), &size); | 2481 | const rc = system.getsockopt(sockfd, SOL_SOCKET, SO_ERROR, @ptrCast([*]u8, &err_code), &size); |
| ... | @@ -3051,6 +3163,31 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 { | ... | @@ -3051,6 +3163,31 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 { |
| 3051 | } | 3163 | } |
| 3052 | } | 3164 | } |
| 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 | pub const RealPathError = error{ | 3191 | pub const RealPathError = error{ |
| 3055 | FileNotFound, | 3192 | FileNotFound, |
| 3056 | AccessDenied, | 3193 | AccessDenied, |
| ... | @@ -3125,6 +3262,7 @@ pub fn realpathC(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealP | ... | @@ -3125,6 +3262,7 @@ pub fn realpathC(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealP |
| 3125 | } | 3262 | } |
| 3126 | 3263 | ||
| 3127 | /// Same as `realpath` except `pathname` is null-terminated and UTF16LE-encoded. | 3264 | /// Same as `realpath` except `pathname` is null-terminated and UTF16LE-encoded. |
| 3265 | /// TODO use ntdll for better semantics | ||
| 3128 | pub fn realpathW(pathname: [*:0]const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { | 3266 | pub fn realpathW(pathname: [*:0]const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { |
| 3129 | const h_file = try windows.CreateFileW( | 3267 | const h_file = try windows.CreateFileW( |
| 3130 | pathname, | 3268 | pathname, |
lib/std/os/bits/dragonfly.zig+2| ... | @@ -283,6 +283,8 @@ pub const F_LOCK = 1; | ... | @@ -283,6 +283,8 @@ pub const F_LOCK = 1; |
| 283 | pub const F_TLOCK = 2; | 283 | pub const F_TLOCK = 2; |
| 284 | pub const F_TEST = 3; | 284 | pub const F_TEST = 3; |
| 285 | 285 | ||
| 286 | pub const FD_CLOEXEC = 1; | ||
| 287 | |||
| 286 | pub const AT_FDCWD = -328243; | 288 | pub const AT_FDCWD = -328243; |
| 287 | pub const AT_SYMLINK_NOFOLLOW = 1; | 289 | pub const AT_SYMLINK_NOFOLLOW = 1; |
| 288 | pub const AT_REMOVEDIR = 2; | 290 | pub const AT_REMOVEDIR = 2; |
lib/std/os/bits/freebsd.zig+2| ... | @@ -355,6 +355,8 @@ pub const F_GETOWN_EX = 16; | ... | @@ -355,6 +355,8 @@ pub const F_GETOWN_EX = 16; |
| 355 | 355 | ||
| 356 | pub const F_GETOWNER_UIDS = 17; | 356 | pub const F_GETOWNER_UIDS = 17; |
| 357 | 357 | ||
| 358 | pub const FD_CLOEXEC = 1; | ||
| 359 | |||
| 358 | pub const SEEK_SET = 0; | 360 | pub const SEEK_SET = 0; |
| 359 | pub const SEEK_CUR = 1; | 361 | pub const SEEK_CUR = 1; |
| 360 | pub const SEEK_END = 2; | 362 | pub const SEEK_END = 2; |
lib/std/os/bits/linux.zig+2| ... | @@ -136,6 +136,8 @@ pub const MAP_FIXED_NOREPLACE = 0x100000; | ... | @@ -136,6 +136,8 @@ pub const MAP_FIXED_NOREPLACE = 0x100000; |
| 136 | /// For anonymous mmap, memory could be uninitialized | 136 | /// For anonymous mmap, memory could be uninitialized |
| 137 | pub const MAP_UNINITIALIZED = 0x4000000; | 137 | pub const MAP_UNINITIALIZED = 0x4000000; |
| 138 | 138 | ||
| 139 | pub const FD_CLOEXEC = 1; | ||
| 140 | |||
| 139 | pub const F_OK = 0; | 141 | pub const F_OK = 0; |
| 140 | pub const X_OK = 1; | 142 | pub const X_OK = 1; |
| 141 | pub const W_OK = 2; | 143 | pub const W_OK = 2; |
lib/std/os/bits/netbsd.zig+2| ... | @@ -312,6 +312,8 @@ pub const F_GETLK = 7; | ... | @@ -312,6 +312,8 @@ pub const F_GETLK = 7; |
| 312 | pub const F_SETLK = 8; | 312 | pub const F_SETLK = 8; |
| 313 | pub const F_SETLKW = 9; | 313 | pub const F_SETLKW = 9; |
| 314 | 314 | ||
| 315 | pub const FD_CLOEXEC = 1; | ||
| 316 | |||
| 315 | pub const SEEK_SET = 0; | 317 | pub const SEEK_SET = 0; |
| 316 | pub const SEEK_CUR = 1; | 318 | pub const SEEK_CUR = 1; |
| 317 | pub const SEEK_END = 2; | 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,17 +465,17 @@ pub fn renameat(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const |
| 465 | return syscall4( | 465 | return syscall4( |
| 466 | SYS_renameat, | 466 | SYS_renameat, |
| 467 | @bitCast(usize, @as(isize, oldfd)), | 467 | @bitCast(usize, @as(isize, oldfd)), |
| 468 | @ptrToInt(old), | 468 | @ptrToInt(oldpath), |
| 469 | @bitCast(usize, @as(isize, newfd)), | 469 | @bitCast(usize, @as(isize, newfd)), |
| 470 | @ptrToInt(new), | 470 | @ptrToInt(newpath), |
| 471 | ); | 471 | ); |
| 472 | } else { | 472 | } else { |
| 473 | return syscall5( | 473 | return syscall5( |
| 474 | SYS_renameat2, | 474 | SYS_renameat2, |
| 475 | @bitCast(usize, @as(isize, oldfd)), | 475 | @bitCast(usize, @as(isize, oldfd)), |
| 476 | @ptrToInt(old), | 476 | @ptrToInt(oldpath), |
| 477 | @bitCast(usize, @as(isize, newfd)), | 477 | @bitCast(usize, @as(isize, newfd)), |
| 478 | @ptrToInt(new), | 478 | @ptrToInt(newpath), |
| 479 | 0, | 479 | 0, |
| 480 | ); | 480 | ); |
| 481 | } | 481 | } |
| ... | @@ -588,6 +588,10 @@ pub fn waitpid(pid: pid_t, status: *u32, flags: u32) usize { | ... | @@ -588,6 +588,10 @@ pub fn waitpid(pid: pid_t, status: *u32, flags: u32) usize { |
| 588 | return syscall4(SYS_wait4, @bitCast(usize, @as(isize, pid)), @ptrToInt(status), flags, 0); | 588 | return syscall4(SYS_wait4, @bitCast(usize, @as(isize, pid)), @ptrToInt(status), flags, 0); |
| 589 | } | 589 | } |
| 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 | var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime); | 595 | var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime); |
| 592 | 596 | ||
| 593 | // We must follow the C calling convention when we call into the VDSO | 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,7 +1,8 @@ |
| 1 | const std = @import("../std.zig"); | 1 | const std = @import("../std.zig"); |
| 2 | const os = std.os; | 2 | const os = std.os; |
| 3 | const testing = std.testing; | 3 | const testing = std.testing; |
| 4 | const expect = std.testing.expect; | 4 | const expect = testing.expect; |
| 5 | const expectEqual = testing.expectEqual; | ||
| 5 | const io = std.io; | 6 | const io = std.io; |
| 6 | const fs = std.fs; | 7 | const fs = std.fs; |
| 7 | const mem = std.mem; | 8 | const mem = std.mem; |
| ... | @@ -19,8 +20,8 @@ test "makePath, put some files in it, deleteTree" { | ... | @@ -19,8 +20,8 @@ test "makePath, put some files in it, deleteTree" { |
| 19 | try fs.cwd().makePath("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c"); | 20 | try fs.cwd().makePath("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c"); |
| 20 | try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c" ++ fs.path.sep_str ++ "file.txt", "nonsense"); | 21 | try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c" ++ fs.path.sep_str ++ "file.txt", "nonsense"); |
| 21 | try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah"); | 22 | try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah"); |
| 22 | try fs.deleteTree("os_test_tmp"); | 23 | try fs.cwd().deleteTree("os_test_tmp"); |
| 23 | if (fs.cwd().openDirTraverse("os_test_tmp")) |dir| { | 24 | if (fs.cwd().openDir("os_test_tmp", .{})) |dir| { |
| 24 | @panic("expected error"); | 25 | @panic("expected error"); |
| 25 | } else |err| { | 26 | } else |err| { |
| 26 | expect(err == error.FileNotFound); | 27 | expect(err == error.FileNotFound); |
| ... | @@ -37,7 +38,7 @@ test "access file" { | ... | @@ -37,7 +38,7 @@ test "access file" { |
| 37 | 38 | ||
| 38 | try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", ""); | 39 | try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", ""); |
| 39 | try os.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", os.F_OK); | 40 | try os.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", os.F_OK); |
| 40 | try fs.deleteTree("os_test_tmp"); | 41 | try fs.cwd().deleteTree("os_test_tmp"); |
| 41 | } | 42 | } |
| 42 | 43 | ||
| 43 | fn testThreadIdFn(thread_id: *Thread.Id) void { | 44 | fn testThreadIdFn(thread_id: *Thread.Id) void { |
| ... | @@ -46,9 +47,9 @@ fn testThreadIdFn(thread_id: *Thread.Id) void { | ... | @@ -46,9 +47,9 @@ fn testThreadIdFn(thread_id: *Thread.Id) void { |
| 46 | 47 | ||
| 47 | test "sendfile" { | 48 | test "sendfile" { |
| 48 | try fs.cwd().makePath("os_test_tmp"); | 49 | try fs.cwd().makePath("os_test_tmp"); |
| 49 | defer fs.deleteTree("os_test_tmp") catch {}; | 50 | defer fs.cwd().deleteTree("os_test_tmp") catch {}; |
| 50 | 51 | ||
| 51 | var dir = try fs.cwd().openDirList("os_test_tmp"); | 52 | var dir = try fs.cwd().openDir("os_test_tmp", .{}); |
| 52 | defer dir.close(); | 53 | defer dir.close(); |
| 53 | 54 | ||
| 54 | const line1 = "line1\n"; | 55 | const line1 = "line1\n"; |
| ... | @@ -112,14 +113,16 @@ test "fs.copyFile" { | ... | @@ -112,14 +113,16 @@ test "fs.copyFile" { |
| 112 | const dest_file = "tmp_test_copy_file2.txt"; | 113 | const dest_file = "tmp_test_copy_file2.txt"; |
| 113 | const dest_file2 = "tmp_test_copy_file3.txt"; | 114 | const dest_file2 = "tmp_test_copy_file3.txt"; |
| 114 | 115 | ||
| 115 | try fs.cwd().writeFile(src_file, data); | 116 | const cwd = fs.cwd(); |
| 116 | defer fs.cwd().deleteFile(src_file) catch {}; | ||
| 117 | 117 | ||
| 118 | try fs.copyFile(src_file, dest_file); | 118 | try cwd.writeFile(src_file, data); |
| 119 | defer fs.cwd().deleteFile(dest_file) catch {}; | 119 | defer cwd.deleteFile(src_file) catch {}; |
| 120 | 120 | ||
| 121 | try fs.copyFileMode(src_file, dest_file2, File.default_mode); | 121 | try cwd.copyFile(src_file, cwd, dest_file, .{}); |
| 122 | defer fs.cwd().deleteFile(dest_file2) catch {}; | 122 | defer cwd.deleteFile(dest_file) catch {}; |
| 123 | |||
| 124 | try cwd.copyFile(src_file, cwd, dest_file2, .{ .override_mode = File.default_mode }); | ||
| 125 | defer cwd.deleteFile(dest_file2) catch {}; | ||
| 123 | 126 | ||
| 124 | try expectFileContents(dest_file, data); | 127 | try expectFileContents(dest_file, data); |
| 125 | try expectFileContents(dest_file2, data); | 128 | try expectFileContents(dest_file2, data); |
| ... | @@ -446,3 +449,32 @@ test "getenv" { | ... | @@ -446,3 +449,32 @@ test "getenv" { |
| 446 | expect(os.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null); | 449 | expect(os.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null); |
| 447 | } | 450 | } |
| 448 | } | 451 | } |
| 452 | |||
| 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,6 +88,82 @@ pub fn CreateFileW( |
| 88 | return result; | 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 | pub const CreatePipeError = error{Unexpected}; | 167 | pub const CreatePipeError = error{Unexpected}; |
| 92 | 168 | ||
| 93 | pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) CreatePipeError!void { | 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,7 +1276,15 @@ pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError { |
| 1200 | // 614 is the length of the longest windows error desciption | 1276 | // 614 is the length of the longest windows error desciption |
| 1201 | var buf_u16: [614]u16 = undefined; | 1277 | var buf_u16: [614]u16 = undefined; |
| 1202 | var buf_u8: [614]u8 = undefined; | 1278 | var buf_u8: [614]u8 = undefined; |
| 1203 | var len = kernel32.FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, null, err, MAKELANGID(LANG.NEUTRAL, SUBLANG.DEFAULT), buf_u16[0..].ptr, buf_u16.len / @sizeOf(TCHAR), null); | 1279 | const len = kernel32.FormatMessageW( |
| 1280 | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | ||
| 1281 | null, | ||
| 1282 | err, | ||
| 1283 | MAKELANGID(LANG.NEUTRAL, SUBLANG.DEFAULT), | ||
| 1284 | &buf_u16, | ||
| 1285 | buf_u16.len / @sizeOf(TCHAR), | ||
| 1286 | null, | ||
| 1287 | ); | ||
| 1204 | _ = std.unicode.utf16leToUtf8(&buf_u8, buf_u16[0..len]) catch unreachable; | 1288 | _ = std.unicode.utf16leToUtf8(&buf_u8, buf_u16[0..len]) catch unreachable; |
| 1205 | std.debug.warn("error.Unexpected: GetLastError({}): {}\n", .{ @enumToInt(err), buf_u8[0..len] }); | 1289 | std.debug.warn("error.Unexpected: GetLastError({}): {}\n", .{ @enumToInt(err), buf_u8[0..len] }); |
| 1206 | std.debug.dumpCurrentStackTrace(null); | 1290 | std.debug.dumpCurrentStackTrace(null); |
lib/std/os/windows/bits.zig+7| ... | @@ -242,6 +242,13 @@ pub const FILE_NAME_INFORMATION = extern struct { | ... | @@ -242,6 +242,13 @@ pub const FILE_NAME_INFORMATION = extern struct { |
| 242 | FileName: [1]WCHAR, | 242 | FileName: [1]WCHAR, |
| 243 | }; | 243 | }; |
| 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 | pub const IO_STATUS_BLOCK = extern struct { | 252 | pub const IO_STATUS_BLOCK = extern struct { |
| 246 | // "DUMMYUNIONNAME" expands to "u" | 253 | // "DUMMYUNIONNAME" expands to "u" |
| 247 | u: extern union { | 254 | u: extern union { |
lib/std/rand.zig+1-1| ... | @@ -5,7 +5,7 @@ | ... | @@ -5,7 +5,7 @@ |
| 5 | // ``` | 5 | // ``` |
| 6 | // var buf: [8]u8 = undefined; | 6 | // var buf: [8]u8 = undefined; |
| 7 | // try std.crypto.randomBytes(buf[0..]); | 7 | // try std.crypto.randomBytes(buf[0..]); |
| 8 | // const seed = mem.readIntSliceLittle(u64, buf[0..8]); | 8 | // const seed = mem.readIntLittle(u64, buf[0..8]); |
| 9 | // | 9 | // |
| 10 | // var r = DefaultPrng.init(seed); | 10 | // var r = DefaultPrng.init(seed); |
| 11 | // | 11 | // |
lib/std/thread.zig+45-6| ... | @@ -6,6 +6,8 @@ const windows = std.os.windows; | ... | @@ -6,6 +6,8 @@ const windows = std.os.windows; |
| 6 | const c = std.c; | 6 | const c = std.c; |
| 7 | const assert = std.debug.assert; | 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 | pub const Thread = struct { | 11 | pub const Thread = struct { |
| 10 | data: Data, | 12 | data: Data, |
| 11 | 13 | ||
| ... | @@ -158,15 +160,34 @@ pub const Thread = struct { | ... | @@ -158,15 +160,34 @@ pub const Thread = struct { |
| 158 | }; | 160 | }; |
| 159 | fn threadMain(raw_arg: windows.LPVOID) callconv(.C) windows.DWORD { | 161 | fn threadMain(raw_arg: windows.LPVOID) callconv(.C) windows.DWORD { |
| 160 | const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*; | 162 | const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*; |
| 163 | |||
| 161 | switch (@typeInfo(@TypeOf(startFn).ReturnType)) { | 164 | switch (@typeInfo(@TypeOf(startFn).ReturnType)) { |
| 162 | .Int => { | 165 | .NoReturn => { |
| 163 | return startFn(arg); | 166 | startFn(arg); |
| 164 | }, | 167 | }, |
| 165 | .Void => { | 168 | .Void => { |
| 166 | startFn(arg); | 169 | startFn(arg); |
| 167 | return 0; | 170 | return 0; |
| 168 | }, | 171 | }, |
| 169 | else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"), | 172 | .Int => |info| { |
| 173 | if (info.bits != 8) { | ||
| 174 | @compileError(bad_startfn_ret); | ||
| 175 | } | ||
| 176 | return startFn(arg); | ||
| 177 | }, | ||
| 178 | .ErrorUnion => |info| { | ||
| 179 | if (info.payload != void) { | ||
| 180 | @compileError(bad_startfn_ret); | ||
| 181 | } | ||
| 182 | startFn(arg) catch |err| { | ||
| 183 | std.debug.warn("error: {}\n", .{@errorName(err)}); | ||
| 184 | if (@errorReturnTrace()) |trace| { | ||
| 185 | std.debug.dumpStackTrace(trace.*); | ||
| 186 | } | ||
| 187 | }; | ||
| 188 | return 0; | ||
| 189 | }, | ||
| 190 | else => @compileError(bad_startfn_ret), | ||
| 170 | } | 191 | } |
| 171 | } | 192 | } |
| 172 | }; | 193 | }; |
| ... | @@ -202,14 +223,32 @@ pub const Thread = struct { | ... | @@ -202,14 +223,32 @@ pub const Thread = struct { |
| 202 | const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*; | 223 | const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*; |
| 203 | 224 | ||
| 204 | switch (@typeInfo(@TypeOf(startFn).ReturnType)) { | 225 | switch (@typeInfo(@TypeOf(startFn).ReturnType)) { |
| 205 | .Int => { | 226 | .NoReturn => { |
| 206 | return startFn(arg); | 227 | startFn(arg); |
| 207 | }, | 228 | }, |
| 208 | .Void => { | 229 | .Void => { |
| 209 | startFn(arg); | 230 | startFn(arg); |
| 210 | return 0; | 231 | return 0; |
| 211 | }, | 232 | }, |
| 212 | else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"), | 233 | .Int => |info| { |
| 234 | if (info.bits != 8) { | ||
| 235 | @compileError(bad_startfn_ret); | ||
| 236 | } | ||
| 237 | return startFn(arg); | ||
| 238 | }, | ||
| 239 | .ErrorUnion => |info| { | ||
| 240 | if (info.payload != void) { | ||
| 241 | @compileError(bad_startfn_ret); | ||
| 242 | } | ||
| 243 | startFn(arg) catch |err| { | ||
| 244 | std.debug.warn("error: {}\n", .{@errorName(err)}); | ||
| 245 | if (@errorReturnTrace()) |trace| { | ||
| 246 | std.debug.dumpStackTrace(trace.*); | ||
| 247 | } | ||
| 248 | }; | ||
| 249 | return 0; | ||
| 250 | }, | ||
| 251 | else => @compileError(bad_startfn_ret), | ||
| 213 | } | 252 | } |
| 214 | } | 253 | } |
| 215 | fn posixThreadMain(ctx: ?*c_void) callconv(.C) ?*c_void { | 254 | fn posixThreadMain(ctx: ?*c_void) callconv(.C) ?*c_void { |
lib/std/unicode.zig+10-10| ... | @@ -251,12 +251,12 @@ pub const Utf16LeIterator = struct { | ... | @@ -251,12 +251,12 @@ pub const Utf16LeIterator = struct { |
| 251 | pub fn nextCodepoint(it: *Utf16LeIterator) !?u21 { | 251 | pub fn nextCodepoint(it: *Utf16LeIterator) !?u21 { |
| 252 | assert(it.i <= it.bytes.len); | 252 | assert(it.i <= it.bytes.len); |
| 253 | if (it.i == it.bytes.len) return null; | 253 | if (it.i == it.bytes.len) return null; |
| 254 | const c0: u21 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]); | 254 | const c0: u21 = mem.readIntLittle(u16, it.bytes[it.i..][0..2]); |
| 255 | if (c0 & ~@as(u21, 0x03ff) == 0xd800) { | 255 | if (c0 & ~@as(u21, 0x03ff) == 0xd800) { |
| 256 | // surrogate pair | 256 | // surrogate pair |
| 257 | it.i += 2; | 257 | it.i += 2; |
| 258 | if (it.i >= it.bytes.len) return error.DanglingSurrogateHalf; | 258 | if (it.i >= it.bytes.len) return error.DanglingSurrogateHalf; |
| 259 | const c1: u21 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]); | 259 | const c1: u21 = mem.readIntLittle(u16, it.bytes[it.i..][0..2]); |
| 260 | if (c1 & ~@as(u21, 0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf; | 260 | if (c1 & ~@as(u21, 0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf; |
| 261 | it.i += 2; | 261 | it.i += 2; |
| 262 | return 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff)); | 262 | return 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff)); |
| ... | @@ -630,11 +630,11 @@ test "utf8ToUtf16LeWithNull" { | ... | @@ -630,11 +630,11 @@ test "utf8ToUtf16LeWithNull" { |
| 630 | } | 630 | } |
| 631 | } | 631 | } |
| 632 | 632 | ||
| 633 | /// Converts a UTF-8 string literal into a UTF-16LE string literal. | 633 | /// Converts a UTF-8 string literal into a UTF-16LE string literal. |
| 634 | pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16LeLen(utf8) :0] u16 { | 634 | pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16LeLen(utf8):0]u16 { |
| 635 | comptime { | 635 | comptime { |
| 636 | const len: usize = calcUtf16LeLen(utf8); | 636 | const len: usize = calcUtf16LeLen(utf8); |
| 637 | var utf16le: [len :0]u16 = [_ :0]u16{0} ** len; | 637 | var utf16le: [len:0]u16 = [_:0]u16{0} ** len; |
| 638 | const utf16le_len = utf8ToUtf16Le(&utf16le, utf8[0..]) catch |err| @compileError(err); | 638 | const utf16le_len = utf8ToUtf16Le(&utf16le, utf8[0..]) catch |err| @compileError(err); |
| 639 | assert(len == utf16le_len); | 639 | assert(len == utf16le_len); |
| 640 | return &utf16le; | 640 | return &utf16le; |
| ... | @@ -660,8 +660,8 @@ fn calcUtf16LeLen(utf8: []const u8) usize { | ... | @@ -660,8 +660,8 @@ fn calcUtf16LeLen(utf8: []const u8) usize { |
| 660 | } | 660 | } |
| 661 | 661 | ||
| 662 | test "utf8ToUtf16LeStringLiteral" { | 662 | test "utf8ToUtf16LeStringLiteral" { |
| 663 | { | 663 | { |
| 664 | const bytes = [_:0]u16{ 0x41 }; | 664 | const bytes = [_:0]u16{0x41}; |
| 665 | const utf16 = utf8ToUtf16LeStringLiteral("A"); | 665 | const utf16 = utf8ToUtf16LeStringLiteral("A"); |
| 666 | testing.expectEqualSlices(u16, &bytes, utf16); | 666 | testing.expectEqualSlices(u16, &bytes, utf16); |
| 667 | testing.expect(utf16[1] == 0); | 667 | testing.expect(utf16[1] == 0); |
| ... | @@ -673,19 +673,19 @@ test "utf8ToUtf16LeStringLiteral" { | ... | @@ -673,19 +673,19 @@ test "utf8ToUtf16LeStringLiteral" { |
| 673 | testing.expect(utf16[2] == 0); | 673 | testing.expect(utf16[2] == 0); |
| 674 | } | 674 | } |
| 675 | { | 675 | { |
| 676 | const bytes = [_:0]u16{ 0x02FF }; | 676 | const bytes = [_:0]u16{0x02FF}; |
| 677 | const utf16 = utf8ToUtf16LeStringLiteral("\u{02FF}"); | 677 | const utf16 = utf8ToUtf16LeStringLiteral("\u{02FF}"); |
| 678 | testing.expectEqualSlices(u16, &bytes, utf16); | 678 | testing.expectEqualSlices(u16, &bytes, utf16); |
| 679 | testing.expect(utf16[1] == 0); | 679 | testing.expect(utf16[1] == 0); |
| 680 | } | 680 | } |
| 681 | { | 681 | { |
| 682 | const bytes = [_:0]u16{ 0x7FF }; | 682 | const bytes = [_:0]u16{0x7FF}; |
| 683 | const utf16 = utf8ToUtf16LeStringLiteral("\u{7FF}"); | 683 | const utf16 = utf8ToUtf16LeStringLiteral("\u{7FF}"); |
| 684 | testing.expectEqualSlices(u16, &bytes, utf16); | 684 | testing.expectEqualSlices(u16, &bytes, utf16); |
| 685 | testing.expect(utf16[1] == 0); | 685 | testing.expect(utf16[1] == 0); |
| 686 | } | 686 | } |
| 687 | { | 687 | { |
| 688 | const bytes = [_:0]u16{ 0x801 }; | 688 | const bytes = [_:0]u16{0x801}; |
| 689 | const utf16 = utf8ToUtf16LeStringLiteral("\u{801}"); | 689 | const utf16 = utf8ToUtf16LeStringLiteral("\u{801}"); |
| 690 | testing.expectEqualSlices(u16, &bytes, utf16); | 690 | testing.expectEqualSlices(u16, &bytes, utf16); |
| 691 | testing.expect(utf16[1] == 0); | 691 | testing.expect(utf16[1] == 0); |
lib/std/zig/ast.zig+66-92| ... | @@ -743,11 +743,11 @@ pub const Node = struct { | ... | @@ -743,11 +743,11 @@ pub const Node = struct { |
| 743 | var i = index; | 743 | var i = index; |
| 744 | 744 | ||
| 745 | switch (self.init_arg_expr) { | 745 | switch (self.init_arg_expr) { |
| 746 | InitArg.Type => |t| { | 746 | .Type => |t| { |
| 747 | if (i < 1) return t; | 747 | if (i < 1) return t; |
| 748 | i -= 1; | 748 | i -= 1; |
| 749 | }, | 749 | }, |
| 750 | InitArg.None, InitArg.Enum => {}, | 750 | .None, .Enum => {}, |
| 751 | } | 751 | } |
| 752 | 752 | ||
| 753 | if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i).*; | 753 | if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i).*; |
| ... | @@ -907,12 +907,7 @@ pub const Node = struct { | ... | @@ -907,12 +907,7 @@ pub const Node = struct { |
| 907 | } | 907 | } |
| 908 | 908 | ||
| 909 | switch (self.return_type) { | 909 | switch (self.return_type) { |
| 910 | // TODO allow this and next prong to share bodies since the types are the same | 910 | .Explicit, .InferErrorSet => |node| { |
| 911 | ReturnType.Explicit => |node| { | ||
| 912 | if (i < 1) return node; | ||
| 913 | i -= 1; | ||
| 914 | }, | ||
| 915 | ReturnType.InferErrorSet => |node| { | ||
| 916 | if (i < 1) return node; | 911 | if (i < 1) return node; |
| 917 | i -= 1; | 912 | i -= 1; |
| 918 | }, | 913 | }, |
| ... | @@ -937,9 +932,7 @@ pub const Node = struct { | ... | @@ -937,9 +932,7 @@ pub const Node = struct { |
| 937 | pub fn lastToken(self: *const FnProto) TokenIndex { | 932 | pub fn lastToken(self: *const FnProto) TokenIndex { |
| 938 | if (self.body_node) |body_node| return body_node.lastToken(); | 933 | if (self.body_node) |body_node| return body_node.lastToken(); |
| 939 | switch (self.return_type) { | 934 | switch (self.return_type) { |
| 940 | // TODO allow this and next prong to share bodies since the types are the same | 935 | .Explicit, .InferErrorSet => |node| return node.lastToken(), |
| 941 | ReturnType.Explicit => |node| return node.lastToken(), | ||
| 942 | ReturnType.InferErrorSet => |node| return node.lastToken(), | ||
| 943 | } | 936 | } |
| 944 | } | 937 | } |
| 945 | }; | 938 | }; |
| ... | @@ -1515,55 +1508,55 @@ pub const Node = struct { | ... | @@ -1515,55 +1508,55 @@ pub const Node = struct { |
| 1515 | i -= 1; | 1508 | i -= 1; |
| 1516 | 1509 | ||
| 1517 | switch (self.op) { | 1510 | switch (self.op) { |
| 1518 | Op.Catch => |maybe_payload| { | 1511 | .Catch => |maybe_payload| { |
| 1519 | if (maybe_payload) |payload| { | 1512 | if (maybe_payload) |payload| { |
| 1520 | if (i < 1) return payload; | 1513 | if (i < 1) return payload; |
| 1521 | i -= 1; | 1514 | i -= 1; |
| 1522 | } | 1515 | } |
| 1523 | }, | 1516 | }, |
| 1524 | 1517 | ||
| 1525 | Op.Add, | 1518 | .Add, |
| 1526 | Op.AddWrap, | 1519 | .AddWrap, |
| 1527 | Op.ArrayCat, | 1520 | .ArrayCat, |
| 1528 | Op.ArrayMult, | 1521 | .ArrayMult, |
| 1529 | Op.Assign, | 1522 | .Assign, |
| 1530 | Op.AssignBitAnd, | 1523 | .AssignBitAnd, |
| 1531 | Op.AssignBitOr, | 1524 | .AssignBitOr, |
| 1532 | Op.AssignBitShiftLeft, | 1525 | .AssignBitShiftLeft, |
| 1533 | Op.AssignBitShiftRight, | 1526 | .AssignBitShiftRight, |
| 1534 | Op.AssignBitXor, | 1527 | .AssignBitXor, |
| 1535 | Op.AssignDiv, | 1528 | .AssignDiv, |
| 1536 | Op.AssignSub, | 1529 | .AssignSub, |
| 1537 | Op.AssignSubWrap, | 1530 | .AssignSubWrap, |
| 1538 | Op.AssignMod, | 1531 | .AssignMod, |
| 1539 | Op.AssignAdd, | 1532 | .AssignAdd, |
| 1540 | Op.AssignAddWrap, | 1533 | .AssignAddWrap, |
| 1541 | Op.AssignMul, | 1534 | .AssignMul, |
| 1542 | Op.AssignMulWrap, | 1535 | .AssignMulWrap, |
| 1543 | Op.BangEqual, | 1536 | .BangEqual, |
| 1544 | Op.BitAnd, | 1537 | .BitAnd, |
| 1545 | Op.BitOr, | 1538 | .BitOr, |
| 1546 | Op.BitShiftLeft, | 1539 | .BitShiftLeft, |
| 1547 | Op.BitShiftRight, | 1540 | .BitShiftRight, |
| 1548 | Op.BitXor, | 1541 | .BitXor, |
| 1549 | Op.BoolAnd, | 1542 | .BoolAnd, |
| 1550 | Op.BoolOr, | 1543 | .BoolOr, |
| 1551 | Op.Div, | 1544 | .Div, |
| 1552 | Op.EqualEqual, | 1545 | .EqualEqual, |
| 1553 | Op.ErrorUnion, | 1546 | .ErrorUnion, |
| 1554 | Op.GreaterOrEqual, | 1547 | .GreaterOrEqual, |
| 1555 | Op.GreaterThan, | 1548 | .GreaterThan, |
| 1556 | Op.LessOrEqual, | 1549 | .LessOrEqual, |
| 1557 | Op.LessThan, | 1550 | .LessThan, |
| 1558 | Op.MergeErrorSets, | 1551 | .MergeErrorSets, |
| 1559 | Op.Mod, | 1552 | .Mod, |
| 1560 | Op.Mul, | 1553 | .Mul, |
| 1561 | Op.MulWrap, | 1554 | .MulWrap, |
| 1562 | Op.Period, | 1555 | .Period, |
| 1563 | Op.Range, | 1556 | .Range, |
| 1564 | Op.Sub, | 1557 | .Sub, |
| 1565 | Op.SubWrap, | 1558 | .SubWrap, |
| 1566 | Op.UnwrapOptional, | 1559 | .UnwrapOptional, |
| 1567 | => {}, | 1560 | => {}, |
| 1568 | } | 1561 | } |
| 1569 | 1562 | ||
| ... | @@ -1594,7 +1587,6 @@ pub const Node = struct { | ... | @@ -1594,7 +1587,6 @@ pub const Node = struct { |
| 1594 | Await, | 1587 | Await, |
| 1595 | BitNot, | 1588 | BitNot, |
| 1596 | BoolNot, | 1589 | BoolNot, |
| 1597 | Cancel, | ||
| 1598 | OptionalType, | 1590 | OptionalType, |
| 1599 | Negation, | 1591 | Negation, |
| 1600 | NegationWrap, | 1592 | NegationWrap, |
| ... | @@ -1631,8 +1623,7 @@ pub const Node = struct { | ... | @@ -1631,8 +1623,7 @@ pub const Node = struct { |
| 1631 | var i = index; | 1623 | var i = index; |
| 1632 | 1624 | ||
| 1633 | switch (self.op) { | 1625 | switch (self.op) { |
| 1634 | // TODO https://github.com/ziglang/zig/issues/1107 | 1626 | .PtrType, .SliceType => |addr_of_info| { |
| 1635 | Op.SliceType => |addr_of_info| { | ||
| 1636 | if (addr_of_info.sentinel) |sentinel| { | 1627 | if (addr_of_info.sentinel) |sentinel| { |
| 1637 | if (i < 1) return sentinel; | 1628 | if (i < 1) return sentinel; |
| 1638 | i -= 1; | 1629 | i -= 1; |
| ... | @@ -1644,14 +1635,7 @@ pub const Node = struct { | ... | @@ -1644,14 +1635,7 @@ pub const Node = struct { |
| 1644 | } | 1635 | } |
| 1645 | }, | 1636 | }, |
| 1646 | 1637 | ||
| 1647 | Op.PtrType => |addr_of_info| { | 1638 | .ArrayType => |array_info| { |
| 1648 | if (addr_of_info.align_info) |align_info| { | ||
| 1649 | if (i < 1) return align_info.node; | ||
| 1650 | i -= 1; | ||
| 1651 | } | ||
| 1652 | }, | ||
| 1653 | |||
| 1654 | Op.ArrayType => |array_info| { | ||
| 1655 | if (i < 1) return array_info.len_expr; | 1639 | if (i < 1) return array_info.len_expr; |
| 1656 | i -= 1; | 1640 | i -= 1; |
| 1657 | if (array_info.sentinel) |sentinel| { | 1641 | if (array_info.sentinel) |sentinel| { |
| ... | @@ -1660,16 +1644,15 @@ pub const Node = struct { | ... | @@ -1660,16 +1644,15 @@ pub const Node = struct { |
| 1660 | } | 1644 | } |
| 1661 | }, | 1645 | }, |
| 1662 | 1646 | ||
| 1663 | Op.AddressOf, | 1647 | .AddressOf, |
| 1664 | Op.Await, | 1648 | .Await, |
| 1665 | Op.BitNot, | 1649 | .BitNot, |
| 1666 | Op.BoolNot, | 1650 | .BoolNot, |
| 1667 | Op.Cancel, | 1651 | .OptionalType, |
| 1668 | Op.OptionalType, | 1652 | .Negation, |
| 1669 | Op.Negation, | 1653 | .NegationWrap, |
| 1670 | Op.NegationWrap, | 1654 | .Try, |
| 1671 | Op.Try, | 1655 | .Resume, |
| 1672 | Op.Resume, | ||
| 1673 | => {}, | 1656 | => {}, |
| 1674 | } | 1657 | } |
| 1675 | 1658 | ||
| ... | @@ -1853,19 +1836,14 @@ pub const Node = struct { | ... | @@ -1853,19 +1836,14 @@ pub const Node = struct { |
| 1853 | var i = index; | 1836 | var i = index; |
| 1854 | 1837 | ||
| 1855 | switch (self.kind) { | 1838 | switch (self.kind) { |
| 1856 | Kind.Break => |maybe_label| { | 1839 | .Break, |
| 1840 | .Continue => |maybe_label| { | ||
| 1857 | if (maybe_label) |label| { | 1841 | if (maybe_label) |label| { |
| 1858 | if (i < 1) return label; | 1842 | if (i < 1) return label; |
| 1859 | i -= 1; | 1843 | i -= 1; |
| 1860 | } | 1844 | } |
| 1861 | }, | 1845 | }, |
| 1862 | Kind.Continue => |maybe_label| { | 1846 | .Return => {}, |
| 1863 | if (maybe_label) |label| { | ||
| 1864 | if (i < 1) return label; | ||
| 1865 | i -= 1; | ||
| 1866 | } | ||
| 1867 | }, | ||
| 1868 | Kind.Return => {}, | ||
| 1869 | } | 1847 | } |
| 1870 | 1848 | ||
| 1871 | if (self.rhs) |rhs| { | 1849 | if (self.rhs) |rhs| { |
| ... | @@ -1886,17 +1864,13 @@ pub const Node = struct { | ... | @@ -1886,17 +1864,13 @@ pub const Node = struct { |
| 1886 | } | 1864 | } |
| 1887 | 1865 | ||
| 1888 | switch (self.kind) { | 1866 | switch (self.kind) { |
| 1889 | Kind.Break => |maybe_label| { | 1867 | .Break, |
| 1890 | if (maybe_label) |label| { | 1868 | .Continue => |maybe_label| { |
| 1891 | return label.lastToken(); | ||
| 1892 | } | ||
| 1893 | }, | ||
| 1894 | Kind.Continue => |maybe_label| { | ||
| 1895 | if (maybe_label) |label| { | 1869 | if (maybe_label) |label| { |
| 1896 | return label.lastToken(); | 1870 | return label.lastToken(); |
| 1897 | } | 1871 | } |
| 1898 | }, | 1872 | }, |
| 1899 | Kind.Return => return self.ltoken, | 1873 | .Return => return self.ltoken, |
| 1900 | } | 1874 | } |
| 1901 | 1875 | ||
| 1902 | return self.ltoken; | 1876 | return self.ltoken; |
| ... | @@ -2137,11 +2111,11 @@ pub const Node = struct { | ... | @@ -2137,11 +2111,11 @@ pub const Node = struct { |
| 2137 | i -= 1; | 2111 | i -= 1; |
| 2138 | 2112 | ||
| 2139 | switch (self.kind) { | 2113 | switch (self.kind) { |
| 2140 | Kind.Variable => |variable_name| { | 2114 | .Variable => |variable_name| { |
| 2141 | if (i < 1) return &variable_name.base; | 2115 | if (i < 1) return &variable_name.base; |
| 2142 | i -= 1; | 2116 | i -= 1; |
| 2143 | }, | 2117 | }, |
| 2144 | Kind.Return => |return_type| { | 2118 | .Return => |return_type| { |
| 2145 | if (i < 1) return return_type; | 2119 | if (i < 1) return return_type; |
| 2146 | i -= 1; | 2120 | i -= 1; |
| 2147 | }, | 2121 | }, |
lib/std/zig/parse.zig+336-351| ... | @@ -23,7 +23,7 @@ pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree { | ... | @@ -23,7 +23,7 @@ pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree { |
| 23 | var arena = std.heap.ArenaAllocator.init(allocator); | 23 | var arena = std.heap.ArenaAllocator.init(allocator); |
| 24 | errdefer arena.deinit(); | 24 | errdefer arena.deinit(); |
| 25 | const tree = try arena.allocator.create(ast.Tree); | 25 | const tree = try arena.allocator.create(ast.Tree); |
| 26 | tree.* = ast.Tree{ | 26 | tree.* = .{ |
| 27 | .source = source, | 27 | .source = source, |
| 28 | .root_node = undefined, | 28 | .root_node = undefined, |
| 29 | .arena_allocator = arena, | 29 | .arena_allocator = arena, |
| ... | @@ -66,10 +66,10 @@ pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree { | ... | @@ -66,10 +66,10 @@ pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree { |
| 66 | /// Root <- skip ContainerMembers eof | 66 | /// Root <- skip ContainerMembers eof |
| 67 | fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!*Node.Root { | 67 | fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!*Node.Root { |
| 68 | const node = try arena.create(Node.Root); | 68 | const node = try arena.create(Node.Root); |
| 69 | node.* = Node.Root{ | 69 | node.* = .{ |
| 70 | .decls = try parseContainerMembers(arena, it, tree), | 70 | .decls = try parseContainerMembers(arena, it, tree), |
| 71 | .eof_token = eatToken(it, .Eof) orelse { | 71 | .eof_token = eatToken(it, .Eof) orelse { |
| 72 | try tree.errors.push(AstError{ | 72 | try tree.errors.push(.{ |
| 73 | .ExpectedContainerMembers = .{ .token = it.index }, | 73 | .ExpectedContainerMembers = .{ .token = it.index }, |
| 74 | }); | 74 | }); |
| 75 | return error.ParseError; | 75 | return error.ParseError; |
| ... | @@ -139,8 +139,8 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No | ... | @@ -139,8 +139,8 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | if (visib_token != null) { | 141 | if (visib_token != null) { |
| 142 | try tree.errors.push(AstError{ | 142 | try tree.errors.push(.{ |
| 143 | .ExpectedPubItem = AstError.ExpectedPubItem{ .token = it.index }, | 143 | .ExpectedPubItem = .{ .token = it.index }, |
| 144 | }); | 144 | }); |
| 145 | return error.ParseError; | 145 | return error.ParseError; |
| 146 | } | 146 | } |
| ... | @@ -157,8 +157,8 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No | ... | @@ -157,8 +157,8 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No |
| 157 | 157 | ||
| 158 | // Dangling doc comment | 158 | // Dangling doc comment |
| 159 | if (doc_comments != null) { | 159 | if (doc_comments != null) { |
| 160 | try tree.errors.push(AstError{ | 160 | try tree.errors.push(.{ |
| 161 | .UnattachedDocComment = AstError.UnattachedDocComment{ .token = doc_comments.?.firstToken() }, | 161 | .UnattachedDocComment = .{ .token = doc_comments.?.firstToken() }, |
| 162 | }); | 162 | }); |
| 163 | } | 163 | } |
| 164 | break; | 164 | break; |
| ... | @@ -177,7 +177,7 @@ fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree) | ... | @@ -177,7 +177,7 @@ fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree) |
| 177 | if (lines.len == 0) return null; | 177 | if (lines.len == 0) return null; |
| 178 | 178 | ||
| 179 | const node = try arena.create(Node.DocComment); | 179 | const node = try arena.create(Node.DocComment); |
| 180 | node.* = Node.DocComment{ | 180 | node.* = .{ |
| 181 | .lines = lines, | 181 | .lines = lines, |
| 182 | }; | 182 | }; |
| 183 | return &node.base; | 183 | return &node.base; |
| ... | @@ -186,15 +186,15 @@ fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree) | ... | @@ -186,15 +186,15 @@ fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree) |
| 186 | /// TestDecl <- KEYWORD_test STRINGLITERALSINGLE Block | 186 | /// TestDecl <- KEYWORD_test STRINGLITERALSINGLE Block |
| 187 | fn parseTestDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 187 | fn parseTestDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 188 | const test_token = eatToken(it, .Keyword_test) orelse return null; | 188 | const test_token = eatToken(it, .Keyword_test) orelse return null; |
| 189 | const name_node = try expectNode(arena, it, tree, parseStringLiteralSingle, AstError{ | 189 | const name_node = try expectNode(arena, it, tree, parseStringLiteralSingle, .{ |
| 190 | .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index }, | 190 | .ExpectedStringLiteral = .{ .token = it.index }, |
| 191 | }); | 191 | }); |
| 192 | const block_node = try expectNode(arena, it, tree, parseBlock, AstError{ | 192 | const block_node = try expectNode(arena, it, tree, parseBlock, .{ |
| 193 | .ExpectedLBrace = AstError.ExpectedLBrace{ .token = it.index }, | 193 | .ExpectedLBrace = .{ .token = it.index }, |
| 194 | }); | 194 | }); |
| 195 | 195 | ||
| 196 | const test_node = try arena.create(Node.TestDecl); | 196 | const test_node = try arena.create(Node.TestDecl); |
| 197 | test_node.* = Node.TestDecl{ | 197 | test_node.* = .{ |
| 198 | .doc_comments = null, | 198 | .doc_comments = null, |
| 199 | .test_token = test_token, | 199 | .test_token = test_token, |
| 200 | .name = name_node, | 200 | .name = name_node, |
| ... | @@ -211,12 +211,12 @@ fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?* | ... | @@ -211,12 +211,12 @@ fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?* |
| 211 | return null; | 211 | return null; |
| 212 | }; | 212 | }; |
| 213 | putBackToken(it, lbrace); | 213 | putBackToken(it, lbrace); |
| 214 | const block_node = try expectNode(arena, it, tree, parseBlockExpr, AstError{ | 214 | const block_node = try expectNode(arena, it, tree, parseBlockExpr, .{ |
| 215 | .ExpectedLabelOrLBrace = AstError.ExpectedLabelOrLBrace{ .token = it.index }, | 215 | .ExpectedLabelOrLBrace = .{ .token = it.index }, |
| 216 | }); | 216 | }); |
| 217 | 217 | ||
| 218 | const comptime_node = try arena.create(Node.Comptime); | 218 | const comptime_node = try arena.create(Node.Comptime); |
| 219 | comptime_node.* = Node.Comptime{ | 219 | comptime_node.* = .{ |
| 220 | .doc_comments = null, | 220 | .doc_comments = null, |
| 221 | .comptime_token = tok, | 221 | .comptime_token = tok, |
| 222 | .expr = block_node, | 222 | .expr = block_node, |
| ... | @@ -250,8 +250,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -250,8 +250,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 250 | fn_node.body_node = body_node; | 250 | fn_node.body_node = body_node; |
| 251 | return node; | 251 | return node; |
| 252 | } | 252 | } |
| 253 | try tree.errors.push(AstError{ | 253 | try tree.errors.push(.{ |
| 254 | .ExpectedSemiOrLBrace = AstError.ExpectedSemiOrLBrace{ .token = it.index }, | 254 | .ExpectedSemiOrLBrace = .{ .token = it.index }, |
| 255 | }); | 255 | }); |
| 256 | return null; | 256 | return null; |
| 257 | } | 257 | } |
| ... | @@ -277,8 +277,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -277,8 +277,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 277 | } | 277 | } |
| 278 | 278 | ||
| 279 | if (thread_local_token != null) { | 279 | if (thread_local_token != null) { |
| 280 | try tree.errors.push(AstError{ | 280 | try tree.errors.push(.{ |
| 281 | .ExpectedVarDecl = AstError.ExpectedVarDecl{ .token = it.index }, | 281 | .ExpectedVarDecl = .{ .token = it.index }, |
| 282 | }); | 282 | }); |
| 283 | return error.ParseError; | 283 | return error.ParseError; |
| 284 | } | 284 | } |
| ... | @@ -291,8 +291,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -291,8 +291,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 291 | } | 291 | } |
| 292 | 292 | ||
| 293 | const use_node = (try parseUse(arena, it, tree)) orelse return null; | 293 | const use_node = (try parseUse(arena, it, tree)) orelse return null; |
| 294 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | 294 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ |
| 295 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 295 | .ExpectedExpr = .{ .token = it.index }, |
| 296 | }); | 296 | }); |
| 297 | const semicolon_token = try expectToken(it, tree, .Semicolon); | 297 | const semicolon_token = try expectToken(it, tree, .Semicolon); |
| 298 | const use_node_raw = use_node.cast(Node.Use).?; | 298 | const use_node_raw = use_node.cast(Node.Use).?; |
| ... | @@ -310,7 +310,7 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -310,7 +310,7 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 310 | if (fnCC == .Extern) { | 310 | if (fnCC == .Extern) { |
| 311 | putBackToken(it, fnCC.Extern); // 'extern' is also used in ContainerDecl | 311 | putBackToken(it, fnCC.Extern); // 'extern' is also used in ContainerDecl |
| 312 | } else { | 312 | } else { |
| 313 | try tree.errors.push(AstError{ | 313 | try tree.errors.push(.{ |
| 314 | .ExpectedToken = .{ .token = it.index, .expected_id = .Keyword_fn }, | 314 | .ExpectedToken = .{ .token = it.index, .expected_id = .Keyword_fn }, |
| 315 | }); | 315 | }); |
| 316 | return error.ParseError; | 316 | return error.ParseError; |
| ... | @@ -328,16 +328,16 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -328,16 +328,16 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 328 | const exclamation_token = eatToken(it, .Bang); | 328 | const exclamation_token = eatToken(it, .Bang); |
| 329 | 329 | ||
| 330 | const return_type_expr = (try parseVarType(arena, it, tree)) orelse | 330 | const return_type_expr = (try parseVarType(arena, it, tree)) orelse |
| 331 | try expectNode(arena, it, tree, parseTypeExpr, AstError{ | 331 | try expectNode(arena, it, tree, parseTypeExpr, .{ |
| 332 | .ExpectedReturnType = AstError.ExpectedReturnType{ .token = it.index }, | 332 | .ExpectedReturnType = .{ .token = it.index }, |
| 333 | }); | 333 | }); |
| 334 | 334 | ||
| 335 | const return_type = if (exclamation_token != null) | 335 | const return_type: Node.FnProto.ReturnType = if (exclamation_token != null) |
| 336 | Node.FnProto.ReturnType{ | 336 | .{ |
| 337 | .InferErrorSet = return_type_expr, | 337 | .InferErrorSet = return_type_expr, |
| 338 | } | 338 | } |
| 339 | else | 339 | else |
| 340 | Node.FnProto.ReturnType{ | 340 | .{ |
| 341 | .Explicit = return_type_expr, | 341 | .Explicit = return_type_expr, |
| 342 | }; | 342 | }; |
| 343 | 343 | ||
| ... | @@ -347,7 +347,7 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -347,7 +347,7 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 347 | null; | 347 | null; |
| 348 | 348 | ||
| 349 | const fn_proto_node = try arena.create(Node.FnProto); | 349 | const fn_proto_node = try arena.create(Node.FnProto); |
| 350 | fn_proto_node.* = Node.FnProto{ | 350 | fn_proto_node.* = .{ |
| 351 | .doc_comments = null, | 351 | .doc_comments = null, |
| 352 | .visib_token = null, | 352 | .visib_token = null, |
| 353 | .fn_token = fn_token, | 353 | .fn_token = fn_token, |
| ... | @@ -382,8 +382,8 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -382,8 +382,8 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 382 | 382 | ||
| 383 | const name_token = try expectToken(it, tree, .Identifier); | 383 | const name_token = try expectToken(it, tree, .Identifier); |
| 384 | const type_node = if (eatToken(it, .Colon) != null) | 384 | const type_node = if (eatToken(it, .Colon) != null) |
| 385 | try expectNode(arena, it, tree, parseTypeExpr, AstError{ | 385 | try expectNode(arena, it, tree, parseTypeExpr, .{ |
| 386 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, | 386 | .ExpectedTypeExpr = .{ .token = it.index }, |
| 387 | }) | 387 | }) |
| 388 | else | 388 | else |
| 389 | null; | 389 | null; |
| ... | @@ -391,14 +391,14 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -391,14 +391,14 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 391 | const section_node = try parseLinkSection(arena, it, tree); | 391 | const section_node = try parseLinkSection(arena, it, tree); |
| 392 | const eq_token = eatToken(it, .Equal); | 392 | const eq_token = eatToken(it, .Equal); |
| 393 | const init_node = if (eq_token != null) blk: { | 393 | const init_node = if (eq_token != null) blk: { |
| 394 | break :blk try expectNode(arena, it, tree, parseExpr, AstError{ | 394 | break :blk try expectNode(arena, it, tree, parseExpr, .{ |
| 395 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 395 | .ExpectedExpr = .{ .token = it.index }, |
| 396 | }); | 396 | }); |
| 397 | } else null; | 397 | } else null; |
| 398 | const semicolon_token = try expectToken(it, tree, .Semicolon); | 398 | const semicolon_token = try expectToken(it, tree, .Semicolon); |
| 399 | 399 | ||
| 400 | const node = try arena.create(Node.VarDecl); | 400 | const node = try arena.create(Node.VarDecl); |
| 401 | node.* = Node.VarDecl{ | 401 | node.* = .{ |
| 402 | .doc_comments = null, | 402 | .doc_comments = null, |
| 403 | .visib_token = null, | 403 | .visib_token = null, |
| 404 | .thread_local_token = null, | 404 | .thread_local_token = null, |
| ... | @@ -433,22 +433,22 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No | ... | @@ -433,22 +433,22 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 433 | node.* = .{ .token = var_tok }; | 433 | node.* = .{ .token = var_tok }; |
| 434 | type_expr = &node.base; | 434 | type_expr = &node.base; |
| 435 | } else { | 435 | } else { |
| 436 | type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ | 436 | type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ |
| 437 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, | 437 | .ExpectedTypeExpr = .{ .token = it.index }, |
| 438 | }); | 438 | }); |
| 439 | align_expr = try parseByteAlign(arena, it, tree); | 439 | align_expr = try parseByteAlign(arena, it, tree); |
| 440 | } | 440 | } |
| 441 | } | 441 | } |
| 442 | 442 | ||
| 443 | const value_expr = if (eatToken(it, .Equal)) |_| | 443 | const value_expr = if (eatToken(it, .Equal)) |_| |
| 444 | try expectNode(arena, it, tree, parseExpr, AstError{ | 444 | try expectNode(arena, it, tree, parseExpr, .{ |
| 445 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 445 | .ExpectedExpr = .{ .token = it.index }, |
| 446 | }) | 446 | }) |
| 447 | else | 447 | else |
| 448 | null; | 448 | null; |
| 449 | 449 | ||
| 450 | const node = try arena.create(Node.ContainerField); | 450 | const node = try arena.create(Node.ContainerField); |
| 451 | node.* = Node.ContainerField{ | 451 | node.* = .{ |
| 452 | .doc_comments = null, | 452 | .doc_comments = null, |
| 453 | .comptime_token = comptime_token, | 453 | .comptime_token = comptime_token, |
| 454 | .name_token = name_token, | 454 | .name_token = name_token, |
| ... | @@ -481,12 +481,12 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No | ... | @@ -481,12 +481,12 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No |
| 481 | } | 481 | } |
| 482 | 482 | ||
| 483 | if (comptime_token) |token| { | 483 | if (comptime_token) |token| { |
| 484 | const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, AstError{ | 484 | const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, .{ |
| 485 | .ExpectedBlockOrAssignment = AstError.ExpectedBlockOrAssignment{ .token = it.index }, | 485 | .ExpectedBlockOrAssignment = .{ .token = it.index }, |
| 486 | }); | 486 | }); |
| 487 | 487 | ||
| 488 | const node = try arena.create(Node.Comptime); | 488 | const node = try arena.create(Node.Comptime); |
| 489 | node.* = Node.Comptime{ | 489 | node.* = .{ |
| 490 | .doc_comments = null, | 490 | .doc_comments = null, |
| 491 | .comptime_token = token, | 491 | .comptime_token = token, |
| 492 | .expr = block_expr, | 492 | .expr = block_expr, |
| ... | @@ -511,13 +511,13 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No | ... | @@ -511,13 +511,13 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No |
| 511 | const semicolon = eatToken(it, .Semicolon); | 511 | const semicolon = eatToken(it, .Semicolon); |
| 512 | 512 | ||
| 513 | const body_node = if (semicolon == null) blk: { | 513 | const body_node = if (semicolon == null) blk: { |
| 514 | break :blk try expectNode(arena, it, tree, parseBlockExprStatement, AstError{ | 514 | break :blk try expectNode(arena, it, tree, parseBlockExprStatement, .{ |
| 515 | .ExpectedBlockOrExpression = AstError.ExpectedBlockOrExpression{ .token = it.index }, | 515 | .ExpectedBlockOrExpression = .{ .token = it.index }, |
| 516 | }); | 516 | }); |
| 517 | } else null; | 517 | } else null; |
| 518 | 518 | ||
| 519 | const node = try arena.create(Node.Suspend); | 519 | const node = try arena.create(Node.Suspend); |
| 520 | node.* = Node.Suspend{ | 520 | node.* = .{ |
| 521 | .suspend_token = suspend_token, | 521 | .suspend_token = suspend_token, |
| 522 | .body = body_node, | 522 | .body = body_node, |
| 523 | }; | 523 | }; |
| ... | @@ -526,11 +526,11 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No | ... | @@ -526,11 +526,11 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No |
| 526 | 526 | ||
| 527 | const defer_token = eatToken(it, .Keyword_defer) orelse eatToken(it, .Keyword_errdefer); | 527 | const defer_token = eatToken(it, .Keyword_defer) orelse eatToken(it, .Keyword_errdefer); |
| 528 | if (defer_token) |token| { | 528 | if (defer_token) |token| { |
| 529 | const expr_node = try expectNode(arena, it, tree, parseBlockExprStatement, AstError{ | 529 | const expr_node = try expectNode(arena, it, tree, parseBlockExprStatement, .{ |
| 530 | .ExpectedBlockOrExpression = AstError.ExpectedBlockOrExpression{ .token = it.index }, | 530 | .ExpectedBlockOrExpression = .{ .token = it.index }, |
| 531 | }); | 531 | }); |
| 532 | const node = try arena.create(Node.Defer); | 532 | const node = try arena.create(Node.Defer); |
| 533 | node.* = Node.Defer{ | 533 | node.* = .{ |
| 534 | .defer_token = token, | 534 | .defer_token = token, |
| 535 | .expr = expr_node, | 535 | .expr = expr_node, |
| 536 | }; | 536 | }; |
| ... | @@ -561,8 +561,8 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -561,8 +561,8 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 561 | } else null; | 561 | } else null; |
| 562 | 562 | ||
| 563 | if (block_expr == null and assign_expr == null) { | 563 | if (block_expr == null and assign_expr == null) { |
| 564 | try tree.errors.push(AstError{ | 564 | try tree.errors.push(.{ |
| 565 | .ExpectedBlockOrAssignment = AstError.ExpectedBlockOrAssignment{ .token = it.index }, | 565 | .ExpectedBlockOrAssignment = .{ .token = it.index }, |
| 566 | }); | 566 | }); |
| 567 | return error.ParseError; | 567 | return error.ParseError; |
| 568 | } | 568 | } |
| ... | @@ -572,12 +572,12 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -572,12 +572,12 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 572 | const else_node = if (semicolon == null) blk: { | 572 | const else_node = if (semicolon == null) blk: { |
| 573 | const else_token = eatToken(it, .Keyword_else) orelse break :blk null; | 573 | const else_token = eatToken(it, .Keyword_else) orelse break :blk null; |
| 574 | const payload = try parsePayload(arena, it, tree); | 574 | const payload = try parsePayload(arena, it, tree); |
| 575 | const else_body = try expectNode(arena, it, tree, parseStatement, AstError{ | 575 | const else_body = try expectNode(arena, it, tree, parseStatement, .{ |
| 576 | .InvalidToken = AstError.InvalidToken{ .token = it.index }, | 576 | .InvalidToken = .{ .token = it.index }, |
| 577 | }); | 577 | }); |
| 578 | 578 | ||
| 579 | const node = try arena.create(Node.Else); | 579 | const node = try arena.create(Node.Else); |
| 580 | node.* = Node.Else{ | 580 | node.* = .{ |
| 581 | .else_token = else_token, | 581 | .else_token = else_token, |
| 582 | .payload = payload, | 582 | .payload = payload, |
| 583 | .body = else_body, | 583 | .body = else_body, |
| ... | @@ -599,8 +599,8 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -599,8 +599,8 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 599 | if_prefix.@"else" = else_node; | 599 | if_prefix.@"else" = else_node; |
| 600 | return if_node; | 600 | return if_node; |
| 601 | } | 601 | } |
| 602 | try tree.errors.push(AstError{ | 602 | try tree.errors.push(.{ |
| 603 | .ExpectedSemiOrElse = AstError.ExpectedSemiOrElse{ .token = it.index }, | 603 | .ExpectedSemiOrElse = .{ .token = it.index }, |
| 604 | }); | 604 | }); |
| 605 | return error.ParseError; | 605 | return error.ParseError; |
| 606 | } | 606 | } |
| ... | @@ -628,8 +628,8 @@ fn parseLabeledStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?* | ... | @@ -628,8 +628,8 @@ fn parseLabeledStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?* |
| 628 | } | 628 | } |
| 629 | 629 | ||
| 630 | if (label_token != null) { | 630 | if (label_token != null) { |
| 631 | try tree.errors.push(AstError{ | 631 | try tree.errors.push(.{ |
| 632 | .ExpectedLabelable = AstError.ExpectedLabelable{ .token = it.index }, | 632 | .ExpectedLabelable = .{ .token = it.index }, |
| 633 | }); | 633 | }); |
| 634 | return error.ParseError; | 634 | return error.ParseError; |
| 635 | } | 635 | } |
| ... | @@ -665,12 +665,12 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -665,12 +665,12 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 665 | for_prefix.body = block_expr_node; | 665 | for_prefix.body = block_expr_node; |
| 666 | 666 | ||
| 667 | if (eatToken(it, .Keyword_else)) |else_token| { | 667 | if (eatToken(it, .Keyword_else)) |else_token| { |
| 668 | const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{ | 668 | const statement_node = try expectNode(arena, it, tree, parseStatement, .{ |
| 669 | .InvalidToken = AstError.InvalidToken{ .token = it.index }, | 669 | .InvalidToken = .{ .token = it.index }, |
| 670 | }); | 670 | }); |
| 671 | 671 | ||
| 672 | const else_node = try arena.create(Node.Else); | 672 | const else_node = try arena.create(Node.Else); |
| 673 | else_node.* = Node.Else{ | 673 | else_node.* = .{ |
| 674 | .else_token = else_token, | 674 | .else_token = else_token, |
| 675 | .payload = null, | 675 | .payload = null, |
| 676 | .body = statement_node, | 676 | .body = statement_node, |
| ... | @@ -689,12 +689,12 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -689,12 +689,12 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 689 | if (eatToken(it, .Semicolon) != null) return node; | 689 | if (eatToken(it, .Semicolon) != null) return node; |
| 690 | 690 | ||
| 691 | if (eatToken(it, .Keyword_else)) |else_token| { | 691 | if (eatToken(it, .Keyword_else)) |else_token| { |
| 692 | const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{ | 692 | const statement_node = try expectNode(arena, it, tree, parseStatement, .{ |
| 693 | .ExpectedStatement = AstError.ExpectedStatement{ .token = it.index }, | 693 | .ExpectedStatement = .{ .token = it.index }, |
| 694 | }); | 694 | }); |
| 695 | 695 | ||
| 696 | const else_node = try arena.create(Node.Else); | 696 | const else_node = try arena.create(Node.Else); |
| 697 | else_node.* = Node.Else{ | 697 | else_node.* = .{ |
| 698 | .else_token = else_token, | 698 | .else_token = else_token, |
| 699 | .payload = null, | 699 | .payload = null, |
| 700 | .body = statement_node, | 700 | .body = statement_node, |
| ... | @@ -703,8 +703,8 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -703,8 +703,8 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 703 | return node; | 703 | return node; |
| 704 | } | 704 | } |
| 705 | 705 | ||
| 706 | try tree.errors.push(AstError{ | 706 | try tree.errors.push(.{ |
| 707 | .ExpectedSemiOrElse = AstError.ExpectedSemiOrElse{ .token = it.index }, | 707 | .ExpectedSemiOrElse = .{ .token = it.index }, |
| 708 | }); | 708 | }); |
| 709 | return null; | 709 | return null; |
| 710 | } | 710 | } |
| ... | @@ -725,12 +725,12 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No | ... | @@ -725,12 +725,12 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 725 | if (eatToken(it, .Keyword_else)) |else_token| { | 725 | if (eatToken(it, .Keyword_else)) |else_token| { |
| 726 | const payload = try parsePayload(arena, it, tree); | 726 | const payload = try parsePayload(arena, it, tree); |
| 727 | 727 | ||
| 728 | const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{ | 728 | const statement_node = try expectNode(arena, it, tree, parseStatement, .{ |
| 729 | .InvalidToken = AstError.InvalidToken{ .token = it.index }, | 729 | .InvalidToken = .{ .token = it.index }, |
| 730 | }); | 730 | }); |
| 731 | 731 | ||
| 732 | const else_node = try arena.create(Node.Else); | 732 | const else_node = try arena.create(Node.Else); |
| 733 | else_node.* = Node.Else{ | 733 | else_node.* = .{ |
| 734 | .else_token = else_token, | 734 | .else_token = else_token, |
| 735 | .payload = payload, | 735 | .payload = payload, |
| 736 | .body = statement_node, | 736 | .body = statement_node, |
| ... | @@ -751,12 +751,12 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No | ... | @@ -751,12 +751,12 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 751 | if (eatToken(it, .Keyword_else)) |else_token| { | 751 | if (eatToken(it, .Keyword_else)) |else_token| { |
| 752 | const payload = try parsePayload(arena, it, tree); | 752 | const payload = try parsePayload(arena, it, tree); |
| 753 | 753 | ||
| 754 | const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{ | 754 | const statement_node = try expectNode(arena, it, tree, parseStatement, .{ |
| 755 | .ExpectedStatement = AstError.ExpectedStatement{ .token = it.index }, | 755 | .ExpectedStatement = .{ .token = it.index }, |
| 756 | }); | 756 | }); |
| 757 | 757 | ||
| 758 | const else_node = try arena.create(Node.Else); | 758 | const else_node = try arena.create(Node.Else); |
| 759 | else_node.* = Node.Else{ | 759 | else_node.* = .{ |
| 760 | .else_token = else_token, | 760 | .else_token = else_token, |
| 761 | .payload = payload, | 761 | .payload = payload, |
| 762 | .body = statement_node, | 762 | .body = statement_node, |
| ... | @@ -765,8 +765,8 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No | ... | @@ -765,8 +765,8 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 765 | return node; | 765 | return node; |
| 766 | } | 766 | } |
| 767 | 767 | ||
| 768 | try tree.errors.push(AstError{ | 768 | try tree.errors.push(.{ |
| 769 | .ExpectedSemiOrElse = AstError.ExpectedSemiOrElse{ .token = it.index }, | 769 | .ExpectedSemiOrElse = .{ .token = it.index }, |
| 770 | }); | 770 | }); |
| 771 | return null; | 771 | return null; |
| 772 | } | 772 | } |
| ... | @@ -894,8 +894,8 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -894,8 +894,8 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 894 | } | 894 | } |
| 895 | 895 | ||
| 896 | if (eatToken(it, .Keyword_comptime)) |token| { | 896 | if (eatToken(it, .Keyword_comptime)) |token| { |
| 897 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | 897 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ |
| 898 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 898 | .ExpectedExpr = .{ .token = it.index }, |
| 899 | }); | 899 | }); |
| 900 | const node = try arena.create(Node.Comptime); | 900 | const node = try arena.create(Node.Comptime); |
| 901 | node.* = .{ | 901 | node.* = .{ |
| ... | @@ -907,8 +907,8 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -907,8 +907,8 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 907 | } | 907 | } |
| 908 | 908 | ||
| 909 | if (eatToken(it, .Keyword_noasync)) |token| { | 909 | if (eatToken(it, .Keyword_noasync)) |token| { |
| 910 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | 910 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ |
| 911 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 911 | .ExpectedExpr = .{ .token = it.index }, |
| 912 | }); | 912 | }); |
| 913 | const node = try arena.create(Node.Noasync); | 913 | const node = try arena.create(Node.Noasync); |
| 914 | node.* = .{ | 914 | node.* = .{ |
| ... | @@ -930,13 +930,13 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -930,13 +930,13 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 930 | } | 930 | } |
| 931 | 931 | ||
| 932 | if (eatToken(it, .Keyword_resume)) |token| { | 932 | if (eatToken(it, .Keyword_resume)) |token| { |
| 933 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | 933 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ |
| 934 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 934 | .ExpectedExpr = .{ .token = it.index }, |
| 935 | }); | 935 | }); |
| 936 | const node = try arena.create(Node.PrefixOp); | 936 | const node = try arena.create(Node.PrefixOp); |
| 937 | node.* = .{ | 937 | node.* = .{ |
| 938 | .op_token = token, | 938 | .op_token = token, |
| 939 | .op = Node.PrefixOp.Op.Resume, | 939 | .op = .Resume, |
| 940 | .rhs = expr_node, | 940 | .rhs = expr_node, |
| 941 | }; | 941 | }; |
| 942 | return &node.base; | 942 | return &node.base; |
| ... | @@ -992,7 +992,7 @@ fn parseBlock(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -992,7 +992,7 @@ fn parseBlock(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 992 | const rbrace = try expectToken(it, tree, .RBrace); | 992 | const rbrace = try expectToken(it, tree, .RBrace); |
| 993 | 993 | ||
| 994 | const block_node = try arena.create(Node.Block); | 994 | const block_node = try arena.create(Node.Block); |
| 995 | block_node.* = Node.Block{ | 995 | block_node.* = .{ |
| 996 | .label = null, | 996 | .label = null, |
| 997 | .lbrace = lbrace, | 997 | .lbrace = lbrace, |
| 998 | .statements = statements, | 998 | .statements = statements, |
| ... | @@ -1019,8 +1019,8 @@ fn parseLoopExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -1019,8 +1019,8 @@ fn parseLoopExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1019 | if (inline_token == null) return null; | 1019 | if (inline_token == null) return null; |
| 1020 | 1020 | ||
| 1021 | // If we've seen "inline", there should have been a "for" or "while" | 1021 | // If we've seen "inline", there should have been a "for" or "while" |
| 1022 | try tree.errors.push(AstError{ | 1022 | try tree.errors.push(.{ |
| 1023 | .ExpectedInlinable = AstError.ExpectedInlinable{ .token = it.index }, | 1023 | .ExpectedInlinable = .{ .token = it.index }, |
| 1024 | }); | 1024 | }); |
| 1025 | return error.ParseError; | 1025 | return error.ParseError; |
| 1026 | } | 1026 | } |
| ... | @@ -1030,18 +1030,18 @@ fn parseForExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -1030,18 +1030,18 @@ fn parseForExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1030 | const node = (try parseForPrefix(arena, it, tree)) orelse return null; | 1030 | const node = (try parseForPrefix(arena, it, tree)) orelse return null; |
| 1031 | const for_prefix = node.cast(Node.For).?; | 1031 | const for_prefix = node.cast(Node.For).?; |
| 1032 | 1032 | ||
| 1033 | const body_node = try expectNode(arena, it, tree, parseExpr, AstError{ | 1033 | const body_node = try expectNode(arena, it, tree, parseExpr, .{ |
| 1034 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 1034 | .ExpectedExpr = .{ .token = it.index }, |
| 1035 | }); | 1035 | }); |
| 1036 | for_prefix.body = body_node; | 1036 | for_prefix.body = body_node; |
| 1037 | 1037 | ||
| 1038 | if (eatToken(it, .Keyword_else)) |else_token| { | 1038 | if (eatToken(it, .Keyword_else)) |else_token| { |
| 1039 | const body = try expectNode(arena, it, tree, parseExpr, AstError{ | 1039 | const body = try expectNode(arena, it, tree, parseExpr, .{ |
| 1040 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 1040 | .ExpectedExpr = .{ .token = it.index }, |
| 1041 | }); | 1041 | }); |
| 1042 | 1042 | ||
| 1043 | const else_node = try arena.create(Node.Else); | 1043 | const else_node = try arena.create(Node.Else); |
| 1044 | else_node.* = Node.Else{ | 1044 | else_node.* = .{ |
| 1045 | .else_token = else_token, | 1045 | .else_token = else_token, |
| 1046 | .payload = null, | 1046 | .payload = null, |
| 1047 | .body = body, | 1047 | .body = body, |
| ... | @@ -1058,19 +1058,19 @@ fn parseWhileExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -1058,19 +1058,19 @@ fn parseWhileExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1058 | const node = (try parseWhilePrefix(arena, it, tree)) orelse return null; | 1058 | const node = (try parseWhilePrefix(arena, it, tree)) orelse return null; |
| 1059 | const while_prefix = node.cast(Node.While).?; | 1059 | const while_prefix = node.cast(Node.While).?; |
| 1060 | 1060 | ||
| 1061 | const body_node = try expectNode(arena, it, tree, parseExpr, AstError{ | 1061 | const body_node = try expectNode(arena, it, tree, parseExpr, .{ |
| 1062 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 1062 | .ExpectedExpr = .{ .token = it.index }, |
| 1063 | }); | 1063 | }); |
| 1064 | while_prefix.body = body_node; | 1064 | while_prefix.body = body_node; |
| 1065 | 1065 | ||
| 1066 | if (eatToken(it, .Keyword_else)) |else_token| { | 1066 | if (eatToken(it, .Keyword_else)) |else_token| { |
| 1067 | const payload = try parsePayload(arena, it, tree); | 1067 | const payload = try parsePayload(arena, it, tree); |
| 1068 | const body = try expectNode(arena, it, tree, parseExpr, AstError{ | 1068 | const body = try expectNode(arena, it, tree, parseExpr, .{ |
| 1069 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 1069 | .ExpectedExpr = .{ .token = it.index }, |
| 1070 | }); | 1070 | }); |
| 1071 | 1071 | ||
| 1072 | const else_node = try arena.create(Node.Else); | 1072 | const else_node = try arena.create(Node.Else); |
| 1073 | else_node.* = Node.Else{ | 1073 | else_node.* = .{ |
| 1074 | .else_token = else_token, | 1074 | .else_token = else_token, |
| 1075 | .payload = payload, | 1075 | .payload = payload, |
| 1076 | .body = body, | 1076 | .body = body, |
| ... | @@ -1098,14 +1098,14 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf | ... | @@ -1098,14 +1098,14 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf |
| 1098 | const lbrace = eatToken(it, .LBrace) orelse return null; | 1098 | const lbrace = eatToken(it, .LBrace) orelse return null; |
| 1099 | var init_list = Node.SuffixOp.Op.InitList.init(arena); | 1099 | var init_list = Node.SuffixOp.Op.InitList.init(arena); |
| 1100 | 1100 | ||
| 1101 | const op = blk: { | 1101 | const op: Node.SuffixOp.Op = blk: { |
| 1102 | if (try parseFieldInit(arena, it, tree)) |field_init| { | 1102 | if (try parseFieldInit(arena, it, tree)) |field_init| { |
| 1103 | try init_list.push(field_init); | 1103 | try init_list.push(field_init); |
| 1104 | while (eatToken(it, .Comma)) |_| { | 1104 | while (eatToken(it, .Comma)) |_| { |
| 1105 | const next = (try parseFieldInit(arena, it, tree)) orelse break; | 1105 | const next = (try parseFieldInit(arena, it, tree)) orelse break; |
| 1106 | try init_list.push(next); | 1106 | try init_list.push(next); |
| 1107 | } | 1107 | } |
| 1108 | break :blk Node.SuffixOp.Op{ .StructInitializer = init_list }; | 1108 | break :blk .{ .StructInitializer = init_list }; |
| 1109 | } | 1109 | } |
| 1110 | 1110 | ||
| 1111 | if (try parseExpr(arena, it, tree)) |expr| { | 1111 | if (try parseExpr(arena, it, tree)) |expr| { |
| ... | @@ -1114,14 +1114,14 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf | ... | @@ -1114,14 +1114,14 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf |
| 1114 | const next = (try parseExpr(arena, it, tree)) orelse break; | 1114 | const next = (try parseExpr(arena, it, tree)) orelse break; |
| 1115 | try init_list.push(next); | 1115 | try init_list.push(next); |
| 1116 | } | 1116 | } |
| 1117 | break :blk Node.SuffixOp.Op{ .ArrayInitializer = init_list }; | 1117 | break :blk .{ .ArrayInitializer = init_list }; |
| 1118 | } | 1118 | } |
| 1119 | 1119 | ||
| 1120 | break :blk Node.SuffixOp.Op{ .StructInitializer = init_list }; | 1120 | break :blk .{ .StructInitializer = init_list }; |
| 1121 | }; | 1121 | }; |
| 1122 | 1122 | ||
| 1123 | const node = try arena.create(Node.SuffixOp); | 1123 | const node = try arena.create(Node.SuffixOp); |
| 1124 | node.* = Node.SuffixOp{ | 1124 | node.* = .{ |
| 1125 | .lhs = .{ .node = undefined }, // set by caller | 1125 | .lhs = .{ .node = undefined }, // set by caller |
| 1126 | .op = op, | 1126 | .op = op, |
| 1127 | .rtoken = try expectToken(it, tree, .RBrace), | 1127 | .rtoken = try expectToken(it, tree, .RBrace), |
| ... | @@ -1140,8 +1140,8 @@ fn parseErrorUnionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No | ... | @@ -1140,8 +1140,8 @@ fn parseErrorUnionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 1140 | 1140 | ||
| 1141 | if (try SimpleBinOpParseFn(.Bang, Node.InfixOp.Op.ErrorUnion)(arena, it, tree)) |node| { | 1141 | if (try SimpleBinOpParseFn(.Bang, Node.InfixOp.Op.ErrorUnion)(arena, it, tree)) |node| { |
| 1142 | const error_union = node.cast(Node.InfixOp).?; | 1142 | const error_union = node.cast(Node.InfixOp).?; |
| 1143 | const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ | 1143 | const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ |
| 1144 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, | 1144 | .ExpectedTypeExpr = .{ .token = it.index }, |
| 1145 | }); | 1145 | }); |
| 1146 | error_union.lhs = suffix_expr; | 1146 | error_union.lhs = suffix_expr; |
| 1147 | error_union.rhs = type_expr; | 1147 | error_union.rhs = type_expr; |
| ... | @@ -1168,8 +1168,8 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -1168,8 +1168,8 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1168 | return parsePrimaryTypeExpr(arena, it, tree); | 1168 | return parsePrimaryTypeExpr(arena, it, tree); |
| 1169 | } | 1169 | } |
| 1170 | // TODO: Implement hack for parsing `async fn ...` in ast_parse_suffix_expr | 1170 | // TODO: Implement hack for parsing `async fn ...` in ast_parse_suffix_expr |
| 1171 | var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, AstError{ | 1171 | var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, .{ |
| 1172 | .ExpectedPrimaryTypeExpr = AstError.ExpectedPrimaryTypeExpr{ .token = it.index }, | 1172 | .ExpectedPrimaryTypeExpr = .{ .token = it.index }, |
| 1173 | }); | 1173 | }); |
| 1174 | 1174 | ||
| 1175 | while (try parseSuffixOp(arena, it, tree)) |node| { | 1175 | while (try parseSuffixOp(arena, it, tree)) |node| { |
| ... | @@ -1182,16 +1182,16 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -1182,16 +1182,16 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1182 | } | 1182 | } |
| 1183 | 1183 | ||
| 1184 | const params = (try parseFnCallArguments(arena, it, tree)) orelse { | 1184 | const params = (try parseFnCallArguments(arena, it, tree)) orelse { |
| 1185 | try tree.errors.push(AstError{ | 1185 | try tree.errors.push(.{ |
| 1186 | .ExpectedParamList = AstError.ExpectedParamList{ .token = it.index }, | 1186 | .ExpectedParamList = .{ .token = it.index }, |
| 1187 | }); | 1187 | }); |
| 1188 | return null; | 1188 | return null; |
| 1189 | }; | 1189 | }; |
| 1190 | const node = try arena.create(Node.SuffixOp); | 1190 | const node = try arena.create(Node.SuffixOp); |
| 1191 | node.* = Node.SuffixOp{ | 1191 | node.* = .{ |
| 1192 | .lhs = .{ .node = res }, | 1192 | .lhs = .{ .node = res }, |
| 1193 | .op = Node.SuffixOp.Op{ | 1193 | .op = .{ |
| 1194 | .Call = Node.SuffixOp.Op.Call{ | 1194 | .Call = .{ |
| 1195 | .params = params.list, | 1195 | .params = params.list, |
| 1196 | .async_token = async_token, | 1196 | .async_token = async_token, |
| 1197 | }, | 1197 | }, |
| ... | @@ -1215,10 +1215,10 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -1215,10 +1215,10 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1215 | } | 1215 | } |
| 1216 | if (try parseFnCallArguments(arena, it, tree)) |params| { | 1216 | if (try parseFnCallArguments(arena, it, tree)) |params| { |
| 1217 | const call = try arena.create(Node.SuffixOp); | 1217 | const call = try arena.create(Node.SuffixOp); |
| 1218 | call.* = Node.SuffixOp{ | 1218 | call.* = .{ |
| 1219 | .lhs = .{ .node = res }, | 1219 | .lhs = .{ .node = res }, |
| 1220 | .op = Node.SuffixOp.Op{ | 1220 | .op = .{ |
| 1221 | .Call = Node.SuffixOp.Op.Call{ | 1221 | .Call = .{ |
| 1222 | .params = params.list, | 1222 | .params = params.list, |
| 1223 | .async_token = null, | 1223 | .async_token = null, |
| 1224 | }, | 1224 | }, |
| ... | @@ -1264,7 +1264,7 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N | ... | @@ -1264,7 +1264,7 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N |
| 1264 | if (try parseBuiltinCall(arena, it, tree)) |node| return node; | 1264 | if (try parseBuiltinCall(arena, it, tree)) |node| return node; |
| 1265 | if (eatToken(it, .CharLiteral)) |token| { | 1265 | if (eatToken(it, .CharLiteral)) |token| { |
| 1266 | const node = try arena.create(Node.CharLiteral); | 1266 | const node = try arena.create(Node.CharLiteral); |
| 1267 | node.* = Node.CharLiteral{ | 1267 | node.* = .{ |
| 1268 | .token = token, | 1268 | .token = token, |
| 1269 | }; | 1269 | }; |
| 1270 | return &node.base; | 1270 | return &node.base; |
| ... | @@ -1300,15 +1300,15 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N | ... | @@ -1300,15 +1300,15 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N |
| 1300 | } | 1300 | } |
| 1301 | if (eatToken(it, .Keyword_error)) |token| { | 1301 | if (eatToken(it, .Keyword_error)) |token| { |
| 1302 | const period = try expectToken(it, tree, .Period); | 1302 | const period = try expectToken(it, tree, .Period); |
| 1303 | const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{ | 1303 | const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ |
| 1304 | .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, | 1304 | .ExpectedIdentifier = .{ .token = it.index }, |
| 1305 | }); | 1305 | }); |
| 1306 | const global_error_set = try createLiteral(arena, Node.ErrorType, token); | 1306 | const global_error_set = try createLiteral(arena, Node.ErrorType, token); |
| 1307 | const node = try arena.create(Node.InfixOp); | 1307 | const node = try arena.create(Node.InfixOp); |
| 1308 | node.* = .{ | 1308 | node.* = .{ |
| 1309 | .op_token = period, | 1309 | .op_token = period, |
| 1310 | .lhs = global_error_set, | 1310 | .lhs = global_error_set, |
| 1311 | .op = Node.InfixOp.Op.Period, | 1311 | .op = .Period, |
| 1312 | .rhs = identifier, | 1312 | .rhs = identifier, |
| 1313 | }; | 1313 | }; |
| 1314 | return &node.base; | 1314 | return &node.base; |
| ... | @@ -1358,7 +1358,7 @@ fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -1358,7 +1358,7 @@ fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 1358 | const rbrace = try expectToken(it, tree, .RBrace); | 1358 | const rbrace = try expectToken(it, tree, .RBrace); |
| 1359 | 1359 | ||
| 1360 | const node = try arena.create(Node.ErrorSetDecl); | 1360 | const node = try arena.create(Node.ErrorSetDecl); |
| 1361 | node.* = Node.ErrorSetDecl{ | 1361 | node.* = .{ |
| 1362 | .error_token = error_token, | 1362 | .error_token = error_token, |
| 1363 | .decls = decls, | 1363 | .decls = decls, |
| 1364 | .rbrace_token = rbrace, | 1364 | .rbrace_token = rbrace, |
| ... | @@ -1369,13 +1369,13 @@ fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -1369,13 +1369,13 @@ fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 1369 | /// GroupedExpr <- LPAREN Expr RPAREN | 1369 | /// GroupedExpr <- LPAREN Expr RPAREN |
| 1370 | fn parseGroupedExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1370 | fn parseGroupedExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1371 | const lparen = eatToken(it, .LParen) orelse return null; | 1371 | const lparen = eatToken(it, .LParen) orelse return null; |
| 1372 | const expr = try expectNode(arena, it, tree, parseExpr, AstError{ | 1372 | const expr = try expectNode(arena, it, tree, parseExpr, .{ |
| 1373 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 1373 | .ExpectedExpr = .{ .token = it.index }, |
| 1374 | }); | 1374 | }); |
| 1375 | const rparen = try expectToken(it, tree, .RParen); | 1375 | const rparen = try expectToken(it, tree, .RParen); |
| 1376 | 1376 | ||
| 1377 | const node = try arena.create(Node.GroupedExpression); | 1377 | const node = try arena.create(Node.GroupedExpression); |
| 1378 | node.* = Node.GroupedExpression{ | 1378 | node.* = .{ |
| 1379 | .lparen = lparen, | 1379 | .lparen = lparen, |
| 1380 | .expr = expr, | 1380 | .expr = expr, |
| 1381 | .rparen = rparen, | 1381 | .rparen = rparen, |
| ... | @@ -1435,8 +1435,8 @@ fn parseLoopTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -1435,8 +1435,8 @@ fn parseLoopTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 1435 | if (inline_token == null) return null; | 1435 | if (inline_token == null) return null; |
| 1436 | 1436 | ||
| 1437 | // If we've seen "inline", there should have been a "for" or "while" | 1437 | // If we've seen "inline", there should have been a "for" or "while" |
| 1438 | try tree.errors.push(AstError{ | 1438 | try tree.errors.push(.{ |
| 1439 | .ExpectedInlinable = AstError.ExpectedInlinable{ .token = it.index }, | 1439 | .ExpectedInlinable = .{ .token = it.index }, |
| 1440 | }); | 1440 | }); |
| 1441 | return error.ParseError; | 1441 | return error.ParseError; |
| 1442 | } | 1442 | } |
| ... | @@ -1446,18 +1446,18 @@ fn parseForTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -1446,18 +1446,18 @@ fn parseForTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 1446 | const node = (try parseForPrefix(arena, it, tree)) orelse return null; | 1446 | const node = (try parseForPrefix(arena, it, tree)) orelse return null; |
| 1447 | const for_prefix = node.cast(Node.For).?; | 1447 | const for_prefix = node.cast(Node.For).?; |
| 1448 | 1448 | ||
| 1449 | const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ | 1449 | const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ |
| 1450 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, | 1450 | .ExpectedTypeExpr = .{ .token = it.index }, |
| 1451 | }); | 1451 | }); |
| 1452 | for_prefix.body = type_expr; | 1452 | for_prefix.body = type_expr; |
| 1453 | 1453 | ||
| 1454 | if (eatToken(it, .Keyword_else)) |else_token| { | 1454 | if (eatToken(it, .Keyword_else)) |else_token| { |
| 1455 | const else_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ | 1455 | const else_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ |
| 1456 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, | 1456 | .ExpectedTypeExpr = .{ .token = it.index }, |
| 1457 | }); | 1457 | }); |
| 1458 | 1458 | ||
| 1459 | const else_node = try arena.create(Node.Else); | 1459 | const else_node = try arena.create(Node.Else); |
| 1460 | else_node.* = Node.Else{ | 1460 | else_node.* = .{ |
| 1461 | .else_token = else_token, | 1461 | .else_token = else_token, |
| 1462 | .payload = null, | 1462 | .payload = null, |
| 1463 | .body = else_expr, | 1463 | .body = else_expr, |
| ... | @@ -1474,20 +1474,20 @@ fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod | ... | @@ -1474,20 +1474,20 @@ fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod |
| 1474 | const node = (try parseWhilePrefix(arena, it, tree)) orelse return null; | 1474 | const node = (try parseWhilePrefix(arena, it, tree)) orelse return null; |
| 1475 | const while_prefix = node.cast(Node.While).?; | 1475 | const while_prefix = node.cast(Node.While).?; |
| 1476 | 1476 | ||
| 1477 | const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ | 1477 | const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ |
| 1478 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, | 1478 | .ExpectedTypeExpr = .{ .token = it.index }, |
| 1479 | }); | 1479 | }); |
| 1480 | while_prefix.body = type_expr; | 1480 | while_prefix.body = type_expr; |
| 1481 | 1481 | ||
| 1482 | if (eatToken(it, .Keyword_else)) |else_token| { | 1482 | if (eatToken(it, .Keyword_else)) |else_token| { |
| 1483 | const payload = try parsePayload(arena, it, tree); | 1483 | const payload = try parsePayload(arena, it, tree); |
| 1484 | 1484 | ||
| 1485 | const else_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ | 1485 | const else_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ |
| 1486 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, | 1486 | .ExpectedTypeExpr = .{ .token = it.index }, |
| 1487 | }); | 1487 | }); |
| 1488 | 1488 | ||
| 1489 | const else_node = try arena.create(Node.Else); | 1489 | const else_node = try arena.create(Node.Else); |
| 1490 | else_node.* = Node.Else{ | 1490 | else_node.* = .{ |
| 1491 | .else_token = else_token, | 1491 | .else_token = else_token, |
| 1492 | .payload = null, | 1492 | .payload = null, |
| 1493 | .body = else_expr, | 1493 | .body = else_expr, |
| ... | @@ -1503,8 +1503,8 @@ fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod | ... | @@ -1503,8 +1503,8 @@ fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod |
| 1503 | fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1503 | fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1504 | const switch_token = eatToken(it, .Keyword_switch) orelse return null; | 1504 | const switch_token = eatToken(it, .Keyword_switch) orelse return null; |
| 1505 | _ = try expectToken(it, tree, .LParen); | 1505 | _ = try expectToken(it, tree, .LParen); |
| 1506 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | 1506 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ |
| 1507 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 1507 | .ExpectedExpr = .{ .token = it.index }, |
| 1508 | }); | 1508 | }); |
| 1509 | _ = try expectToken(it, tree, .RParen); | 1509 | _ = try expectToken(it, tree, .RParen); |
| 1510 | _ = try expectToken(it, tree, .LBrace); | 1510 | _ = try expectToken(it, tree, .LBrace); |
| ... | @@ -1512,7 +1512,7 @@ fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -1512,7 +1512,7 @@ fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1512 | const rbrace = try expectToken(it, tree, .RBrace); | 1512 | const rbrace = try expectToken(it, tree, .RBrace); |
| 1513 | 1513 | ||
| 1514 | const node = try arena.create(Node.Switch); | 1514 | const node = try arena.create(Node.Switch); |
| 1515 | node.* = Node.Switch{ | 1515 | node.* = .{ |
| 1516 | .switch_token = switch_token, | 1516 | .switch_token = switch_token, |
| 1517 | .expr = expr_node, | 1517 | .expr = expr_node, |
| 1518 | .cases = cases, | 1518 | .cases = cases, |
| ... | @@ -1526,12 +1526,12 @@ fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -1526,12 +1526,12 @@ fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1526 | const asm_token = eatToken(it, .Keyword_asm) orelse return null; | 1526 | const asm_token = eatToken(it, .Keyword_asm) orelse return null; |
| 1527 | const volatile_token = eatToken(it, .Keyword_volatile); | 1527 | const volatile_token = eatToken(it, .Keyword_volatile); |
| 1528 | _ = try expectToken(it, tree, .LParen); | 1528 | _ = try expectToken(it, tree, .LParen); |
| 1529 | const template = try expectNode(arena, it, tree, parseExpr, AstError{ | 1529 | const template = try expectNode(arena, it, tree, parseExpr, .{ |
| 1530 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 1530 | .ExpectedExpr = .{ .token = it.index }, |
| 1531 | }); | 1531 | }); |
| 1532 | 1532 | ||
| 1533 | const node = try arena.create(Node.Asm); | 1533 | const node = try arena.create(Node.Asm); |
| 1534 | node.* = Node.Asm{ | 1534 | node.* = .{ |
| 1535 | .asm_token = asm_token, | 1535 | .asm_token = asm_token, |
| 1536 | .volatile_token = volatile_token, | 1536 | .volatile_token = volatile_token, |
| 1537 | .template = template, | 1537 | .template = template, |
| ... | @@ -1553,7 +1553,7 @@ fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -1553,7 +1553,7 @@ fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 1553 | // anon enum literal | 1553 | // anon enum literal |
| 1554 | if (eatToken(it, .Identifier)) |name| { | 1554 | if (eatToken(it, .Identifier)) |name| { |
| 1555 | const node = try arena.create(Node.EnumLiteral); | 1555 | const node = try arena.create(Node.EnumLiteral); |
| 1556 | node.* = Node.EnumLiteral{ | 1556 | node.* = .{ |
| 1557 | .dot = dot, | 1557 | .dot = dot, |
| 1558 | .name = name, | 1558 | .name = name, |
| 1559 | }; | 1559 | }; |
| ... | @@ -1580,32 +1580,32 @@ fn parseAsmOutput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: | ... | @@ -1580,32 +1580,32 @@ fn parseAsmOutput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: |
| 1580 | /// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN | 1580 | /// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN |
| 1581 | fn parseAsmOutputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmOutput { | 1581 | fn parseAsmOutputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmOutput { |
| 1582 | const lbracket = eatToken(it, .LBracket) orelse return null; | 1582 | const lbracket = eatToken(it, .LBracket) orelse return null; |
| 1583 | const name = try expectNode(arena, it, tree, parseIdentifier, AstError{ | 1583 | const name = try expectNode(arena, it, tree, parseIdentifier, .{ |
| 1584 | .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, | 1584 | .ExpectedIdentifier = .{ .token = it.index }, |
| 1585 | }); | 1585 | }); |
| 1586 | _ = try expectToken(it, tree, .RBracket); | 1586 | _ = try expectToken(it, tree, .RBracket); |
| 1587 | 1587 | ||
| 1588 | const constraint = try expectNode(arena, it, tree, parseStringLiteral, AstError{ | 1588 | const constraint = try expectNode(arena, it, tree, parseStringLiteral, .{ |
| 1589 | .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index }, | 1589 | .ExpectedStringLiteral = .{ .token = it.index }, |
| 1590 | }); | 1590 | }); |
| 1591 | 1591 | ||
| 1592 | _ = try expectToken(it, tree, .LParen); | 1592 | _ = try expectToken(it, tree, .LParen); |
| 1593 | const kind = blk: { | 1593 | const kind: Node.AsmOutput.Kind = blk: { |
| 1594 | if (eatToken(it, .Arrow) != null) { | 1594 | if (eatToken(it, .Arrow) != null) { |
| 1595 | const return_ident = try expectNode(arena, it, tree, parseTypeExpr, AstError{ | 1595 | const return_ident = try expectNode(arena, it, tree, parseTypeExpr, .{ |
| 1596 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, | 1596 | .ExpectedTypeExpr = .{ .token = it.index }, |
| 1597 | }); | 1597 | }); |
| 1598 | break :blk Node.AsmOutput.Kind{ .Return = return_ident }; | 1598 | break :blk .{ .Return = return_ident }; |
| 1599 | } | 1599 | } |
| 1600 | const variable = try expectNode(arena, it, tree, parseIdentifier, AstError{ | 1600 | const variable = try expectNode(arena, it, tree, parseIdentifier, .{ |
| 1601 | .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, | 1601 | .ExpectedIdentifier = .{ .token = it.index }, |
| 1602 | }); | 1602 | }); |
| 1603 | break :blk Node.AsmOutput.Kind{ .Variable = variable.cast(Node.Identifier).? }; | 1603 | break :blk .{ .Variable = variable.cast(Node.Identifier).? }; |
| 1604 | }; | 1604 | }; |
| 1605 | const rparen = try expectToken(it, tree, .RParen); | 1605 | const rparen = try expectToken(it, tree, .RParen); |
| 1606 | 1606 | ||
| 1607 | const node = try arena.create(Node.AsmOutput); | 1607 | const node = try arena.create(Node.AsmOutput); |
| 1608 | node.* = Node.AsmOutput{ | 1608 | node.* = .{ |
| 1609 | .lbracket = lbracket, | 1609 | .lbracket = lbracket, |
| 1610 | .symbolic_name = name, | 1610 | .symbolic_name = name, |
| 1611 | .constraint = constraint, | 1611 | .constraint = constraint, |
| ... | @@ -1625,23 +1625,23 @@ fn parseAsmInput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: * | ... | @@ -1625,23 +1625,23 @@ fn parseAsmInput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: * |
| 1625 | /// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN | 1625 | /// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN |
| 1626 | fn parseAsmInputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmInput { | 1626 | fn parseAsmInputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmInput { |
| 1627 | const lbracket = eatToken(it, .LBracket) orelse return null; | 1627 | const lbracket = eatToken(it, .LBracket) orelse return null; |
| 1628 | const name = try expectNode(arena, it, tree, parseIdentifier, AstError{ | 1628 | const name = try expectNode(arena, it, tree, parseIdentifier, .{ |
| 1629 | .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, | 1629 | .ExpectedIdentifier = .{ .token = it.index }, |
| 1630 | }); | 1630 | }); |
| 1631 | _ = try expectToken(it, tree, .RBracket); | 1631 | _ = try expectToken(it, tree, .RBracket); |
| 1632 | 1632 | ||
| 1633 | const constraint = try expectNode(arena, it, tree, parseStringLiteral, AstError{ | 1633 | const constraint = try expectNode(arena, it, tree, parseStringLiteral, .{ |
| 1634 | .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index }, | 1634 | .ExpectedStringLiteral = .{ .token = it.index }, |
| 1635 | }); | 1635 | }); |
| 1636 | 1636 | ||
| 1637 | _ = try expectToken(it, tree, .LParen); | 1637 | _ = try expectToken(it, tree, .LParen); |
| 1638 | const expr = try expectNode(arena, it, tree, parseExpr, AstError{ | 1638 | const expr = try expectNode(arena, it, tree, parseExpr, .{ |
| 1639 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 1639 | .ExpectedExpr = .{ .token = it.index }, |
| 1640 | }); | 1640 | }); |
| 1641 | const rparen = try expectToken(it, tree, .RParen); | 1641 | const rparen = try expectToken(it, tree, .RParen); |
| 1642 | 1642 | ||
| 1643 | const node = try arena.create(Node.AsmInput); | 1643 | const node = try arena.create(Node.AsmInput); |
| 1644 | node.* = Node.AsmInput{ | 1644 | node.* = .{ |
| 1645 | .lbracket = lbracket, | 1645 | .lbracket = lbracket, |
| 1646 | .symbolic_name = name, | 1646 | .symbolic_name = name, |
| 1647 | .constraint = constraint, | 1647 | .constraint = constraint, |
| ... | @@ -1664,8 +1664,8 @@ fn parseAsmClobbers(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node | ... | @@ -1664,8 +1664,8 @@ fn parseAsmClobbers(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node |
| 1664 | /// BreakLabel <- COLON IDENTIFIER | 1664 | /// BreakLabel <- COLON IDENTIFIER |
| 1665 | fn parseBreakLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1665 | fn parseBreakLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1666 | _ = eatToken(it, .Colon) orelse return null; | 1666 | _ = eatToken(it, .Colon) orelse return null; |
| 1667 | return try expectNode(arena, it, tree, parseIdentifier, AstError{ | 1667 | return try expectNode(arena, it, tree, parseIdentifier, .{ |
| 1668 | .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, | 1668 | .ExpectedIdentifier = .{ .token = it.index }, |
| 1669 | }); | 1669 | }); |
| 1670 | } | 1670 | } |
| 1671 | 1671 | ||
| ... | @@ -1694,12 +1694,12 @@ fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -1694,12 +1694,12 @@ fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1694 | putBackToken(it, period_token); | 1694 | putBackToken(it, period_token); |
| 1695 | return null; | 1695 | return null; |
| 1696 | }; | 1696 | }; |
| 1697 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | 1697 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ |
| 1698 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 1698 | .ExpectedExpr = .{ .token = it.index }, |
| 1699 | }); | 1699 | }); |
| 1700 | 1700 | ||
| 1701 | const node = try arena.create(Node.FieldInitializer); | 1701 | const node = try arena.create(Node.FieldInitializer); |
| 1702 | node.* = Node.FieldInitializer{ | 1702 | node.* = .{ |
| 1703 | .period_token = period_token, | 1703 | .period_token = period_token, |
| 1704 | .name_token = name_token, | 1704 | .name_token = name_token, |
| 1705 | .expr = expr_node, | 1705 | .expr = expr_node, |
| ... | @@ -1711,8 +1711,8 @@ fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -1711,8 +1711,8 @@ fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1711 | fn parseWhileContinueExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1711 | fn parseWhileContinueExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1712 | _ = eatToken(it, .Colon) orelse return null; | 1712 | _ = eatToken(it, .Colon) orelse return null; |
| 1713 | _ = try expectToken(it, tree, .LParen); | 1713 | _ = try expectToken(it, tree, .LParen); |
| 1714 | const node = try expectNode(arena, it, tree, parseAssignExpr, AstError{ | 1714 | const node = try expectNode(arena, it, tree, parseAssignExpr, .{ |
| 1715 | .ExpectedExprOrAssignment = AstError.ExpectedExprOrAssignment{ .token = it.index }, | 1715 | .ExpectedExprOrAssignment = .{ .token = it.index }, |
| 1716 | }); | 1716 | }); |
| 1717 | _ = try expectToken(it, tree, .RParen); | 1717 | _ = try expectToken(it, tree, .RParen); |
| 1718 | return node; | 1718 | return node; |
| ... | @@ -1722,8 +1722,8 @@ fn parseWhileContinueExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? | ... | @@ -1722,8 +1722,8 @@ fn parseWhileContinueExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? |
| 1722 | fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1722 | fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1723 | _ = eatToken(it, .Keyword_linksection) orelse return null; | 1723 | _ = eatToken(it, .Keyword_linksection) orelse return null; |
| 1724 | _ = try expectToken(it, tree, .LParen); | 1724 | _ = try expectToken(it, tree, .LParen); |
| 1725 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | 1725 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ |
| 1726 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 1726 | .ExpectedExpr = .{ .token = it.index }, |
| 1727 | }); | 1727 | }); |
| 1728 | _ = try expectToken(it, tree, .RParen); | 1728 | _ = try expectToken(it, tree, .RParen); |
| 1729 | return expr_node; | 1729 | return expr_node; |
| ... | @@ -1733,8 +1733,8 @@ fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -1733,8 +1733,8 @@ fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 1733 | fn parseCallconv(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1733 | fn parseCallconv(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1734 | _ = eatToken(it, .Keyword_callconv) orelse return null; | 1734 | _ = eatToken(it, .Keyword_callconv) orelse return null; |
| 1735 | _ = try expectToken(it, tree, .LParen); | 1735 | _ = try expectToken(it, tree, .LParen); |
| 1736 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | 1736 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ |
| 1737 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 1737 | .ExpectedExpr = .{ .token = it.index }, |
| 1738 | }); | 1738 | }); |
| 1739 | _ = try expectToken(it, tree, .RParen); | 1739 | _ = try expectToken(it, tree, .RParen); |
| 1740 | return expr_node; | 1740 | return expr_node; |
| ... | @@ -1775,14 +1775,14 @@ fn parseParamDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -1775,14 +1775,14 @@ fn parseParamDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1775 | comptime_token == null and | 1775 | comptime_token == null and |
| 1776 | name_token == null and | 1776 | name_token == null and |
| 1777 | doc_comments == null) return null; | 1777 | doc_comments == null) return null; |
| 1778 | try tree.errors.push(AstError{ | 1778 | try tree.errors.push(.{ |
| 1779 | .ExpectedParamType = AstError.ExpectedParamType{ .token = it.index }, | 1779 | .ExpectedParamType = .{ .token = it.index }, |
| 1780 | }); | 1780 | }); |
| 1781 | return error.ParseError; | 1781 | return error.ParseError; |
| 1782 | }; | 1782 | }; |
| 1783 | 1783 | ||
| 1784 | const param_decl = try arena.create(Node.ParamDecl); | 1784 | const param_decl = try arena.create(Node.ParamDecl); |
| 1785 | param_decl.* = Node.ParamDecl{ | 1785 | param_decl.* = .{ |
| 1786 | .doc_comments = doc_comments, | 1786 | .doc_comments = doc_comments, |
| 1787 | .comptime_token = comptime_token, | 1787 | .comptime_token = comptime_token, |
| 1788 | .noalias_token = noalias_token, | 1788 | .noalias_token = noalias_token, |
| ... | @@ -1821,14 +1821,14 @@ const ParamType = union(enum) { | ... | @@ -1821,14 +1821,14 @@ const ParamType = union(enum) { |
| 1821 | fn parseIfPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1821 | fn parseIfPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1822 | const if_token = eatToken(it, .Keyword_if) orelse return null; | 1822 | const if_token = eatToken(it, .Keyword_if) orelse return null; |
| 1823 | _ = try expectToken(it, tree, .LParen); | 1823 | _ = try expectToken(it, tree, .LParen); |
| 1824 | const condition = try expectNode(arena, it, tree, parseExpr, AstError{ | 1824 | const condition = try expectNode(arena, it, tree, parseExpr, .{ |
| 1825 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 1825 | .ExpectedExpr = .{ .token = it.index }, |
| 1826 | }); | 1826 | }); |
| 1827 | _ = try expectToken(it, tree, .RParen); | 1827 | _ = try expectToken(it, tree, .RParen); |
| 1828 | const payload = try parsePtrPayload(arena, it, tree); | 1828 | const payload = try parsePtrPayload(arena, it, tree); |
| 1829 | 1829 | ||
| 1830 | const node = try arena.create(Node.If); | 1830 | const node = try arena.create(Node.If); |
| 1831 | node.* = Node.If{ | 1831 | node.* = .{ |
| 1832 | .if_token = if_token, | 1832 | .if_token = if_token, |
| 1833 | .condition = condition, | 1833 | .condition = condition, |
| 1834 | .payload = payload, | 1834 | .payload = payload, |
| ... | @@ -1843,8 +1843,8 @@ fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -1843,8 +1843,8 @@ fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 1843 | const while_token = eatToken(it, .Keyword_while) orelse return null; | 1843 | const while_token = eatToken(it, .Keyword_while) orelse return null; |
| 1844 | 1844 | ||
| 1845 | _ = try expectToken(it, tree, .LParen); | 1845 | _ = try expectToken(it, tree, .LParen); |
| 1846 | const condition = try expectNode(arena, it, tree, parseExpr, AstError{ | 1846 | const condition = try expectNode(arena, it, tree, parseExpr, .{ |
| 1847 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 1847 | .ExpectedExpr = .{ .token = it.index }, |
| 1848 | }); | 1848 | }); |
| 1849 | _ = try expectToken(it, tree, .RParen); | 1849 | _ = try expectToken(it, tree, .RParen); |
| 1850 | 1850 | ||
| ... | @@ -1852,7 +1852,7 @@ fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -1852,7 +1852,7 @@ fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 1852 | const continue_expr = try parseWhileContinueExpr(arena, it, tree); | 1852 | const continue_expr = try parseWhileContinueExpr(arena, it, tree); |
| 1853 | 1853 | ||
| 1854 | const node = try arena.create(Node.While); | 1854 | const node = try arena.create(Node.While); |
| 1855 | node.* = Node.While{ | 1855 | node.* = .{ |
| 1856 | .label = null, | 1856 | .label = null, |
| 1857 | .inline_token = null, | 1857 | .inline_token = null, |
| 1858 | .while_token = while_token, | 1858 | .while_token = while_token, |
| ... | @@ -1870,17 +1870,17 @@ fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -1870,17 +1870,17 @@ fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1870 | const for_token = eatToken(it, .Keyword_for) orelse return null; | 1870 | const for_token = eatToken(it, .Keyword_for) orelse return null; |
| 1871 | 1871 | ||
| 1872 | _ = try expectToken(it, tree, .LParen); | 1872 | _ = try expectToken(it, tree, .LParen); |
| 1873 | const array_expr = try expectNode(arena, it, tree, parseExpr, AstError{ | 1873 | const array_expr = try expectNode(arena, it, tree, parseExpr, .{ |
| 1874 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 1874 | .ExpectedExpr = .{ .token = it.index }, |
| 1875 | }); | 1875 | }); |
| 1876 | _ = try expectToken(it, tree, .RParen); | 1876 | _ = try expectToken(it, tree, .RParen); |
| 1877 | 1877 | ||
| 1878 | const payload = try expectNode(arena, it, tree, parsePtrIndexPayload, AstError{ | 1878 | const payload = try expectNode(arena, it, tree, parsePtrIndexPayload, .{ |
| 1879 | .ExpectedPayload = AstError.ExpectedPayload{ .token = it.index }, | 1879 | .ExpectedPayload = .{ .token = it.index }, |
| 1880 | }); | 1880 | }); |
| 1881 | 1881 | ||
| 1882 | const node = try arena.create(Node.For); | 1882 | const node = try arena.create(Node.For); |
| 1883 | node.* = Node.For{ | 1883 | node.* = .{ |
| 1884 | .label = null, | 1884 | .label = null, |
| 1885 | .inline_token = null, | 1885 | .inline_token = null, |
| 1886 | .for_token = for_token, | 1886 | .for_token = for_token, |
| ... | @@ -1895,13 +1895,13 @@ fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -1895,13 +1895,13 @@ fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1895 | /// Payload <- PIPE IDENTIFIER PIPE | 1895 | /// Payload <- PIPE IDENTIFIER PIPE |
| 1896 | fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1896 | fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1897 | const lpipe = eatToken(it, .Pipe) orelse return null; | 1897 | const lpipe = eatToken(it, .Pipe) orelse return null; |
| 1898 | const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{ | 1898 | const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ |
| 1899 | .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, | 1899 | .ExpectedIdentifier = .{ .token = it.index }, |
| 1900 | }); | 1900 | }); |
| 1901 | const rpipe = try expectToken(it, tree, .Pipe); | 1901 | const rpipe = try expectToken(it, tree, .Pipe); |
| 1902 | 1902 | ||
| 1903 | const node = try arena.create(Node.Payload); | 1903 | const node = try arena.create(Node.Payload); |
| 1904 | node.* = Node.Payload{ | 1904 | node.* = .{ |
| 1905 | .lpipe = lpipe, | 1905 | .lpipe = lpipe, |
| 1906 | .error_symbol = identifier, | 1906 | .error_symbol = identifier, |
| 1907 | .rpipe = rpipe, | 1907 | .rpipe = rpipe, |
| ... | @@ -1913,13 +1913,13 @@ fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -1913,13 +1913,13 @@ fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1913 | fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1913 | fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1914 | const lpipe = eatToken(it, .Pipe) orelse return null; | 1914 | const lpipe = eatToken(it, .Pipe) orelse return null; |
| 1915 | const asterisk = eatToken(it, .Asterisk); | 1915 | const asterisk = eatToken(it, .Asterisk); |
| 1916 | const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{ | 1916 | const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ |
| 1917 | .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, | 1917 | .ExpectedIdentifier = .{ .token = it.index }, |
| 1918 | }); | 1918 | }); |
| 1919 | const rpipe = try expectToken(it, tree, .Pipe); | 1919 | const rpipe = try expectToken(it, tree, .Pipe); |
| 1920 | 1920 | ||
| 1921 | const node = try arena.create(Node.PointerPayload); | 1921 | const node = try arena.create(Node.PointerPayload); |
| 1922 | node.* = Node.PointerPayload{ | 1922 | node.* = .{ |
| 1923 | .lpipe = lpipe, | 1923 | .lpipe = lpipe, |
| 1924 | .ptr_token = asterisk, | 1924 | .ptr_token = asterisk, |
| 1925 | .value_symbol = identifier, | 1925 | .value_symbol = identifier, |
| ... | @@ -1932,21 +1932,21 @@ fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -1932,21 +1932,21 @@ fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1932 | fn parsePtrIndexPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 1932 | fn parsePtrIndexPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1933 | const lpipe = eatToken(it, .Pipe) orelse return null; | 1933 | const lpipe = eatToken(it, .Pipe) orelse return null; |
| 1934 | const asterisk = eatToken(it, .Asterisk); | 1934 | const asterisk = eatToken(it, .Asterisk); |
| 1935 | const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{ | 1935 | const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ |
| 1936 | .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, | 1936 | .ExpectedIdentifier = .{ .token = it.index }, |
| 1937 | }); | 1937 | }); |
| 1938 | 1938 | ||
| 1939 | const index = if (eatToken(it, .Comma) == null) | 1939 | const index = if (eatToken(it, .Comma) == null) |
| 1940 | null | 1940 | null |
| 1941 | else | 1941 | else |
| 1942 | try expectNode(arena, it, tree, parseIdentifier, AstError{ | 1942 | try expectNode(arena, it, tree, parseIdentifier, .{ |
| 1943 | .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, | 1943 | .ExpectedIdentifier = .{ .token = it.index }, |
| 1944 | }); | 1944 | }); |
| 1945 | 1945 | ||
| 1946 | const rpipe = try expectToken(it, tree, .Pipe); | 1946 | const rpipe = try expectToken(it, tree, .Pipe); |
| 1947 | 1947 | ||
| 1948 | const node = try arena.create(Node.PointerIndexPayload); | 1948 | const node = try arena.create(Node.PointerIndexPayload); |
| 1949 | node.* = Node.PointerIndexPayload{ | 1949 | node.* = .{ |
| 1950 | .lpipe = lpipe, | 1950 | .lpipe = lpipe, |
| 1951 | .ptr_token = asterisk, | 1951 | .ptr_token = asterisk, |
| 1952 | .value_symbol = identifier, | 1952 | .value_symbol = identifier, |
| ... | @@ -1961,8 +1961,8 @@ fn parseSwitchProng(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -1961,8 +1961,8 @@ fn parseSwitchProng(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 1961 | const node = (try parseSwitchCase(arena, it, tree)) orelse return null; | 1961 | const node = (try parseSwitchCase(arena, it, tree)) orelse return null; |
| 1962 | const arrow = try expectToken(it, tree, .EqualAngleBracketRight); | 1962 | const arrow = try expectToken(it, tree, .EqualAngleBracketRight); |
| 1963 | const payload = try parsePtrPayload(arena, it, tree); | 1963 | const payload = try parsePtrPayload(arena, it, tree); |
| 1964 | const expr = try expectNode(arena, it, tree, parseAssignExpr, AstError{ | 1964 | const expr = try expectNode(arena, it, tree, parseAssignExpr, .{ |
| 1965 | .ExpectedExprOrAssignment = AstError.ExpectedExprOrAssignment{ .token = it.index }, | 1965 | .ExpectedExprOrAssignment = .{ .token = it.index }, |
| 1966 | }); | 1966 | }); |
| 1967 | 1967 | ||
| 1968 | const switch_case = node.cast(Node.SwitchCase).?; | 1968 | const switch_case = node.cast(Node.SwitchCase).?; |
| ... | @@ -1987,14 +1987,14 @@ fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -1987,14 +1987,14 @@ fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 1987 | } | 1987 | } |
| 1988 | } else if (eatToken(it, .Keyword_else)) |else_token| { | 1988 | } else if (eatToken(it, .Keyword_else)) |else_token| { |
| 1989 | const else_node = try arena.create(Node.SwitchElse); | 1989 | const else_node = try arena.create(Node.SwitchElse); |
| 1990 | else_node.* = Node.SwitchElse{ | 1990 | else_node.* = .{ |
| 1991 | .token = else_token, | 1991 | .token = else_token, |
| 1992 | }; | 1992 | }; |
| 1993 | try list.push(&else_node.base); | 1993 | try list.push(&else_node.base); |
| 1994 | } else return null; | 1994 | } else return null; |
| 1995 | 1995 | ||
| 1996 | const node = try arena.create(Node.SwitchCase); | 1996 | const node = try arena.create(Node.SwitchCase); |
| 1997 | node.* = Node.SwitchCase{ | 1997 | node.* = .{ |
| 1998 | .items = list, | 1998 | .items = list, |
| 1999 | .arrow_token = undefined, // set by caller | 1999 | .arrow_token = undefined, // set by caller |
| 2000 | .payload = null, | 2000 | .payload = null, |
| ... | @@ -2007,15 +2007,15 @@ fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2007,15 +2007,15 @@ fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2007 | fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2007 | fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2008 | const expr = (try parseExpr(arena, it, tree)) orelse return null; | 2008 | const expr = (try parseExpr(arena, it, tree)) orelse return null; |
| 2009 | if (eatToken(it, .Ellipsis3)) |token| { | 2009 | if (eatToken(it, .Ellipsis3)) |token| { |
| 2010 | const range_end = try expectNode(arena, it, tree, parseExpr, AstError{ | 2010 | const range_end = try expectNode(arena, it, tree, parseExpr, .{ |
| 2011 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 2011 | .ExpectedExpr = .{ .token = it.index }, |
| 2012 | }); | 2012 | }); |
| 2013 | 2013 | ||
| 2014 | const node = try arena.create(Node.InfixOp); | 2014 | const node = try arena.create(Node.InfixOp); |
| 2015 | node.* = Node.InfixOp{ | 2015 | node.* = .{ |
| 2016 | .op_token = token, | 2016 | .op_token = token, |
| 2017 | .lhs = expr, | 2017 | .lhs = expr, |
| 2018 | .op = Node.InfixOp.Op{ .Range = {} }, | 2018 | .op = .Range, |
| 2019 | .rhs = range_end, | 2019 | .rhs = range_end, |
| 2020 | }; | 2020 | }; |
| 2021 | return &node.base; | 2021 | return &node.base; |
| ... | @@ -2039,24 +2039,22 @@ fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2039,24 +2039,22 @@ fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2039 | /// / MINUSPERCENTEQUAL | 2039 | /// / MINUSPERCENTEQUAL |
| 2040 | /// / EQUAL | 2040 | /// / EQUAL |
| 2041 | fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2041 | fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2042 | const Op = Node.InfixOp.Op; | ||
| 2043 | |||
| 2044 | const token = nextToken(it); | 2042 | const token = nextToken(it); |
| 2045 | const op = switch (token.ptr.id) { | 2043 | const op: Node.InfixOp.Op = switch (token.ptr.id) { |
| 2046 | .AsteriskEqual => Op{ .AssignMul = {} }, | 2044 | .AsteriskEqual => .AssignMul, |
| 2047 | .SlashEqual => Op{ .AssignDiv = {} }, | 2045 | .SlashEqual => .AssignDiv, |
| 2048 | .PercentEqual => Op{ .AssignMod = {} }, | 2046 | .PercentEqual => .AssignMod, |
| 2049 | .PlusEqual => Op{ .AssignAdd = {} }, | 2047 | .PlusEqual => .AssignAdd, |
| 2050 | .MinusEqual => Op{ .AssignSub = {} }, | 2048 | .MinusEqual => .AssignSub, |
| 2051 | .AngleBracketAngleBracketLeftEqual => Op{ .AssignBitShiftLeft = {} }, | 2049 | .AngleBracketAngleBracketLeftEqual => .AssignBitShiftLeft, |
| 2052 | .AngleBracketAngleBracketRightEqual => Op{ .AssignBitShiftRight = {} }, | 2050 | .AngleBracketAngleBracketRightEqual => .AssignBitShiftRight, |
| 2053 | .AmpersandEqual => Op{ .AssignBitAnd = {} }, | 2051 | .AmpersandEqual => .AssignBitAnd, |
| 2054 | .CaretEqual => Op{ .AssignBitXor = {} }, | 2052 | .CaretEqual => .AssignBitXor, |
| 2055 | .PipeEqual => Op{ .AssignBitOr = {} }, | 2053 | .PipeEqual => .AssignBitOr, |
| 2056 | .AsteriskPercentEqual => Op{ .AssignMulWrap = {} }, | 2054 | .AsteriskPercentEqual => .AssignMulWrap, |
| 2057 | .PlusPercentEqual => Op{ .AssignAddWrap = {} }, | 2055 | .PlusPercentEqual => .AssignAddWrap, |
| 2058 | .MinusPercentEqual => Op{ .AssignSubWrap = {} }, | 2056 | .MinusPercentEqual => .AssignSubWrap, |
| 2059 | .Equal => Op{ .Assign = {} }, | 2057 | .Equal => .Assign, |
| 2060 | else => { | 2058 | else => { |
| 2061 | putBackToken(it, token.index); | 2059 | putBackToken(it, token.index); |
| 2062 | return null; | 2060 | return null; |
| ... | @@ -2064,7 +2062,7 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2064,7 +2062,7 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2064 | }; | 2062 | }; |
| 2065 | 2063 | ||
| 2066 | const node = try arena.create(Node.InfixOp); | 2064 | const node = try arena.create(Node.InfixOp); |
| 2067 | node.* = Node.InfixOp{ | 2065 | node.* = .{ |
| 2068 | .op_token = token.index, | 2066 | .op_token = token.index, |
| 2069 | .lhs = undefined, // set by caller | 2067 | .lhs = undefined, // set by caller |
| 2070 | .op = op, | 2068 | .op = op, |
| ... | @@ -2081,16 +2079,14 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2081,16 +2079,14 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2081 | /// / LARROWEQUAL | 2079 | /// / LARROWEQUAL |
| 2082 | /// / RARROWEQUAL | 2080 | /// / RARROWEQUAL |
| 2083 | fn parseCompareOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2081 | fn parseCompareOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2084 | const ops = Node.InfixOp.Op; | ||
| 2085 | |||
| 2086 | const token = nextToken(it); | 2082 | const token = nextToken(it); |
| 2087 | const op = switch (token.ptr.id) { | 2083 | const op: Node.InfixOp.Op = switch (token.ptr.id) { |
| 2088 | .EqualEqual => ops{ .EqualEqual = {} }, | 2084 | .EqualEqual => .EqualEqual, |
| 2089 | .BangEqual => ops{ .BangEqual = {} }, | 2085 | .BangEqual => .BangEqual, |
| 2090 | .AngleBracketLeft => ops{ .LessThan = {} }, | 2086 | .AngleBracketLeft => .LessThan, |
| 2091 | .AngleBracketRight => ops{ .GreaterThan = {} }, | 2087 | .AngleBracketRight => .GreaterThan, |
| 2092 | .AngleBracketLeftEqual => ops{ .LessOrEqual = {} }, | 2088 | .AngleBracketLeftEqual => .LessOrEqual, |
| 2093 | .AngleBracketRightEqual => ops{ .GreaterOrEqual = {} }, | 2089 | .AngleBracketRightEqual => .GreaterOrEqual, |
| 2094 | else => { | 2090 | else => { |
| 2095 | putBackToken(it, token.index); | 2091 | putBackToken(it, token.index); |
| 2096 | return null; | 2092 | return null; |
| ... | @@ -2107,15 +2103,13 @@ fn parseCompareOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2107,15 +2103,13 @@ fn parseCompareOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2107 | /// / KEYWORD_orelse | 2103 | /// / KEYWORD_orelse |
| 2108 | /// / KEYWORD_catch Payload? | 2104 | /// / KEYWORD_catch Payload? |
| 2109 | fn parseBitwiseOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2105 | fn parseBitwiseOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2110 | const ops = Node.InfixOp.Op; | ||
| 2111 | |||
| 2112 | const token = nextToken(it); | 2106 | const token = nextToken(it); |
| 2113 | const op = switch (token.ptr.id) { | 2107 | const op: Node.InfixOp.Op = switch (token.ptr.id) { |
| 2114 | .Ampersand => ops{ .BitAnd = {} }, | 2108 | .Ampersand => .BitAnd, |
| 2115 | .Caret => ops{ .BitXor = {} }, | 2109 | .Caret => .BitXor, |
| 2116 | .Pipe => ops{ .BitOr = {} }, | 2110 | .Pipe => .BitOr, |
| 2117 | .Keyword_orelse => ops{ .UnwrapOptional = {} }, | 2111 | .Keyword_orelse => .UnwrapOptional, |
| 2118 | .Keyword_catch => ops{ .Catch = try parsePayload(arena, it, tree) }, | 2112 | .Keyword_catch => .{ .Catch = try parsePayload(arena, it, tree) }, |
| 2119 | else => { | 2113 | else => { |
| 2120 | putBackToken(it, token.index); | 2114 | putBackToken(it, token.index); |
| 2121 | return null; | 2115 | return null; |
| ... | @@ -2129,12 +2123,10 @@ fn parseBitwiseOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2129,12 +2123,10 @@ fn parseBitwiseOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2129 | /// <- LARROW2 | 2123 | /// <- LARROW2 |
| 2130 | /// / RARROW2 | 2124 | /// / RARROW2 |
| 2131 | fn parseBitShiftOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2125 | fn parseBitShiftOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2132 | const ops = Node.InfixOp.Op; | ||
| 2133 | |||
| 2134 | const token = nextToken(it); | 2126 | const token = nextToken(it); |
| 2135 | const op = switch (token.ptr.id) { | 2127 | const op: Node.InfixOp.Op = switch (token.ptr.id) { |
| 2136 | .AngleBracketAngleBracketLeft => ops{ .BitShiftLeft = {} }, | 2128 | .AngleBracketAngleBracketLeft => .BitShiftLeft, |
| 2137 | .AngleBracketAngleBracketRight => ops{ .BitShiftRight = {} }, | 2129 | .AngleBracketAngleBracketRight => .BitShiftRight, |
| 2138 | else => { | 2130 | else => { |
| 2139 | putBackToken(it, token.index); | 2131 | putBackToken(it, token.index); |
| 2140 | return null; | 2132 | return null; |
| ... | @@ -2151,15 +2143,13 @@ fn parseBitShiftOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2151,15 +2143,13 @@ fn parseBitShiftOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2151 | /// / PLUSPERCENT | 2143 | /// / PLUSPERCENT |
| 2152 | /// / MINUSPERCENT | 2144 | /// / MINUSPERCENT |
| 2153 | fn parseAdditionOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2145 | fn parseAdditionOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2154 | const ops = Node.InfixOp.Op; | ||
| 2155 | |||
| 2156 | const token = nextToken(it); | 2146 | const token = nextToken(it); |
| 2157 | const op = switch (token.ptr.id) { | 2147 | const op: Node.InfixOp.Op = switch (token.ptr.id) { |
| 2158 | .Plus => ops{ .Add = {} }, | 2148 | .Plus => .Add, |
| 2159 | .Minus => ops{ .Sub = {} }, | 2149 | .Minus => .Sub, |
| 2160 | .PlusPlus => ops{ .ArrayCat = {} }, | 2150 | .PlusPlus => .ArrayCat, |
| 2161 | .PlusPercent => ops{ .AddWrap = {} }, | 2151 | .PlusPercent => .AddWrap, |
| 2162 | .MinusPercent => ops{ .SubWrap = {} }, | 2152 | .MinusPercent => .SubWrap, |
| 2163 | else => { | 2153 | else => { |
| 2164 | putBackToken(it, token.index); | 2154 | putBackToken(it, token.index); |
| 2165 | return null; | 2155 | return null; |
| ... | @@ -2177,16 +2167,14 @@ fn parseAdditionOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2177,16 +2167,14 @@ fn parseAdditionOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2177 | /// / ASTERISK2 | 2167 | /// / ASTERISK2 |
| 2178 | /// / ASTERISKPERCENT | 2168 | /// / ASTERISKPERCENT |
| 2179 | fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2169 | fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2180 | const ops = Node.InfixOp.Op; | ||
| 2181 | |||
| 2182 | const token = nextToken(it); | 2170 | const token = nextToken(it); |
| 2183 | const op = switch (token.ptr.id) { | 2171 | const op: Node.InfixOp.Op = switch (token.ptr.id) { |
| 2184 | .PipePipe => ops{ .BoolOr = {} }, | 2172 | .PipePipe => .MergeErrorSets, |
| 2185 | .Asterisk => ops{ .Mul = {} }, | 2173 | .Asterisk => .Mul, |
| 2186 | .Slash => ops{ .Div = {} }, | 2174 | .Slash => .Div, |
| 2187 | .Percent => ops{ .Mod = {} }, | 2175 | .Percent => .Mod, |
| 2188 | .AsteriskAsterisk => ops{ .ArrayMult = {} }, | 2176 | .AsteriskAsterisk => .ArrayMult, |
| 2189 | .AsteriskPercent => ops{ .MulWrap = {} }, | 2177 | .AsteriskPercent => .MulWrap, |
| 2190 | else => { | 2178 | else => { |
| 2191 | putBackToken(it, token.index); | 2179 | putBackToken(it, token.index); |
| 2192 | return null; | 2180 | return null; |
| ... | @@ -2205,17 +2193,15 @@ fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2205,17 +2193,15 @@ fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2205 | /// / KEYWORD_try | 2193 | /// / KEYWORD_try |
| 2206 | /// / KEYWORD_await | 2194 | /// / KEYWORD_await |
| 2207 | fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2195 | fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2208 | const ops = Node.PrefixOp.Op; | ||
| 2209 | |||
| 2210 | const token = nextToken(it); | 2196 | const token = nextToken(it); |
| 2211 | const op = switch (token.ptr.id) { | 2197 | const op: Node.PrefixOp.Op = switch (token.ptr.id) { |
| 2212 | .Bang => ops{ .BoolNot = {} }, | 2198 | .Bang => .BoolNot, |
| 2213 | .Minus => ops{ .Negation = {} }, | 2199 | .Minus => .Negation, |
| 2214 | .Tilde => ops{ .BitNot = {} }, | 2200 | .Tilde => .BitNot, |
| 2215 | .MinusPercent => ops{ .NegationWrap = {} }, | 2201 | .MinusPercent => .NegationWrap, |
| 2216 | .Ampersand => ops{ .AddressOf = {} }, | 2202 | .Ampersand => .AddressOf, |
| 2217 | .Keyword_try => ops{ .Try = {} }, | 2203 | .Keyword_try => .Try, |
| 2218 | .Keyword_await => ops{ .Await = .{} }, | 2204 | .Keyword_await => .Await, |
| 2219 | else => { | 2205 | else => { |
| 2220 | putBackToken(it, token.index); | 2206 | putBackToken(it, token.index); |
| 2221 | return null; | 2207 | return null; |
| ... | @@ -2223,7 +2209,7 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2223,7 +2209,7 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2223 | }; | 2209 | }; |
| 2224 | 2210 | ||
| 2225 | const node = try arena.create(Node.PrefixOp); | 2211 | const node = try arena.create(Node.PrefixOp); |
| 2226 | node.* = Node.PrefixOp{ | 2212 | node.* = .{ |
| 2227 | .op_token = token.index, | 2213 | .op_token = token.index, |
| 2228 | .op = op, | 2214 | .op = op, |
| 2229 | .rhs = undefined, // set by caller | 2215 | .rhs = undefined, // set by caller |
| ... | @@ -2246,9 +2232,9 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2246,9 +2232,9 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2246 | fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2232 | fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2247 | if (eatToken(it, .QuestionMark)) |token| { | 2233 | if (eatToken(it, .QuestionMark)) |token| { |
| 2248 | const node = try arena.create(Node.PrefixOp); | 2234 | const node = try arena.create(Node.PrefixOp); |
| 2249 | node.* = Node.PrefixOp{ | 2235 | node.* = .{ |
| 2250 | .op_token = token, | 2236 | .op_token = token, |
| 2251 | .op = Node.PrefixOp.Op.OptionalType, | 2237 | .op = .OptionalType, |
| 2252 | .rhs = undefined, // set by caller | 2238 | .rhs = undefined, // set by caller |
| 2253 | }; | 2239 | }; |
| 2254 | return &node.base; | 2240 | return &node.base; |
| ... | @@ -2264,7 +2250,7 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -2264,7 +2250,7 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2264 | return null; | 2250 | return null; |
| 2265 | }; | 2251 | }; |
| 2266 | const node = try arena.create(Node.AnyFrameType); | 2252 | const node = try arena.create(Node.AnyFrameType); |
| 2267 | node.* = Node.AnyFrameType{ | 2253 | node.* = .{ |
| 2268 | .anyframe_token = token, | 2254 | .anyframe_token = token, |
| 2269 | .result = Node.AnyFrameType.Result{ | 2255 | .result = Node.AnyFrameType.Result{ |
| 2270 | .arrow_token = arrow, | 2256 | .arrow_token = arrow, |
| ... | @@ -2286,18 +2272,18 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -2286,18 +2272,18 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2286 | while (true) { | 2272 | while (true) { |
| 2287 | if (eatToken(it, .Keyword_align)) |align_token| { | 2273 | if (eatToken(it, .Keyword_align)) |align_token| { |
| 2288 | const lparen = try expectToken(it, tree, .LParen); | 2274 | const lparen = try expectToken(it, tree, .LParen); |
| 2289 | const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ | 2275 | const expr_node = try expectNode(arena, it, tree, parseExpr, .{ |
| 2290 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 2276 | .ExpectedExpr = .{ .token = it.index }, |
| 2291 | }); | 2277 | }); |
| 2292 | 2278 | ||
| 2293 | // Optional bit range | 2279 | // Optional bit range |
| 2294 | const bit_range = if (eatToken(it, .Colon)) |_| bit_range_value: { | 2280 | const bit_range = if (eatToken(it, .Colon)) |_| bit_range_value: { |
| 2295 | const range_start = try expectNode(arena, it, tree, parseIntegerLiteral, AstError{ | 2281 | const range_start = try expectNode(arena, it, tree, parseIntegerLiteral, .{ |
| 2296 | .ExpectedIntegerLiteral = AstError.ExpectedIntegerLiteral{ .token = it.index }, | 2282 | .ExpectedIntegerLiteral = .{ .token = it.index }, |
| 2297 | }); | 2283 | }); |
| 2298 | _ = try expectToken(it, tree, .Colon); | 2284 | _ = try expectToken(it, tree, .Colon); |
| 2299 | const range_end = try expectNode(arena, it, tree, parseIntegerLiteral, AstError{ | 2285 | const range_end = try expectNode(arena, it, tree, parseIntegerLiteral, .{ |
| 2300 | .ExpectedIntegerLiteral = AstError.ExpectedIntegerLiteral{ .token = it.index }, | 2286 | .ExpectedIntegerLiteral = .{ .token = it.index }, |
| 2301 | }); | 2287 | }); |
| 2302 | 2288 | ||
| 2303 | break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{ | 2289 | break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{ |
| ... | @@ -2340,8 +2326,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -2340,8 +2326,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2340 | while (true) { | 2326 | while (true) { |
| 2341 | if (try parseByteAlign(arena, it, tree)) |align_expr| { | 2327 | if (try parseByteAlign(arena, it, tree)) |align_expr| { |
| 2342 | if (slice_type.align_info != null) { | 2328 | if (slice_type.align_info != null) { |
| 2343 | try tree.errors.push(AstError{ | 2329 | try tree.errors.push(.{ |
| 2344 | .ExtraAlignQualifier = AstError.ExtraAlignQualifier{ .token = it.index }, | 2330 | .ExtraAlignQualifier = .{ .token = it.index }, |
| 2345 | }); | 2331 | }); |
| 2346 | return error.ParseError; | 2332 | return error.ParseError; |
| 2347 | } | 2333 | } |
| ... | @@ -2353,8 +2339,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -2353,8 +2339,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2353 | } | 2339 | } |
| 2354 | if (eatToken(it, .Keyword_const)) |const_token| { | 2340 | if (eatToken(it, .Keyword_const)) |const_token| { |
| 2355 | if (slice_type.const_token != null) { | 2341 | if (slice_type.const_token != null) { |
| 2356 | try tree.errors.push(AstError{ | 2342 | try tree.errors.push(.{ |
| 2357 | .ExtraConstQualifier = AstError.ExtraConstQualifier{ .token = it.index }, | 2343 | .ExtraConstQualifier = .{ .token = it.index }, |
| 2358 | }); | 2344 | }); |
| 2359 | return error.ParseError; | 2345 | return error.ParseError; |
| 2360 | } | 2346 | } |
| ... | @@ -2363,8 +2349,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -2363,8 +2349,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2363 | } | 2349 | } |
| 2364 | if (eatToken(it, .Keyword_volatile)) |volatile_token| { | 2350 | if (eatToken(it, .Keyword_volatile)) |volatile_token| { |
| 2365 | if (slice_type.volatile_token != null) { | 2351 | if (slice_type.volatile_token != null) { |
| 2366 | try tree.errors.push(AstError{ | 2352 | try tree.errors.push(.{ |
| 2367 | .ExtraVolatileQualifier = AstError.ExtraVolatileQualifier{ .token = it.index }, | 2353 | .ExtraVolatileQualifier = .{ .token = it.index }, |
| 2368 | }); | 2354 | }); |
| 2369 | return error.ParseError; | 2355 | return error.ParseError; |
| 2370 | } | 2356 | } |
| ... | @@ -2373,8 +2359,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -2373,8 +2359,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2373 | } | 2359 | } |
| 2374 | if (eatToken(it, .Keyword_allowzero)) |allowzero_token| { | 2360 | if (eatToken(it, .Keyword_allowzero)) |allowzero_token| { |
| 2375 | if (slice_type.allowzero_token != null) { | 2361 | if (slice_type.allowzero_token != null) { |
| 2376 | try tree.errors.push(AstError{ | 2362 | try tree.errors.push(.{ |
| 2377 | .ExtraAllowZeroQualifier = AstError.ExtraAllowZeroQualifier{ .token = it.index }, | 2363 | .ExtraAllowZeroQualifier = .{ .token = it.index }, |
| 2378 | }); | 2364 | }); |
| 2379 | return error.ParseError; | 2365 | return error.ParseError; |
| 2380 | } | 2366 | } |
| ... | @@ -2398,15 +2384,14 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -2398,15 +2384,14 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2398 | /// / DOTASTERISK | 2384 | /// / DOTASTERISK |
| 2399 | /// / DOTQUESTIONMARK | 2385 | /// / DOTQUESTIONMARK |
| 2400 | fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2386 | fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2401 | const Op = Node.SuffixOp.Op; | ||
| 2402 | const OpAndToken = struct { | 2387 | const OpAndToken = struct { |
| 2403 | op: Node.SuffixOp.Op, | 2388 | op: Node.SuffixOp.Op, |
| 2404 | token: TokenIndex, | 2389 | token: TokenIndex, |
| 2405 | }; | 2390 | }; |
| 2406 | const op_and_token = blk: { | 2391 | const op_and_token: OpAndToken = blk: { |
| 2407 | if (eatToken(it, .LBracket)) |_| { | 2392 | if (eatToken(it, .LBracket)) |_| { |
| 2408 | const index_expr = try expectNode(arena, it, tree, parseExpr, AstError{ | 2393 | const index_expr = try expectNode(arena, it, tree, parseExpr, .{ |
| 2409 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 2394 | .ExpectedExpr = .{ .token = it.index }, |
| 2410 | }); | 2395 | }); |
| 2411 | 2396 | ||
| 2412 | if (eatToken(it, .Ellipsis2) != null) { | 2397 | if (eatToken(it, .Ellipsis2) != null) { |
| ... | @@ -2415,9 +2400,9 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2415,9 +2400,9 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2415 | try parseExpr(arena, it, tree) | 2400 | try parseExpr(arena, it, tree) |
| 2416 | else | 2401 | else |
| 2417 | null; | 2402 | null; |
| 2418 | break :blk OpAndToken{ | 2403 | break :blk .{ |
| 2419 | .op = Op{ | 2404 | .op = .{ |
| 2420 | .Slice = Op.Slice{ | 2405 | .Slice = .{ |
| 2421 | .start = index_expr, | 2406 | .start = index_expr, |
| 2422 | .end = end_expr, | 2407 | .end = end_expr, |
| 2423 | .sentinel = sentinel, | 2408 | .sentinel = sentinel, |
| ... | @@ -2427,14 +2412,14 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2427,14 +2412,14 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2427 | }; | 2412 | }; |
| 2428 | } | 2413 | } |
| 2429 | 2414 | ||
| 2430 | break :blk OpAndToken{ | 2415 | break :blk .{ |
| 2431 | .op = Op{ .ArrayAccess = index_expr }, | 2416 | .op = .{ .ArrayAccess = index_expr }, |
| 2432 | .token = try expectToken(it, tree, .RBracket), | 2417 | .token = try expectToken(it, tree, .RBracket), |
| 2433 | }; | 2418 | }; |
| 2434 | } | 2419 | } |
| 2435 | 2420 | ||
| 2436 | if (eatToken(it, .PeriodAsterisk)) |period_asterisk| { | 2421 | if (eatToken(it, .PeriodAsterisk)) |period_asterisk| { |
| 2437 | break :blk OpAndToken{ .op = Op{ .Deref = {} }, .token = period_asterisk }; | 2422 | break :blk .{ .op = .Deref, .token = period_asterisk }; |
| 2438 | } | 2423 | } |
| 2439 | 2424 | ||
| 2440 | if (eatToken(it, .Period)) |period| { | 2425 | if (eatToken(it, .Period)) |period| { |
| ... | @@ -2443,19 +2428,19 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2443,19 +2428,19 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2443 | // Should there be an ast.Node.SuffixOp.FieldAccess variant? Or should | 2428 | // Should there be an ast.Node.SuffixOp.FieldAccess variant? Or should |
| 2444 | // this grammar rule be altered? | 2429 | // this grammar rule be altered? |
| 2445 | const node = try arena.create(Node.InfixOp); | 2430 | const node = try arena.create(Node.InfixOp); |
| 2446 | node.* = Node.InfixOp{ | 2431 | node.* = .{ |
| 2447 | .op_token = period, | 2432 | .op_token = period, |
| 2448 | .lhs = undefined, // set by caller | 2433 | .lhs = undefined, // set by caller |
| 2449 | .op = Node.InfixOp.Op.Period, | 2434 | .op = .Period, |
| 2450 | .rhs = identifier, | 2435 | .rhs = identifier, |
| 2451 | }; | 2436 | }; |
| 2452 | return &node.base; | 2437 | return &node.base; |
| 2453 | } | 2438 | } |
| 2454 | if (eatToken(it, .QuestionMark)) |question_mark| { | 2439 | if (eatToken(it, .QuestionMark)) |question_mark| { |
| 2455 | break :blk OpAndToken{ .op = Op{ .UnwrapOptional = {} }, .token = question_mark }; | 2440 | break :blk .{ .op = .UnwrapOptional, .token = question_mark }; |
| 2456 | } | 2441 | } |
| 2457 | try tree.errors.push(AstError{ | 2442 | try tree.errors.push(.{ |
| 2458 | .ExpectedSuffixOp = AstError.ExpectedSuffixOp{ .token = it.index }, | 2443 | .ExpectedSuffixOp = .{ .token = it.index }, |
| 2459 | }); | 2444 | }); |
| 2460 | return null; | 2445 | return null; |
| 2461 | } | 2446 | } |
| ... | @@ -2464,7 +2449,7 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2464,7 +2449,7 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2464 | }; | 2449 | }; |
| 2465 | 2450 | ||
| 2466 | const node = try arena.create(Node.SuffixOp); | 2451 | const node = try arena.create(Node.SuffixOp); |
| 2467 | node.* = Node.SuffixOp{ | 2452 | node.* = .{ |
| 2468 | .lhs = undefined, // set by caller | 2453 | .lhs = undefined, // set by caller |
| 2469 | .op = op_and_token.op, | 2454 | .op = op_and_token.op, |
| 2470 | .rtoken = op_and_token.token, | 2455 | .rtoken = op_and_token.token, |
| ... | @@ -2491,22 +2476,22 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No | ... | @@ -2491,22 +2476,22 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 2491 | const lbracket = eatToken(it, .LBracket) orelse return null; | 2476 | const lbracket = eatToken(it, .LBracket) orelse return null; |
| 2492 | const expr = try parseExpr(arena, it, tree); | 2477 | const expr = try parseExpr(arena, it, tree); |
| 2493 | const sentinel = if (eatToken(it, .Colon)) |_| | 2478 | const sentinel = if (eatToken(it, .Colon)) |_| |
| 2494 | try expectNode(arena, it, tree, parseExpr, AstError{ | 2479 | try expectNode(arena, it, tree, parseExpr, .{ |
| 2495 | .ExpectedExpr = .{ .token = it.index }, | 2480 | .ExpectedExpr = .{ .token = it.index }, |
| 2496 | }) | 2481 | }) |
| 2497 | else | 2482 | else |
| 2498 | null; | 2483 | null; |
| 2499 | const rbracket = try expectToken(it, tree, .RBracket); | 2484 | const rbracket = try expectToken(it, tree, .RBracket); |
| 2500 | 2485 | ||
| 2501 | const op = if (expr) |len_expr| | 2486 | const op: Node.PrefixOp.Op = if (expr) |len_expr| |
| 2502 | Node.PrefixOp.Op{ | 2487 | .{ |
| 2503 | .ArrayType = .{ | 2488 | .ArrayType = .{ |
| 2504 | .len_expr = len_expr, | 2489 | .len_expr = len_expr, |
| 2505 | .sentinel = sentinel, | 2490 | .sentinel = sentinel, |
| 2506 | }, | 2491 | }, |
| 2507 | } | 2492 | } |
| 2508 | else | 2493 | else |
| 2509 | Node.PrefixOp.Op{ | 2494 | .{ |
| 2510 | .SliceType = Node.PrefixOp.PtrInfo{ | 2495 | .SliceType = Node.PrefixOp.PtrInfo{ |
| 2511 | .allowzero_token = null, | 2496 | .allowzero_token = null, |
| 2512 | .align_info = null, | 2497 | .align_info = null, |
| ... | @@ -2517,7 +2502,7 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No | ... | @@ -2517,7 +2502,7 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 2517 | }; | 2502 | }; |
| 2518 | 2503 | ||
| 2519 | const node = try arena.create(Node.PrefixOp); | 2504 | const node = try arena.create(Node.PrefixOp); |
| 2520 | node.* = Node.PrefixOp{ | 2505 | node.* = .{ |
| 2521 | .op_token = lbracket, | 2506 | .op_token = lbracket, |
| 2522 | .op = op, | 2507 | .op = op, |
| 2523 | .rhs = undefined, // set by caller | 2508 | .rhs = undefined, // set by caller |
| ... | @@ -2533,7 +2518,7 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No | ... | @@ -2533,7 +2518,7 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 2533 | fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2518 | fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2534 | if (eatToken(it, .Asterisk)) |asterisk| { | 2519 | if (eatToken(it, .Asterisk)) |asterisk| { |
| 2535 | const sentinel = if (eatToken(it, .Colon)) |_| | 2520 | const sentinel = if (eatToken(it, .Colon)) |_| |
| 2536 | try expectNode(arena, it, tree, parseExpr, AstError{ | 2521 | try expectNode(arena, it, tree, parseExpr, .{ |
| 2537 | .ExpectedExpr = .{ .token = it.index }, | 2522 | .ExpectedExpr = .{ .token = it.index }, |
| 2538 | }) | 2523 | }) |
| 2539 | else | 2524 | else |
| ... | @@ -2549,17 +2534,17 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -2549,17 +2534,17 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2549 | 2534 | ||
| 2550 | if (eatToken(it, .AsteriskAsterisk)) |double_asterisk| { | 2535 | if (eatToken(it, .AsteriskAsterisk)) |double_asterisk| { |
| 2551 | const node = try arena.create(Node.PrefixOp); | 2536 | const node = try arena.create(Node.PrefixOp); |
| 2552 | node.* = Node.PrefixOp{ | 2537 | node.* = .{ |
| 2553 | .op_token = double_asterisk, | 2538 | .op_token = double_asterisk, |
| 2554 | .op = Node.PrefixOp.Op{ .PtrType = .{} }, | 2539 | .op = .{ .PtrType = .{} }, |
| 2555 | .rhs = undefined, // set by caller | 2540 | .rhs = undefined, // set by caller |
| 2556 | }; | 2541 | }; |
| 2557 | 2542 | ||
| 2558 | // Special case for **, which is its own token | 2543 | // Special case for **, which is its own token |
| 2559 | const child = try arena.create(Node.PrefixOp); | 2544 | const child = try arena.create(Node.PrefixOp); |
| 2560 | child.* = Node.PrefixOp{ | 2545 | child.* = .{ |
| 2561 | .op_token = double_asterisk, | 2546 | .op_token = double_asterisk, |
| 2562 | .op = Node.PrefixOp.Op{ .PtrType = .{} }, | 2547 | .op = .{ .PtrType = .{} }, |
| 2563 | .rhs = undefined, // set by caller | 2548 | .rhs = undefined, // set by caller |
| 2564 | }; | 2549 | }; |
| 2565 | node.rhs = &child.base; | 2550 | node.rhs = &child.base; |
| ... | @@ -2586,7 +2571,7 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -2586,7 +2571,7 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2586 | } | 2571 | } |
| 2587 | } | 2572 | } |
| 2588 | const sentinel = if (eatToken(it, .Colon)) |_| | 2573 | const sentinel = if (eatToken(it, .Colon)) |_| |
| 2589 | try expectNode(arena, it, tree, parseExpr, AstError{ | 2574 | try expectNode(arena, it, tree, parseExpr, .{ |
| 2590 | .ExpectedExpr = .{ .token = it.index }, | 2575 | .ExpectedExpr = .{ .token = it.index }, |
| 2591 | }) | 2576 | }) |
| 2592 | else | 2577 | else |
| ... | @@ -2629,8 +2614,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? | ... | @@ -2629,8 +2614,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? |
| 2629 | .Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} }, | 2614 | .Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} }, |
| 2630 | .Keyword_enum => blk: { | 2615 | .Keyword_enum => blk: { |
| 2631 | if (eatToken(it, .LParen) != null) { | 2616 | if (eatToken(it, .LParen) != null) { |
| 2632 | const expr = try expectNode(arena, it, tree, parseExpr, AstError{ | 2617 | const expr = try expectNode(arena, it, tree, parseExpr, .{ |
| 2633 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 2618 | .ExpectedExpr = .{ .token = it.index }, |
| 2634 | }); | 2619 | }); |
| 2635 | _ = try expectToken(it, tree, .RParen); | 2620 | _ = try expectToken(it, tree, .RParen); |
| 2636 | break :blk Node.ContainerDecl.InitArg{ .Type = expr }; | 2621 | break :blk Node.ContainerDecl.InitArg{ .Type = expr }; |
| ... | @@ -2641,8 +2626,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? | ... | @@ -2641,8 +2626,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? |
| 2641 | if (eatToken(it, .LParen) != null) { | 2626 | if (eatToken(it, .LParen) != null) { |
| 2642 | if (eatToken(it, .Keyword_enum) != null) { | 2627 | if (eatToken(it, .Keyword_enum) != null) { |
| 2643 | if (eatToken(it, .LParen) != null) { | 2628 | if (eatToken(it, .LParen) != null) { |
| 2644 | const expr = try expectNode(arena, it, tree, parseExpr, AstError{ | 2629 | const expr = try expectNode(arena, it, tree, parseExpr, .{ |
| 2645 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 2630 | .ExpectedExpr = .{ .token = it.index }, |
| 2646 | }); | 2631 | }); |
| 2647 | _ = try expectToken(it, tree, .RParen); | 2632 | _ = try expectToken(it, tree, .RParen); |
| 2648 | _ = try expectToken(it, tree, .RParen); | 2633 | _ = try expectToken(it, tree, .RParen); |
| ... | @@ -2651,8 +2636,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? | ... | @@ -2651,8 +2636,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? |
| 2651 | _ = try expectToken(it, tree, .RParen); | 2636 | _ = try expectToken(it, tree, .RParen); |
| 2652 | break :blk Node.ContainerDecl.InitArg{ .Enum = null }; | 2637 | break :blk Node.ContainerDecl.InitArg{ .Enum = null }; |
| 2653 | } | 2638 | } |
| 2654 | const expr = try expectNode(arena, it, tree, parseExpr, AstError{ | 2639 | const expr = try expectNode(arena, it, tree, parseExpr, .{ |
| 2655 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 2640 | .ExpectedExpr = .{ .token = it.index }, |
| 2656 | }); | 2641 | }); |
| 2657 | _ = try expectToken(it, tree, .RParen); | 2642 | _ = try expectToken(it, tree, .RParen); |
| 2658 | break :blk Node.ContainerDecl.InitArg{ .Type = expr }; | 2643 | break :blk Node.ContainerDecl.InitArg{ .Type = expr }; |
| ... | @@ -2666,7 +2651,7 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? | ... | @@ -2666,7 +2651,7 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? |
| 2666 | }; | 2651 | }; |
| 2667 | 2652 | ||
| 2668 | const node = try arena.create(Node.ContainerDecl); | 2653 | const node = try arena.create(Node.ContainerDecl); |
| 2669 | node.* = Node.ContainerDecl{ | 2654 | node.* = .{ |
| 2670 | .layout_token = null, | 2655 | .layout_token = null, |
| 2671 | .kind_token = kind_token.index, | 2656 | .kind_token = kind_token.index, |
| 2672 | .init_arg_expr = init_arg_expr, | 2657 | .init_arg_expr = init_arg_expr, |
| ... | @@ -2681,8 +2666,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? | ... | @@ -2681,8 +2666,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? |
| 2681 | fn parseByteAlign(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2666 | fn parseByteAlign(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2682 | _ = eatToken(it, .Keyword_align) orelse return null; | 2667 | _ = eatToken(it, .Keyword_align) orelse return null; |
| 2683 | _ = try expectToken(it, tree, .LParen); | 2668 | _ = try expectToken(it, tree, .LParen); |
| 2684 | const expr = try expectNode(arena, it, tree, parseExpr, AstError{ | 2669 | const expr = try expectNode(arena, it, tree, parseExpr, .{ |
| 2685 | .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, | 2670 | .ExpectedExpr = .{ .token = it.index }, |
| 2686 | }); | 2671 | }); |
| 2687 | _ = try expectToken(it, tree, .RParen); | 2672 | _ = try expectToken(it, tree, .RParen); |
| 2688 | return expr; | 2673 | return expr; |
| ... | @@ -2738,7 +2723,7 @@ fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) No | ... | @@ -2738,7 +2723,7 @@ fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) No |
| 2738 | pub fn parse(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node { | 2723 | pub fn parse(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node { |
| 2739 | const op_token = eatToken(it, token) orelse return null; | 2724 | const op_token = eatToken(it, token) orelse return null; |
| 2740 | const node = try arena.create(Node.InfixOp); | 2725 | const node = try arena.create(Node.InfixOp); |
| 2741 | node.* = Node.InfixOp{ | 2726 | node.* = .{ |
| 2742 | .op_token = op_token, | 2727 | .op_token = op_token, |
| 2743 | .lhs = undefined, // set by caller | 2728 | .lhs = undefined, // set by caller |
| 2744 | .op = op, | 2729 | .op = op, |
| ... | @@ -2754,13 +2739,13 @@ fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) No | ... | @@ -2754,13 +2739,13 @@ fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) No |
| 2754 | fn parseBuiltinCall(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2739 | fn parseBuiltinCall(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2755 | const token = eatToken(it, .Builtin) orelse return null; | 2740 | const token = eatToken(it, .Builtin) orelse return null; |
| 2756 | const params = (try parseFnCallArguments(arena, it, tree)) orelse { | 2741 | const params = (try parseFnCallArguments(arena, it, tree)) orelse { |
| 2757 | try tree.errors.push(AstError{ | 2742 | try tree.errors.push(.{ |
| 2758 | .ExpectedParamList = AstError.ExpectedParamList{ .token = it.index }, | 2743 | .ExpectedParamList = .{ .token = it.index }, |
| 2759 | }); | 2744 | }); |
| 2760 | return error.ParseError; | 2745 | return error.ParseError; |
| 2761 | }; | 2746 | }; |
| 2762 | const node = try arena.create(Node.BuiltinCall); | 2747 | const node = try arena.create(Node.BuiltinCall); |
| 2763 | node.* = Node.BuiltinCall{ | 2748 | node.* = .{ |
| 2764 | .builtin_token = token, | 2749 | .builtin_token = token, |
| 2765 | .params = params.list, | 2750 | .params = params.list, |
| 2766 | .rparen_token = params.rparen, | 2751 | .rparen_token = params.rparen, |
| ... | @@ -2773,7 +2758,7 @@ fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2773,7 +2758,7 @@ fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2773 | const token = eatToken(it, .Identifier) orelse return null; | 2758 | const token = eatToken(it, .Identifier) orelse return null; |
| 2774 | 2759 | ||
| 2775 | const node = try arena.create(Node.ErrorTag); | 2760 | const node = try arena.create(Node.ErrorTag); |
| 2776 | node.* = Node.ErrorTag{ | 2761 | node.* = .{ |
| 2777 | .doc_comments = doc_comments, | 2762 | .doc_comments = doc_comments, |
| 2778 | .name_token = token, | 2763 | .name_token = token, |
| 2779 | }; | 2764 | }; |
| ... | @@ -2783,7 +2768,7 @@ fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2783,7 +2768,7 @@ fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2783 | fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2768 | fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2784 | const token = eatToken(it, .Identifier) orelse return null; | 2769 | const token = eatToken(it, .Identifier) orelse return null; |
| 2785 | const node = try arena.create(Node.Identifier); | 2770 | const node = try arena.create(Node.Identifier); |
| 2786 | node.* = Node.Identifier{ | 2771 | node.* = .{ |
| 2787 | .token = token, | 2772 | .token = token, |
| 2788 | }; | 2773 | }; |
| 2789 | return &node.base; | 2774 | return &node.base; |
| ... | @@ -2792,7 +2777,7 @@ fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2792,7 +2777,7 @@ fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2792 | fn parseVarType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2777 | fn parseVarType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2793 | const token = eatToken(it, .Keyword_var) orelse return null; | 2778 | const token = eatToken(it, .Keyword_var) orelse return null; |
| 2794 | const node = try arena.create(Node.VarType); | 2779 | const node = try arena.create(Node.VarType); |
| 2795 | node.* = Node.VarType{ | 2780 | node.* = .{ |
| 2796 | .token = token, | 2781 | .token = token, |
| 2797 | }; | 2782 | }; |
| 2798 | return &node.base; | 2783 | return &node.base; |
| ... | @@ -2810,7 +2795,7 @@ fn createLiteral(arena: *Allocator, comptime T: type, token: TokenIndex) !*Node | ... | @@ -2810,7 +2795,7 @@ fn createLiteral(arena: *Allocator, comptime T: type, token: TokenIndex) !*Node |
| 2810 | fn parseStringLiteralSingle(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2795 | fn parseStringLiteralSingle(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2811 | if (eatToken(it, .StringLiteral)) |token| { | 2796 | if (eatToken(it, .StringLiteral)) |token| { |
| 2812 | const node = try arena.create(Node.StringLiteral); | 2797 | const node = try arena.create(Node.StringLiteral); |
| 2813 | node.* = Node.StringLiteral{ | 2798 | node.* = .{ |
| 2814 | .token = token, | 2799 | .token = token, |
| 2815 | }; | 2800 | }; |
| 2816 | return &node.base; | 2801 | return &node.base; |
| ... | @@ -2824,7 +2809,7 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod | ... | @@ -2824,7 +2809,7 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod |
| 2824 | 2809 | ||
| 2825 | if (eatToken(it, .MultilineStringLiteralLine)) |first_line| { | 2810 | if (eatToken(it, .MultilineStringLiteralLine)) |first_line| { |
| 2826 | const node = try arena.create(Node.MultilineStringLiteral); | 2811 | const node = try arena.create(Node.MultilineStringLiteral); |
| 2827 | node.* = Node.MultilineStringLiteral{ | 2812 | node.* = .{ |
| 2828 | .lines = Node.MultilineStringLiteral.LineList.init(arena), | 2813 | .lines = Node.MultilineStringLiteral.LineList.init(arena), |
| 2829 | }; | 2814 | }; |
| 2830 | try node.lines.push(first_line); | 2815 | try node.lines.push(first_line); |
| ... | @@ -2840,7 +2825,7 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod | ... | @@ -2840,7 +2825,7 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod |
| 2840 | fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2825 | fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2841 | const token = eatToken(it, .IntegerLiteral) orelse return null; | 2826 | const token = eatToken(it, .IntegerLiteral) orelse return null; |
| 2842 | const node = try arena.create(Node.IntegerLiteral); | 2827 | const node = try arena.create(Node.IntegerLiteral); |
| 2843 | node.* = Node.IntegerLiteral{ | 2828 | node.* = .{ |
| 2844 | .token = token, | 2829 | .token = token, |
| 2845 | }; | 2830 | }; |
| 2846 | return &node.base; | 2831 | return &node.base; |
| ... | @@ -2849,7 +2834,7 @@ fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No | ... | @@ -2849,7 +2834,7 @@ fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 2849 | fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2834 | fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2850 | const token = eatToken(it, .FloatLiteral) orelse return null; | 2835 | const token = eatToken(it, .FloatLiteral) orelse return null; |
| 2851 | const node = try arena.create(Node.FloatLiteral); | 2836 | const node = try arena.create(Node.FloatLiteral); |
| 2852 | node.* = Node.FloatLiteral{ | 2837 | node.* = .{ |
| 2853 | .token = token, | 2838 | .token = token, |
| 2854 | }; | 2839 | }; |
| 2855 | return &node.base; | 2840 | return &node.base; |
| ... | @@ -2858,9 +2843,9 @@ fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node | ... | @@ -2858,9 +2843,9 @@ fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 2858 | fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2843 | fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2859 | const token = eatToken(it, .Keyword_try) orelse return null; | 2844 | const token = eatToken(it, .Keyword_try) orelse return null; |
| 2860 | const node = try arena.create(Node.PrefixOp); | 2845 | const node = try arena.create(Node.PrefixOp); |
| 2861 | node.* = Node.PrefixOp{ | 2846 | node.* = .{ |
| 2862 | .op_token = token, | 2847 | .op_token = token, |
| 2863 | .op = Node.PrefixOp.Op.Try, | 2848 | .op = .Try, |
| 2864 | .rhs = undefined, // set by caller | 2849 | .rhs = undefined, // set by caller |
| 2865 | }; | 2850 | }; |
| 2866 | return &node.base; | 2851 | return &node.base; |
| ... | @@ -2869,7 +2854,7 @@ fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -2869,7 +2854,7 @@ fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2869 | fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 2854 | fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 2870 | const token = eatToken(it, .Keyword_usingnamespace) orelse return null; | 2855 | const token = eatToken(it, .Keyword_usingnamespace) orelse return null; |
| 2871 | const node = try arena.create(Node.Use); | 2856 | const node = try arena.create(Node.Use); |
| 2872 | node.* = Node.Use{ | 2857 | node.* = .{ |
| 2873 | .doc_comments = null, | 2858 | .doc_comments = null, |
| 2874 | .visib_token = null, | 2859 | .visib_token = null, |
| 2875 | .use_token = token, | 2860 | .use_token = token, |
| ... | @@ -2884,17 +2869,17 @@ fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: Node | ... | @@ -2884,17 +2869,17 @@ fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: Node |
| 2884 | const node = (try parseIfPrefix(arena, it, tree)) orelse return null; | 2869 | const node = (try parseIfPrefix(arena, it, tree)) orelse return null; |
| 2885 | const if_prefix = node.cast(Node.If).?; | 2870 | const if_prefix = node.cast(Node.If).?; |
| 2886 | 2871 | ||
| 2887 | if_prefix.body = try expectNode(arena, it, tree, bodyParseFn, AstError{ | 2872 | if_prefix.body = try expectNode(arena, it, tree, bodyParseFn, .{ |
| 2888 | .InvalidToken = AstError.InvalidToken{ .token = it.index }, | 2873 | .InvalidToken = .{ .token = it.index }, |
| 2889 | }); | 2874 | }); |
| 2890 | 2875 | ||
| 2891 | const else_token = eatToken(it, .Keyword_else) orelse return node; | 2876 | const else_token = eatToken(it, .Keyword_else) orelse return node; |
| 2892 | const payload = try parsePayload(arena, it, tree); | 2877 | const payload = try parsePayload(arena, it, tree); |
| 2893 | const else_expr = try expectNode(arena, it, tree, bodyParseFn, AstError{ | 2878 | const else_expr = try expectNode(arena, it, tree, bodyParseFn, .{ |
| 2894 | .InvalidToken = AstError.InvalidToken{ .token = it.index }, | 2879 | .InvalidToken = .{ .token = it.index }, |
| 2895 | }); | 2880 | }); |
| 2896 | const else_node = try arena.create(Node.Else); | 2881 | const else_node = try arena.create(Node.Else); |
| 2897 | else_node.* = Node.Else{ | 2882 | else_node.* = .{ |
| 2898 | .else_token = else_token, | 2883 | .else_token = else_token, |
| 2899 | .payload = payload, | 2884 | .payload = payload, |
| 2900 | .body = else_expr, | 2885 | .body = else_expr, |
| ... | @@ -2914,7 +2899,7 @@ fn parseDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.D | ... | @@ -2914,7 +2899,7 @@ fn parseDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.D |
| 2914 | if (lines.len == 0) return null; | 2899 | if (lines.len == 0) return null; |
| 2915 | 2900 | ||
| 2916 | const node = try arena.create(Node.DocComment); | 2901 | const node = try arena.create(Node.DocComment); |
| 2917 | node.* = Node.DocComment{ | 2902 | node.* = .{ |
| 2918 | .lines = lines, | 2903 | .lines = lines, |
| 2919 | }; | 2904 | }; |
| 2920 | return node; | 2905 | return node; |
| ... | @@ -2925,7 +2910,7 @@ fn parseAppendedDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree, a | ... | @@ -2925,7 +2910,7 @@ fn parseAppendedDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree, a |
| 2925 | const comment_token = eatToken(it, .DocComment) orelse return null; | 2910 | const comment_token = eatToken(it, .DocComment) orelse return null; |
| 2926 | if (tree.tokensOnSameLine(after_token, comment_token)) { | 2911 | if (tree.tokensOnSameLine(after_token, comment_token)) { |
| 2927 | const node = try arena.create(Node.DocComment); | 2912 | const node = try arena.create(Node.DocComment); |
| 2928 | node.* = Node.DocComment{ | 2913 | node.* = .{ |
| 2929 | .lines = Node.DocComment.LineList.init(arena), | 2914 | .lines = Node.DocComment.LineList.init(arena), |
| 2930 | }; | 2915 | }; |
| 2931 | try node.lines.push(comment_token); | 2916 | try node.lines.push(comment_token); |
| ... | @@ -2974,14 +2959,14 @@ fn parsePrefixOpExpr( | ... | @@ -2974,14 +2959,14 @@ fn parsePrefixOpExpr( |
| 2974 | switch (rightmost_op.id) { | 2959 | switch (rightmost_op.id) { |
| 2975 | .PrefixOp => { | 2960 | .PrefixOp => { |
| 2976 | const prefix_op = rightmost_op.cast(Node.PrefixOp).?; | 2961 | const prefix_op = rightmost_op.cast(Node.PrefixOp).?; |
| 2977 | prefix_op.rhs = try expectNode(arena, it, tree, childParseFn, AstError{ | 2962 | prefix_op.rhs = try expectNode(arena, it, tree, childParseFn, .{ |
| 2978 | .InvalidToken = AstError.InvalidToken{ .token = it.index }, | 2963 | .InvalidToken = .{ .token = it.index }, |
| 2979 | }); | 2964 | }); |
| 2980 | }, | 2965 | }, |
| 2981 | .AnyFrameType => { | 2966 | .AnyFrameType => { |
| 2982 | const prom = rightmost_op.cast(Node.AnyFrameType).?; | 2967 | const prom = rightmost_op.cast(Node.AnyFrameType).?; |
| 2983 | prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, AstError{ | 2968 | prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, .{ |
| 2984 | .InvalidToken = AstError.InvalidToken{ .token = it.index }, | 2969 | .InvalidToken = .{ .token = it.index }, |
| 2985 | }); | 2970 | }); |
| 2986 | }, | 2971 | }, |
| 2987 | else => unreachable, | 2972 | else => unreachable, |
| ... | @@ -3010,8 +2995,8 @@ fn parseBinOpExpr( | ... | @@ -3010,8 +2995,8 @@ fn parseBinOpExpr( |
| 3010 | var res = (try childParseFn(arena, it, tree)) orelse return null; | 2995 | var res = (try childParseFn(arena, it, tree)) orelse return null; |
| 3011 | 2996 | ||
| 3012 | while (try opParseFn(arena, it, tree)) |node| { | 2997 | while (try opParseFn(arena, it, tree)) |node| { |
| 3013 | const right = try expectNode(arena, it, tree, childParseFn, AstError{ | 2998 | const right = try expectNode(arena, it, tree, childParseFn, .{ |
| 3014 | .InvalidToken = AstError.InvalidToken{ .token = it.index }, | 2999 | .InvalidToken = .{ .token = it.index }, |
| 3015 | }); | 3000 | }); |
| 3016 | const left = res; | 3001 | const left = res; |
| 3017 | res = node; | 3002 | res = node; |
| ... | @@ -3031,7 +3016,7 @@ fn parseBinOpExpr( | ... | @@ -3031,7 +3016,7 @@ fn parseBinOpExpr( |
| 3031 | 3016 | ||
| 3032 | fn createInfixOp(arena: *Allocator, index: TokenIndex, op: Node.InfixOp.Op) !*Node { | 3017 | fn createInfixOp(arena: *Allocator, index: TokenIndex, op: Node.InfixOp.Op) !*Node { |
| 3033 | const node = try arena.create(Node.InfixOp); | 3018 | const node = try arena.create(Node.InfixOp); |
| 3034 | node.* = Node.InfixOp{ | 3019 | node.* = .{ |
| 3035 | .op_token = index, | 3020 | .op_token = index, |
| 3036 | .lhs = undefined, // set by caller | 3021 | .lhs = undefined, // set by caller |
| 3037 | .op = op, | 3022 | .op = op, |
| ... | @@ -3051,8 +3036,8 @@ fn eatAnnotatedToken(it: *TokenIterator, id: Token.Id) ?AnnotatedToken { | ... | @@ -3051,8 +3036,8 @@ fn eatAnnotatedToken(it: *TokenIterator, id: Token.Id) ?AnnotatedToken { |
| 3051 | fn expectToken(it: *TokenIterator, tree: *Tree, id: Token.Id) Error!TokenIndex { | 3036 | fn expectToken(it: *TokenIterator, tree: *Tree, id: Token.Id) Error!TokenIndex { |
| 3052 | const token = nextToken(it); | 3037 | const token = nextToken(it); |
| 3053 | if (token.ptr.id != id) { | 3038 | if (token.ptr.id != id) { |
| 3054 | try tree.errors.push(AstError{ | 3039 | try tree.errors.push(.{ |
| 3055 | .ExpectedToken = AstError.ExpectedToken{ .token = token.index, .expected_id = id }, | 3040 | .ExpectedToken = .{ .token = token.index, .expected_id = id }, |
| 3056 | }); | 3041 | }); |
| 3057 | return error.ParseError; | 3042 | return error.ParseError; |
| 3058 | } | 3043 | } |
lib/std/zig/parser_test.zig+2| ... | @@ -1509,6 +1509,8 @@ test "zig fmt: error set declaration" { | ... | @@ -1509,6 +1509,8 @@ test "zig fmt: error set declaration" { |
| 1509 | \\const Error = error{OutOfMemory}; | 1509 | \\const Error = error{OutOfMemory}; |
| 1510 | \\const Error = error{}; | 1510 | \\const Error = error{}; |
| 1511 | \\ | 1511 | \\ |
| 1512 | \\const Error = error{ OutOfMemory, OutOfTime }; | ||
| 1513 | \\ | ||
| 1512 | ); | 1514 | ); |
| 1513 | } | 1515 | } |
| 1514 | 1516 |
lib/std/zig/render.zig+41-18| ... | @@ -583,7 +583,6 @@ fn renderExpression( | ... | @@ -583,7 +583,6 @@ fn renderExpression( |
| 583 | }, | 583 | }, |
| 584 | 584 | ||
| 585 | .Try, | 585 | .Try, |
| 586 | .Cancel, | ||
| 587 | .Resume, | 586 | .Resume, |
| 588 | => { | 587 | => { |
| 589 | try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space); | 588 | try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space); |
| ... | @@ -1269,25 +1268,51 @@ fn renderExpression( | ... | @@ -1269,25 +1268,51 @@ fn renderExpression( |
| 1269 | } | 1268 | } |
| 1270 | 1269 | ||
| 1271 | try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None); // error | 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); | 1272 | const src_has_trailing_comma = blk: { |
| 1276 | while (it.next()) |node| { | 1273 | const maybe_comma = tree.prevToken(err_set_decl.rbrace_token); |
| 1277 | try stream.writeByteNTimes(' ', new_indent); | 1274 | break :blk tree.tokens.at(maybe_comma).id == .Comma; |
| 1275 | }; | ||
| 1278 | 1276 | ||
| 1279 | if (it.peek()) |next_node| { | 1277 | if (src_has_trailing_comma) { |
| 1280 | try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.None); | 1278 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // { |
| 1281 | try renderToken(tree, stream, tree.nextToken(node.*.lastToken()), new_indent, start_col, Space.Newline); // , | 1279 | const new_indent = indent + indent_delta; |
| 1282 | 1280 | ||
| 1283 | try renderExtraNewline(tree, stream, start_col, next_node.*); | 1281 | var it = err_set_decl.decls.iterator(0); |
| 1284 | } else { | 1282 | while (it.next()) |node| { |
| 1285 | try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.Comma); | 1283 | try stream.writeByteNTimes(' ', new_indent); |
| 1284 | |||
| 1285 | if (it.peek()) |next_node| { | ||
| 1286 | try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.None); | ||
| 1287 | try renderToken(tree, stream, tree.nextToken(node.*.lastToken()), new_indent, start_col, Space.Newline); // , | ||
| 1288 | |||
| 1289 | try renderExtraNewline(tree, stream, start_col, next_node.*); | ||
| 1290 | } else { | ||
| 1291 | try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.Comma); | ||
| 1292 | } | ||
| 1286 | } | 1293 | } |
| 1287 | } | ||
| 1288 | 1294 | ||
| 1289 | try stream.writeByteNTimes(' ', indent); | 1295 | try stream.writeByteNTimes(' ', indent); |
| 1290 | return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // } | 1296 | return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // } |
| 1297 | } else { | ||
| 1298 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); // { | ||
| 1299 | |||
| 1300 | var it = err_set_decl.decls.iterator(0); | ||
| 1301 | while (it.next()) |node| { | ||
| 1302 | if (it.peek()) |next_node| { | ||
| 1303 | try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None); | ||
| 1304 | |||
| 1305 | const comma_token = tree.nextToken(node.*.lastToken()); | ||
| 1306 | assert(tree.tokens.at(comma_token).id == .Comma); | ||
| 1307 | try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // , | ||
| 1308 | try renderExtraNewline(tree, stream, start_col, next_node.*); | ||
| 1309 | } else { | ||
| 1310 | try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Space); | ||
| 1311 | } | ||
| 1312 | } | ||
| 1313 | |||
| 1314 | return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // } | ||
| 1315 | } | ||
| 1291 | }, | 1316 | }, |
| 1292 | 1317 | ||
| 1293 | .ErrorTag => { | 1318 | .ErrorTag => { |
| ... | @@ -1590,8 +1615,7 @@ fn renderExpression( | ... | @@ -1590,8 +1615,7 @@ fn renderExpression( |
| 1590 | } | 1615 | } |
| 1591 | } else { | 1616 | } else { |
| 1592 | var it = switch_case.items.iterator(0); | 1617 | var it = switch_case.items.iterator(0); |
| 1593 | while (true) { | 1618 | while (it.next()) |node| { |
| 1594 | const node = it.next().?; | ||
| 1595 | if (it.peek()) |next_node| { | 1619 | if (it.peek()) |next_node| { |
| 1596 | try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None); | 1620 | try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None); |
| 1597 | 1621 | ||
| ... | @@ -1602,7 +1626,6 @@ fn renderExpression( | ... | @@ -1602,7 +1626,6 @@ fn renderExpression( |
| 1602 | } else { | 1626 | } else { |
| 1603 | try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Comma); | 1627 | try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Comma); |
| 1604 | try stream.writeByteNTimes(' ', indent); | 1628 | try stream.writeByteNTimes(' ', indent); |
| 1605 | break; | ||
| 1606 | } | 1629 | } |
| 1607 | } | 1630 | } |
| 1608 | } | 1631 | } |
lib/std/zig/system.zig+1-1| ... | @@ -754,7 +754,7 @@ pub const NativeTargetInfo = struct { | ... | @@ -754,7 +754,7 @@ pub const NativeTargetInfo = struct { |
| 754 | const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr)); | 754 | const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr)); |
| 755 | var it = mem.tokenize(rpath_list, ":"); | 755 | var it = mem.tokenize(rpath_list, ":"); |
| 756 | while (it.next()) |rpath| { | 756 | while (it.next()) |rpath| { |
| 757 | var dir = fs.cwd().openDirList(rpath) catch |err| switch (err) { | 757 | var dir = fs.cwd().openDir(rpath, .{}) catch |err| switch (err) { |
| 758 | error.NameTooLong => unreachable, | 758 | error.NameTooLong => unreachable, |
| 759 | error.InvalidUtf8 => unreachable, | 759 | error.InvalidUtf8 => unreachable, |
| 760 | error.BadPathName => unreachable, | 760 | error.BadPathName => unreachable, |
src-self-hosted/c_int.zig+4-4| ... | @@ -69,9 +69,9 @@ pub const CInt = struct { | ... | @@ -69,9 +69,9 @@ pub const CInt = struct { |
| 69 | }; | 69 | }; |
| 70 | 70 | ||
| 71 | pub fn sizeInBits(cint: CInt, self: Target) u32 { | 71 | pub fn sizeInBits(cint: CInt, self: Target) u32 { |
| 72 | const arch = self.getArch(); | 72 | const arch = self.cpu.arch; |
| 73 | switch (self.os.tag) { | 73 | switch (self.os.tag) { |
| 74 | .freestanding, .other => switch (self.getArch()) { | 74 | .freestanding, .other => switch (self.cpu.arch) { |
| 75 | .msp430 => switch (cint.id) { | 75 | .msp430 => switch (cint.id) { |
| 76 | .Short, | 76 | .Short, |
| 77 | .UShort, | 77 | .UShort, |
| ... | @@ -94,7 +94,7 @@ pub const CInt = struct { | ... | @@ -94,7 +94,7 @@ pub const CInt = struct { |
| 94 | => return 32, | 94 | => return 32, |
| 95 | .Long, | 95 | .Long, |
| 96 | .ULong, | 96 | .ULong, |
| 97 | => return self.getArchPtrBitWidth(), | 97 | => return self.cpu.arch.ptrBitWidth(), |
| 98 | .LongLong, | 98 | .LongLong, |
| 99 | .ULongLong, | 99 | .ULongLong, |
| 100 | => return 64, | 100 | => return 64, |
| ... | @@ -114,7 +114,7 @@ pub const CInt = struct { | ... | @@ -114,7 +114,7 @@ pub const CInt = struct { |
| 114 | => return 32, | 114 | => return 32, |
| 115 | .Long, | 115 | .Long, |
| 116 | .ULong, | 116 | .ULong, |
| 117 | => return self.getArchPtrBitWidth(), | 117 | => return self.cpu.arch.ptrBitWidth(), |
| 118 | .LongLong, | 118 | .LongLong, |
| 119 | .ULongLong, | 119 | .ULongLong, |
| 120 | => return 64, | 120 | => return 64, |
src-self-hosted/compilation.zig+17-13| ... | @@ -95,7 +95,7 @@ pub const ZigCompiler = struct { | ... | @@ -95,7 +95,7 @@ pub const ZigCompiler = struct { |
| 95 | 95 | ||
| 96 | pub fn getNativeLibC(self: *ZigCompiler) !*LibCInstallation { | 96 | pub fn getNativeLibC(self: *ZigCompiler) !*LibCInstallation { |
| 97 | if (self.native_libc.start()) |ptr| return ptr; | 97 | if (self.native_libc.start()) |ptr| return ptr; |
| 98 | try self.native_libc.data.findNative(self.allocator); | 98 | self.native_libc.data = try LibCInstallation.findNative(.{ .allocator = self.allocator }); |
| 99 | self.native_libc.resolve(); | 99 | self.native_libc.resolve(); |
| 100 | return &self.native_libc.data; | 100 | return &self.native_libc.data; |
| 101 | } | 101 | } |
| ... | @@ -126,7 +126,7 @@ pub const Compilation = struct { | ... | @@ -126,7 +126,7 @@ pub const Compilation = struct { |
| 126 | name: Buffer, | 126 | name: Buffer, |
| 127 | llvm_triple: Buffer, | 127 | llvm_triple: Buffer, |
| 128 | root_src_path: ?[]const u8, | 128 | root_src_path: ?[]const u8, |
| 129 | target: Target, | 129 | target: std.Target, |
| 130 | llvm_target: *llvm.Target, | 130 | llvm_target: *llvm.Target, |
| 131 | build_mode: builtin.Mode, | 131 | build_mode: builtin.Mode, |
| 132 | zig_lib_dir: []const u8, | 132 | zig_lib_dir: []const u8, |
| ... | @@ -338,7 +338,7 @@ pub const Compilation = struct { | ... | @@ -338,7 +338,7 @@ pub const Compilation = struct { |
| 338 | zig_compiler: *ZigCompiler, | 338 | zig_compiler: *ZigCompiler, |
| 339 | name: []const u8, | 339 | name: []const u8, |
| 340 | root_src_path: ?[]const u8, | 340 | root_src_path: ?[]const u8, |
| 341 | target: Target, | 341 | target: std.zig.CrossTarget, |
| 342 | kind: Kind, | 342 | kind: Kind, |
| 343 | build_mode: builtin.Mode, | 343 | build_mode: builtin.Mode, |
| 344 | is_static: bool, | 344 | is_static: bool, |
| ... | @@ -370,13 +370,18 @@ pub const Compilation = struct { | ... | @@ -370,13 +370,18 @@ pub const Compilation = struct { |
| 370 | zig_compiler: *ZigCompiler, | 370 | zig_compiler: *ZigCompiler, |
| 371 | name: []const u8, | 371 | name: []const u8, |
| 372 | root_src_path: ?[]const u8, | 372 | root_src_path: ?[]const u8, |
| 373 | target: Target, | 373 | cross_target: std.zig.CrossTarget, |
| 374 | kind: Kind, | 374 | kind: Kind, |
| 375 | build_mode: builtin.Mode, | 375 | build_mode: builtin.Mode, |
| 376 | is_static: bool, | 376 | is_static: bool, |
| 377 | zig_lib_dir: []const u8, | 377 | zig_lib_dir: []const u8, |
| 378 | ) !void { | 378 | ) !void { |
| 379 | const allocator = zig_compiler.allocator; | 379 | const allocator = zig_compiler.allocator; |
| 380 | |||
| 381 | // TODO merge this line with stage2.zig crossTargetToTarget | ||
| 382 | const target_info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator, cross_target); | ||
| 383 | const target = target_info.target; | ||
| 384 | |||
| 380 | var comp = Compilation{ | 385 | var comp = Compilation{ |
| 381 | .arena_allocator = std.heap.ArenaAllocator.init(allocator), | 386 | .arena_allocator = std.heap.ArenaAllocator.init(allocator), |
| 382 | .zig_compiler = zig_compiler, | 387 | .zig_compiler = zig_compiler, |
| ... | @@ -419,7 +424,7 @@ pub const Compilation = struct { | ... | @@ -419,7 +424,7 @@ pub const Compilation = struct { |
| 419 | .target_machine = undefined, | 424 | .target_machine = undefined, |
| 420 | .target_data_ref = undefined, | 425 | .target_data_ref = undefined, |
| 421 | .target_layout_str = undefined, | 426 | .target_layout_str = undefined, |
| 422 | .target_ptr_bits = target.getArchPtrBitWidth(), | 427 | .target_ptr_bits = target.cpu.arch.ptrBitWidth(), |
| 423 | 428 | ||
| 424 | .root_package = undefined, | 429 | .root_package = undefined, |
| 425 | .std_package = undefined, | 430 | .std_package = undefined, |
| ... | @@ -440,7 +445,7 @@ pub const Compilation = struct { | ... | @@ -440,7 +445,7 @@ pub const Compilation = struct { |
| 440 | } | 445 | } |
| 441 | 446 | ||
| 442 | comp.name = try Buffer.init(comp.arena(), name); | 447 | comp.name = try Buffer.init(comp.arena(), name); |
| 443 | comp.llvm_triple = try util.getTriple(comp.arena(), target); | 448 | comp.llvm_triple = try util.getLLVMTriple(comp.arena(), target); |
| 444 | comp.llvm_target = try util.llvmTargetFromTriple(comp.llvm_triple); | 449 | comp.llvm_target = try util.llvmTargetFromTriple(comp.llvm_triple); |
| 445 | comp.zig_std_dir = try fs.path.join(comp.arena(), &[_][]const u8{ zig_lib_dir, "std" }); | 450 | comp.zig_std_dir = try fs.path.join(comp.arena(), &[_][]const u8{ zig_lib_dir, "std" }); |
| 446 | 451 | ||
| ... | @@ -455,10 +460,8 @@ pub const Compilation = struct { | ... | @@ -455,10 +460,8 @@ pub const Compilation = struct { |
| 455 | var target_specific_cpu_features: ?[*:0]u8 = null; | 460 | var target_specific_cpu_features: ?[*:0]u8 = null; |
| 456 | defer llvm.DisposeMessage(target_specific_cpu_args); | 461 | defer llvm.DisposeMessage(target_specific_cpu_args); |
| 457 | defer llvm.DisposeMessage(target_specific_cpu_features); | 462 | defer llvm.DisposeMessage(target_specific_cpu_features); |
| 458 | if (target == Target.Native) { | 463 | |
| 459 | target_specific_cpu_args = llvm.GetHostCPUName() orelse return error.OutOfMemory; | 464 | // TODO detect native CPU & features here |
| 460 | target_specific_cpu_features = llvm.GetNativeFeatures() orelse return error.OutOfMemory; | ||
| 461 | } | ||
| 462 | 465 | ||
| 463 | comp.target_machine = llvm.CreateTargetMachine( | 466 | comp.target_machine = llvm.CreateTargetMachine( |
| 464 | comp.llvm_target, | 467 | comp.llvm_target, |
| ... | @@ -517,8 +520,7 @@ pub const Compilation = struct { | ... | @@ -517,8 +520,7 @@ pub const Compilation = struct { |
| 517 | 520 | ||
| 518 | if (comp.tmp_dir.getOrNull()) |tmp_dir_result| | 521 | if (comp.tmp_dir.getOrNull()) |tmp_dir_result| |
| 519 | if (tmp_dir_result.*) |tmp_dir| { | 522 | if (tmp_dir_result.*) |tmp_dir| { |
| 520 | // TODO evented I/O? | 523 | fs.cwd().deleteTree(tmp_dir) catch {}; |
| 521 | fs.deleteTree(tmp_dir) catch {}; | ||
| 522 | } else |_| {}; | 524 | } else |_| {}; |
| 523 | } | 525 | } |
| 524 | 526 | ||
| ... | @@ -1122,7 +1124,9 @@ pub const Compilation = struct { | ... | @@ -1122,7 +1124,9 @@ pub const Compilation = struct { |
| 1122 | self.libc_link_lib = link_lib; | 1124 | self.libc_link_lib = link_lib; |
| 1123 | 1125 | ||
| 1124 | // get a head start on looking for the native libc | 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 | try self.deinit_group.call(startFindingNativeLibC, .{self}); | 1130 | try self.deinit_group.call(startFindingNativeLibC, .{self}); |
| 1127 | } | 1131 | } |
| 1128 | } | 1132 | } |
src-self-hosted/errmsg.zig+4-7| ... | @@ -164,8 +164,7 @@ pub const Msg = struct { | ... | @@ -164,8 +164,7 @@ pub const Msg = struct { |
| 164 | const realpath_copy = try mem.dupe(comp.gpa(), u8, tree_scope.root().realpath); | 164 | const realpath_copy = try mem.dupe(comp.gpa(), u8, tree_scope.root().realpath); |
| 165 | errdefer comp.gpa().free(realpath_copy); | 165 | errdefer comp.gpa().free(realpath_copy); |
| 166 | 166 | ||
| 167 | var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; | 167 | try parse_error.render(&tree_scope.tree.tokens, text_buf.outStream()); |
| 168 | try parse_error.render(&tree_scope.tree.tokens, out_stream); | ||
| 169 | 168 | ||
| 170 | const msg = try comp.gpa().create(Msg); | 169 | const msg = try comp.gpa().create(Msg); |
| 171 | msg.* = Msg{ | 170 | msg.* = Msg{ |
| ... | @@ -204,8 +203,7 @@ pub const Msg = struct { | ... | @@ -204,8 +203,7 @@ pub const Msg = struct { |
| 204 | const realpath_copy = try mem.dupe(allocator, u8, realpath); | 203 | const realpath_copy = try mem.dupe(allocator, u8, realpath); |
| 205 | errdefer allocator.free(realpath_copy); | 204 | errdefer allocator.free(realpath_copy); |
| 206 | 205 | ||
| 207 | var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; | 206 | try parse_error.render(&tree.tokens, text_buf.outStream()); |
| 208 | try parse_error.render(&tree.tokens, out_stream); | ||
| 209 | 207 | ||
| 210 | const msg = try allocator.create(Msg); | 208 | const msg = try allocator.create(Msg); |
| 211 | msg.* = Msg{ | 209 | msg.* = Msg{ |
| ... | @@ -272,7 +270,7 @@ pub const Msg = struct { | ... | @@ -272,7 +270,7 @@ pub const Msg = struct { |
| 272 | }); | 270 | }); |
| 273 | try stream.writeByteNTimes(' ', start_loc.column); | 271 | try stream.writeByteNTimes(' ', start_loc.column); |
| 274 | try stream.writeByteNTimes('~', last_token.end - first_token.start); | 272 | try stream.writeByteNTimes('~', last_token.end - first_token.start); |
| 275 | try stream.write("\n"); | 273 | try stream.writeAll("\n"); |
| 276 | } | 274 | } |
| 277 | 275 | ||
| 278 | pub fn printToFile(msg: *const Msg, file: fs.File, color: Color) !void { | 276 | pub fn printToFile(msg: *const Msg, file: fs.File, color: Color) !void { |
| ... | @@ -281,7 +279,6 @@ pub const Msg = struct { | ... | @@ -281,7 +279,6 @@ pub const Msg = struct { |
| 281 | .On => true, | 279 | .On => true, |
| 282 | .Off => false, | 280 | .Off => false, |
| 283 | }; | 281 | }; |
| 284 | var stream = &file.outStream().stream; | 282 | return msg.printToStream(file.outStream(), color_on); |
| 285 | return msg.printToStream(stream, color_on); | ||
| 286 | } | 283 | } |
| 287 | }; | 284 | }; |
src-self-hosted/ir.zig+1-1| ... | @@ -1099,7 +1099,6 @@ pub const Builder = struct { | ... | @@ -1099,7 +1099,6 @@ pub const Builder = struct { |
| 1099 | .Await => return error.Unimplemented, | 1099 | .Await => return error.Unimplemented, |
| 1100 | .BitNot => return error.Unimplemented, | 1100 | .BitNot => return error.Unimplemented, |
| 1101 | .BoolNot => return error.Unimplemented, | 1101 | .BoolNot => return error.Unimplemented, |
| 1102 | .Cancel => return error.Unimplemented, | ||
| 1103 | .OptionalType => return error.Unimplemented, | 1102 | .OptionalType => return error.Unimplemented, |
| 1104 | .Negation => return error.Unimplemented, | 1103 | .Negation => return error.Unimplemented, |
| 1105 | .NegationWrap => return error.Unimplemented, | 1104 | .NegationWrap => return error.Unimplemented, |
| ... | @@ -1188,6 +1187,7 @@ pub const Builder = struct { | ... | @@ -1188,6 +1187,7 @@ pub const Builder = struct { |
| 1188 | .ParamDecl => return error.Unimplemented, | 1187 | .ParamDecl => return error.Unimplemented, |
| 1189 | .FieldInitializer => return error.Unimplemented, | 1188 | .FieldInitializer => return error.Unimplemented, |
| 1190 | .EnumLiteral => return error.Unimplemented, | 1189 | .EnumLiteral => return error.Unimplemented, |
| 1190 | .Noasync => return error.Unimplemented, | ||
| 1191 | } | 1191 | } |
| 1192 | } | 1192 | } |
| 1193 | 1193 |
src-self-hosted/libc_installation.zig+5-5| ... | @@ -280,7 +280,7 @@ pub const LibCInstallation = struct { | ... | @@ -280,7 +280,7 @@ pub const LibCInstallation = struct { |
| 280 | // search in reverse order | 280 | // search in reverse order |
| 281 | const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1); | 281 | const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1); |
| 282 | const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " "); | 282 | const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " "); |
| 283 | var search_dir = fs.cwd().openDirList(search_path) catch |err| switch (err) { | 283 | var search_dir = fs.cwd().openDir(search_path, .{}) catch |err| switch (err) { |
| 284 | error.FileNotFound, | 284 | error.FileNotFound, |
| 285 | error.NotDir, | 285 | error.NotDir, |
| 286 | error.NoDevice, | 286 | error.NoDevice, |
| ... | @@ -335,7 +335,7 @@ pub const LibCInstallation = struct { | ... | @@ -335,7 +335,7 @@ pub const LibCInstallation = struct { |
| 335 | const stream = result_buf.outStream(); | 335 | const stream = result_buf.outStream(); |
| 336 | try stream.print("{}\\Include\\{}\\ucrt", .{ search.path, search.version }); | 336 | try stream.print("{}\\Include\\{}\\ucrt", .{ search.path, search.version }); |
| 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 | error.FileNotFound, | 339 | error.FileNotFound, |
| 340 | error.NotDir, | 340 | error.NotDir, |
| 341 | error.NoDevice, | 341 | error.NoDevice, |
| ... | @@ -382,7 +382,7 @@ pub const LibCInstallation = struct { | ... | @@ -382,7 +382,7 @@ pub const LibCInstallation = struct { |
| 382 | const stream = result_buf.outStream(); | 382 | const stream = result_buf.outStream(); |
| 383 | try stream.print("{}\\Lib\\{}\\ucrt\\{}", .{ search.path, search.version, arch_sub_dir }); | 383 | try stream.print("{}\\Lib\\{}\\ucrt\\{}", .{ search.path, search.version, arch_sub_dir }); |
| 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 | error.FileNotFound, | 386 | error.FileNotFound, |
| 387 | error.NotDir, | 387 | error.NotDir, |
| 388 | error.NoDevice, | 388 | error.NoDevice, |
| ... | @@ -437,7 +437,7 @@ pub const LibCInstallation = struct { | ... | @@ -437,7 +437,7 @@ pub const LibCInstallation = struct { |
| 437 | const stream = result_buf.outStream(); | 437 | const stream = result_buf.outStream(); |
| 438 | try stream.print("{}\\Lib\\{}\\um\\{}", .{ search.path, search.version, arch_sub_dir }); | 438 | try stream.print("{}\\Lib\\{}\\um\\{}", .{ search.path, search.version, arch_sub_dir }); |
| 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 | error.FileNotFound, | 441 | error.FileNotFound, |
| 442 | error.NotDir, | 442 | error.NotDir, |
| 443 | error.NoDevice, | 443 | error.NoDevice, |
| ... | @@ -475,7 +475,7 @@ pub const LibCInstallation = struct { | ... | @@ -475,7 +475,7 @@ pub const LibCInstallation = struct { |
| 475 | 475 | ||
| 476 | try result_buf.append("\\include"); | 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 | error.FileNotFound, | 479 | error.FileNotFound, |
| 480 | error.NotDir, | 480 | error.NotDir, |
| 481 | error.NoDevice, | 481 | error.NoDevice, |
src-self-hosted/link.zig+54-58| ... | @@ -56,12 +56,13 @@ pub fn link(comp: *Compilation) !void { | ... | @@ -56,12 +56,13 @@ pub fn link(comp: *Compilation) !void { |
| 56 | if (comp.haveLibC()) { | 56 | if (comp.haveLibC()) { |
| 57 | // TODO https://github.com/ziglang/zig/issues/3190 | 57 | // TODO https://github.com/ziglang/zig/issues/3190 |
| 58 | var libc = ctx.comp.override_libc orelse blk: { | 58 | var libc = ctx.comp.override_libc orelse blk: { |
| 59 | switch (comp.target) { | 59 | @panic("this code has bitrotted"); |
| 60 | Target.Native => { | 60 | //switch (comp.target) { |
| 61 | break :blk comp.zig_compiler.getNativeLibC() catch return error.LibCRequiredButNotProvidedOrFound; | 61 | // Target.Native => { |
| 62 | }, | 62 | // break :blk comp.zig_compiler.getNativeLibC() catch return error.LibCRequiredButNotProvidedOrFound; |
| 63 | else => return error.LibCRequiredButNotProvidedOrFound, | 63 | // }, |
| 64 | } | 64 | // else => return error.LibCRequiredButNotProvidedOrFound, |
| 65 | //} | ||
| 65 | }; | 66 | }; |
| 66 | ctx.libc = libc; | 67 | ctx.libc = libc; |
| 67 | } | 68 | } |
| ... | @@ -155,11 +156,11 @@ fn constructLinkerArgsElf(ctx: *Context) !void { | ... | @@ -155,11 +156,11 @@ fn constructLinkerArgsElf(ctx: *Context) !void { |
| 155 | //bool shared = !g->is_static && is_lib; | 156 | //bool shared = !g->is_static && is_lib; |
| 156 | //Buf *soname = nullptr; | 157 | //Buf *soname = nullptr; |
| 157 | if (ctx.comp.is_static) { | 158 | if (ctx.comp.is_static) { |
| 158 | if (util.isArmOrThumb(ctx.comp.target)) { | 159 | //if (util.isArmOrThumb(ctx.comp.target)) { |
| 159 | try ctx.args.append("-Bstatic"); | 160 | // try ctx.args.append("-Bstatic"); |
| 160 | } else { | 161 | //} else { |
| 161 | try ctx.args.append("-static"); | 162 | // try ctx.args.append("-static"); |
| 162 | } | 163 | //} |
| 163 | } | 164 | } |
| 164 | //} else if (shared) { | 165 | //} else if (shared) { |
| 165 | // lj->args.append("-shared"); | 166 | // lj->args.append("-shared"); |
| ... | @@ -176,29 +177,24 @@ fn constructLinkerArgsElf(ctx: *Context) !void { | ... | @@ -176,29 +177,24 @@ fn constructLinkerArgsElf(ctx: *Context) !void { |
| 176 | 177 | ||
| 177 | if (ctx.link_in_crt) { | 178 | if (ctx.link_in_crt) { |
| 178 | const crt1o = if (ctx.comp.is_static) "crt1.o" else "Scrt1.o"; | 179 | const crt1o = if (ctx.comp.is_static) "crt1.o" else "Scrt1.o"; |
| 179 | const crtbegino = if (ctx.comp.is_static) "crtbeginT.o" else "crtbegin.o"; | 180 | try addPathJoin(ctx, ctx.libc.crt_dir.?, crt1o); |
| 180 | try addPathJoin(ctx, ctx.libc.lib_dir.?, crt1o); | 181 | try addPathJoin(ctx, ctx.libc.crt_dir.?, "crti.o"); |
| 181 | try addPathJoin(ctx, ctx.libc.lib_dir.?, "crti.o"); | ||
| 182 | try addPathJoin(ctx, ctx.libc.static_lib_dir.?, crtbegino); | ||
| 183 | } | 182 | } |
| 184 | 183 | ||
| 185 | if (ctx.comp.haveLibC()) { | 184 | if (ctx.comp.haveLibC()) { |
| 186 | try ctx.args.append("-L"); | 185 | try ctx.args.append("-L"); |
| 187 | // TODO addNullByte should probably return [:0]u8 | 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"); | 189 | //if (!ctx.comp.is_static) { |
| 191 | try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.static_lib_dir.?)).ptr)); | 190 | // const dl = blk: { |
| 192 | 191 | // //if (ctx.libc.dynamic_linker_path) |dl| break :blk dl; | |
| 193 | if (!ctx.comp.is_static) { | 192 | // //if (util.getDynamicLinkerPath(ctx.comp.target)) |dl| break :blk dl; |
| 194 | const dl = blk: { | 193 | // return error.LibCMissingDynamicLinker; |
| 195 | if (ctx.libc.dynamic_linker_path) |dl| break :blk dl; | 194 | // }; |
| 196 | if (util.getDynamicLinkerPath(ctx.comp.target)) |dl| break :blk dl; | 195 | // try ctx.args.append("-dynamic-linker"); |
| 197 | return error.LibCMissingDynamicLinker; | 196 | // try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr)); |
| 198 | }; | 197 | //} |
| 199 | try ctx.args.append("-dynamic-linker"); | ||
| 200 | try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr)); | ||
| 201 | } | ||
| 202 | } | 198 | } |
| 203 | 199 | ||
| 204 | //if (shared) { | 200 | //if (shared) { |
| ... | @@ -265,13 +261,12 @@ fn constructLinkerArgsElf(ctx: *Context) !void { | ... | @@ -265,13 +261,12 @@ fn constructLinkerArgsElf(ctx: *Context) !void { |
| 265 | 261 | ||
| 266 | // crt end | 262 | // crt end |
| 267 | if (ctx.link_in_crt) { | 263 | if (ctx.link_in_crt) { |
| 268 | try addPathJoin(ctx, ctx.libc.static_lib_dir.?, "crtend.o"); | 264 | try addPathJoin(ctx, ctx.libc.crt_dir.?, "crtn.o"); |
| 269 | try addPathJoin(ctx, ctx.libc.lib_dir.?, "crtn.o"); | ||
| 270 | } | 265 | } |
| 271 | 266 | ||
| 272 | if (ctx.comp.target != Target.Native) { | 267 | //if (ctx.comp.target != Target.Native) { |
| 273 | try ctx.args.append("--allow-shlib-undefined"); | 268 | // try ctx.args.append("--allow-shlib-undefined"); |
| 274 | } | 269 | //} |
| 275 | } | 270 | } |
| 276 | 271 | ||
| 277 | fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void { | 272 | fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void { |
| ... | @@ -287,7 +282,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { | ... | @@ -287,7 +282,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { |
| 287 | try ctx.args.append("-DEBUG"); | 282 | try ctx.args.append("-DEBUG"); |
| 288 | } | 283 | } |
| 289 | 284 | ||
| 290 | switch (ctx.comp.target.getArch()) { | 285 | switch (ctx.comp.target.cpu.arch) { |
| 291 | .i386 => try ctx.args.append("-MACHINE:X86"), | 286 | .i386 => try ctx.args.append("-MACHINE:X86"), |
| 292 | .x86_64 => try ctx.args.append("-MACHINE:X64"), | 287 | .x86_64 => try ctx.args.append("-MACHINE:X64"), |
| 293 | .aarch64 => try ctx.args.append("-MACHINE:ARM"), | 288 | .aarch64 => try ctx.args.append("-MACHINE:ARM"), |
| ... | @@ -302,7 +297,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { | ... | @@ -302,7 +297,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { |
| 302 | if (ctx.comp.haveLibC()) { | 297 | if (ctx.comp.haveLibC()) { |
| 303 | try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.msvc_lib_dir.?})).ptr)); | 298 | try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.msvc_lib_dir.?})).ptr)); |
| 304 | try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.kernel32_lib_dir.?})).ptr)); | 299 | try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.kernel32_lib_dir.?})).ptr)); |
| 305 | try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.lib_dir.?})).ptr)); | 300 | try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.crt_dir.?})).ptr)); |
| 306 | } | 301 | } |
| 307 | 302 | ||
| 308 | if (ctx.link_in_crt) { | 303 | if (ctx.link_in_crt) { |
| ... | @@ -417,7 +412,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { | ... | @@ -417,7 +412,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { |
| 417 | } | 412 | } |
| 418 | }, | 413 | }, |
| 419 | .IPhoneOS => { | 414 | .IPhoneOS => { |
| 420 | if (ctx.comp.target.getArch() == .aarch64) { | 415 | if (ctx.comp.target.cpu.arch == .aarch64) { |
| 421 | // iOS does not need any crt1 files for arm64 | 416 | // iOS does not need any crt1 files for arm64 |
| 422 | } else if (platform.versionLessThan(3, 1)) { | 417 | } else if (platform.versionLessThan(3, 1)) { |
| 423 | try ctx.args.append("-lcrt1.o"); | 418 | try ctx.args.append("-lcrt1.o"); |
| ... | @@ -435,28 +430,29 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { | ... | @@ -435,28 +430,29 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { |
| 435 | } | 430 | } |
| 436 | try addFnObjects(ctx); | 431 | try addFnObjects(ctx); |
| 437 | 432 | ||
| 438 | if (ctx.comp.target == Target.Native) { | 433 | // TODO |
| 439 | for (ctx.comp.link_libs_list.toSliceConst()) |lib| { | 434 | //if (ctx.comp.target == Target.Native) { |
| 440 | if (mem.eql(u8, lib.name, "c")) { | 435 | // for (ctx.comp.link_libs_list.toSliceConst()) |lib| { |
| 441 | // on Darwin, libSystem has libc in it, but also you have to use it | 436 | // if (mem.eql(u8, lib.name, "c")) { |
| 442 | // to make syscalls because the syscall numbers are not documented | 437 | // // on Darwin, libSystem has libc in it, but also you have to use it |
| 443 | // and change between versions. | 438 | // // to make syscalls because the syscall numbers are not documented |
| 444 | // so we always link against libSystem | 439 | // // and change between versions. |
| 445 | try ctx.args.append("-lSystem"); | 440 | // // so we always link against libSystem |
| 446 | } else { | 441 | // try ctx.args.append("-lSystem"); |
| 447 | if (mem.indexOfScalar(u8, lib.name, '/') == null) { | 442 | // } else { |
| 448 | const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", .{lib.name}); | 443 | // if (mem.indexOfScalar(u8, lib.name, '/') == null) { |
| 449 | try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); | 444 | // const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", .{lib.name}); |
| 450 | } else { | 445 | // try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); |
| 451 | const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name); | 446 | // } else { |
| 452 | try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); | 447 | // const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name); |
| 453 | } | 448 | // try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); |
| 454 | } | 449 | // } |
| 455 | } | 450 | // } |
| 456 | } else { | 451 | // } |
| 457 | try ctx.args.append("-undefined"); | 452 | //} else { |
| 458 | try ctx.args.append("dynamic_lookup"); | 453 | // try ctx.args.append("-undefined"); |
| 459 | } | 454 | // try ctx.args.append("dynamic_lookup"); |
| 455 | //} | ||
| 460 | 456 | ||
| 461 | if (platform.kind == .MacOS) { | 457 | if (platform.kind == .MacOS) { |
| 462 | if (platform.versionLessThan(10, 5)) { | 458 | if (platform.versionLessThan(10, 5)) { |
src-self-hosted/main.zig+56-47| ... | @@ -18,10 +18,6 @@ const Target = std.Target; | ... | @@ -18,10 +18,6 @@ const Target = std.Target; |
| 18 | const errmsg = @import("errmsg.zig"); | 18 | const errmsg = @import("errmsg.zig"); |
| 19 | const LibCInstallation = @import("libc_installation.zig").LibCInstallation; | 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 | pub const io_mode = .evented; | 21 | pub const io_mode = .evented; |
| 26 | 22 | ||
| 27 | pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB | 23 | pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB |
| ... | @@ -51,17 +47,14 @@ const Command = struct { | ... | @@ -51,17 +47,14 @@ const Command = struct { |
| 51 | pub fn main() !void { | 47 | pub fn main() !void { |
| 52 | const allocator = std.heap.c_allocator; | 48 | const allocator = std.heap.c_allocator; |
| 53 | 49 | ||
| 54 | stdout = &std.io.getStdOut().outStream().stream; | 50 | const stderr = io.getStdErr().outStream(); |
| 55 | |||
| 56 | stderr_file = std.io.getStdErr(); | ||
| 57 | stderr = &stderr_file.outStream().stream; | ||
| 58 | 51 | ||
| 59 | const args = try process.argsAlloc(allocator); | 52 | const args = try process.argsAlloc(allocator); |
| 60 | defer process.argsFree(allocator, args); | 53 | defer process.argsFree(allocator, args); |
| 61 | 54 | ||
| 62 | if (args.len <= 1) { | 55 | if (args.len <= 1) { |
| 63 | try stderr.write("expected command argument\n\n"); | 56 | try stderr.writeAll("expected command argument\n\n"); |
| 64 | try stderr.write(usage); | 57 | try stderr.writeAll(usage); |
| 65 | process.exit(1); | 58 | process.exit(1); |
| 66 | } | 59 | } |
| 67 | 60 | ||
| ... | @@ -78,8 +71,8 @@ pub fn main() !void { | ... | @@ -78,8 +71,8 @@ pub fn main() !void { |
| 78 | } else if (mem.eql(u8, cmd, "libc")) { | 71 | } else if (mem.eql(u8, cmd, "libc")) { |
| 79 | return cmdLibC(allocator, cmd_args); | 72 | return cmdLibC(allocator, cmd_args); |
| 80 | } else if (mem.eql(u8, cmd, "targets")) { | 73 | } else if (mem.eql(u8, cmd, "targets")) { |
| 81 | const info = try std.zig.system.NativeTargetInfo.detect(allocator); | 74 | const info = try std.zig.system.NativeTargetInfo.detect(allocator, .{}); |
| 82 | defer info.deinit(allocator); | 75 | const stdout = io.getStdOut().outStream(); |
| 83 | return @import("print_targets.zig").cmdTargets(allocator, cmd_args, stdout, info.target); | 76 | return @import("print_targets.zig").cmdTargets(allocator, cmd_args, stdout, info.target); |
| 84 | } else if (mem.eql(u8, cmd, "version")) { | 77 | } else if (mem.eql(u8, cmd, "version")) { |
| 85 | return cmdVersion(allocator, cmd_args); | 78 | return cmdVersion(allocator, cmd_args); |
| ... | @@ -91,7 +84,7 @@ pub fn main() !void { | ... | @@ -91,7 +84,7 @@ pub fn main() !void { |
| 91 | return cmdInternal(allocator, cmd_args); | 84 | return cmdInternal(allocator, cmd_args); |
| 92 | } else { | 85 | } else { |
| 93 | try stderr.print("unknown command: {}\n\n", .{args[1]}); | 86 | try stderr.print("unknown command: {}\n\n", .{args[1]}); |
| 94 | try stderr.write(usage); | 87 | try stderr.writeAll(usage); |
| 95 | process.exit(1); | 88 | process.exit(1); |
| 96 | } | 89 | } |
| 97 | } | 90 | } |
| ... | @@ -156,6 +149,8 @@ const usage_build_generic = | ... | @@ -156,6 +149,8 @@ const usage_build_generic = |
| 156 | ; | 149 | ; |
| 157 | 150 | ||
| 158 | fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Compilation.Kind) !void { | 151 | fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Compilation.Kind) !void { |
| 152 | const stderr = io.getStdErr().outStream(); | ||
| 153 | |||
| 159 | var color: errmsg.Color = .Auto; | 154 | var color: errmsg.Color = .Auto; |
| 160 | var build_mode: std.builtin.Mode = .Debug; | 155 | var build_mode: std.builtin.Mode = .Debug; |
| 161 | var emit_bin = true; | 156 | var emit_bin = true; |
| ... | @@ -208,11 +203,11 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co | ... | @@ -208,11 +203,11 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 208 | const arg = args[i]; | 203 | const arg = args[i]; |
| 209 | if (mem.startsWith(u8, arg, "-")) { | 204 | if (mem.startsWith(u8, arg, "-")) { |
| 210 | if (mem.eql(u8, arg, "--help")) { | 205 | if (mem.eql(u8, arg, "--help")) { |
| 211 | try stdout.write(usage_build_generic); | 206 | try io.getStdOut().writeAll(usage_build_generic); |
| 212 | process.exit(0); | 207 | process.exit(0); |
| 213 | } else if (mem.eql(u8, arg, "--color")) { | 208 | } else if (mem.eql(u8, arg, "--color")) { |
| 214 | if (i + 1 >= args.len) { | 209 | if (i + 1 >= args.len) { |
| 215 | try stderr.write("expected [auto|on|off] after --color\n"); | 210 | try stderr.writeAll("expected [auto|on|off] after --color\n"); |
| 216 | process.exit(1); | 211 | process.exit(1); |
| 217 | } | 212 | } |
| 218 | i += 1; | 213 | i += 1; |
| ... | @@ -229,7 +224,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co | ... | @@ -229,7 +224,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 229 | } | 224 | } |
| 230 | } else if (mem.eql(u8, arg, "--mode")) { | 225 | } else if (mem.eql(u8, arg, "--mode")) { |
| 231 | if (i + 1 >= args.len) { | 226 | if (i + 1 >= args.len) { |
| 232 | try stderr.write("expected [Debug|ReleaseSafe|ReleaseFast|ReleaseSmall] after --mode\n"); | 227 | try stderr.writeAll("expected [Debug|ReleaseSafe|ReleaseFast|ReleaseSmall] after --mode\n"); |
| 233 | process.exit(1); | 228 | process.exit(1); |
| 234 | } | 229 | } |
| 235 | i += 1; | 230 | i += 1; |
| ... | @@ -248,49 +243,49 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co | ... | @@ -248,49 +243,49 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 248 | } | 243 | } |
| 249 | } else if (mem.eql(u8, arg, "--name")) { | 244 | } else if (mem.eql(u8, arg, "--name")) { |
| 250 | if (i + 1 >= args.len) { | 245 | if (i + 1 >= args.len) { |
| 251 | try stderr.write("expected parameter after --name\n"); | 246 | try stderr.writeAll("expected parameter after --name\n"); |
| 252 | process.exit(1); | 247 | process.exit(1); |
| 253 | } | 248 | } |
| 254 | i += 1; | 249 | i += 1; |
| 255 | provided_name = args[i]; | 250 | provided_name = args[i]; |
| 256 | } else if (mem.eql(u8, arg, "--ver-major")) { | 251 | } else if (mem.eql(u8, arg, "--ver-major")) { |
| 257 | if (i + 1 >= args.len) { | 252 | if (i + 1 >= args.len) { |
| 258 | try stderr.write("expected parameter after --ver-major\n"); | 253 | try stderr.writeAll("expected parameter after --ver-major\n"); |
| 259 | process.exit(1); | 254 | process.exit(1); |
| 260 | } | 255 | } |
| 261 | i += 1; | 256 | i += 1; |
| 262 | version.major = try std.fmt.parseInt(u32, args[i], 10); | 257 | version.major = try std.fmt.parseInt(u32, args[i], 10); |
| 263 | } else if (mem.eql(u8, arg, "--ver-minor")) { | 258 | } else if (mem.eql(u8, arg, "--ver-minor")) { |
| 264 | if (i + 1 >= args.len) { | 259 | if (i + 1 >= args.len) { |
| 265 | try stderr.write("expected parameter after --ver-minor\n"); | 260 | try stderr.writeAll("expected parameter after --ver-minor\n"); |
| 266 | process.exit(1); | 261 | process.exit(1); |
| 267 | } | 262 | } |
| 268 | i += 1; | 263 | i += 1; |
| 269 | version.minor = try std.fmt.parseInt(u32, args[i], 10); | 264 | version.minor = try std.fmt.parseInt(u32, args[i], 10); |
| 270 | } else if (mem.eql(u8, arg, "--ver-patch")) { | 265 | } else if (mem.eql(u8, arg, "--ver-patch")) { |
| 271 | if (i + 1 >= args.len) { | 266 | if (i + 1 >= args.len) { |
| 272 | try stderr.write("expected parameter after --ver-patch\n"); | 267 | try stderr.writeAll("expected parameter after --ver-patch\n"); |
| 273 | process.exit(1); | 268 | process.exit(1); |
| 274 | } | 269 | } |
| 275 | i += 1; | 270 | i += 1; |
| 276 | version.patch = try std.fmt.parseInt(u32, args[i], 10); | 271 | version.patch = try std.fmt.parseInt(u32, args[i], 10); |
| 277 | } else if (mem.eql(u8, arg, "--linker-script")) { | 272 | } else if (mem.eql(u8, arg, "--linker-script")) { |
| 278 | if (i + 1 >= args.len) { | 273 | if (i + 1 >= args.len) { |
| 279 | try stderr.write("expected parameter after --linker-script\n"); | 274 | try stderr.writeAll("expected parameter after --linker-script\n"); |
| 280 | process.exit(1); | 275 | process.exit(1); |
| 281 | } | 276 | } |
| 282 | i += 1; | 277 | i += 1; |
| 283 | linker_script = args[i]; | 278 | linker_script = args[i]; |
| 284 | } else if (mem.eql(u8, arg, "--libc")) { | 279 | } else if (mem.eql(u8, arg, "--libc")) { |
| 285 | if (i + 1 >= args.len) { | 280 | if (i + 1 >= args.len) { |
| 286 | try stderr.write("expected parameter after --libc\n"); | 281 | try stderr.writeAll("expected parameter after --libc\n"); |
| 287 | process.exit(1); | 282 | process.exit(1); |
| 288 | } | 283 | } |
| 289 | i += 1; | 284 | i += 1; |
| 290 | libc_arg = args[i]; | 285 | libc_arg = args[i]; |
| 291 | } else if (mem.eql(u8, arg, "-mllvm")) { | 286 | } else if (mem.eql(u8, arg, "-mllvm")) { |
| 292 | if (i + 1 >= args.len) { | 287 | if (i + 1 >= args.len) { |
| 293 | try stderr.write("expected parameter after -mllvm\n"); | 288 | try stderr.writeAll("expected parameter after -mllvm\n"); |
| 294 | process.exit(1); | 289 | process.exit(1); |
| 295 | } | 290 | } |
| 296 | i += 1; | 291 | i += 1; |
| ... | @@ -300,14 +295,14 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co | ... | @@ -300,14 +295,14 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 300 | try mllvm_flags.append(args[i]); | 295 | try mllvm_flags.append(args[i]); |
| 301 | } else if (mem.eql(u8, arg, "-mmacosx-version-min")) { | 296 | } else if (mem.eql(u8, arg, "-mmacosx-version-min")) { |
| 302 | if (i + 1 >= args.len) { | 297 | if (i + 1 >= args.len) { |
| 303 | try stderr.write("expected parameter after -mmacosx-version-min\n"); | 298 | try stderr.writeAll("expected parameter after -mmacosx-version-min\n"); |
| 304 | process.exit(1); | 299 | process.exit(1); |
| 305 | } | 300 | } |
| 306 | i += 1; | 301 | i += 1; |
| 307 | macosx_version_min = args[i]; | 302 | macosx_version_min = args[i]; |
| 308 | } else if (mem.eql(u8, arg, "-mios-version-min")) { | 303 | } else if (mem.eql(u8, arg, "-mios-version-min")) { |
| 309 | if (i + 1 >= args.len) { | 304 | if (i + 1 >= args.len) { |
| 310 | try stderr.write("expected parameter after -mios-version-min\n"); | 305 | try stderr.writeAll("expected parameter after -mios-version-min\n"); |
| 311 | process.exit(1); | 306 | process.exit(1); |
| 312 | } | 307 | } |
| 313 | i += 1; | 308 | i += 1; |
| ... | @@ -348,7 +343,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co | ... | @@ -348,7 +343,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 348 | linker_rdynamic = true; | 343 | linker_rdynamic = true; |
| 349 | } else if (mem.eql(u8, arg, "--pkg-begin")) { | 344 | } else if (mem.eql(u8, arg, "--pkg-begin")) { |
| 350 | if (i + 2 >= args.len) { | 345 | if (i + 2 >= args.len) { |
| 351 | try stderr.write("expected [name] [path] after --pkg-begin\n"); | 346 | try stderr.writeAll("expected [name] [path] after --pkg-begin\n"); |
| 352 | process.exit(1); | 347 | process.exit(1); |
| 353 | } | 348 | } |
| 354 | i += 1; | 349 | i += 1; |
| ... | @@ -363,7 +358,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co | ... | @@ -363,7 +358,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 363 | if (cur_pkg.parent) |parent| { | 358 | if (cur_pkg.parent) |parent| { |
| 364 | cur_pkg = parent; | 359 | cur_pkg = parent; |
| 365 | } else { | 360 | } else { |
| 366 | try stderr.write("encountered --pkg-end with no matching --pkg-begin\n"); | 361 | try stderr.writeAll("encountered --pkg-end with no matching --pkg-begin\n"); |
| 367 | process.exit(1); | 362 | process.exit(1); |
| 368 | } | 363 | } |
| 369 | } else if (mem.startsWith(u8, arg, "-l")) { | 364 | } else if (mem.startsWith(u8, arg, "-l")) { |
| ... | @@ -411,18 +406,18 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co | ... | @@ -411,18 +406,18 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 411 | var it = mem.separate(basename, "."); | 406 | var it = mem.separate(basename, "."); |
| 412 | break :blk it.next() orelse basename; | 407 | break :blk it.next() orelse basename; |
| 413 | } else { | 408 | } else { |
| 414 | try stderr.write("--name [name] not provided and unable to infer\n"); | 409 | try stderr.writeAll("--name [name] not provided and unable to infer\n"); |
| 415 | process.exit(1); | 410 | process.exit(1); |
| 416 | } | 411 | } |
| 417 | }; | 412 | }; |
| 418 | 413 | ||
| 419 | if (root_src_file == null and link_objects.len == 0 and assembly_files.len == 0) { | 414 | if (root_src_file == null and link_objects.len == 0 and assembly_files.len == 0) { |
| 420 | try stderr.write("Expected source file argument or at least one --object or --assembly argument\n"); | 415 | try stderr.writeAll("Expected source file argument or at least one --object or --assembly argument\n"); |
| 421 | process.exit(1); | 416 | process.exit(1); |
| 422 | } | 417 | } |
| 423 | 418 | ||
| 424 | if (out_type == Compilation.Kind.Obj and link_objects.len != 0) { | 419 | if (out_type == Compilation.Kind.Obj and link_objects.len != 0) { |
| 425 | try stderr.write("When building an object file, --object arguments are invalid\n"); | 420 | try stderr.writeAll("When building an object file, --object arguments are invalid\n"); |
| 426 | process.exit(1); | 421 | process.exit(1); |
| 427 | } | 422 | } |
| 428 | 423 | ||
| ... | @@ -440,7 +435,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co | ... | @@ -440,7 +435,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 440 | &zig_compiler, | 435 | &zig_compiler, |
| 441 | root_name, | 436 | root_name, |
| 442 | root_src_file, | 437 | root_src_file, |
| 443 | Target.Native, | 438 | .{}, |
| 444 | out_type, | 439 | out_type, |
| 445 | build_mode, | 440 | build_mode, |
| 446 | !is_dynamic, | 441 | !is_dynamic, |
| ... | @@ -478,7 +473,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co | ... | @@ -478,7 +473,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 478 | comp.linker_rdynamic = linker_rdynamic; | 473 | comp.linker_rdynamic = linker_rdynamic; |
| 479 | 474 | ||
| 480 | if (macosx_version_min != null and ios_version_min != null) { | 475 | if (macosx_version_min != null and ios_version_min != null) { |
| 481 | try stderr.write("-mmacosx-version-min and -mios-version-min options not allowed together\n"); | 476 | try stderr.writeAll("-mmacosx-version-min and -mios-version-min options not allowed together\n"); |
| 482 | process.exit(1); | 477 | process.exit(1); |
| 483 | } | 478 | } |
| 484 | 479 | ||
| ... | @@ -501,6 +496,8 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co | ... | @@ -501,6 +496,8 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 501 | } | 496 | } |
| 502 | 497 | ||
| 503 | fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void { | 498 | fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void { |
| 499 | const stderr_file = io.getStdErr(); | ||
| 500 | const stderr = stderr_file.outStream(); | ||
| 504 | var count: usize = 0; | 501 | var count: usize = 0; |
| 505 | while (!comp.cancelled) { | 502 | while (!comp.cancelled) { |
| 506 | const build_event = comp.events.get(); | 503 | const build_event = comp.events.get(); |
| ... | @@ -551,7 +548,8 @@ const Fmt = struct { | ... | @@ -551,7 +548,8 @@ const Fmt = struct { |
| 551 | }; | 548 | }; |
| 552 | 549 | ||
| 553 | fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_file: []const u8) void { | 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 | stderr.print("Unable to parse libc path file '{}': {}.\n" ++ | 553 | stderr.print("Unable to parse libc path file '{}': {}.\n" ++ |
| 556 | "Try running `zig libc` to see an example for the native target.\n", .{ | 554 | "Try running `zig libc` to see an example for the native target.\n", .{ |
| 557 | libc_paths_file, | 555 | libc_paths_file, |
| ... | @@ -562,6 +560,7 @@ fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_fil | ... | @@ -562,6 +560,7 @@ fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_fil |
| 562 | } | 560 | } |
| 563 | 561 | ||
| 564 | fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void { | 562 | fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void { |
| 563 | const stderr = io.getStdErr().outStream(); | ||
| 565 | switch (args.len) { | 564 | switch (args.len) { |
| 566 | 0 => {}, | 565 | 0 => {}, |
| 567 | 1 => { | 566 | 1 => { |
| ... | @@ -582,10 +581,12 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void { | ... | @@ -582,10 +581,12 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void { |
| 582 | stderr.print("unable to find libc: {}\n", .{@errorName(err)}) catch {}; | 581 | stderr.print("unable to find libc: {}\n", .{@errorName(err)}) catch {}; |
| 583 | process.exit(1); | 582 | process.exit(1); |
| 584 | }; | 583 | }; |
| 585 | libc.render(stdout) catch process.exit(1); | 584 | libc.render(io.getStdOut().outStream()) catch process.exit(1); |
| 586 | } | 585 | } |
| 587 | 586 | ||
| 588 | fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { | 587 | fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { |
| 588 | const stderr_file = io.getStdErr(); | ||
| 589 | const stderr = stderr_file.outStream(); | ||
| 589 | var color: errmsg.Color = .Auto; | 590 | var color: errmsg.Color = .Auto; |
| 590 | var stdin_flag: bool = false; | 591 | var stdin_flag: bool = false; |
| 591 | var check_flag: bool = false; | 592 | var check_flag: bool = false; |
| ... | @@ -597,11 +598,12 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { | ... | @@ -597,11 +598,12 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { |
| 597 | const arg = args[i]; | 598 | const arg = args[i]; |
| 598 | if (mem.startsWith(u8, arg, "-")) { | 599 | if (mem.startsWith(u8, arg, "-")) { |
| 599 | if (mem.eql(u8, arg, "--help")) { | 600 | if (mem.eql(u8, arg, "--help")) { |
| 600 | try stdout.write(usage_fmt); | 601 | const stdout = io.getStdOut().outStream(); |
| 602 | try stdout.writeAll(usage_fmt); | ||
| 601 | process.exit(0); | 603 | process.exit(0); |
| 602 | } else if (mem.eql(u8, arg, "--color")) { | 604 | } else if (mem.eql(u8, arg, "--color")) { |
| 603 | if (i + 1 >= args.len) { | 605 | if (i + 1 >= args.len) { |
| 604 | try stderr.write("expected [auto|on|off] after --color\n"); | 606 | try stderr.writeAll("expected [auto|on|off] after --color\n"); |
| 605 | process.exit(1); | 607 | process.exit(1); |
| 606 | } | 608 | } |
| 607 | i += 1; | 609 | i += 1; |
| ... | @@ -632,14 +634,13 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { | ... | @@ -632,14 +634,13 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { |
| 632 | 634 | ||
| 633 | if (stdin_flag) { | 635 | if (stdin_flag) { |
| 634 | if (input_files.len != 0) { | 636 | if (input_files.len != 0) { |
| 635 | try stderr.write("cannot use --stdin with positional arguments\n"); | 637 | try stderr.writeAll("cannot use --stdin with positional arguments\n"); |
| 636 | process.exit(1); | 638 | process.exit(1); |
| 637 | } | 639 | } |
| 638 | 640 | ||
| 639 | var stdin_file = io.getStdIn(); | 641 | const stdin = io.getStdIn().inStream(); |
| 640 | var stdin = stdin_file.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 | defer allocator.free(source_code); | 644 | defer allocator.free(source_code); |
| 644 | 645 | ||
| 645 | const tree = std.zig.parse(allocator, source_code) catch |err| { | 646 | const tree = std.zig.parse(allocator, source_code) catch |err| { |
| ... | @@ -653,7 +654,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { | ... | @@ -653,7 +654,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { |
| 653 | const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, tree, "<stdin>"); | 654 | const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, tree, "<stdin>"); |
| 654 | defer msg.destroy(); | 655 | defer msg.destroy(); |
| 655 | 656 | ||
| 656 | try msg.printToFile(stderr_file, color); | 657 | try msg.printToFile(io.getStdErr(), color); |
| 657 | } | 658 | } |
| 658 | if (tree.errors.len != 0) { | 659 | if (tree.errors.len != 0) { |
| 659 | process.exit(1); | 660 | process.exit(1); |
| ... | @@ -664,12 +665,13 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { | ... | @@ -664,12 +665,13 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { |
| 664 | process.exit(code); | 665 | process.exit(code); |
| 665 | } | 666 | } |
| 666 | 667 | ||
| 668 | const stdout = io.getStdOut().outStream(); | ||
| 667 | _ = try std.zig.render(allocator, stdout, tree); | 669 | _ = try std.zig.render(allocator, stdout, tree); |
| 668 | return; | 670 | return; |
| 669 | } | 671 | } |
| 670 | 672 | ||
| 671 | if (input_files.len == 0) { | 673 | if (input_files.len == 0) { |
| 672 | try stderr.write("expected at least one source file argument\n"); | 674 | try stderr.writeAll("expected at least one source file argument\n"); |
| 673 | process.exit(1); | 675 | process.exit(1); |
| 674 | } | 676 | } |
| 675 | 677 | ||
| ... | @@ -713,6 +715,9 @@ const FmtError = error{ | ... | @@ -713,6 +715,9 @@ const FmtError = error{ |
| 713 | } || fs.File.OpenError; | 715 | } || fs.File.OpenError; |
| 714 | 716 | ||
| 715 | async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void { | 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 | const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref); | 721 | const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref); |
| 717 | defer fmt.allocator.free(file_path); | 722 | defer fmt.allocator.free(file_path); |
| 718 | 723 | ||
| ... | @@ -729,7 +734,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro | ... | @@ -729,7 +734,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro |
| 729 | max_src_size, | 734 | max_src_size, |
| 730 | ) catch |err| switch (err) { | 735 | ) catch |err| switch (err) { |
| 731 | error.IsDir, error.AccessDenied => { | 736 | error.IsDir, error.AccessDenied => { |
| 732 | var dir = try fs.cwd().openDirList(file_path); | 737 | var dir = try fs.cwd().openDir(file_path, .{ .iterate = true }); |
| 733 | defer dir.close(); | 738 | defer dir.close(); |
| 734 | 739 | ||
| 735 | var group = event.Group(FmtError!void).init(fmt.allocator); | 740 | var group = event.Group(FmtError!void).init(fmt.allocator); |
| ... | @@ -791,11 +796,13 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro | ... | @@ -791,11 +796,13 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro |
| 791 | } | 796 | } |
| 792 | 797 | ||
| 793 | fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void { | 798 | fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void { |
| 799 | const stdout = io.getStdOut().outStream(); | ||
| 794 | try stdout.print("{}\n", .{c.ZIG_VERSION_STRING}); | 800 | try stdout.print("{}\n", .{c.ZIG_VERSION_STRING}); |
| 795 | } | 801 | } |
| 796 | 802 | ||
| 797 | fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void { | 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 | pub const info_zen = | 808 | pub const info_zen = |
| ... | @@ -816,7 +823,7 @@ pub const info_zen = | ... | @@ -816,7 +823,7 @@ pub const info_zen = |
| 816 | ; | 823 | ; |
| 817 | 824 | ||
| 818 | fn cmdZen(allocator: *Allocator, args: []const []const u8) !void { | 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 | const usage_internal = | 829 | const usage_internal = |
| ... | @@ -829,8 +836,9 @@ const usage_internal = | ... | @@ -829,8 +836,9 @@ const usage_internal = |
| 829 | ; | 836 | ; |
| 830 | 837 | ||
| 831 | fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void { | 838 | fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void { |
| 839 | const stderr = io.getStdErr().outStream(); | ||
| 832 | if (args.len == 0) { | 840 | if (args.len == 0) { |
| 833 | try stderr.write(usage_internal); | 841 | try stderr.writeAll(usage_internal); |
| 834 | process.exit(1); | 842 | process.exit(1); |
| 835 | } | 843 | } |
| 836 | 844 | ||
| ... | @@ -849,10 +857,11 @@ fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void { | ... | @@ -849,10 +857,11 @@ fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void { |
| 849 | } | 857 | } |
| 850 | 858 | ||
| 851 | try stderr.print("unknown sub command: {}\n\n", .{args[0]}); | 859 | try stderr.print("unknown sub command: {}\n\n", .{args[0]}); |
| 852 | try stderr.write(usage_internal); | 860 | try stderr.writeAll(usage_internal); |
| 853 | } | 861 | } |
| 854 | 862 | ||
| 855 | fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void { | 863 | fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void { |
| 864 | const stdout = io.getStdOut().outStream(); | ||
| 856 | try stdout.print( | 865 | try stdout.print( |
| 857 | \\ZIG_CMAKE_BINARY_DIR {} | 866 | \\ZIG_CMAKE_BINARY_DIR {} |
| 858 | \\ZIG_CXX_COMPILER {} | 867 | \\ZIG_CXX_COMPILER {} |
src-self-hosted/print_targets.zig+1-1| ... | @@ -72,7 +72,7 @@ pub fn cmdTargets( | ... | @@ -72,7 +72,7 @@ pub fn cmdTargets( |
| 72 | }; | 72 | }; |
| 73 | defer allocator.free(zig_lib_dir); | 73 | defer allocator.free(zig_lib_dir); |
| 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 | defer dir.close(); | 76 | defer dir.close(); |
| 77 | 77 | ||
| 78 | const vers_txt = try dir.readFileAlloc(allocator, "libc/glibc/vers.txt", 10 * 1024); | 78 | const vers_txt = try dir.readFileAlloc(allocator, "libc/glibc/vers.txt", 10 * 1024); |
src-self-hosted/stage2.zig+2-2| ... | @@ -128,7 +128,7 @@ export fn stage2_translate_c( | ... | @@ -128,7 +128,7 @@ export fn stage2_translate_c( |
| 128 | args_end: [*]?[*]const u8, | 128 | args_end: [*]?[*]const u8, |
| 129 | resources_path: [*:0]const u8, | 129 | resources_path: [*:0]const u8, |
| 130 | ) Error { | 130 | ) Error { |
| 131 | var errors = @as([*]translate_c.ClangErrMsg, undefined)[0..0]; | 131 | var errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{}; |
| 132 | out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) { | 132 | out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) { |
| 133 | error.SemanticAnalyzeFail => { | 133 | error.SemanticAnalyzeFail => { |
| 134 | out_errors_ptr.* = errors.ptr; | 134 | out_errors_ptr.* = errors.ptr; |
| ... | @@ -319,7 +319,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { | ... | @@ -319,7 +319,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { |
| 319 | const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) { | 319 | const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) { |
| 320 | error.IsDir, error.AccessDenied => { | 320 | error.IsDir, error.AccessDenied => { |
| 321 | // TODO make event based (and dir.next()) | 321 | // TODO make event based (and dir.next()) |
| 322 | var dir = try fs.cwd().openDirList(file_path); | 322 | var dir = try fs.cwd().openDir(file_path, .{ .iterate = true }); |
| 323 | defer dir.close(); | 323 | defer dir.close(); |
| 324 | 324 | ||
| 325 | var dir_it = dir.iterate(); | 325 | var dir_it = dir.iterate(); |
src-self-hosted/test.zig+2-2| ... | @@ -57,11 +57,11 @@ pub const TestContext = struct { | ... | @@ -57,11 +57,11 @@ pub const TestContext = struct { |
| 57 | errdefer allocator.free(self.zig_lib_dir); | 57 | errdefer allocator.free(self.zig_lib_dir); |
| 58 | 58 | ||
| 59 | try std.fs.cwd().makePath(tmp_dir_name); | 59 | try std.fs.cwd().makePath(tmp_dir_name); |
| 60 | errdefer std.fs.deleteTree(tmp_dir_name) catch {}; | 60 | errdefer std.fs.cwd().deleteTree(tmp_dir_name) catch {}; |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | fn deinit(self: *TestContext) void { | 63 | fn deinit(self: *TestContext) void { |
| 64 | std.fs.deleteTree(tmp_dir_name) catch {}; | 64 | std.fs.cwd().deleteTree(tmp_dir_name) catch {}; |
| 65 | allocator.free(self.zig_lib_dir); | 65 | allocator.free(self.zig_lib_dir); |
| 66 | self.zig_compiler.deinit(); | 66 | self.zig_compiler.deinit(); |
| 67 | } | 67 | } |
src-self-hosted/translate_c.zig+12-14| ... | @@ -1744,20 +1744,18 @@ fn writeEscapedString(buf: []u8, s: []const u8) void { | ... | @@ -1744,20 +1744,18 @@ fn writeEscapedString(buf: []u8, s: []const u8) void { |
| 1744 | // Returns either a string literal or a slice of `buf`. | 1744 | // Returns either a string literal or a slice of `buf`. |
| 1745 | fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 { | 1745 | fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 { |
| 1746 | return switch (c) { | 1746 | return switch (c) { |
| 1747 | '\"' => "\\\""[0..], | 1747 | '\"' => "\\\"", |
| 1748 | '\'' => "\\'"[0..], | 1748 | '\'' => "\\'", |
| 1749 | '\\' => "\\\\"[0..], | 1749 | '\\' => "\\\\", |
| 1750 | '\n' => "\\n"[0..], | 1750 | '\n' => "\\n", |
| 1751 | '\r' => "\\r"[0..], | 1751 | '\r' => "\\r", |
| 1752 | '\t' => "\\t"[0..], | 1752 | '\t' => "\\t", |
| 1753 | else => { | 1753 | // Handle the remaining escapes Zig doesn't support by turning them |
| 1754 | // Handle the remaining escapes Zig doesn't support by turning them | 1754 | // into their respective hex representation |
| 1755 | // into their respective hex representation | 1755 | else => if (std.ascii.isCntrl(c)) |
| 1756 | if (std.ascii.isCntrl(c)) | 1756 | std.fmt.bufPrint(char_buf, "\\x{x:0<2}", .{c}) catch unreachable |
| 1757 | return std.fmt.bufPrint(char_buf[0..], "\\x{x:0<2}", .{c}) catch unreachable | 1757 | else |
| 1758 | else | 1758 | std.fmt.bufPrint(char_buf, "{c}", .{c}) catch unreachable, |
| 1759 | return std.fmt.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable; | ||
| 1760 | }, | ||
| 1761 | }; | 1759 | }; |
| 1762 | } | 1760 | } |
| 1763 | 1761 |
src-self-hosted/util.zig+13-2| ... | @@ -3,8 +3,7 @@ const Target = std.Target; | ... | @@ -3,8 +3,7 @@ const Target = std.Target; |
| 3 | const llvm = @import("llvm.zig"); | 3 | const llvm = @import("llvm.zig"); |
| 4 | 4 | ||
| 5 | pub fn getDarwinArchString(self: Target) [:0]const u8 { | 5 | pub fn getDarwinArchString(self: Target) [:0]const u8 { |
| 6 | const arch = self.getArch(); | 6 | switch (self.cpu.arch) { |
| 7 | switch (arch) { | ||
| 8 | .aarch64 => return "arm64", | 7 | .aarch64 => return "arm64", |
| 9 | .thumb, | 8 | .thumb, |
| 10 | .arm, | 9 | .arm, |
| ... | @@ -34,3 +33,15 @@ pub fn initializeAllTargets() void { | ... | @@ -34,3 +33,15 @@ pub fn initializeAllTargets() void { |
| 34 | llvm.InitializeAllAsmPrinters(); | 33 | llvm.InitializeAllAsmPrinters(); |
| 35 | llvm.InitializeAllAsmParsers(); | 34 | llvm.InitializeAllAsmParsers(); |
| 36 | } | 35 | } |
| 36 | |||
| 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,6 +231,7 @@ enum ConstPtrSpecial { |
| 231 | // The pointer is a reference to a single object. | 231 | // The pointer is a reference to a single object. |
| 232 | ConstPtrSpecialRef, | 232 | ConstPtrSpecialRef, |
| 233 | // The pointer points to an element in an underlying array. | 233 | // The pointer points to an element in an underlying array. |
| 234 | // Not to be confused with ConstPtrSpecialSubArray. | ||
| 234 | ConstPtrSpecialBaseArray, | 235 | ConstPtrSpecialBaseArray, |
| 235 | // The pointer points to a field in an underlying struct. | 236 | // The pointer points to a field in an underlying struct. |
| 236 | ConstPtrSpecialBaseStruct, | 237 | ConstPtrSpecialBaseStruct, |
| ... | @@ -257,6 +258,10 @@ enum ConstPtrSpecial { | ... | @@ -257,6 +258,10 @@ enum ConstPtrSpecial { |
| 257 | // types to be the same, so all optionals of pointer types use x_ptr | 258 | // types to be the same, so all optionals of pointer types use x_ptr |
| 258 | // instead of x_optional. | 259 | // instead of x_optional. |
| 259 | ConstPtrSpecialNull, | 260 | ConstPtrSpecialNull, |
| 261 | // The pointer points to a sub-array (not an individual element). | ||
| 262 | // Not to be confused with ConstPtrSpecialBaseArray. However, it uses the same | ||
| 263 | // union payload struct (base_array). | ||
| 264 | ConstPtrSpecialSubArray, | ||
| 260 | }; | 265 | }; |
| 261 | 266 | ||
| 262 | enum ConstPtrMut { | 267 | enum ConstPtrMut { |
| ... | @@ -3705,6 +3710,7 @@ struct IrInstGenSlice { | ... | @@ -3705,6 +3710,7 @@ struct IrInstGenSlice { |
| 3705 | IrInstGen *start; | 3710 | IrInstGen *start; |
| 3706 | IrInstGen *end; | 3711 | IrInstGen *end; |
| 3707 | IrInstGen *result_loc; | 3712 | IrInstGen *result_loc; |
| 3713 | ZigValue *sentinel; | ||
| 3708 | bool safety_check_on; | 3714 | bool safety_check_on; |
| 3709 | }; | 3715 | }; |
| 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,6 +780,8 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa |
| 780 | } | 780 | } |
| 781 | 781 | ||
| 782 | ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ZigValue *sentinel) { | 782 | ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ZigValue *sentinel) { |
| 783 | Error err; | ||
| 784 | |||
| 783 | TypeId type_id = {}; | 785 | TypeId type_id = {}; |
| 784 | type_id.id = ZigTypeIdArray; | 786 | type_id.id = ZigTypeIdArray; |
| 785 | type_id.data.array.codegen = g; | 787 | type_id.data.array.codegen = g; |
| ... | @@ -791,7 +793,11 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi | ... | @@ -791,7 +793,11 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi |
| 791 | return existing_entry->value; | 793 | return existing_entry->value; |
| 792 | } | 794 | } |
| 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 | ZigType *entry = new_type_table_entry(ZigTypeIdArray); | 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,15 +809,8 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi |
| 803 | } | 809 | } |
| 804 | buf_appendf(&entry->name, "]%s", buf_ptr(&child_type->name)); | 810 | buf_appendf(&entry->name, "]%s", buf_ptr(&child_type->name)); |
| 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 | entry->size_in_bits = child_type->size_in_bits * full_array_size; | 812 | entry->size_in_bits = child_type->size_in_bits * full_array_size; |
| 814 | entry->abi_align = child_type->abi_align; | 813 | entry->abi_align = (full_array_size == 0) ? 0 : child_type->abi_align; |
| 815 | entry->abi_size = child_type->abi_size * full_array_size; | 814 | entry->abi_size = child_type->abi_size * full_array_size; |
| 816 | 815 | ||
| 817 | entry->data.array.child_type = child_type; | 816 | entry->data.array.child_type = child_type; |
| ... | @@ -1197,7 +1196,8 @@ Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent | ... | @@ -1197,7 +1196,8 @@ Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent |
| 1197 | LazyValueArrayType *lazy_array_type = | 1196 | LazyValueArrayType *lazy_array_type = |
| 1198 | reinterpret_cast<LazyValueArrayType *>(type_val->data.x_lazy); | 1197 | reinterpret_cast<LazyValueArrayType *>(type_val->data.x_lazy); |
| 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 | *is_zero_bits = true; | 1201 | *is_zero_bits = true; |
| 1202 | return ErrorNone; | 1202 | return ErrorNone; |
| 1203 | } | 1203 | } |
| ... | @@ -1452,7 +1452,7 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, ZigV | ... | @@ -1452,7 +1452,7 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, ZigV |
| 1452 | case LazyValueIdArrayType: { | 1452 | case LazyValueIdArrayType: { |
| 1453 | LazyValueArrayType *lazy_array_type = | 1453 | LazyValueArrayType *lazy_array_type = |
| 1454 | reinterpret_cast<LazyValueArrayType *>(type_val->data.x_lazy); | 1454 | reinterpret_cast<LazyValueArrayType *>(type_val->data.x_lazy); |
| 1455 | if (lazy_array_type->length < 1) | 1455 | if (lazy_array_type->length == 0) |
| 1456 | return OnePossibleValueYes; | 1456 | return OnePossibleValueYes; |
| 1457 | return type_val_resolve_has_one_possible_value(g, lazy_array_type->elem_type->value); | 1457 | return type_val_resolve_has_one_possible_value(g, lazy_array_type->elem_type->value); |
| 1458 | } | 1458 | } |
| ... | @@ -4488,7 +4488,14 @@ static uint32_t get_async_frame_align_bytes(CodeGen *g) { | ... | @@ -4488,7 +4488,14 @@ static uint32_t get_async_frame_align_bytes(CodeGen *g) { |
| 4488 | } | 4488 | } |
| 4489 | 4489 | ||
| 4490 | uint32_t get_ptr_align(CodeGen *g, ZigType *type) { | 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 | if (ptr_type->id == ZigTypeIdPointer) { | 4499 | if (ptr_type->id == ZigTypeIdPointer) { |
| 4493 | return (ptr_type->data.pointer.explicit_alignment == 0) ? | 4500 | return (ptr_type->data.pointer.explicit_alignment == 0) ? |
| 4494 | get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment; | 4501 | get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment; |
| ... | @@ -4505,8 +4512,15 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) { | ... | @@ -4505,8 +4512,15 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) { |
| 4505 | } | 4512 | } |
| 4506 | } | 4513 | } |
| 4507 | 4514 | ||
| 4508 | bool get_ptr_const(ZigType *type) { | 4515 | bool get_ptr_const(CodeGen *g, ZigType *type) { |
| 4509 | ZigType *ptr_type = get_src_ptr_type(type); | 4516 | ZigType *ptr_type; |
| 4517 | if (type->id == ZigTypeIdStruct) { | ||
| 4518 | assert(type->data.structure.special == StructSpecialSlice); | ||
| 4519 | TypeStructField *ptr_field = type->data.structure.fields[slice_ptr_index]; | ||
| 4520 | ptr_type = resolve_struct_field_type(g, ptr_field); | ||
| 4521 | } else { | ||
| 4522 | ptr_type = get_src_ptr_type(type); | ||
| 4523 | } | ||
| 4510 | if (ptr_type->id == ZigTypeIdPointer) { | 4524 | if (ptr_type->id == ZigTypeIdPointer) { |
| 4511 | return ptr_type->data.pointer.is_const; | 4525 | return ptr_type->data.pointer.is_const; |
| 4512 | } else if (ptr_type->id == ZigTypeIdFn) { | 4526 | } else if (ptr_type->id == ZigTypeIdFn) { |
| ... | @@ -5282,6 +5296,11 @@ static uint32_t hash_const_val_ptr(ZigValue *const_val) { | ... | @@ -5282,6 +5296,11 @@ static uint32_t hash_const_val_ptr(ZigValue *const_val) { |
| 5282 | hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val); | 5296 | hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val); |
| 5283 | hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index); | 5297 | hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index); |
| 5284 | return hash_val; | 5298 | return hash_val; |
| 5299 | case ConstPtrSpecialSubArray: | ||
| 5300 | hash_val += (uint32_t)2643358777; | ||
| 5301 | hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val); | ||
| 5302 | hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index); | ||
| 5303 | return hash_val; | ||
| 5285 | case ConstPtrSpecialBaseStruct: | 5304 | case ConstPtrSpecialBaseStruct: |
| 5286 | hash_val += (uint32_t)3518317043; | 5305 | hash_val += (uint32_t)3518317043; |
| 5287 | hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val); | 5306 | hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val); |
| ... | @@ -5811,18 +5830,13 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) { | ... | @@ -5811,18 +5830,13 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) { |
| 5811 | // The elements array cannot be left unpopulated | 5830 | // The elements array cannot be left unpopulated |
| 5812 | ZigType *array_type = result->type; | 5831 | ZigType *array_type = result->type; |
| 5813 | ZigType *elem_type = array_type->data.array.child_type; | 5832 | ZigType *elem_type = array_type->data.array.child_type; |
| 5814 | ZigValue *sentinel_value = array_type->data.array.sentinel; | 5833 | const size_t elem_count = array_type->data.array.len; |
| 5815 | const size_t elem_count = array_type->data.array.len + (sentinel_value != nullptr); | ||
| 5816 | 5834 | ||
| 5817 | result->data.x_array.data.s_none.elements = g->pass1_arena->allocate<ZigValue>(elem_count); | 5835 | result->data.x_array.data.s_none.elements = g->pass1_arena->allocate<ZigValue>(elem_count); |
| 5818 | for (size_t i = 0; i < elem_count; i += 1) { | 5836 | for (size_t i = 0; i < elem_count; i += 1) { |
| 5819 | ZigValue *elem_val = &result->data.x_array.data.s_none.elements[i]; | 5837 | ZigValue *elem_val = &result->data.x_array.data.s_none.elements[i]; |
| 5820 | copy_const_val(g, elem_val, get_the_one_possible_value(g, elem_type)); | 5838 | copy_const_val(g, elem_val, get_the_one_possible_value(g, elem_type)); |
| 5821 | } | 5839 | } |
| 5822 | if (sentinel_value != nullptr) { | ||
| 5823 | ZigValue *last_elem_val = &result->data.x_array.data.s_none.elements[elem_count - 1]; | ||
| 5824 | copy_const_val(g, last_elem_val, sentinel_value); | ||
| 5825 | } | ||
| 5826 | } else if (result->type->id == ZigTypeIdPointer) { | 5840 | } else if (result->type->id == ZigTypeIdPointer) { |
| 5827 | result->data.x_ptr.special = ConstPtrSpecialRef; | 5841 | result->data.x_ptr.special = ConstPtrSpecialRef; |
| 5828 | result->data.x_ptr.data.ref.pointee = get_the_one_possible_value(g, result->type->data.pointer.child_type); | 5842 | result->data.x_ptr.data.ref.pointee = get_the_one_possible_value(g, result->type->data.pointer.child_type); |
| ... | @@ -6753,6 +6767,7 @@ bool const_values_equal_ptr(ZigValue *a, ZigValue *b) { | ... | @@ -6753,6 +6767,7 @@ bool const_values_equal_ptr(ZigValue *a, ZigValue *b) { |
| 6753 | return false; | 6767 | return false; |
| 6754 | return true; | 6768 | return true; |
| 6755 | case ConstPtrSpecialBaseArray: | 6769 | case ConstPtrSpecialBaseArray: |
| 6770 | case ConstPtrSpecialSubArray: | ||
| 6756 | if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val) { | 6771 | if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val) { |
| 6757 | return false; | 6772 | return false; |
| 6758 | } | 6773 | } |
| ... | @@ -7010,6 +7025,7 @@ static void render_const_val_ptr(CodeGen *g, Buf *buf, ZigValue *const_val, ZigT | ... | @@ -7010,6 +7025,7 @@ static void render_const_val_ptr(CodeGen *g, Buf *buf, ZigValue *const_val, ZigT |
| 7010 | render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); | 7025 | render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); |
| 7011 | return; | 7026 | return; |
| 7012 | case ConstPtrSpecialBaseArray: | 7027 | case ConstPtrSpecialBaseArray: |
| 7028 | case ConstPtrSpecialSubArray: | ||
| 7013 | buf_appendf(buf, "*"); | 7029 | buf_appendf(buf, "*"); |
| 7014 | // TODO we need a source node for const_ptr_pointee because it can generate compile errors | 7030 | // TODO we need a source node for const_ptr_pointee because it can generate compile errors |
| 7015 | render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); | 7031 | render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); |
src/analyze.hpp+1-1| ... | @@ -76,7 +76,7 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool all | ... | @@ -76,7 +76,7 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool all |
| 76 | 76 | ||
| 77 | ZigType *get_src_ptr_type(ZigType *type); | 77 | ZigType *get_src_ptr_type(ZigType *type); |
| 78 | uint32_t get_ptr_align(CodeGen *g, ZigType *type); | 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 | ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry); | 80 | ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry); |
| 81 | ZigType *container_ref_type(ZigType *type_entry); | 81 | ZigType *container_ref_type(ZigType *type_entry); |
| 82 | bool type_is_complete(ZigType *type_entry); | 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,12 +5413,16 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI |
| 5413 | ZigType *array_type = array_ptr_type->data.pointer.child_type; | 5413 | ZigType *array_type = array_ptr_type->data.pointer.child_type; |
| 5414 | LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); | 5414 | LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); |
| 5415 | 5415 | ||
| 5416 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); | ||
| 5417 | |||
| 5418 | bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); | 5416 | bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); |
| 5419 | 5417 | ||
| 5420 | ZigType *res_slice_ptr_type = instruction->base.value->type->data.structure.fields[slice_ptr_index]->type_entry; | 5418 | ZigType *result_type = instruction->base.value->type; |
| 5421 | ZigValue *sentinel = res_slice_ptr_type->data.pointer.sentinel; | 5419 | if (!type_has_bits(g, result_type)) { |
| 5420 | return nullptr; | ||
| 5421 | } | ||
| 5422 | |||
| 5423 | // This is not whether the result type has a sentinel, but whether there should be a sentinel check, | ||
| 5424 | // e.g. if they used [a..b :s] syntax. | ||
| 5425 | ZigValue *sentinel = instruction->sentinel; | ||
| 5422 | 5426 | ||
| 5423 | if (array_type->id == ZigTypeIdArray || | 5427 | if (array_type->id == ZigTypeIdArray || |
| 5424 | (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) | 5428 | (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) |
| ... | @@ -5453,6 +5457,8 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI | ... | @@ -5453,6 +5457,8 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI |
| 5453 | } | 5457 | } |
| 5454 | } | 5458 | } |
| 5455 | if (!type_has_bits(g, array_type)) { | 5459 | if (!type_has_bits(g, array_type)) { |
| 5460 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); | ||
| 5461 | |||
| 5456 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); | 5462 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); |
| 5457 | 5463 | ||
| 5458 | // TODO if runtime safety is on, store 0xaaaaaaa in ptr field | 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,20 +5467,26 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI |
| 5461 | return tmp_struct_ptr; | 5467 | return tmp_struct_ptr; |
| 5462 | } | 5468 | } |
| 5463 | 5469 | ||
| 5464 | |||
| 5465 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, ""); | ||
| 5466 | LLVMValueRef indices[] = { | 5470 | LLVMValueRef indices[] = { |
| 5467 | LLVMConstNull(g->builtin_types.entry_usize->llvm_type), | 5471 | LLVMConstNull(g->builtin_types.entry_usize->llvm_type), |
| 5468 | start_val, | 5472 | start_val, |
| 5469 | }; | 5473 | }; |
| 5470 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); | 5474 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); |
| 5471 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); | 5475 | if (result_type->id == ZigTypeIdPointer) { |
| 5476 | ir_assert(instruction->result_loc == nullptr, &instruction->base); | ||
| 5477 | LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); | ||
| 5478 | return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); | ||
| 5479 | } else { | ||
| 5480 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); | ||
| 5481 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, ""); | ||
| 5482 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); | ||
| 5472 | 5483 | ||
| 5473 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); | 5484 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); |
| 5474 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); | 5485 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); |
| 5475 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | 5486 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); |
| 5476 | 5487 | ||
| 5477 | return tmp_struct_ptr; | 5488 | return tmp_struct_ptr; |
| 5489 | } | ||
| 5478 | } else if (array_type->id == ZigTypeIdPointer) { | 5490 | } else if (array_type->id == ZigTypeIdPointer) { |
| 5479 | assert(array_type->data.pointer.ptr_len != PtrLenSingle); | 5491 | assert(array_type->data.pointer.ptr_len != PtrLenSingle); |
| 5480 | LLVMValueRef start_val = ir_llvm_value(g, instruction->start); | 5492 | LLVMValueRef start_val = ir_llvm_value(g, instruction->start); |
| ... | @@ -5488,24 +5500,39 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI | ... | @@ -5488,24 +5500,39 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI |
| 5488 | } | 5500 | } |
| 5489 | } | 5501 | } |
| 5490 | 5502 | ||
| 5491 | if (type_has_bits(g, array_type)) { | 5503 | if (!type_has_bits(g, array_type)) { |
| 5492 | size_t gen_ptr_index = instruction->base.value->type->data.structure.fields[slice_ptr_index]->gen_index; | 5504 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); |
| 5493 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, ""); | 5505 | size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index; |
| 5494 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, ""); | 5506 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, ""); |
| 5495 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); | 5507 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); |
| 5508 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | ||
| 5509 | return tmp_struct_ptr; | ||
| 5496 | } | 5510 | } |
| 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 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, ""); | 5526 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, ""); |
| 5500 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); | 5527 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); |
| 5501 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | 5528 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); |
| 5502 | 5529 | ||
| 5503 | return tmp_struct_ptr; | 5530 | return tmp_struct_ptr; |
| 5531 | |||
| 5504 | } else if (array_type->id == ZigTypeIdStruct) { | 5532 | } else if (array_type->id == ZigTypeIdStruct) { |
| 5505 | assert(array_type->data.structure.special == StructSpecialSlice); | 5533 | assert(array_type->data.structure.special == StructSpecialSlice); |
| 5506 | assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); | 5534 | assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); |
| 5507 | assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); | 5535 | assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); |
| 5508 | assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(tmp_struct_ptr))) == LLVMStructTypeKind); | ||
| 5509 | 5536 | ||
| 5510 | size_t ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index; | 5537 | size_t ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index; |
| 5511 | assert(ptr_index != SIZE_MAX); | 5538 | assert(ptr_index != SIZE_MAX); |
| ... | @@ -5542,15 +5569,22 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI | ... | @@ -5542,15 +5569,22 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI |
| 5542 | } | 5569 | } |
| 5543 | } | 5570 | } |
| 5544 | 5571 | ||
| 5545 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)ptr_index, ""); | ||
| 5546 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, ""); | 5572 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, ""); |
| 5547 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); | 5573 | if (result_type->id == ZigTypeIdPointer) { |
| 5574 | ir_assert(instruction->result_loc == nullptr, &instruction->base); | ||
| 5575 | LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); | ||
| 5576 | return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); | ||
| 5577 | } else { | ||
| 5578 | LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); | ||
| 5579 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)ptr_index, ""); | ||
| 5580 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); | ||
| 5548 | 5581 | ||
| 5549 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)len_index, ""); | 5582 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)len_index, ""); |
| 5550 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); | 5583 | LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); |
| 5551 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | 5584 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); |
| 5552 | 5585 | ||
| 5553 | return tmp_struct_ptr; | 5586 | return tmp_struct_ptr; |
| 5587 | } | ||
| 5554 | } else { | 5588 | } else { |
| 5555 | zig_unreachable(); | 5589 | zig_unreachable(); |
| 5556 | } | 5590 | } |
| ... | @@ -6635,7 +6669,6 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ZigValue *array_co | ... | @@ -6635,7 +6669,6 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ZigValue *array_co |
| 6635 | }; | 6669 | }; |
| 6636 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); | 6670 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); |
| 6637 | } else { | 6671 | } else { |
| 6638 | assert(parent->id == ConstParentIdScalar); | ||
| 6639 | return base_ptr; | 6672 | return base_ptr; |
| 6640 | } | 6673 | } |
| 6641 | } | 6674 | } |
| ... | @@ -6785,6 +6818,22 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Zig | ... | @@ -6785,6 +6818,22 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Zig |
| 6785 | used_bits += packed_bits_size; | 6818 | used_bits += packed_bits_size; |
| 6786 | } | 6819 | } |
| 6787 | } | 6820 | } |
| 6821 | |||
| 6822 | if (type_entry->data.array.sentinel != nullptr) { | ||
| 6823 | ZigValue *elem_val = type_entry->data.array.sentinel; | ||
| 6824 | LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, elem_val); | ||
| 6825 | |||
| 6826 | if (is_big_endian) { | ||
| 6827 | LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, packed_bits_size, false); | ||
| 6828 | val = LLVMConstShl(val, shift_amt); | ||
| 6829 | val = LLVMConstOr(val, child_val); | ||
| 6830 | } else { | ||
| 6831 | LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false); | ||
| 6832 | LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt); | ||
| 6833 | val = LLVMConstOr(val, child_val_shifted); | ||
| 6834 | used_bits += packed_bits_size; | ||
| 6835 | } | ||
| 6836 | } | ||
| 6788 | return val; | 6837 | return val; |
| 6789 | } | 6838 | } |
| 6790 | case ZigTypeIdVector: | 6839 | case ZigTypeIdVector: |
| ... | @@ -6847,24 +6896,16 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ZigValue *const_val, const cha | ... | @@ -6847,24 +6896,16 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ZigValue *const_val, const cha |
| 6847 | return const_val->llvm_value; | 6896 | return const_val->llvm_value; |
| 6848 | } | 6897 | } |
| 6849 | case ConstPtrSpecialBaseArray: | 6898 | case ConstPtrSpecialBaseArray: |
| 6899 | case ConstPtrSpecialSubArray: | ||
| 6850 | { | 6900 | { |
| 6851 | ZigValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val; | 6901 | ZigValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val; |
| 6852 | assert(array_const_val->type->id == ZigTypeIdArray); | 6902 | assert(array_const_val->type->id == ZigTypeIdArray); |
| 6853 | if (!type_has_bits(g, array_const_val->type)) { | 6903 | if (!type_has_bits(g, array_const_val->type)) { |
| 6854 | if (array_const_val->type->data.array.sentinel != nullptr) { | 6904 | // make this a null pointer |
| 6855 | ZigValue *pointee = array_const_val->type->data.array.sentinel; | 6905 | ZigType *usize = g->builtin_types.entry_usize; |
| 6856 | render_const_val(g, pointee, ""); | 6906 | const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), |
| 6857 | render_const_val_global(g, pointee, ""); | 6907 | get_llvm_type(g, const_val->type)); |
| 6858 | const_val->llvm_value = LLVMConstBitCast(pointee->llvm_global, | 6908 | return const_val->llvm_value; |
| 6859 | get_llvm_type(g, const_val->type)); | ||
| 6860 | return const_val->llvm_value; | ||
| 6861 | } else { | ||
| 6862 | // make this a null pointer | ||
| 6863 | ZigType *usize = g->builtin_types.entry_usize; | ||
| 6864 | const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), | ||
| 6865 | get_llvm_type(g, const_val->type)); | ||
| 6866 | return const_val->llvm_value; | ||
| 6867 | } | ||
| 6868 | } | 6909 | } |
| 6869 | size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; | 6910 | size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; |
| 6870 | LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, elem_index); | 6911 | LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, elem_index); |
| ... | @@ -9644,6 +9685,21 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose | ... | @@ -9644,6 +9685,21 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose |
| 9644 | return ErrorNone; | 9685 | return ErrorNone; |
| 9645 | } | 9686 | } |
| 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 | // returns true if it was a cache miss | 9703 | // returns true if it was a cache miss |
| 9648 | static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { | 9704 | static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { |
| 9649 | Error err; | 9705 | Error err; |
| ... | @@ -9661,7 +9717,12 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { | ... | @@ -9661,7 +9717,12 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { |
| 9661 | buf_len(c_source_basename), 0); | 9717 | buf_len(c_source_basename), 0); |
| 9662 | 9718 | ||
| 9663 | Buf *final_o_basename = buf_alloc(); | 9719 | Buf *final_o_basename = buf_alloc(); |
| 9664 | os_path_extname(c_source_basename, final_o_basename, nullptr); | 9720 | // We special case when doing build-obj for just one C file |
| 9721 | if (main_output_dir_is_just_one_c_object_pre(g)) { | ||
| 9722 | buf_init_from_buf(final_o_basename, g->root_out_name); | ||
| 9723 | } else { | ||
| 9724 | os_path_extname(c_source_basename, final_o_basename, nullptr); | ||
| 9725 | } | ||
| 9665 | buf_append_str(final_o_basename, target_o_file_ext(g->zig_target)); | 9726 | buf_append_str(final_o_basename, target_o_file_ext(g->zig_target)); |
| 9666 | 9727 | ||
| 9667 | CacheHash *cache_hash; | 9728 | CacheHash *cache_hash; |
| ... | @@ -10461,10 +10522,6 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { | ... | @@ -10461,10 +10522,6 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { |
| 10461 | return ErrorNone; | 10522 | return ErrorNone; |
| 10462 | } | 10523 | } |
| 10463 | 10524 | ||
| 10464 | static bool need_llvm_module(CodeGen *g) { | ||
| 10465 | return buf_len(&g->main_pkg->root_src_path) != 0; | ||
| 10466 | } | ||
| 10467 | |||
| 10468 | static void resolve_out_paths(CodeGen *g) { | 10525 | static void resolve_out_paths(CodeGen *g) { |
| 10469 | assert(g->output_dir != nullptr); | 10526 | assert(g->output_dir != nullptr); |
| 10470 | assert(g->root_out_name != nullptr); | 10527 | assert(g->root_out_name != nullptr); |
| ... | @@ -10476,10 +10533,6 @@ static void resolve_out_paths(CodeGen *g) { | ... | @@ -10476,10 +10533,6 @@ static void resolve_out_paths(CodeGen *g) { |
| 10476 | case OutTypeUnknown: | 10533 | case OutTypeUnknown: |
| 10477 | zig_unreachable(); | 10534 | zig_unreachable(); |
| 10478 | case OutTypeObj: | 10535 | case OutTypeObj: |
| 10479 | if (g->enable_cache && g->link_objects.length == 1 && !need_llvm_module(g)) { | ||
| 10480 | buf_init_from_buf(&g->bin_file_output_path, g->link_objects.at(0)); | ||
| 10481 | return; | ||
| 10482 | } | ||
| 10483 | if (need_llvm_module(g) && g->link_objects.length != 0 && !g->enable_cache && | 10536 | if (need_llvm_module(g) && g->link_objects.length != 0 && !g->enable_cache && |
| 10484 | buf_eql_buf(o_basename, out_basename)) | 10537 | buf_eql_buf(o_basename, out_basename)) |
| 10485 | { | 10538 | { |
| ... | @@ -10574,6 +10627,16 @@ static void output_type_information(CodeGen *g) { | ... | @@ -10574,6 +10627,16 @@ static void output_type_information(CodeGen *g) { |
| 10574 | } | 10627 | } |
| 10575 | } | 10628 | } |
| 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 | void codegen_build_and_link(CodeGen *g) { | 10640 | void codegen_build_and_link(CodeGen *g) { |
| 10578 | Error err; | 10641 | Error err; |
| 10579 | assert(g->out_type != OutTypeUnknown); | 10642 | assert(g->out_type != OutTypeUnknown); |
| ... | @@ -10616,8 +10679,7 @@ void codegen_build_and_link(CodeGen *g) { | ... | @@ -10616,8 +10679,7 @@ void codegen_build_and_link(CodeGen *g) { |
| 10616 | } | 10679 | } |
| 10617 | 10680 | ||
| 10618 | if (g->enable_cache && buf_len(&digest) != 0) { | 10681 | if (g->enable_cache && buf_len(&digest) != 0) { |
| 10619 | g->output_dir = buf_sprintf("%s" OS_SEP CACHE_OUT_SUBDIR OS_SEP "%s", | 10682 | init_output_dir(g, &digest); |
| 10620 | buf_ptr(g->cache_dir), buf_ptr(&digest)); | ||
| 10621 | resolve_out_paths(g); | 10683 | resolve_out_paths(g); |
| 10622 | } else { | 10684 | } else { |
| 10623 | if (need_llvm_module(g)) { | 10685 | if (need_llvm_module(g)) { |
| ... | @@ -10638,8 +10700,7 @@ void codegen_build_and_link(CodeGen *g) { | ... | @@ -10638,8 +10700,7 @@ void codegen_build_and_link(CodeGen *g) { |
| 10638 | exit(1); | 10700 | exit(1); |
| 10639 | } | 10701 | } |
| 10640 | } | 10702 | } |
| 10641 | g->output_dir = buf_sprintf("%s" OS_SEP CACHE_OUT_SUBDIR OS_SEP "%s", | 10703 | init_output_dir(g, &digest); |
| 10642 | buf_ptr(g->cache_dir), buf_ptr(&digest)); | ||
| 10643 | 10704 | ||
| 10644 | if ((err = os_make_path(g->output_dir))) { | 10705 | if ((err = os_make_path(g->output_dir))) { |
| 10645 | fprintf(stderr, "Unable to create output directory: %s\n", err_str(err)); | 10706 | fprintf(stderr, "Unable to create output directory: %s\n", err_str(err)); |
src/ir.cpp+327-96| ... | @@ -784,14 +784,32 @@ static ZigValue *const_ptr_pointee_unchecked_no_isf(CodeGen *g, ZigValue *const_ | ... | @@ -784,14 +784,32 @@ static ZigValue *const_ptr_pointee_unchecked_no_isf(CodeGen *g, ZigValue *const_ |
| 784 | break; | 784 | break; |
| 785 | case ConstPtrSpecialBaseArray: { | 785 | case ConstPtrSpecialBaseArray: { |
| 786 | ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val; | 786 | ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val; |
| 787 | if (const_val->data.x_ptr.data.base_array.elem_index == array_val->type->data.array.len) { | 787 | size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; |
| 788 | if (elem_index == array_val->type->data.array.len) { | ||
| 788 | result = array_val->type->data.array.sentinel; | 789 | result = array_val->type->data.array.sentinel; |
| 789 | } else { | 790 | } else { |
| 790 | expand_undef_array(g, array_val); | 791 | expand_undef_array(g, array_val); |
| 791 | result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index]; | 792 | result = &array_val->data.x_array.data.s_none.elements[elem_index]; |
| 792 | } | 793 | } |
| 793 | break; | 794 | break; |
| 794 | } | 795 | } |
| 796 | case ConstPtrSpecialSubArray: { | ||
| 797 | ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val; | ||
| 798 | size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; | ||
| 799 | |||
| 800 | // TODO handle sentinel terminated arrays | ||
| 801 | expand_undef_array(g, array_val); | ||
| 802 | result = g->pass1_arena->create<ZigValue>(); | ||
| 803 | result->special = array_val->special; | ||
| 804 | result->type = get_array_type(g, array_val->type->data.array.child_type, | ||
| 805 | array_val->type->data.array.len - elem_index, nullptr); | ||
| 806 | result->data.x_array.special = ConstArraySpecialNone; | ||
| 807 | result->data.x_array.data.s_none.elements = &array_val->data.x_array.data.s_none.elements[elem_index]; | ||
| 808 | result->parent.id = ConstParentIdArray; | ||
| 809 | result->parent.data.p_array.array_val = array_val; | ||
| 810 | result->parent.data.p_array.elem_index = elem_index; | ||
| 811 | break; | ||
| 812 | } | ||
| 795 | case ConstPtrSpecialBaseStruct: { | 813 | case ConstPtrSpecialBaseStruct: { |
| 796 | ZigValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val; | 814 | ZigValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val; |
| 797 | expand_undef_struct(g, struct_val); | 815 | expand_undef_struct(g, struct_val); |
| ... | @@ -849,11 +867,6 @@ static bool is_slice(ZigType *type) { | ... | @@ -849,11 +867,6 @@ static bool is_slice(ZigType *type) { |
| 849 | return type->id == ZigTypeIdStruct && type->data.structure.special == StructSpecialSlice; | 867 | return type->id == ZigTypeIdStruct && type->data.structure.special == StructSpecialSlice; |
| 850 | } | 868 | } |
| 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 | // This function returns true when you can change the type of a ZigValue and the | 870 | // This function returns true when you can change the type of a ZigValue and the |
| 858 | // value remains meaningful. | 871 | // value remains meaningful. |
| 859 | static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expected, ZigType *actual) { | 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,7 +3732,8 @@ static IrInstSrc *ir_build_slice_src(IrBuilderSrc *irb, Scope *scope, AstNode *s |
| 3719 | } | 3732 | } |
| 3720 | 3733 | ||
| 3721 | static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *slice_type, | 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 | IrInstGenSlice *instruction = ir_build_inst_gen<IrInstGenSlice>( | 3738 | IrInstGenSlice *instruction = ir_build_inst_gen<IrInstGenSlice>( |
| 3725 | &ira->new_irb, source_instruction->scope, source_instruction->source_node); | 3739 | &ira->new_irb, source_instruction->scope, source_instruction->source_node); |
| ... | @@ -3729,11 +3743,12 @@ static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction, | ... | @@ -3729,11 +3743,12 @@ static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction, |
| 3729 | instruction->end = end; | 3743 | instruction->end = end; |
| 3730 | instruction->safety_check_on = safety_check_on; | 3744 | instruction->safety_check_on = safety_check_on; |
| 3731 | instruction->result_loc = result_loc; | 3745 | instruction->result_loc = result_loc; |
| 3746 | instruction->sentinel = sentinel; | ||
| 3732 | 3747 | ||
| 3733 | ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block); | 3748 | ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block); |
| 3734 | ir_ref_inst_gen(start, ira->new_irb.current_basic_block); | 3749 | ir_ref_inst_gen(start, ira->new_irb.current_basic_block); |
| 3735 | if (end) ir_ref_inst_gen(end, ira->new_irb.current_basic_block); | 3750 | if (end != nullptr) ir_ref_inst_gen(end, ira->new_irb.current_basic_block); |
| 3736 | ir_ref_inst_gen(result_loc, ira->new_irb.current_basic_block); | 3751 | if (result_loc != nullptr) ir_ref_inst_gen(result_loc, ira->new_irb.current_basic_block); |
| 3737 | 3752 | ||
| 3738 | return &instruction->base; | 3753 | return &instruction->base; |
| 3739 | } | 3754 | } |
| ... | @@ -12644,41 +12659,80 @@ static IrInstGen *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInst* sourc | ... | @@ -12644,41 +12659,80 @@ static IrInstGen *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInst* sourc |
| 12644 | Error err; | 12659 | Error err; |
| 12645 | 12660 | ||
| 12646 | assert(array_ptr->value->type->id == ZigTypeIdPointer); | 12661 | assert(array_ptr->value->type->id == ZigTypeIdPointer); |
| 12662 | assert(array_ptr->value->type->data.pointer.child_type->id == ZigTypeIdArray); | ||
| 12663 | |||
| 12664 | ZigType *array_type = array_ptr->value->type->data.pointer.child_type; | ||
| 12665 | size_t array_len = array_type->data.array.len; | ||
| 12666 | |||
| 12667 | // A zero-sized array can be casted regardless of the destination alignment, or | ||
| 12668 | // whether the pointer is undefined, and the result is always comptime known. | ||
| 12669 | // TODO However, this is exposing a result location bug that I failed to solve on the first try. | ||
| 12670 | // If you want to try to fix the bug, uncomment this block and get the tests passing. | ||
| 12671 | //if (array_len == 0 && array_type->data.array.sentinel == nullptr) { | ||
| 12672 | // ZigValue *undef_array = ira->codegen->pass1_arena->create<ZigValue>(); | ||
| 12673 | // undef_array->special = ConstValSpecialUndef; | ||
| 12674 | // undef_array->type = array_type; | ||
| 12675 | |||
| 12676 | // IrInstGen *result = ir_const(ira, source_instr, wanted_type); | ||
| 12677 | // init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false); | ||
| 12678 | // result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst; | ||
| 12679 | // result->value->type = wanted_type; | ||
| 12680 | // return result; | ||
| 12681 | //} | ||
| 12647 | 12682 | ||
| 12648 | if ((err = type_resolve(ira->codegen, array_ptr->value->type, ResolveStatusAlignmentKnown))) { | 12683 | if ((err = type_resolve(ira->codegen, array_ptr->value->type, ResolveStatusAlignmentKnown))) { |
| 12649 | return ira->codegen->invalid_inst_gen; | 12684 | return ira->codegen->invalid_inst_gen; |
| 12650 | } | 12685 | } |
| 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 | if (array_len != 0) { | 12687 | if (array_len != 0) { |
| 12659 | wanted_type = adjust_slice_align(ira->codegen, wanted_type, | 12688 | wanted_type = adjust_slice_align(ira->codegen, wanted_type, |
| 12660 | get_ptr_align(ira->codegen, array_ptr->value->type)); | 12689 | get_ptr_align(ira->codegen, array_ptr->value->type)); |
| 12661 | } | 12690 | } |
| 12662 | 12691 | ||
| 12663 | if (instr_is_comptime(array_ptr)) { | 12692 | if (instr_is_comptime(array_ptr)) { |
| 12664 | ZigValue *array_ptr_val = ir_resolve_const(ira, array_ptr, UndefBad); | 12693 | UndefAllowed undef_allowed = (array_len == 0) ? UndefOk : UndefBad; |
| 12694 | ZigValue *array_ptr_val = ir_resolve_const(ira, array_ptr, undef_allowed); | ||
| 12665 | if (array_ptr_val == nullptr) | 12695 | if (array_ptr_val == nullptr) |
| 12666 | return ira->codegen->invalid_inst_gen; | 12696 | return ira->codegen->invalid_inst_gen; |
| 12667 | ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, array_ptr_val, source_instr->source_node); | 12697 | ir_assert(is_slice(wanted_type), source_instr); |
| 12668 | if (pointee == nullptr) | 12698 | if (array_ptr_val->special == ConstValSpecialUndef) { |
| 12669 | return ira->codegen->invalid_inst_gen; | 12699 | ZigValue *undef_array = ira->codegen->pass1_arena->create<ZigValue>(); |
| 12670 | if (pointee->special != ConstValSpecialRuntime) { | 12700 | undef_array->special = ConstValSpecialUndef; |
| 12671 | assert(array_ptr_val->type->id == ZigTypeIdPointer); | 12701 | undef_array->type = array_type; |
| 12672 | ZigType *array_type = array_ptr_val->type->data.pointer.child_type; | ||
| 12673 | assert(is_slice(wanted_type)); | ||
| 12674 | bool is_const = wanted_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const; | ||
| 12675 | 12702 | ||
| 12676 | IrInstGen *result = ir_const(ira, source_instr, wanted_type); | 12703 | IrInstGen *result = ir_const(ira, source_instr, wanted_type); |
| 12677 | init_const_slice(ira->codegen, result->value, pointee, 0, array_type->data.array.len, is_const); | 12704 | init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false); |
| 12678 | result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut; | 12705 | result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst; |
| 12679 | result->value->type = wanted_type; | 12706 | result->value->type = wanted_type; |
| 12680 | return result; | 12707 | return result; |
| 12681 | } | 12708 | } |
| 12709 | bool wanted_const = wanted_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const; | ||
| 12710 | // Optimization to avoid creating unnecessary ZigValue in const_ptr_pointee | ||
| 12711 | if (array_ptr_val->data.x_ptr.special == ConstPtrSpecialSubArray) { | ||
| 12712 | ZigValue *array_val = array_ptr_val->data.x_ptr.data.base_array.array_val; | ||
| 12713 | if (array_val->special != ConstValSpecialRuntime) { | ||
| 12714 | IrInstGen *result = ir_const(ira, source_instr, wanted_type); | ||
| 12715 | init_const_slice(ira->codegen, result->value, array_val, | ||
| 12716 | array_ptr_val->data.x_ptr.data.base_array.elem_index, | ||
| 12717 | array_type->data.array.len, wanted_const); | ||
| 12718 | result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut; | ||
| 12719 | result->value->type = wanted_type; | ||
| 12720 | return result; | ||
| 12721 | } | ||
| 12722 | } else { | ||
| 12723 | ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, array_ptr_val, source_instr->source_node); | ||
| 12724 | if (pointee == nullptr) | ||
| 12725 | return ira->codegen->invalid_inst_gen; | ||
| 12726 | if (pointee->special != ConstValSpecialRuntime) { | ||
| 12727 | assert(array_ptr_val->type->id == ZigTypeIdPointer); | ||
| 12728 | |||
| 12729 | IrInstGen *result = ir_const(ira, source_instr, wanted_type); | ||
| 12730 | init_const_slice(ira->codegen, result->value, pointee, 0, array_type->data.array.len, wanted_const); | ||
| 12731 | result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut; | ||
| 12732 | result->value->type = wanted_type; | ||
| 12733 | return result; | ||
| 12734 | } | ||
| 12735 | } | ||
| 12682 | } | 12736 | } |
| 12683 | 12737 | ||
| 12684 | if (result_loc == nullptr) result_loc = no_result_loc(); | 12738 | if (result_loc == nullptr) result_loc = no_result_loc(); |
| ... | @@ -14548,7 +14602,7 @@ static IrInstGen *ir_analyze_cast(IrAnalyze *ira, IrInst *source_instr, | ... | @@ -14548,7 +14602,7 @@ static IrInstGen *ir_analyze_cast(IrAnalyze *ira, IrInst *source_instr, |
| 14548 | return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); | 14602 | return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); |
| 14549 | } | 14603 | } |
| 14550 | 14604 | ||
| 14551 | // *[N]T to ?[]const T | 14605 | // *[N]T to ?[]T |
| 14552 | if (wanted_type->id == ZigTypeIdOptional && | 14606 | if (wanted_type->id == ZigTypeIdOptional && |
| 14553 | is_slice(wanted_type->data.maybe.child_type) && | 14607 | is_slice(wanted_type->data.maybe.child_type) && |
| 14554 | actual_type->id == ZigTypeIdPointer && | 14608 | actual_type->id == ZigTypeIdPointer && |
| ... | @@ -19884,6 +19938,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source | ... | @@ -19884,6 +19938,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source |
| 19884 | buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf), pointee); | 19938 | buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf), pointee); |
| 19885 | if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) | 19939 | if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) |
| 19886 | return err; | 19940 | return err; |
| 19941 | buf_deinit(&buf); | ||
| 19887 | return ErrorNone; | 19942 | return ErrorNone; |
| 19888 | } | 19943 | } |
| 19889 | 19944 | ||
| ... | @@ -19903,6 +19958,31 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source | ... | @@ -19903,6 +19958,31 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source |
| 19903 | dst_size, buf_ptr(&pointee->type->name), src_size)); | 19958 | dst_size, buf_ptr(&pointee->type->name), src_size)); |
| 19904 | return ErrorSemanticAnalyzeFail; | 19959 | return ErrorSemanticAnalyzeFail; |
| 19905 | } | 19960 | } |
| 19961 | case ConstPtrSpecialSubArray: { | ||
| 19962 | ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val; | ||
| 19963 | assert(array_val->type->id == ZigTypeIdArray); | ||
| 19964 | if (array_val->data.x_array.special != ConstArraySpecialNone) | ||
| 19965 | zig_panic("TODO"); | ||
| 19966 | if (dst_size > src_size) { | ||
| 19967 | size_t elem_index = ptr_val->data.x_ptr.data.base_array.elem_index; | ||
| 19968 | opt_ir_add_error_node(ira, codegen, source_node, | ||
| 19969 | buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from %s at index %" ZIG_PRI_usize " which is %" ZIG_PRI_usize " bytes", | ||
| 19970 | dst_size, buf_ptr(&array_val->type->name), elem_index, src_size)); | ||
| 19971 | return ErrorSemanticAnalyzeFail; | ||
| 19972 | } | ||
| 19973 | size_t elem_size = src_size; | ||
| 19974 | size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1); | ||
| 19975 | Buf buf = BUF_INIT; | ||
| 19976 | buf_resize(&buf, elem_count * elem_size); | ||
| 19977 | for (size_t i = 0; i < elem_count; i += 1) { | ||
| 19978 | ZigValue *elem_val = &array_val->data.x_array.data.s_none.elements[i]; | ||
| 19979 | buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); | ||
| 19980 | } | ||
| 19981 | if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) | ||
| 19982 | return err; | ||
| 19983 | buf_deinit(&buf); | ||
| 19984 | return ErrorNone; | ||
| 19985 | } | ||
| 19906 | case ConstPtrSpecialBaseArray: { | 19986 | case ConstPtrSpecialBaseArray: { |
| 19907 | ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val; | 19987 | ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val; |
| 19908 | assert(array_val->type->id == ZigTypeIdArray); | 19988 | assert(array_val->type->id == ZigTypeIdArray); |
| ... | @@ -19926,6 +20006,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source | ... | @@ -19926,6 +20006,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source |
| 19926 | } | 20006 | } |
| 19927 | if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) | 20007 | if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) |
| 19928 | return err; | 20008 | return err; |
| 20009 | buf_deinit(&buf); | ||
| 19929 | return ErrorNone; | 20010 | return ErrorNone; |
| 19930 | } | 20011 | } |
| 19931 | case ConstPtrSpecialBaseStruct: | 20012 | case ConstPtrSpecialBaseStruct: |
| ... | @@ -20505,6 +20586,44 @@ static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_ | ... | @@ -20505,6 +20586,44 @@ static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_ |
| 20505 | allow_zero); | 20586 | allow_zero); |
| 20506 | } | 20587 | } |
| 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 | static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemPtr *elem_ptr_instruction) { | 20627 | static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemPtr *elem_ptr_instruction) { |
| 20509 | Error err; | 20628 | Error err; |
| 20510 | IrInstGen *array_ptr = elem_ptr_instruction->array_ptr->child; | 20629 | IrInstGen *array_ptr = elem_ptr_instruction->array_ptr->child; |
| ... | @@ -20545,11 +20664,6 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP | ... | @@ -20545,11 +20664,6 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP |
| 20545 | } | 20664 | } |
| 20546 | 20665 | ||
| 20547 | if (array_type->id == ZigTypeIdArray) { | 20666 | if (array_type->id == ZigTypeIdArray) { |
| 20548 | if (array_type->data.array.len == 0) { | ||
| 20549 | ir_add_error_node(ira, elem_ptr_instruction->base.base.source_node, | ||
| 20550 | buf_sprintf("index 0 outside array of size 0")); | ||
| 20551 | return ira->codegen->invalid_inst_gen; | ||
| 20552 | } | ||
| 20553 | ZigType *child_type = array_type->data.array.child_type; | 20667 | ZigType *child_type = array_type->data.array.child_type; |
| 20554 | if (ptr_type->data.pointer.host_int_bytes == 0) { | 20668 | if (ptr_type->data.pointer.host_int_bytes == 0) { |
| 20555 | return_type = get_pointer_to_type_extra(ira->codegen, child_type, | 20669 | return_type = get_pointer_to_type_extra(ira->codegen, child_type, |
| ... | @@ -20648,29 +20762,11 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP | ... | @@ -20648,29 +20762,11 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP |
| 20648 | get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index, | 20762 | get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index, |
| 20649 | nullptr, nullptr); | 20763 | nullptr, nullptr); |
| 20650 | } else if (return_type->data.pointer.explicit_alignment != 0) { | 20764 | } else if (return_type->data.pointer.explicit_alignment != 0) { |
| 20651 | // figure out the largest alignment possible | 20765 | uint32_t chosen_align; |
| 20652 | 20766 | if ((err = compute_elem_align(ira, return_type->data.pointer.child_type, | |
| 20653 | if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown))) | 20767 | return_type->data.pointer.explicit_alignment, index, &chosen_align))) |
| 20768 | { | ||
| 20654 | return ira->codegen->invalid_inst_gen; | 20769 | return ira->codegen->invalid_inst_gen; |
| 20655 | |||
| 20656 | uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type); | ||
| 20657 | uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type); | ||
| 20658 | uint64_t ptr_align = get_ptr_align(ira->codegen, return_type); | ||
| 20659 | |||
| 20660 | uint64_t chosen_align = abi_align; | ||
| 20661 | if (ptr_align >= abi_align) { | ||
| 20662 | while (ptr_align > abi_align) { | ||
| 20663 | if ((index * elem_size) % ptr_align == 0) { | ||
| 20664 | chosen_align = ptr_align; | ||
| 20665 | break; | ||
| 20666 | } | ||
| 20667 | ptr_align >>= 1; | ||
| 20668 | } | ||
| 20669 | } else if (elem_size >= ptr_align && elem_size % ptr_align == 0) { | ||
| 20670 | chosen_align = ptr_align; | ||
| 20671 | } else { | ||
| 20672 | // can't get here because guaranteed elem_size >= abi_align | ||
| 20673 | zig_unreachable(); | ||
| 20674 | } | 20770 | } |
| 20675 | return_type = adjust_ptr_align(ira->codegen, return_type, chosen_align); | 20771 | return_type = adjust_ptr_align(ira->codegen, return_type, chosen_align); |
| 20676 | } | 20772 | } |
| ... | @@ -20791,6 +20887,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP | ... | @@ -20791,6 +20887,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP |
| 20791 | } | 20887 | } |
| 20792 | break; | 20888 | break; |
| 20793 | case ConstPtrSpecialBaseArray: | 20889 | case ConstPtrSpecialBaseArray: |
| 20890 | case ConstPtrSpecialSubArray: | ||
| 20794 | { | 20891 | { |
| 20795 | size_t offset = array_ptr_val->data.x_ptr.data.base_array.elem_index; | 20892 | size_t offset = array_ptr_val->data.x_ptr.data.base_array.elem_index; |
| 20796 | new_index = offset + index; | 20893 | new_index = offset + index; |
| ... | @@ -20861,6 +20958,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP | ... | @@ -20861,6 +20958,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP |
| 20861 | out_val->data.x_ptr.special = ConstPtrSpecialRef; | 20958 | out_val->data.x_ptr.special = ConstPtrSpecialRef; |
| 20862 | out_val->data.x_ptr.data.ref.pointee = ptr_field->data.x_ptr.data.ref.pointee; | 20959 | out_val->data.x_ptr.data.ref.pointee = ptr_field->data.x_ptr.data.ref.pointee; |
| 20863 | break; | 20960 | break; |
| 20961 | case ConstPtrSpecialSubArray: | ||
| 20864 | case ConstPtrSpecialBaseArray: | 20962 | case ConstPtrSpecialBaseArray: |
| 20865 | { | 20963 | { |
| 20866 | size_t offset = ptr_field->data.x_ptr.data.base_array.elem_index; | 20964 | size_t offset = ptr_field->data.x_ptr.data.base_array.elem_index; |
| ... | @@ -25412,11 +25510,22 @@ static IrInstGen *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstSrcE | ... | @@ -25412,11 +25510,22 @@ static IrInstGen *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstSrcE |
| 25412 | static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { | 25510 | static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { |
| 25413 | Error err; | 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 | assert(ptr_type != nullptr); | 25520 | assert(ptr_type != nullptr); |
| 25417 | if (ptr_type->id == ZigTypeIdPointer) { | 25521 | if (ptr_type->id == ZigTypeIdPointer) { |
| 25418 | if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) | 25522 | if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) |
| 25419 | return err; | 25523 | return err; |
| 25524 | } else if (is_slice(ptr_type)) { | ||
| 25525 | TypeStructField *ptr_field = ptr_type->data.structure.fields[slice_ptr_index]; | ||
| 25526 | ZigType *slice_ptr_type = resolve_struct_field_type(ira->codegen, ptr_field); | ||
| 25527 | if ((err = type_resolve(ira->codegen, slice_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) | ||
| 25528 | return err; | ||
| 25420 | } | 25529 | } |
| 25421 | 25530 | ||
| 25422 | *result_align = get_ptr_align(ira->codegen, ty); | 25531 | *result_align = get_ptr_align(ira->codegen, ty); |
| ... | @@ -25871,6 +25980,7 @@ static IrInstGen *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstSrcMemset | ... | @@ -25871,6 +25980,7 @@ static IrInstGen *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstSrcMemset |
| 25871 | start = 0; | 25980 | start = 0; |
| 25872 | bound_end = 1; | 25981 | bound_end = 1; |
| 25873 | break; | 25982 | break; |
| 25983 | case ConstPtrSpecialSubArray: | ||
| 25874 | case ConstPtrSpecialBaseArray: | 25984 | case ConstPtrSpecialBaseArray: |
| 25875 | { | 25985 | { |
| 25876 | ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; | 25986 | ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; |
| ... | @@ -26004,6 +26114,7 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy | ... | @@ -26004,6 +26114,7 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy |
| 26004 | dest_start = 0; | 26114 | dest_start = 0; |
| 26005 | dest_end = 1; | 26115 | dest_end = 1; |
| 26006 | break; | 26116 | break; |
| 26117 | case ConstPtrSpecialSubArray: | ||
| 26007 | case ConstPtrSpecialBaseArray: | 26118 | case ConstPtrSpecialBaseArray: |
| 26008 | { | 26119 | { |
| 26009 | ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; | 26120 | ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; |
| ... | @@ -26047,6 +26158,7 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy | ... | @@ -26047,6 +26158,7 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy |
| 26047 | src_start = 0; | 26158 | src_start = 0; |
| 26048 | src_end = 1; | 26159 | src_end = 1; |
| 26049 | break; | 26160 | break; |
| 26161 | case ConstPtrSpecialSubArray: | ||
| 26050 | case ConstPtrSpecialBaseArray: | 26162 | case ConstPtrSpecialBaseArray: |
| 26051 | { | 26163 | { |
| 26052 | ZigValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val; | 26164 | ZigValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val; |
| ... | @@ -26090,7 +26202,19 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy | ... | @@ -26090,7 +26202,19 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy |
| 26090 | return ir_build_memcpy_gen(ira, &instruction->base.base, casted_dest_ptr, casted_src_ptr, casted_count); | 26202 | return ir_build_memcpy_gen(ira, &instruction->base.base, casted_dest_ptr, casted_src_ptr, casted_count); |
| 26091 | } | 26203 | } |
| 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 | static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *instruction) { | 26215 | static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *instruction) { |
| 26216 | Error err; | ||
| 26217 | |||
| 26094 | IrInstGen *ptr_ptr = instruction->ptr->child; | 26218 | IrInstGen *ptr_ptr = instruction->ptr->child; |
| 26095 | if (type_is_invalid(ptr_ptr->value->type)) | 26219 | if (type_is_invalid(ptr_ptr->value->type)) |
| 26096 | return ira->codegen->invalid_inst_gen; | 26220 | return ira->codegen->invalid_inst_gen; |
| ... | @@ -26120,6 +26244,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i | ... | @@ -26120,6 +26244,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26120 | end = nullptr; | 26244 | end = nullptr; |
| 26121 | } | 26245 | } |
| 26122 | 26246 | ||
| 26247 | ZigValue *slice_sentinel_val = nullptr; | ||
| 26123 | ZigType *non_sentinel_slice_ptr_type; | 26248 | ZigType *non_sentinel_slice_ptr_type; |
| 26124 | ZigType *elem_type; | 26249 | ZigType *elem_type; |
| 26125 | 26250 | ||
| ... | @@ -26170,6 +26295,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i | ... | @@ -26170,6 +26295,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26170 | } | 26295 | } |
| 26171 | } else if (is_slice(array_type)) { | 26296 | } else if (is_slice(array_type)) { |
| 26172 | ZigType *maybe_sentineled_slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; | 26297 | ZigType *maybe_sentineled_slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; |
| 26298 | slice_sentinel_val = maybe_sentineled_slice_ptr_type->data.pointer.sentinel; | ||
| 26173 | non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr); | 26299 | non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr); |
| 26174 | elem_type = non_sentinel_slice_ptr_type->data.pointer.child_type; | 26300 | elem_type = non_sentinel_slice_ptr_type->data.pointer.child_type; |
| 26175 | } else { | 26301 | } else { |
| ... | @@ -26178,7 +26304,6 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i | ... | @@ -26178,7 +26304,6 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26178 | return ira->codegen->invalid_inst_gen; | 26304 | return ira->codegen->invalid_inst_gen; |
| 26179 | } | 26305 | } |
| 26180 | 26306 | ||
| 26181 | ZigType *return_type; | ||
| 26182 | ZigValue *sentinel_val = nullptr; | 26307 | ZigValue *sentinel_val = nullptr; |
| 26183 | if (instruction->sentinel) { | 26308 | if (instruction->sentinel) { |
| 26184 | IrInstGen *uncasted_sentinel = instruction->sentinel->child; | 26309 | IrInstGen *uncasted_sentinel = instruction->sentinel->child; |
| ... | @@ -26190,11 +26315,76 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i | ... | @@ -26190,11 +26315,76 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26190 | sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); | 26315 | sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); |
| 26191 | if (sentinel_val == nullptr) | 26316 | if (sentinel_val == nullptr) |
| 26192 | return ira->codegen->invalid_inst_gen; | 26317 | return ira->codegen->invalid_inst_gen; |
| 26193 | ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, sentinel_val); | 26318 | } |
| 26319 | |||
| 26320 | ZigType *child_array_type = (array_type->id == ZigTypeIdPointer && | ||
| 26321 | array_type->data.pointer.ptr_len == PtrLenSingle) ? array_type->data.pointer.child_type : array_type; | ||
| 26322 | |||
| 26323 | ZigType *return_type; | ||
| 26324 | |||
| 26325 | // If start index and end index are both comptime known, then the result type is a pointer to array | ||
| 26326 | // not a slice. However, if the start or end index is a lazy value, and the result location is a slice, | ||
| 26327 | // then the pointer-to-array would be casted to a slice anyway. So, we preserve the laziness of these | ||
| 26328 | // values by making the return type a slice. | ||
| 26329 | ZigType *res_loc_type = get_result_loc_type(ira, instruction->result_loc); | ||
| 26330 | bool result_loc_is_slice = (res_loc_type != nullptr && is_slice(res_loc_type)); | ||
| 26331 | bool end_is_known = !result_loc_is_slice && | ||
| 26332 | ((end != nullptr && value_is_comptime(end->value)) || | ||
| 26333 | (end == nullptr && child_array_type->id == ZigTypeIdArray)); | ||
| 26334 | |||
| 26335 | ZigValue *array_sentinel = sentinel_val; | ||
| 26336 | if (end_is_known) { | ||
| 26337 | uint64_t end_scalar; | ||
| 26338 | if (end != nullptr) { | ||
| 26339 | ZigValue *end_val = ir_resolve_const(ira, end, UndefBad); | ||
| 26340 | if (!end_val) | ||
| 26341 | return ira->codegen->invalid_inst_gen; | ||
| 26342 | end_scalar = bigint_as_u64(&end_val->data.x_bigint); | ||
| 26343 | } else { | ||
| 26344 | end_scalar = child_array_type->data.array.len; | ||
| 26345 | } | ||
| 26346 | array_sentinel = (child_array_type->id == ZigTypeIdArray && end_scalar == child_array_type->data.array.len) | ||
| 26347 | ? child_array_type->data.array.sentinel : sentinel_val; | ||
| 26348 | |||
| 26349 | if (value_is_comptime(casted_start->value)) { | ||
| 26350 | ZigValue *start_val = ir_resolve_const(ira, casted_start, UndefBad); | ||
| 26351 | if (!start_val) | ||
| 26352 | return ira->codegen->invalid_inst_gen; | ||
| 26353 | |||
| 26354 | uint64_t start_scalar = bigint_as_u64(&start_val->data.x_bigint); | ||
| 26355 | |||
| 26356 | if (start_scalar > end_scalar) { | ||
| 26357 | ir_add_error(ira, &instruction->base.base, buf_sprintf("out of bounds slice")); | ||
| 26358 | return ira->codegen->invalid_inst_gen; | ||
| 26359 | } | ||
| 26360 | |||
| 26361 | uint32_t base_ptr_align = non_sentinel_slice_ptr_type->data.pointer.explicit_alignment; | ||
| 26362 | uint32_t ptr_byte_alignment = 0; | ||
| 26363 | if (end_scalar > start_scalar) { | ||
| 26364 | if ((err = compute_elem_align(ira, elem_type, base_ptr_align, start_scalar, &ptr_byte_alignment))) | ||
| 26365 | return ira->codegen->invalid_inst_gen; | ||
| 26366 | } | ||
| 26367 | |||
| 26368 | ZigType *return_array_type = get_array_type(ira->codegen, elem_type, end_scalar - start_scalar, | ||
| 26369 | array_sentinel); | ||
| 26370 | return_type = get_pointer_to_type_extra(ira->codegen, return_array_type, | ||
| 26371 | non_sentinel_slice_ptr_type->data.pointer.is_const, | ||
| 26372 | non_sentinel_slice_ptr_type->data.pointer.is_volatile, | ||
| 26373 | PtrLenSingle, ptr_byte_alignment, 0, 0, false); | ||
| 26374 | goto done_with_return_type; | ||
| 26375 | } | ||
| 26376 | } else if (array_sentinel == nullptr && end == nullptr) { | ||
| 26377 | array_sentinel = slice_sentinel_val; | ||
| 26378 | } | ||
| 26379 | if (array_sentinel != nullptr) { | ||
| 26380 | // TODO deal with non-abi-alignment here | ||
| 26381 | ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, array_sentinel); | ||
| 26194 | return_type = get_slice_type(ira->codegen, slice_ptr_type); | 26382 | return_type = get_slice_type(ira->codegen, slice_ptr_type); |
| 26195 | } else { | 26383 | } else { |
| 26384 | // TODO deal with non-abi-alignment here | ||
| 26196 | return_type = get_slice_type(ira->codegen, non_sentinel_slice_ptr_type); | 26385 | return_type = get_slice_type(ira->codegen, non_sentinel_slice_ptr_type); |
| 26197 | } | 26386 | } |
| 26387 | done_with_return_type: | ||
| 26198 | 26388 | ||
| 26199 | if (instr_is_comptime(ptr_ptr) && | 26389 | if (instr_is_comptime(ptr_ptr) && |
| 26200 | value_is_comptime(casted_start->value) && | 26390 | value_is_comptime(casted_start->value) && |
| ... | @@ -26205,12 +26395,8 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i | ... | @@ -26205,12 +26395,8 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26205 | size_t abs_offset; | 26395 | size_t abs_offset; |
| 26206 | size_t rel_end; | 26396 | size_t rel_end; |
| 26207 | bool ptr_is_undef = false; | 26397 | bool ptr_is_undef = false; |
| 26208 | if (array_type->id == ZigTypeIdArray || | 26398 | if (child_array_type->id == ZigTypeIdArray) { |
| 26209 | (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) | ||
| 26210 | { | ||
| 26211 | if (array_type->id == ZigTypeIdPointer) { | 26399 | if (array_type->id == ZigTypeIdPointer) { |
| 26212 | ZigType *child_array_type = array_type->data.pointer.child_type; | ||
| 26213 | assert(child_array_type->id == ZigTypeIdArray); | ||
| 26214 | parent_ptr = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.base.source_node); | 26400 | parent_ptr = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.base.source_node); |
| 26215 | if (parent_ptr == nullptr) | 26401 | if (parent_ptr == nullptr) |
| 26216 | return ira->codegen->invalid_inst_gen; | 26402 | return ira->codegen->invalid_inst_gen; |
| ... | @@ -26221,6 +26407,10 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i | ... | @@ -26221,6 +26407,10 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26221 | abs_offset = 0; | 26407 | abs_offset = 0; |
| 26222 | rel_end = SIZE_MAX; | 26408 | rel_end = SIZE_MAX; |
| 26223 | ptr_is_undef = true; | 26409 | ptr_is_undef = true; |
| 26410 | } else if (parent_ptr->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { | ||
| 26411 | array_val = nullptr; | ||
| 26412 | abs_offset = 0; | ||
| 26413 | rel_end = SIZE_MAX; | ||
| 26224 | } else { | 26414 | } else { |
| 26225 | array_val = const_ptr_pointee(ira, ira->codegen, parent_ptr, instruction->base.base.source_node); | 26415 | array_val = const_ptr_pointee(ira, ira->codegen, parent_ptr, instruction->base.base.source_node); |
| 26226 | if (array_val == nullptr) | 26416 | if (array_val == nullptr) |
| ... | @@ -26263,6 +26453,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i | ... | @@ -26263,6 +26453,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26263 | rel_end = 1; | 26453 | rel_end = 1; |
| 26264 | } | 26454 | } |
| 26265 | break; | 26455 | break; |
| 26456 | case ConstPtrSpecialSubArray: | ||
| 26266 | case ConstPtrSpecialBaseArray: | 26457 | case ConstPtrSpecialBaseArray: |
| 26267 | array_val = parent_ptr->data.x_ptr.data.base_array.array_val; | 26458 | array_val = parent_ptr->data.x_ptr.data.base_array.array_val; |
| 26268 | abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index; | 26459 | abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index; |
| ... | @@ -26313,6 +26504,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i | ... | @@ -26313,6 +26504,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26313 | abs_offset = SIZE_MAX; | 26504 | abs_offset = SIZE_MAX; |
| 26314 | rel_end = 1; | 26505 | rel_end = 1; |
| 26315 | break; | 26506 | break; |
| 26507 | case ConstPtrSpecialSubArray: | ||
| 26316 | case ConstPtrSpecialBaseArray: | 26508 | case ConstPtrSpecialBaseArray: |
| 26317 | array_val = parent_ptr->data.x_ptr.data.base_array.array_val; | 26509 | array_val = parent_ptr->data.x_ptr.data.base_array.array_val; |
| 26318 | abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index; | 26510 | abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index; |
| ... | @@ -26373,15 +26565,28 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i | ... | @@ -26373,15 +26565,28 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26373 | } | 26565 | } |
| 26374 | 26566 | ||
| 26375 | IrInstGen *result = ir_const(ira, &instruction->base.base, return_type); | 26567 | IrInstGen *result = ir_const(ira, &instruction->base.base, return_type); |
| 26376 | ZigValue *out_val = result->value; | ||
| 26377 | out_val->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, 2); | ||
| 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 | if (array_val) { | 26584 | if (array_val) { |
| 26382 | size_t index = abs_offset + start_scalar; | 26585 | size_t index = abs_offset + start_scalar; |
| 26383 | bool is_const = slice_is_const(return_type); | 26586 | init_const_ptr_array(ira->codegen, ptr_val, array_val, index, return_type_is_const, PtrLenUnknown); |
| 26384 | init_const_ptr_array(ira->codegen, ptr_val, array_val, index, is_const, PtrLenUnknown); | 26587 | if (return_type->id == ZigTypeIdPointer) { |
| 26588 | ptr_val->data.x_ptr.special = ConstPtrSpecialSubArray; | ||
| 26589 | } | ||
| 26385 | if (array_type->id == ZigTypeIdArray) { | 26590 | if (array_type->id == ZigTypeIdArray) { |
| 26386 | ptr_val->data.x_ptr.mut = ptr_ptr->value->data.x_ptr.mut; | 26591 | ptr_val->data.x_ptr.mut = ptr_ptr->value->data.x_ptr.mut; |
| 26387 | } else if (is_slice(array_type)) { | 26592 | } else if (is_slice(array_type)) { |
| ... | @@ -26391,16 +26596,17 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i | ... | @@ -26391,16 +26596,17 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26391 | } | 26596 | } |
| 26392 | } else if (ptr_is_undef) { | 26597 | } else if (ptr_is_undef) { |
| 26393 | ptr_val->type = get_pointer_to_type(ira->codegen, parent_ptr->type->data.pointer.child_type, | 26598 | ptr_val->type = get_pointer_to_type(ira->codegen, parent_ptr->type->data.pointer.child_type, |
| 26394 | slice_is_const(return_type)); | 26599 | return_type_is_const); |
| 26395 | ptr_val->special = ConstValSpecialUndef; | 26600 | ptr_val->special = ConstValSpecialUndef; |
| 26396 | } else switch (parent_ptr->data.x_ptr.special) { | 26601 | } else switch (parent_ptr->data.x_ptr.special) { |
| 26397 | case ConstPtrSpecialInvalid: | 26602 | case ConstPtrSpecialInvalid: |
| 26398 | case ConstPtrSpecialDiscard: | 26603 | case ConstPtrSpecialDiscard: |
| 26399 | zig_unreachable(); | 26604 | zig_unreachable(); |
| 26400 | case ConstPtrSpecialRef: | 26605 | case ConstPtrSpecialRef: |
| 26401 | init_const_ptr_ref(ira->codegen, ptr_val, | 26606 | init_const_ptr_ref(ira->codegen, ptr_val, parent_ptr->data.x_ptr.data.ref.pointee, |
| 26402 | parent_ptr->data.x_ptr.data.ref.pointee, slice_is_const(return_type)); | 26607 | return_type_is_const); |
| 26403 | break; | 26608 | break; |
| 26609 | case ConstPtrSpecialSubArray: | ||
| 26404 | case ConstPtrSpecialBaseArray: | 26610 | case ConstPtrSpecialBaseArray: |
| 26405 | zig_unreachable(); | 26611 | zig_unreachable(); |
| 26406 | case ConstPtrSpecialBaseStruct: | 26612 | case ConstPtrSpecialBaseStruct: |
| ... | @@ -26415,7 +26621,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i | ... | @@ -26415,7 +26621,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26415 | init_const_ptr_hard_coded_addr(ira->codegen, ptr_val, | 26621 | init_const_ptr_hard_coded_addr(ira->codegen, ptr_val, |
| 26416 | parent_ptr->type->data.pointer.child_type, | 26622 | parent_ptr->type->data.pointer.child_type, |
| 26417 | parent_ptr->data.x_ptr.data.hard_coded_addr.addr + start_scalar, | 26623 | parent_ptr->data.x_ptr.data.hard_coded_addr.addr + start_scalar, |
| 26418 | slice_is_const(return_type)); | 26624 | return_type_is_const); |
| 26419 | break; | 26625 | break; |
| 26420 | case ConstPtrSpecialFunction: | 26626 | case ConstPtrSpecialFunction: |
| 26421 | zig_panic("TODO"); | 26627 | zig_panic("TODO"); |
| ... | @@ -26423,26 +26629,11 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i | ... | @@ -26423,26 +26629,11 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26423 | zig_panic("TODO"); | 26629 | zig_panic("TODO"); |
| 26424 | } | 26630 | } |
| 26425 | 26631 | ||
| 26426 | ZigValue *len_val = out_val->data.x_struct.fields[slice_len_index]; | 26632 | // In the case of pointer-to-array, we must restore this because above it overwrites ptr_val->type |
| 26427 | init_const_usize(ira->codegen, len_val, end_scalar - start_scalar); | 26633 | result->value->type = return_type; |
| 26428 | |||
| 26429 | return result; | 26634 | return result; |
| 26430 | } | 26635 | } |
| 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 | if (generate_non_null_assert) { | 26637 | if (generate_non_null_assert) { |
| 26447 | IrInstGen *ptr_val = ir_get_deref(ira, &instruction->base.base, ptr_ptr, nullptr); | 26638 | IrInstGen *ptr_val = ir_get_deref(ira, &instruction->base.base, ptr_ptr, nullptr); |
| 26448 | 26639 | ||
| ... | @@ -26452,8 +26643,26 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i | ... | @@ -26452,8 +26643,26 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i |
| 26452 | ir_build_assert_non_null(ira, &instruction->base.base, ptr_val); | 26643 | ir_build_assert_non_null(ira, &instruction->base.base, ptr_val); |
| 26453 | } | 26644 | } |
| 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 | return ir_build_slice_gen(ira, &instruction->base.base, return_type, ptr_ptr, | 26664 | return ir_build_slice_gen(ira, &instruction->base.base, return_type, ptr_ptr, |
| 26456 | casted_start, end, instruction->safety_check_on, result_loc); | 26665 | casted_start, end, instruction->safety_check_on, result_loc, sentinel_val); |
| 26457 | } | 26666 | } |
| 26458 | 26667 | ||
| 26459 | static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasField *instruction) { | 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,10 +27688,18 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn |
| 27479 | // We have a check for zero bits later so we use get_src_ptr_type to | 27688 | // We have a check for zero bits later so we use get_src_ptr_type to |
| 27480 | // validate src_type and dest_type. | 27689 | // validate src_type and dest_type. |
| 27481 | 27690 | ||
| 27482 | ZigType *src_ptr_type = get_src_ptr_type(src_type); | 27691 | ZigType *if_slice_ptr_type; |
| 27483 | if (src_ptr_type == nullptr) { | 27692 | if (is_slice(src_type)) { |
| 27484 | ir_add_error(ira, ptr_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); | 27693 | TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index]; |
| 27485 | return ira->codegen->invalid_inst_gen; | 27694 | if_slice_ptr_type = resolve_struct_field_type(ira->codegen, ptr_field); |
| 27695 | } else { | ||
| 27696 | if_slice_ptr_type = src_type; | ||
| 27697 | |||
| 27698 | ZigType *src_ptr_type = get_src_ptr_type(src_type); | ||
| 27699 | if (src_ptr_type == nullptr) { | ||
| 27700 | ir_add_error(ira, ptr_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); | ||
| 27701 | return ira->codegen->invalid_inst_gen; | ||
| 27702 | } | ||
| 27486 | } | 27703 | } |
| 27487 | 27704 | ||
| 27488 | ZigType *dest_ptr_type = get_src_ptr_type(dest_type); | 27705 | ZigType *dest_ptr_type = get_src_ptr_type(dest_type); |
| ... | @@ -27492,7 +27709,7 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn | ... | @@ -27492,7 +27709,7 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn |
| 27492 | return ira->codegen->invalid_inst_gen; | 27709 | return ira->codegen->invalid_inst_gen; |
| 27493 | } | 27710 | } |
| 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 | ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier")); | 27713 | ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier")); |
| 27497 | return ira->codegen->invalid_inst_gen; | 27714 | return ira->codegen->invalid_inst_gen; |
| 27498 | } | 27715 | } |
| ... | @@ -27510,7 +27727,10 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn | ... | @@ -27510,7 +27727,10 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn |
| 27510 | if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown))) | 27727 | if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown))) |
| 27511 | return ira->codegen->invalid_inst_gen; | 27728 | return ira->codegen->invalid_inst_gen; |
| 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 | ErrorMsg *msg = ir_add_error(ira, source_instr, | 27734 | ErrorMsg *msg = ir_add_error(ira, source_instr, |
| 27515 | buf_sprintf("'%s' and '%s' do not have the same in-memory representation", | 27735 | buf_sprintf("'%s' and '%s' do not have the same in-memory representation", |
| 27516 | buf_ptr(&src_type->name), buf_ptr(&dest_type->name))); | 27736 | buf_ptr(&src_type->name), buf_ptr(&dest_type->name))); |
| ... | @@ -27521,6 +27741,14 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn | ... | @@ -27521,6 +27741,14 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn |
| 27521 | return ira->codegen->invalid_inst_gen; | 27741 | return ira->codegen->invalid_inst_gen; |
| 27522 | } | 27742 | } |
| 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 | if (instr_is_comptime(ptr)) { | 27752 | if (instr_is_comptime(ptr)) { |
| 27525 | bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type); | 27753 | bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type); |
| 27526 | UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad; | 27754 | UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad; |
| ... | @@ -27624,6 +27852,9 @@ static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ZigValue | ... | @@ -27624,6 +27852,9 @@ static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ZigValue |
| 27624 | buf_write_value_bytes(codegen, &buf[buf_i], elem); | 27852 | buf_write_value_bytes(codegen, &buf[buf_i], elem); |
| 27625 | buf_i += type_size(codegen, elem->type); | 27853 | buf_i += type_size(codegen, elem->type); |
| 27626 | } | 27854 | } |
| 27855 | if (val->type->id == ZigTypeIdArray && val->type->data.array.sentinel != nullptr) { | ||
| 27856 | buf_write_value_bytes(codegen, &buf[buf_i], val->type->data.array.sentinel); | ||
| 27857 | } | ||
| 27627 | } | 27858 | } |
| 27628 | 27859 | ||
| 27629 | static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ZigValue *val) { | 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,6 +566,7 @@ static const char *build_libc_object(CodeGen *parent_gen, const char *name, CFil |
| 566 | Stage2ProgressNode *progress_node) | 566 | Stage2ProgressNode *progress_node) |
| 567 | { | 567 | { |
| 568 | CodeGen *child_gen = create_child_codegen(parent_gen, nullptr, OutTypeObj, nullptr, name, progress_node); | 568 | CodeGen *child_gen = create_child_codegen(parent_gen, nullptr, OutTypeObj, nullptr, name, progress_node); |
| 569 | child_gen->root_out_name = buf_create_from_str(name); | ||
| 569 | ZigList<CFile *> c_source_files = {0}; | 570 | ZigList<CFile *> c_source_files = {0}; |
| 570 | c_source_files.append(c_file); | 571 | c_source_files.append(c_file); |
| 571 | child_gen->c_source_files = c_source_files; | 572 | child_gen->c_source_files = c_source_files; |
src/main.cpp+2-1| ... | @@ -1291,6 +1291,7 @@ static int main0(int argc, char **argv) { | ... | @@ -1291,6 +1291,7 @@ static int main0(int argc, char **argv) { |
| 1291 | if (g->enable_cache) { | 1291 | if (g->enable_cache) { |
| 1292 | #if defined(ZIG_OS_WINDOWS) | 1292 | #if defined(ZIG_OS_WINDOWS) |
| 1293 | buf_replace(&g->bin_file_output_path, '/', '\\'); | 1293 | buf_replace(&g->bin_file_output_path, '/', '\\'); |
| 1294 | buf_replace(g->output_dir, '/', '\\'); | ||
| 1294 | #endif | 1295 | #endif |
| 1295 | if (final_output_dir_step != nullptr) { | 1296 | if (final_output_dir_step != nullptr) { |
| 1296 | Buf *dest_basename = buf_alloc(); | 1297 | Buf *dest_basename = buf_alloc(); |
| ... | @@ -1304,7 +1305,7 @@ static int main0(int argc, char **argv) { | ... | @@ -1304,7 +1305,7 @@ static int main0(int argc, char **argv) { |
| 1304 | return main_exit(root_progress_node, EXIT_FAILURE); | 1305 | return main_exit(root_progress_node, EXIT_FAILURE); |
| 1305 | } | 1306 | } |
| 1306 | } else { | 1307 | } else { |
| 1307 | if (printf("%s\n", buf_ptr(&g->bin_file_output_path)) < 0) | 1308 | if (printf("%s\n", buf_ptr(g->output_dir)) < 0) |
| 1308 | return main_exit(root_progress_node, EXIT_FAILURE); | 1309 | return main_exit(root_progress_node, EXIT_FAILURE); |
| 1309 | } | 1310 | } |
| 1310 | } | 1311 | } |
test/cli.zig+1-1| ... | @@ -36,7 +36,7 @@ pub fn main() !void { | ... | @@ -36,7 +36,7 @@ pub fn main() !void { |
| 36 | testMissingOutputPath, | 36 | testMissingOutputPath, |
| 37 | }; | 37 | }; |
| 38 | for (test_fns) |testFn| { | 38 | for (test_fns) |testFn| { |
| 39 | try fs.deleteTree(dir_path); | 39 | try fs.cwd().deleteTree(dir_path); |
| 40 | try fs.cwd().makeDir(dir_path); | 40 | try fs.cwd().makeDir(dir_path); |
| 41 | try testFn(zig_exe, dir_path); | 41 | try testFn(zig_exe, dir_path); |
| 42 | } | 42 | } |
test/compare_output.zig+1-1| ... | @@ -292,7 +292,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -292,7 +292,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 292 | \\pub export fn main() c_int { | 292 | \\pub export fn main() c_int { |
| 293 | \\ var array = [_]u32{ 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 }; | 293 | \\ var array = [_]u32{ 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 }; |
| 294 | \\ | 294 | \\ |
| 295 | \\ c.qsort(@ptrCast(?*c_void, array[0..].ptr), @intCast(c_ulong, array.len), @sizeOf(i32), compare_fn); | 295 | \\ c.qsort(@ptrCast(?*c_void, &array), @intCast(c_ulong, array.len), @sizeOf(i32), compare_fn); |
| 296 | \\ | 296 | \\ |
| 297 | \\ for (array) |item, i| { | 297 | \\ for (array) |item, i| { |
| 298 | \\ if (item != i) { | 298 | \\ if (item != i) { |
test/compile_errors.zig+2-14| ... | @@ -103,18 +103,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -103,18 +103,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 103 | "tmp.zig:3:23: error: pointer to size 0 type has no address", | 103 | "tmp.zig:3:23: error: pointer to size 0 type has no address", |
| 104 | }); | 104 | }); |
| 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 | cases.addTest("access invalid @typeInfo decl", | 106 | cases.addTest("access invalid @typeInfo decl", |
| 119 | \\const A = B; | 107 | \\const A = B; |
| 120 | \\test "Crash" { | 108 | \\test "Crash" { |
| ... | @@ -1918,8 +1906,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -1918,8 +1906,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1918 | cases.add("reading past end of pointer casted array", | 1906 | cases.add("reading past end of pointer casted array", |
| 1919 | \\comptime { | 1907 | \\comptime { |
| 1920 | \\ const array: [4]u8 = "aoeu".*; | 1908 | \\ const array: [4]u8 = "aoeu".*; |
| 1921 | \\ const slice = array[1..]; | 1909 | \\ const sub_array = array[1..]; |
| 1922 | \\ const int_ptr = @ptrCast(*const u24, slice.ptr); | 1910 | \\ const int_ptr = @ptrCast(*const u24, sub_array); |
| 1923 | \\ const deref = int_ptr.*; | 1911 | \\ const deref = int_ptr.*; |
| 1924 | \\} | 1912 | \\} |
| 1925 | , &[_][]const u8{ | 1913 | , &[_][]const u8{ |
test/runtime_safety.zig+1-1| ... | @@ -69,7 +69,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { | ... | @@ -69,7 +69,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 69 | \\} | 69 | \\} |
| 70 | \\pub fn main() void { | 70 | \\pub fn main() void { |
| 71 | \\ var buf: [4]u8 = undefined; | 71 | \\ var buf: [4]u8 = undefined; |
| 72 | \\ const ptr = buf[0..].ptr; | 72 | \\ const ptr: [*]u8 = &buf; |
| 73 | \\ const slice = ptr[0..3 :0]; | 73 | \\ const slice = ptr[0..3 :0]; |
| 74 | \\} | 74 | \\} |
| 75 | ); | 75 | ); |
test/stage1/behavior/align.zig+22-14| ... | @@ -5,10 +5,17 @@ const builtin = @import("builtin"); | ... | @@ -5,10 +5,17 @@ const builtin = @import("builtin"); |
| 5 | var foo: u8 align(4) = 100; | 5 | var foo: u8 align(4) = 100; |
| 6 | 6 | ||
| 7 | test "global variable alignment" { | 7 | test "global variable alignment" { |
| 8 | expect(@TypeOf(&foo).alignment == 4); | 8 | comptime expect(@TypeOf(&foo).alignment == 4); |
| 9 | expect(@TypeOf(&foo) == *align(4) u8); | 9 | comptime expect(@TypeOf(&foo) == *align(4) u8); |
| 10 | const slice = @as(*[1]u8, &foo)[0..]; | 10 | { |
| 11 | expect(@TypeOf(slice) == []align(4) u8); | 11 | const slice = @as(*[1]u8, &foo)[0..]; |
| 12 | comptime expect(@TypeOf(slice) == *align(4) [1]u8); | ||
| 13 | } | ||
| 14 | { | ||
| 15 | var runtime_zero: usize = 0; | ||
| 16 | const slice = @as(*[1]u8, &foo)[runtime_zero..]; | ||
| 17 | comptime expect(@TypeOf(slice) == []align(4) u8); | ||
| 18 | } | ||
| 12 | } | 19 | } |
| 13 | 20 | ||
| 14 | fn derp() align(@sizeOf(usize) * 2) i32 { | 21 | fn derp() align(@sizeOf(usize) * 2) i32 { |
| ... | @@ -171,18 +178,19 @@ test "runtime known array index has best alignment possible" { | ... | @@ -171,18 +178,19 @@ test "runtime known array index has best alignment possible" { |
| 171 | 178 | ||
| 172 | // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2 | 179 | // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2 |
| 173 | var smaller align(2) = [_]u32{ 1, 2, 3, 4 }; | 180 | var smaller align(2) = [_]u32{ 1, 2, 3, 4 }; |
| 174 | comptime expect(@TypeOf(smaller[0..]) == []align(2) u32); | 181 | var runtime_zero: usize = 0; |
| 175 | comptime expect(@TypeOf(smaller[0..].ptr) == [*]align(2) u32); | 182 | comptime expect(@TypeOf(smaller[runtime_zero..]) == []align(2) u32); |
| 176 | testIndex(smaller[0..].ptr, 0, *align(2) u32); | 183 | comptime expect(@TypeOf(smaller[runtime_zero..].ptr) == [*]align(2) u32); |
| 177 | testIndex(smaller[0..].ptr, 1, *align(2) u32); | 184 | testIndex(smaller[runtime_zero..].ptr, 0, *align(2) u32); |
| 178 | testIndex(smaller[0..].ptr, 2, *align(2) u32); | 185 | testIndex(smaller[runtime_zero..].ptr, 1, *align(2) u32); |
| 179 | testIndex(smaller[0..].ptr, 3, *align(2) u32); | 186 | testIndex(smaller[runtime_zero..].ptr, 2, *align(2) u32); |
| 187 | testIndex(smaller[runtime_zero..].ptr, 3, *align(2) u32); | ||
| 180 | 188 | ||
| 181 | // has to use ABI alignment because index known at runtime only | 189 | // has to use ABI alignment because index known at runtime only |
| 182 | testIndex2(array[0..].ptr, 0, *u8); | 190 | testIndex2(array[runtime_zero..].ptr, 0, *u8); |
| 183 | testIndex2(array[0..].ptr, 1, *u8); | 191 | testIndex2(array[runtime_zero..].ptr, 1, *u8); |
| 184 | testIndex2(array[0..].ptr, 2, *u8); | 192 | testIndex2(array[runtime_zero..].ptr, 2, *u8); |
| 185 | testIndex2(array[0..].ptr, 3, *u8); | 193 | testIndex2(array[runtime_zero..].ptr, 3, *u8); |
| 186 | } | 194 | } |
| 187 | fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void { | 195 | fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void { |
| 188 | comptime expect(@TypeOf(&smaller[index]) == T); | 196 | comptime expect(@TypeOf(&smaller[index]) == T); |
test/stage1/behavior/array.zig+38| ... | @@ -28,6 +28,24 @@ fn getArrayLen(a: []const u32) usize { | ... | @@ -28,6 +28,24 @@ fn getArrayLen(a: []const u32) usize { |
| 28 | return a.len; | 28 | return a.len; |
| 29 | } | 29 | } |
| 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 | test "void arrays" { | 49 | test "void arrays" { |
| 32 | var array: [4]void = undefined; | 50 | var array: [4]void = undefined; |
| 33 | array[0] = void{}; | 51 | array[0] = void{}; |
| ... | @@ -376,3 +394,23 @@ test "type deduction for array subscript expression" { | ... | @@ -376,3 +394,23 @@ test "type deduction for array subscript expression" { |
| 376 | S.doTheTest(); | 394 | S.doTheTest(); |
| 377 | comptime S.doTheTest(); | 395 | comptime S.doTheTest(); |
| 378 | } | 396 | } |
| 397 | |||
| 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,7 +431,8 @@ fn incrementVoidPtrValue(value: ?*c_void) void { |
| 431 | 431 | ||
| 432 | test "implicit cast from [*]T to ?*c_void" { | 432 | test "implicit cast from [*]T to ?*c_void" { |
| 433 | var a = [_]u8{ 3, 2, 1 }; | 433 | var a = [_]u8{ 3, 2, 1 }; |
| 434 | incrementVoidPtrArray(a[0..].ptr, 3); | 434 | var runtime_zero: usize = 0; |
| 435 | incrementVoidPtrArray(a[runtime_zero..].ptr, 3); | ||
| 435 | expect(std.mem.eql(u8, &a, &[_]u8{ 4, 3, 2 })); | 436 | expect(std.mem.eql(u8, &a, &[_]u8{ 4, 3, 2 })); |
| 436 | } | 437 | } |
| 437 | 438 |
test/stage1/behavior/eval.zig+1-1| ... | @@ -524,7 +524,7 @@ test "comptime slice of slice preserves comptime var" { | ... | @@ -524,7 +524,7 @@ test "comptime slice of slice preserves comptime var" { |
| 524 | test "comptime slice of pointer preserves comptime var" { | 524 | test "comptime slice of pointer preserves comptime var" { |
| 525 | comptime { | 525 | comptime { |
| 526 | var buff: [10]u8 = undefined; | 526 | var buff: [10]u8 = undefined; |
| 527 | var a = buff[0..].ptr; | 527 | var a = @ptrCast([*]u8, &buff); |
| 528 | a[0..1][0] = 1; | 528 | a[0..1][0] = 1; |
| 529 | expect(buff[0..][0..][0] == 1); | 529 | expect(buff[0..][0..][0] == 1); |
| 530 | } | 530 | } |
test/stage1/behavior/misc.zig+9-5| ... | @@ -102,8 +102,8 @@ test "memcpy and memset intrinsics" { | ... | @@ -102,8 +102,8 @@ test "memcpy and memset intrinsics" { |
| 102 | var foo: [20]u8 = undefined; | 102 | var foo: [20]u8 = undefined; |
| 103 | var bar: [20]u8 = undefined; | 103 | var bar: [20]u8 = undefined; |
| 104 | 104 | ||
| 105 | @memset(foo[0..].ptr, 'A', foo.len); | 105 | @memset(&foo, 'A', foo.len); |
| 106 | @memcpy(bar[0..].ptr, foo[0..].ptr, bar.len); | 106 | @memcpy(&bar, &foo, bar.len); |
| 107 | 107 | ||
| 108 | if (bar[11] != 'A') unreachable; | 108 | if (bar[11] != 'A') unreachable; |
| 109 | } | 109 | } |
| ... | @@ -565,12 +565,16 @@ test "volatile load and store" { | ... | @@ -565,12 +565,16 @@ test "volatile load and store" { |
| 565 | expect(ptr.* == 1235); | 565 | expect(ptr.* == 1235); |
| 566 | } | 566 | } |
| 567 | 567 | ||
| 568 | test "slice string literal has type []const u8" { | 568 | test "slice string literal has correct type" { |
| 569 | comptime { | 569 | comptime { |
| 570 | expect(@TypeOf("aoeu"[0..]) == []const u8); | 570 | expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8); |
| 571 | const array = [_]i32{ 1, 2, 3, 4 }; | 571 | const array = [_]i32{ 1, 2, 3, 4 }; |
| 572 | expect(@TypeOf(array[0..]) == []const i32); | 572 | expect(@TypeOf(array[0..]) == *const [4]i32); |
| 573 | } | 573 | } |
| 574 | var runtime_zero: usize = 0; | ||
| 575 | comptime expect(@TypeOf("aoeu"[runtime_zero..]) == [:0]const u8); | ||
| 576 | const array = [_]i32{ 1, 2, 3, 4 }; | ||
| 577 | comptime expect(@TypeOf(array[runtime_zero..]) == []const i32); | ||
| 574 | } | 578 | } |
| 575 | 579 | ||
| 576 | test "pointer child field" { | 580 | test "pointer child field" { |
test/stage1/behavior/pointers.zig+5-4| ... | @@ -159,12 +159,13 @@ test "allowzero pointer and slice" { | ... | @@ -159,12 +159,13 @@ test "allowzero pointer and slice" { |
| 159 | var opt_ptr: ?[*]allowzero i32 = ptr; | 159 | var opt_ptr: ?[*]allowzero i32 = ptr; |
| 160 | expect(opt_ptr != null); | 160 | expect(opt_ptr != null); |
| 161 | expect(@ptrToInt(ptr) == 0); | 161 | expect(@ptrToInt(ptr) == 0); |
| 162 | var slice = ptr[0..10]; | 162 | var runtime_zero: usize = 0; |
| 163 | expect(@TypeOf(slice) == []allowzero i32); | 163 | var slice = ptr[runtime_zero..10]; |
| 164 | comptime expect(@TypeOf(slice) == []allowzero i32); | ||
| 164 | expect(@ptrToInt(&slice[5]) == 20); | 165 | expect(@ptrToInt(&slice[5]) == 20); |
| 165 | 166 | ||
| 166 | expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero); | 167 | comptime expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero); |
| 167 | expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero); | 168 | comptime expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero); |
| 168 | } | 169 | } |
| 169 | 170 | ||
| 170 | test "assign null directly to C pointer and test null equality" { | 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,7 +13,7 @@ fn testReinterpretBytesAsInteger() void { |
| 13 | builtin.Endian.Little => 0xab785634, | 13 | builtin.Endian.Little => 0xab785634, |
| 14 | builtin.Endian.Big => 0x345678ab, | 14 | builtin.Endian.Big => 0x345678ab, |
| 15 | }; | 15 | }; |
| 16 | expect(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected); | 16 | expect(@ptrCast(*align(1) const u32, bytes[1..5]).* == expected); |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | test "reinterpret bytes of an array into an extern struct" { | 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,10 +7,10 @@ const mem = std.mem; |
| 7 | const x = @intToPtr([*]i32, 0x1000)[0..0x500]; | 7 | const x = @intToPtr([*]i32, 0x1000)[0..0x500]; |
| 8 | const y = x[0x100..]; | 8 | const y = x[0x100..]; |
| 9 | test "compile time slice of pointer to hard coded address" { | 9 | test "compile time slice of pointer to hard coded address" { |
| 10 | expect(@ptrToInt(x.ptr) == 0x1000); | 10 | expect(@ptrToInt(x) == 0x1000); |
| 11 | expect(x.len == 0x500); | 11 | expect(x.len == 0x500); |
| 12 | 12 | ||
| 13 | expect(@ptrToInt(y.ptr) == 0x1100); | 13 | expect(@ptrToInt(y) == 0x1100); |
| 14 | expect(y.len == 0x400); | 14 | expect(y.len == 0x400); |
| 15 | } | 15 | } |
| 16 | 16 | ||
| ... | @@ -47,7 +47,9 @@ test "C pointer slice access" { | ... | @@ -47,7 +47,9 @@ test "C pointer slice access" { |
| 47 | var buf: [10]u32 = [1]u32{42} ** 10; | 47 | var buf: [10]u32 = [1]u32{42} ** 10; |
| 48 | const c_ptr = @ptrCast([*c]const u32, &buf); | 48 | const c_ptr = @ptrCast([*c]const u32, &buf); |
| 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 | for (c_ptr[0..5]) |*cl| { | 54 | for (c_ptr[0..5]) |*cl| { |
| 53 | expectEqual(@as(u32, 42), cl.*); | 55 | expectEqual(@as(u32, 42), cl.*); |
| ... | @@ -107,7 +109,9 @@ test "obtaining a null terminated slice" { | ... | @@ -107,7 +109,9 @@ test "obtaining a null terminated slice" { |
| 107 | const ptr2 = buf[0..runtime_len :0]; | 109 | const ptr2 = buf[0..runtime_len :0]; |
| 108 | // ptr2 is a null-terminated slice | 110 | // ptr2 is a null-terminated slice |
| 109 | comptime expect(@TypeOf(ptr2) == [:0]u8); | 111 | comptime expect(@TypeOf(ptr2) == [:0]u8); |
| 110 | comptime expect(@TypeOf(ptr2[0..2]) == []u8); | 112 | comptime expect(@TypeOf(ptr2[0..2]) == *[2]u8); |
| 113 | var runtime_zero: usize = 0; | ||
| 114 | comptime expect(@TypeOf(ptr2[runtime_zero..2]) == []u8); | ||
| 111 | } | 115 | } |
| 112 | 116 | ||
| 113 | test "empty array to slice" { | 117 | test "empty array to slice" { |
| ... | @@ -126,3 +130,150 @@ test "empty array to slice" { | ... | @@ -126,3 +130,150 @@ test "empty array to slice" { |
| 126 | S.doTheTest(); | 130 | S.doTheTest(); |
| 127 | comptime S.doTheTest(); | 131 | comptime S.doTheTest(); |
| 128 | } | 132 | } |
| 133 | |||
| 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,8 +409,8 @@ const Bitfields = packed struct { |
| 409 | test "native bit field understands endianness" { | 409 | test "native bit field understands endianness" { |
| 410 | var all: u64 = 0x7765443322221111; | 410 | var all: u64 = 0x7765443322221111; |
| 411 | var bytes: [8]u8 = undefined; | 411 | var bytes: [8]u8 = undefined; |
| 412 | @memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8); | 412 | @memcpy(&bytes, @ptrCast([*]u8, &all), 8); |
| 413 | var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*; | 413 | var bitfields = @ptrCast(*Bitfields, &bytes).*; |
| 414 | 414 | ||
| 415 | expect(bitfields.f1 == 0x1111); | 415 | expect(bitfields.f1 == 0x1111); |
| 416 | expect(bitfields.f2 == 0x2222); | 416 | expect(bitfields.f2 == 0x2222); |