authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-24 15:08:23-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-24 15:08:23-07:00
log8e6c2b7a47c3c19269cf03075eaeddb7ee61c42d
tree6fca0ca2a2929fe9fbb66dc960451d77cefb04bc
parent38441b5eab3c9371f8412aa46a277f37fc026a79
parent8b9434871ea437840d25f073b945466359f402f9

Merge remote-tracking branch 'origin/master' into ast-memory-layout


43 files changed, 620 insertions(+), 164 deletions(-)

doc/langref.html.in+22-8
...@@ -310,7 +310,7 @@ pub fn main() !void {...@@ -310,7 +310,7 @@ pub fn main() !void {
310 <p>310 <p>
311 The two arguments passed to the <code>stdout.print()</code> function, <code>"Hello, {s}!\n"</code>311 The two arguments passed to the <code>stdout.print()</code> function, <code>"Hello, {s}!\n"</code>
312 and <code>.{"world"}</code>, are evaluated at {#link|compile-time|comptime#}. The code sample is312 and <code>.{"world"}</code>, are evaluated at {#link|compile-time|comptime#}. The code sample is
313 purposely written to show how to perform {#link|string|String Literals and Character Literals#}313 purposely written to show how to perform {#link|string|String Literals and Unicode Code Point Literals#}
314 substitution in the <code>print</code> function. The curly-braces inside of the first argument314 substitution in the <code>print</code> function. The curly-braces inside of the first argument
315 are substituted with the compile-time known value inside of the second argument315 are substituted with the compile-time known value inside of the second argument
316 (known as an {#link|anonymous struct literal|Anonymous Struct Literals#}). The <code>\n</code>316 (known as an {#link|anonymous struct literal|Anonymous Struct Literals#}). The <code>\n</code>
...@@ -682,18 +682,31 @@ pub fn main() void {...@@ -682,18 +682,31 @@ pub fn main() void {
682 </div>682 </div>
683 {#see_also|Optionals|undefined#}683 {#see_also|Optionals|undefined#}
684 {#header_close#}684 {#header_close#}
685 {#header_open|String Literals and Character Literals#}685 {#header_open|String Literals and Unicode Code Point Literals#}
686 <p>686 <p>
687 String literals are single-item constant {#link|Pointers#} to null-terminated UTF-8 encoded byte arrays.687 String literals are single-item constant {#link|Pointers#} to null-terminated byte arrays.
688 The type of string literals encodes both the length, and the fact that they are null-terminated,688 The type of string literals encodes both the length, and the fact that they are null-terminated,
689 and thus they can be {#link|coerced|Type Coercion#} to both {#link|Slices#} and689 and thus they can be {#link|coerced|Type Coercion#} to both {#link|Slices#} and
690 {#link|Null-Terminated Pointers|Sentinel-Terminated Pointers#}.690 {#link|Null-Terminated Pointers|Sentinel-Terminated Pointers#}.
691 Dereferencing string literals converts them to {#link|Arrays#}.691 Dereferencing string literals converts them to {#link|Arrays#}.
692 </p>692 </p>
693 <p>693 <p>
694 Character literals have type {#syntax#}comptime_int{#endsyntax#}, the same as694 The encoding of a string in Zig is de-facto assumed to be UTF-8.
695 Because Zig source code is {#link|UTF-8 encoded|Source Encoding#}, any non-ASCII bytes appearing within a string literal
696 in source code carry their UTF-8 meaning into the content of the string in the Zig program;
697 the bytes are not modified by the compiler.
698 However, it is possible to embbed non-UTF-8 bytes into a string literal using <code>\xNN</code> notation.
699 </p>
700 <p>
701 Unicode code point literals have type {#syntax#}comptime_int{#endsyntax#}, the same as
695 {#link|Integer Literals#}. All {#link|Escape Sequences#} are valid in both string literals702 {#link|Integer Literals#}. All {#link|Escape Sequences#} are valid in both string literals
696 and character literals.703 and Unicode code point literals.
704 </p>
705 <p>
706 In many other programming languages, a Unicode code point literal is called a "character literal".
707 However, there is <a href="https://unicode.org/glossary">no precise technical definition of a "character"</a>
708 in recent versions of the Unicode specification (as of Unicode 13.0).
709 In Zig, a Unicode code point literal corresponds to the Unicode definition of a code point.
697 </p>710 </p>
698 {#code_begin|test#}711 {#code_begin|test#}
699const expect = @import("std").testing.expect;712const expect = @import("std").testing.expect;
...@@ -709,6 +722,7 @@ test "string literals" {...@@ -709,6 +722,7 @@ test "string literals" {
709 expect('\u{1f4a9}' == 128169);722 expect('\u{1f4a9}' == 128169);
710 expect('💯' == 128175);723 expect('💯' == 128175);
711 expect(mem.eql(u8, "hello", "h\x65llo"));724 expect(mem.eql(u8, "hello", "h\x65llo"));
725 expect("\xff"[0] == 0xff); // non-UTF-8 strings are possible with \xNN notation.
712}726}
713 {#code_end#}727 {#code_end#}
714 {#see_also|Arrays|Zig Test|Source Encoding#}728 {#see_also|Arrays|Zig Test|Source Encoding#}
...@@ -749,11 +763,11 @@ test "string literals" {...@@ -749,11 +763,11 @@ test "string literals" {
749 </tr>763 </tr>
750 <tr>764 <tr>
751 <td><code>\xNN</code></td>765 <td><code>\xNN</code></td>
752 <td>hexadecimal 8-bit character code (2 digits)</td>766 <td>hexadecimal 8-bit byte value (2 digits)</td>
753 </tr>767 </tr>
754 <tr>768 <tr>
755 <td><code>\u{NNNNNN}</code></td>769 <td><code>\u{NNNNNN}</code></td>
756 <td>hexadecimal Unicode character code UTF-8 encoded (1 or more digits)</td>770 <td>hexadecimal Unicode code point UTF-8 encoded (1 or more digits)</td>
757 </tr>771 </tr>
758 </table>772 </table>
759 </div>773 </div>
...@@ -7414,7 +7428,7 @@ test "main" {...@@ -7414,7 +7428,7 @@ test "main" {
7414 This function returns a compile time constant pointer to null-terminated,7428 This function returns a compile time constant pointer to null-terminated,
7415 fixed-size array with length equal to the byte count of the file given by7429 fixed-size array with length equal to the byte count of the file given by
7416 {#syntax#}path{#endsyntax#}. The contents of the array are the contents of the file.7430 {#syntax#}path{#endsyntax#}. The contents of the array are the contents of the file.
7417 This is equivalent to a {#link|string literal|String Literals and Character Literals#}7431 This is equivalent to a {#link|string literal|String Literals and Unicode Code Point Literals#}
7418 with the file contents.7432 with the file contents.
7419 </p>7433 </p>
7420 <p>7434 <p>
lib/std/Progress.zig+17-1
...@@ -25,6 +25,13 @@ terminal: ?std.fs.File = undefined,...@@ -25,6 +25,13 @@ terminal: ?std.fs.File = undefined,
25/// Whether the terminal supports ANSI escape codes.25/// Whether the terminal supports ANSI escape codes.
26supports_ansi_escape_codes: bool = false,26supports_ansi_escape_codes: bool = false,
2727
28/// If the terminal is "dumb", don't print output.
29/// This can be useful if you don't want to print all
30/// the stages of code generation if there are a lot.
31/// You should not use it if the user should see output
32/// for example showing the user what tests run.
33dont_print_on_dumb: bool = false,
34
28root: Node = undefined,35root: Node = undefined,
2936
30/// Keeps track of how much time has passed since the beginning.37/// Keeps track of how much time has passed since the beginning.
...@@ -141,6 +148,9 @@ pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) !*...@@ -141,6 +148,9 @@ pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) !*
141 self.supports_ansi_escape_codes = true;148 self.supports_ansi_escape_codes = true;
142 } else if (std.builtin.os.tag == .windows and stderr.isTty()) {149 } else if (std.builtin.os.tag == .windows and stderr.isTty()) {
143 self.terminal = stderr;150 self.terminal = stderr;
151 } else if (std.builtin.os.tag != .windows) {
152 // we are in a "dumb" terminal like in acme or writing to a file
153 self.terminal = stderr;
144 }154 }
145 self.root = Node{155 self.root = Node{
146 .context = self,156 .context = self,
...@@ -178,6 +188,8 @@ pub fn refresh(self: *Progress) void {...@@ -178,6 +188,8 @@ pub fn refresh(self: *Progress) void {
178}188}
179189
180fn refreshWithHeldLock(self: *Progress) void {190fn refreshWithHeldLock(self: *Progress) void {
191 const is_dumb = !self.supports_ansi_escape_codes and !(std.builtin.os.tag == .windows);
192 if (is_dumb and self.dont_print_on_dumb) return;
181 const file = self.terminal orelse return;193 const file = self.terminal orelse return;
182194
183 const prev_columns_written = self.columns_written;195 const prev_columns_written = self.columns_written;
...@@ -226,7 +238,11 @@ fn refreshWithHeldLock(self: *Progress) void {...@@ -226,7 +238,11 @@ fn refreshWithHeldLock(self: *Progress) void {
226238
227 if (windows.kernel32.SetConsoleCursorPosition(file.handle, cursor_pos) != windows.TRUE)239 if (windows.kernel32.SetConsoleCursorPosition(file.handle, cursor_pos) != windows.TRUE)
228 unreachable;240 unreachable;
229 } else unreachable;241 } else {
242 // we are in a "dumb" terminal like in acme or writing to a file
243 self.output_buffer[end] = '\n';
244 end += 1;
245 }
230246
231 self.columns_written = 0;247 self.columns_written = 0;
232 }248 }
lib/std/Thread/Semaphore.zig+1-1
...@@ -13,7 +13,7 @@ cond: Condition = .{},...@@ -13,7 +13,7 @@ cond: Condition = .{},
13//! It is OK to initialize this field to any value.13//! It is OK to initialize this field to any value.
14permits: usize = 0,14permits: usize = 0,
1515
16const RwLock = @This();16const Semaphore = @This();
17const std = @import("../std.zig");17const std = @import("../std.zig");
18const Mutex = std.Thread.Mutex;18const Mutex = std.Thread.Mutex;
19const Condition = std.Thread.Condition;19const Condition = std.Thread.Condition;
lib/std/build.zig+46-5
...@@ -543,7 +543,7 @@ pub const Builder = struct {...@@ -543,7 +543,7 @@ pub const Builder = struct {
543 .Scalar => |s| {543 .Scalar => |s| {
544 const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) {544 const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) {
545 error.Overflow => {545 error.Overflow => {
546 warn("-D{s} value {} cannot fit into type {s}.\n\n", .{ name, s, @typeName(T) });546 warn("-D{s} value {s} cannot fit into type {s}.\n\n", .{ name, s, @typeName(T) });
547 self.markInvalidUserInput();547 self.markInvalidUserInput();
548 return null;548 return null;
549 },549 },
...@@ -1308,6 +1308,12 @@ const BuildOptionArtifactArg = struct {...@@ -1308,6 +1308,12 @@ const BuildOptionArtifactArg = struct {
1308 artifact: *LibExeObjStep,1308 artifact: *LibExeObjStep,
1309};1309};
13101310
1311const BuildOptionWriteFileArg = struct {
1312 name: []const u8,
1313 write_file: *WriteFileStep,
1314 basename: []const u8,
1315};
1316
1311pub const LibExeObjStep = struct {1317pub const LibExeObjStep = struct {
1312 step: Step,1318 step: Step,
1313 builder: *Builder,1319 builder: *Builder,
...@@ -1355,6 +1361,7 @@ pub const LibExeObjStep = struct {...@@ -1355,6 +1361,7 @@ pub const LibExeObjStep = struct {
1355 packages: ArrayList(Pkg),1361 packages: ArrayList(Pkg),
1356 build_options_contents: std.ArrayList(u8),1362 build_options_contents: std.ArrayList(u8),
1357 build_options_artifact_args: std.ArrayList(BuildOptionArtifactArg),1363 build_options_artifact_args: std.ArrayList(BuildOptionArtifactArg),
1364 build_options_write_file_args: std.ArrayList(BuildOptionWriteFileArg),
13581365
1359 object_src: []const u8,1366 object_src: []const u8,
13601367
...@@ -1515,6 +1522,7 @@ pub const LibExeObjStep = struct {...@@ -1515,6 +1522,7 @@ pub const LibExeObjStep = struct {
1515 .object_src = undefined,1522 .object_src = undefined,
1516 .build_options_contents = std.ArrayList(u8).init(builder.allocator),1523 .build_options_contents = std.ArrayList(u8).init(builder.allocator),
1517 .build_options_artifact_args = std.ArrayList(BuildOptionArtifactArg).init(builder.allocator),1524 .build_options_artifact_args = std.ArrayList(BuildOptionArtifactArg).init(builder.allocator),
1525 .build_options_write_file_args = std.ArrayList(BuildOptionWriteFileArg).init(builder.allocator),
1518 .c_std = Builder.CStd.C99,1526 .c_std = Builder.CStd.C99,
1519 .override_lib_dir = null,1527 .override_lib_dir = null,
1520 .main_pkg_path = null,1528 .main_pkg_path = null,
...@@ -2008,6 +2016,23 @@ pub const LibExeObjStep = struct {...@@ -2008,6 +2016,23 @@ pub const LibExeObjStep = struct {
2008 self.step.dependOn(&artifact.step);2016 self.step.dependOn(&artifact.step);
2009 }2017 }
20102018
2019 /// The value is the path in the cache dir.
2020 /// Adds a dependency automatically.
2021 /// basename refers to the basename of the WriteFileStep
2022 pub fn addBuildOptionWriteFile(
2023 self: *LibExeObjStep,
2024 name: []const u8,
2025 write_file: *WriteFileStep,
2026 basename: []const u8,
2027 ) void {
2028 self.build_options_write_file_args.append(.{
2029 .name = name,
2030 .write_file = write_file,
2031 .basename = basename,
2032 }) catch unreachable;
2033 self.step.dependOn(&write_file.step);
2034 }
2035
2011 pub fn addSystemIncludeDir(self: *LibExeObjStep, path: []const u8) void {2036 pub fn addSystemIncludeDir(self: *LibExeObjStep, path: []const u8) void {
2012 self.include_dirs.append(IncludeDir{ .RawPathSystem = self.builder.dupe(path) }) catch unreachable;2037 self.include_dirs.append(IncludeDir{ .RawPathSystem = self.builder.dupe(path) }) catch unreachable;
2013 }2038 }
...@@ -2228,11 +2253,27 @@ pub const LibExeObjStep = struct {...@@ -2228,11 +2253,27 @@ pub const LibExeObjStep = struct {
2228 }2253 }
2229 }2254 }
22302255
2231 if (self.build_options_contents.items.len > 0 or self.build_options_artifact_args.items.len > 0) {2256 if (self.build_options_contents.items.len > 0 or
2232 // Render build artifact options at the last minute, now that the path is known.2257 self.build_options_artifact_args.items.len > 0 or
2258 self.build_options_write_file_args.items.len > 0)
2259 {
2260 // Render build artifact and write file options at the last minute, now that the path is known.
2261 //
2262 // Note that pathFromRoot uses resolve path, so this will have
2263 // correct behavior even if getOutputPath is already absolute.
2233 for (self.build_options_artifact_args.items) |item| {2264 for (self.build_options_artifact_args.items) |item| {
2234 const out = self.build_options_contents.writer();2265 self.addBuildOption(
2235 out.print("pub const {s}: []const u8 = \"{}\";\n", .{ item.name, std.zig.fmtEscapes(item.artifact.getOutputPath()) }) catch unreachable;2266 []const u8,
2267 item.name,
2268 self.builder.pathFromRoot(item.artifact.getOutputPath()),
2269 );
2270 }
2271 for (self.build_options_write_file_args.items) |item| {
2272 self.addBuildOption(
2273 []const u8,
2274 item.name,
2275 self.builder.pathFromRoot(item.write_file.getOutputPath(item.basename)),
2276 );
2236 }2277 }
22372278
2238 const build_options_file = try fs.path.join(2279 const build_options_file = try fs.path.join(
lib/std/c.zig+2
...@@ -100,6 +100,8 @@ pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: u64)...@@ -100,6 +100,8 @@ pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: u64)
100pub extern "c" fn mmap(addr: ?*align(page_size) c_void, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: u64) *c_void;100pub extern "c" fn mmap(addr: ?*align(page_size) c_void, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: u64) *c_void;
101pub extern "c" fn munmap(addr: *align(page_size) c_void, len: usize) c_int;101pub extern "c" fn munmap(addr: *align(page_size) c_void, len: usize) c_int;
102pub extern "c" fn mprotect(addr: *align(page_size) c_void, len: usize, prot: c_uint) c_int;102pub extern "c" fn mprotect(addr: *align(page_size) c_void, len: usize, prot: c_uint) c_int;
103pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: c_int) c_int;
104pub extern "c" fn linkat(oldfd: fd_t, oldpath: [*:0]const u8, newfd: fd_t, newpath: [*:0]const u8, flags: c_int) c_int;
103pub extern "c" fn unlink(path: [*:0]const u8) c_int;105pub extern "c" fn unlink(path: [*:0]const u8) c_int;
104pub extern "c" fn unlinkat(dirfd: fd_t, path: [*:0]const u8, flags: c_uint) c_int;106pub extern "c" fn unlinkat(dirfd: fd_t, path: [*:0]const u8, flags: c_uint) c_int;
105pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;107pub extern "c" fn getcwd(buf: [*]u8, size: usize) ?[*]u8;
lib/std/crypto/25519/ed25519.zig+5-5
...@@ -207,7 +207,7 @@ pub const Ed25519 = struct {...@@ -207,7 +207,7 @@ pub const Ed25519 = struct {
207207
208test "ed25519 key pair creation" {208test "ed25519 key pair creation" {
209 var seed: [32]u8 = undefined;209 var seed: [32]u8 = undefined;
210 try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");210 _ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
211 const key_pair = try Ed25519.KeyPair.create(seed);211 const key_pair = try Ed25519.KeyPair.create(seed);
212 var buf: [256]u8 = undefined;212 var buf: [256]u8 = undefined;
213 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{key_pair.secret_key}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");213 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{key_pair.secret_key}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
...@@ -216,7 +216,7 @@ test "ed25519 key pair creation" {...@@ -216,7 +216,7 @@ test "ed25519 key pair creation" {
216216
217test "ed25519 signature" {217test "ed25519 signature" {
218 var seed: [32]u8 = undefined;218 var seed: [32]u8 = undefined;
219 try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");219 _ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
220 const key_pair = try Ed25519.KeyPair.create(seed);220 const key_pair = try Ed25519.KeyPair.create(seed);
221221
222 const sig = try Ed25519.sign("test", key_pair, null);222 const sig = try Ed25519.sign("test", key_pair, null);
...@@ -339,11 +339,11 @@ test "ed25519 test vectors" {...@@ -339,11 +339,11 @@ test "ed25519 test vectors" {
339 };339 };
340 for (entries) |entry, i| {340 for (entries) |entry, i| {
341 var msg: [entry.msg_hex.len / 2]u8 = undefined;341 var msg: [entry.msg_hex.len / 2]u8 = undefined;
342 try fmt.hexToBytes(&msg, entry.msg_hex);342 _ = try fmt.hexToBytes(&msg, entry.msg_hex);
343 var public_key: [32]u8 = undefined;343 var public_key: [32]u8 = undefined;
344 try fmt.hexToBytes(&public_key, entry.public_key_hex);344 _ = try fmt.hexToBytes(&public_key, entry.public_key_hex);
345 var sig: [64]u8 = undefined;345 var sig: [64]u8 = undefined;
346 try fmt.hexToBytes(&sig, entry.sig_hex);346 _ = try fmt.hexToBytes(&sig, entry.sig_hex);
347 if (entry.expected) |error_type| {347 if (entry.expected) |error_type| {
348 std.testing.expectError(error_type, Ed25519.verify(sig, &msg, public_key));348 std.testing.expectError(error_type, Ed25519.verify(sig, &msg, public_key));
349 } else {349 } else {
lib/std/crypto/25519/ristretto255.zig+1-1
...@@ -173,7 +173,7 @@ test "ristretto255" {...@@ -173,7 +173,7 @@ test "ristretto255" {
173 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{p.toBytes()}), "E2F2AE0A6ABC4E71A884A961C500515F58E30B6AA582DD8DB6A65945E08D2D76");173 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{p.toBytes()}), "E2F2AE0A6ABC4E71A884A961C500515F58E30B6AA582DD8DB6A65945E08D2D76");
174174
175 var r: [Ristretto255.encoded_length]u8 = undefined;175 var r: [Ristretto255.encoded_length]u8 = undefined;
176 try fmt.hexToBytes(r[0..], "6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919");176 _ = try fmt.hexToBytes(r[0..], "6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919");
177 var q = try Ristretto255.fromBytes(r);177 var q = try Ristretto255.fromBytes(r);
178 q = q.dbl().add(p);178 q = q.dbl().add(p);
179 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{q.toBytes()}), "E882B131016B52C1D3337080187CF768423EFCCBB517BB495AB812C4160FF44E");179 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{q.toBytes()}), "E882B131016B52C1D3337080187CF768423EFCCBB517BB495AB812C4160FF44E");
lib/std/crypto/25519/x25519.zig+2-2
...@@ -85,8 +85,8 @@ const htest = @import("../test.zig");...@@ -85,8 +85,8 @@ const htest = @import("../test.zig");
85test "x25519 public key calculation from secret key" {85test "x25519 public key calculation from secret key" {
86 var sk: [32]u8 = undefined;86 var sk: [32]u8 = undefined;
87 var pk_expected: [32]u8 = undefined;87 var pk_expected: [32]u8 = undefined;
88 try fmt.hexToBytes(sk[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");88 _ = try fmt.hexToBytes(sk[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
89 try fmt.hexToBytes(pk_expected[0..], "f1814f0e8ff1043d8a44d25babff3cedcae6c22c3edaa48f857ae70de2baae50");89 _ = try fmt.hexToBytes(pk_expected[0..], "f1814f0e8ff1043d8a44d25babff3cedcae6c22c3edaa48f857ae70de2baae50");
90 const pk_calculated = try X25519.recoverPublicKey(sk);90 const pk_calculated = try X25519.recoverPublicKey(sk);
91 std.testing.expectEqual(pk_calculated, pk_expected);91 std.testing.expectEqual(pk_calculated, pk_expected);
92}92}
lib/std/crypto/aes.zig+4-4
...@@ -122,11 +122,11 @@ test "expand 128-bit key" {...@@ -122,11 +122,11 @@ test "expand 128-bit key" {
122 var exp: [16]u8 = undefined;122 var exp: [16]u8 = undefined;
123123
124 for (enc.key_schedule.round_keys) |round_key, i| {124 for (enc.key_schedule.round_keys) |round_key, i| {
125 try std.fmt.hexToBytes(&exp, exp_enc[i]);125 _ = try std.fmt.hexToBytes(&exp, exp_enc[i]);
126 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());126 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
127 }127 }
128 for (enc.key_schedule.round_keys) |round_key, i| {128 for (enc.key_schedule.round_keys) |round_key, i| {
129 try std.fmt.hexToBytes(&exp, exp_dec[i]);129 _ = try std.fmt.hexToBytes(&exp, exp_dec[i]);
130 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());130 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
131 }131 }
132}132}
...@@ -144,11 +144,11 @@ test "expand 256-bit key" {...@@ -144,11 +144,11 @@ test "expand 256-bit key" {
144 var exp: [16]u8 = undefined;144 var exp: [16]u8 = undefined;
145145
146 for (enc.key_schedule.round_keys) |round_key, i| {146 for (enc.key_schedule.round_keys) |round_key, i| {
147 try std.fmt.hexToBytes(&exp, exp_enc[i]);147 _ = try std.fmt.hexToBytes(&exp, exp_enc[i]);
148 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());148 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
149 }149 }
150 for (dec.key_schedule.round_keys) |round_key, i| {150 for (dec.key_schedule.round_keys) |round_key, i| {
151 try std.fmt.hexToBytes(&exp, exp_dec[i]);151 _ = try std.fmt.hexToBytes(&exp, exp_dec[i]);
152 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());152 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
153 }153 }
154}154}
lib/std/crypto/blake3.zig+1-1
...@@ -663,7 +663,7 @@ fn testBlake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void {...@@ -663,7 +663,7 @@ fn testBlake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void {
663663
664 // Compare to expected value664 // Compare to expected value
665 var expected_bytes: [expected_hex.len / 2]u8 = undefined;665 var expected_bytes: [expected_hex.len / 2]u8 = undefined;
666 fmt.hexToBytes(expected_bytes[0..], expected_hex[0..]) catch unreachable;666 _ = fmt.hexToBytes(expected_bytes[0..], expected_hex[0..]) catch unreachable;
667 testing.expectEqual(actual_bytes, expected_bytes);667 testing.expectEqual(actual_bytes, expected_bytes);
668668
669 // Restore initial state669 // Restore initial state
lib/std/crypto/gimli.zig+11-11
...@@ -270,7 +270,7 @@ pub fn hash(out: []u8, in: []const u8, options: Hash.Options) void {...@@ -270,7 +270,7 @@ pub fn hash(out: []u8, in: []const u8, options: Hash.Options) void {
270test "hash" {270test "hash" {
271 // a test vector (30) from NIST KAT submission.271 // a test vector (30) from NIST KAT submission.
272 var msg: [58 / 2]u8 = undefined;272 var msg: [58 / 2]u8 = undefined;
273 try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C");273 _ = try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C");
274 var md: [32]u8 = undefined;274 var md: [32]u8 = undefined;
275 hash(&md, &msg, .{});275 hash(&md, &msg, .{});
276 htest.assertEqual("1C9A03DC6A5DDC5444CFC6F4B154CFF5CF081633B2CEA4D7D0AE7CCFED5AAA44", &md);276 htest.assertEqual("1C9A03DC6A5DDC5444CFC6F4B154CFF5CF081633B2CEA4D7D0AE7CCFED5AAA44", &md);
...@@ -278,7 +278,7 @@ test "hash" {...@@ -278,7 +278,7 @@ test "hash" {
278278
279test "hash test vector 17" {279test "hash test vector 17" {
280 var msg: [32 / 2]u8 = undefined;280 var msg: [32 / 2]u8 = undefined;
281 try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F");281 _ = try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F");
282 var md: [32]u8 = undefined;282 var md: [32]u8 = undefined;
283 hash(&md, &msg, .{});283 hash(&md, &msg, .{});
284 htest.assertEqual("404C130AF1B9023A7908200919F690FFBB756D5176E056FFDE320016A37C7282", &md);284 htest.assertEqual("404C130AF1B9023A7908200919F690FFBB756D5176E056FFDE320016A37C7282", &md);
...@@ -286,7 +286,7 @@ test "hash test vector 17" {...@@ -286,7 +286,7 @@ test "hash test vector 17" {
286286
287test "hash test vector 33" {287test "hash test vector 33" {
288 var msg: [32]u8 = undefined;288 var msg: [32]u8 = undefined;
289 try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");289 _ = try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
290 var md: [32]u8 = undefined;290 var md: [32]u8 = undefined;
291 hash(&md, &msg, .{});291 hash(&md, &msg, .{});
292 htest.assertEqual("A8F4FA28708BDA7EFB4C1914CA4AFA9E475B82D588D36504F87DBB0ED9AB3C4B", &md);292 htest.assertEqual("A8F4FA28708BDA7EFB4C1914CA4AFA9E475B82D588D36504F87DBB0ED9AB3C4B", &md);
...@@ -436,9 +436,9 @@ pub const Aead = struct {...@@ -436,9 +436,9 @@ pub const Aead = struct {
436436
437test "cipher" {437test "cipher" {
438 var key: [32]u8 = undefined;438 var key: [32]u8 = undefined;
439 try std.fmt.hexToBytes(&key, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");439 _ = try std.fmt.hexToBytes(&key, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
440 var nonce: [16]u8 = undefined;440 var nonce: [16]u8 = undefined;
441 try std.fmt.hexToBytes(&nonce, "000102030405060708090A0B0C0D0E0F");441 _ = try std.fmt.hexToBytes(&nonce, "000102030405060708090A0B0C0D0E0F");
442 { // test vector (1) from NIST KAT submission.442 { // test vector (1) from NIST KAT submission.
443 const ad: [0]u8 = undefined;443 const ad: [0]u8 = undefined;
444 const pt: [0]u8 = undefined;444 const pt: [0]u8 = undefined;
...@@ -456,7 +456,7 @@ test "cipher" {...@@ -456,7 +456,7 @@ test "cipher" {
456 { // test vector (34) from NIST KAT submission.456 { // test vector (34) from NIST KAT submission.
457 const ad: [0]u8 = undefined;457 const ad: [0]u8 = undefined;
458 var pt: [2 / 2]u8 = undefined;458 var pt: [2 / 2]u8 = undefined;
459 try std.fmt.hexToBytes(&pt, "00");459 _ = try std.fmt.hexToBytes(&pt, "00");
460460
461 var ct: [pt.len]u8 = undefined;461 var ct: [pt.len]u8 = undefined;
462 var tag: [16]u8 = undefined;462 var tag: [16]u8 = undefined;
...@@ -470,9 +470,9 @@ test "cipher" {...@@ -470,9 +470,9 @@ test "cipher" {
470 }470 }
471 { // test vector (106) from NIST KAT submission.471 { // test vector (106) from NIST KAT submission.
472 var ad: [12 / 2]u8 = undefined;472 var ad: [12 / 2]u8 = undefined;
473 try std.fmt.hexToBytes(&ad, "000102030405");473 _ = try std.fmt.hexToBytes(&ad, "000102030405");
474 var pt: [6 / 2]u8 = undefined;474 var pt: [6 / 2]u8 = undefined;
475 try std.fmt.hexToBytes(&pt, "000102");475 _ = try std.fmt.hexToBytes(&pt, "000102");
476476
477 var ct: [pt.len]u8 = undefined;477 var ct: [pt.len]u8 = undefined;
478 var tag: [16]u8 = undefined;478 var tag: [16]u8 = undefined;
...@@ -486,9 +486,9 @@ test "cipher" {...@@ -486,9 +486,9 @@ test "cipher" {
486 }486 }
487 { // test vector (790) from NIST KAT submission.487 { // test vector (790) from NIST KAT submission.
488 var ad: [60 / 2]u8 = undefined;488 var ad: [60 / 2]u8 = undefined;
489 try std.fmt.hexToBytes(&ad, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D");489 _ = try std.fmt.hexToBytes(&ad, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D");
490 var pt: [46 / 2]u8 = undefined;490 var pt: [46 / 2]u8 = undefined;
491 try std.fmt.hexToBytes(&pt, "000102030405060708090A0B0C0D0E0F10111213141516");491 _ = try std.fmt.hexToBytes(&pt, "000102030405060708090A0B0C0D0E0F10111213141516");
492492
493 var ct: [pt.len]u8 = undefined;493 var ct: [pt.len]u8 = undefined;
494 var tag: [16]u8 = undefined;494 var tag: [16]u8 = undefined;
...@@ -503,7 +503,7 @@ test "cipher" {...@@ -503,7 +503,7 @@ test "cipher" {
503 { // test vector (1057) from NIST KAT submission.503 { // test vector (1057) from NIST KAT submission.
504 const ad: [0]u8 = undefined;504 const ad: [0]u8 = undefined;
505 var pt: [64 / 2]u8 = undefined;505 var pt: [64 / 2]u8 = undefined;
506 try std.fmt.hexToBytes(&pt, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");506 _ = try std.fmt.hexToBytes(&pt, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
507507
508 var ct: [pt.len]u8 = undefined;508 var ct: [pt.len]u8 = undefined;
509 var tag: [16]u8 = undefined;509 var tag: [16]u8 = undefined;
lib/std/event/loop.zig+4-5
...@@ -440,13 +440,11 @@ pub const Loop = struct {...@@ -440,13 +440,11 @@ pub const Loop = struct {
440 .overlapped = ResumeNode.overlapped_init,440 .overlapped = ResumeNode.overlapped_init,
441 },441 },
442 };442 };
443 var need_to_delete = false;443 var need_to_delete = true;
444 defer if (need_to_delete) self.linuxRemoveFd(fd);444 defer if (need_to_delete) self.linuxRemoveFd(fd);
445445
446 suspend {446 suspend {
447 if (self.linuxAddFd(fd, &resume_node.base, flags)) |_| {447 self.linuxAddFd(fd, &resume_node.base, flags) catch |err| switch (err) {
448 need_to_delete = true;
449 } else |err| switch (err) {
450 error.FileDescriptorNotRegistered => unreachable,448 error.FileDescriptorNotRegistered => unreachable,
451 error.OperationCausesCircularLoop => unreachable,449 error.OperationCausesCircularLoop => unreachable,
452 error.FileDescriptorIncompatibleWithEpoll => unreachable,450 error.FileDescriptorIncompatibleWithEpoll => unreachable,
...@@ -456,6 +454,7 @@ pub const Loop = struct {...@@ -456,6 +454,7 @@ pub const Loop = struct {
456 error.UserResourceLimitReached,454 error.UserResourceLimitReached,
457 error.Unexpected,455 error.Unexpected,
458 => {456 => {
457 need_to_delete = false;
459 // Fall back to a blocking poll(). Ideally this codepath is never hit, since458 // Fall back to a blocking poll(). Ideally this codepath is never hit, since
460 // epoll should be just fine. But this is better than incorrect behavior.459 // epoll should be just fine. But this is better than incorrect behavior.
461 var poll_flags: i16 = 0;460 var poll_flags: i16 = 0;
...@@ -479,7 +478,7 @@ pub const Loop = struct {...@@ -479,7 +478,7 @@ pub const Loop = struct {
479 };478 };
480 resume @frame();479 resume @frame();
481 },480 },
482 }481 };
483 }482 }
484 }483 }
485484
lib/std/fifo.zig+7-3
...@@ -44,6 +44,8 @@ pub fn LinearFifo(...@@ -44,6 +44,8 @@ pub fn LinearFifo(
44 count: usize,44 count: usize,
4545
46 const Self = @This();46 const Self = @This();
47 pub const Reader = std.io.Reader(*Self, error{}, readFn);
48 pub const Writer = std.io.Writer(*Self, error{OutOfMemory}, appendWrite);
4749
48 // Type of Self argument for slice operations.50 // Type of Self argument for slice operations.
49 // If buffer is inline (Static) then we need to ensure we haven't51 // If buffer is inline (Static) then we need to ensure we haven't
...@@ -153,7 +155,7 @@ pub fn LinearFifo(...@@ -153,7 +155,7 @@ pub fn LinearFifo(
153 var start = self.head + offset;155 var start = self.head + offset;
154 if (start >= self.buf.len) {156 if (start >= self.buf.len) {
155 start -= self.buf.len;157 start -= self.buf.len;
156 return self.buf[start .. self.count - offset];158 return self.buf[start .. start + (self.count - offset)];
157 } else {159 } else {
158 const end = math.min(self.head + self.count, self.buf.len);160 const end = math.min(self.head + self.count, self.buf.len);
159 return self.buf[start..end];161 return self.buf[start..end];
...@@ -228,7 +230,7 @@ pub fn LinearFifo(...@@ -228,7 +230,7 @@ pub fn LinearFifo(
228 return self.read(dest);230 return self.read(dest);
229 }231 }
230232
231 pub fn reader(self: *Self) std.io.Reader(*Self, error{}, readFn) {233 pub fn reader(self: *Self) Reader {
232 return .{ .context = self };234 return .{ .context = self };
233 }235 }
234236
...@@ -318,7 +320,7 @@ pub fn LinearFifo(...@@ -318,7 +320,7 @@ pub fn LinearFifo(
318 return bytes.len;320 return bytes.len;
319 }321 }
320322
321 pub fn writer(self: *Self) std.io.Writer(*Self, error{OutOfMemory}, appendWrite) {323 pub fn writer(self: *Self) Writer {
322 return .{ .context = self };324 return .{ .context = self };
323 }325 }
324326
...@@ -427,6 +429,8 @@ test "LinearFifo(u8, .Dynamic)" {...@@ -427,6 +429,8 @@ test "LinearFifo(u8, .Dynamic)" {
427 fifo.writeAssumeCapacity("6<chars<11");429 fifo.writeAssumeCapacity("6<chars<11");
428 testing.expectEqualSlices(u8, "HELLO6<char", fifo.readableSlice(0));430 testing.expectEqualSlices(u8, "HELLO6<char", fifo.readableSlice(0));
429 testing.expectEqualSlices(u8, "s<11", fifo.readableSlice(11));431 testing.expectEqualSlices(u8, "s<11", fifo.readableSlice(11));
432 testing.expectEqualSlices(u8, "11", fifo.readableSlice(13));
433 testing.expectEqualSlices(u8, "", fifo.readableSlice(15));
430 fifo.discard(11);434 fifo.discard(11);
431 testing.expectEqualSlices(u8, "s<11", fifo.readableSlice(0));435 testing.expectEqualSlices(u8, "s<11", fifo.readableSlice(0));
432 fifo.discard(4);436 fifo.discard(4);
lib/std/fmt.zig+22-17
...@@ -524,7 +524,7 @@ pub fn formatType(...@@ -524,7 +524,7 @@ pub fn formatType(
524 if (actual_fmt.len == 0)524 if (actual_fmt.len == 0)
525 @compileError("cannot format array ref without a specifier (i.e. {s} or {*})");525 @compileError("cannot format array ref without a specifier (i.e. {s} or {*})");
526 if (info.child == u8) {526 if (info.child == u8) {
527 if (comptime mem.indexOfScalar(u8, "sxXeEzZ", actual_fmt[0]) != null) {527 if (comptime mem.indexOfScalar(u8, "sxXeE", actual_fmt[0]) != null) {
528 return formatText(value, actual_fmt, options, writer);528 return formatText(value, actual_fmt, options, writer);
529 }529 }
530 }530 }
...@@ -542,7 +542,7 @@ pub fn formatType(...@@ -542,7 +542,7 @@ pub fn formatType(
542 return formatType(mem.span(value), actual_fmt, options, writer, max_depth);542 return formatType(mem.span(value), actual_fmt, options, writer, max_depth);
543 }543 }
544 if (ptr_info.child == u8) {544 if (ptr_info.child == u8) {
545 if (comptime mem.indexOfScalar(u8, "sxXeEzZ", actual_fmt[0]) != null) {545 if (comptime mem.indexOfScalar(u8, "sxXeE", actual_fmt[0]) != null) {
546 return formatText(mem.span(value), actual_fmt, options, writer);546 return formatText(mem.span(value), actual_fmt, options, writer);
547 }547 }
548 }548 }
...@@ -555,7 +555,7 @@ pub fn formatType(...@@ -555,7 +555,7 @@ pub fn formatType(
555 return writer.writeAll("{ ... }");555 return writer.writeAll("{ ... }");
556 }556 }
557 if (ptr_info.child == u8) {557 if (ptr_info.child == u8) {
558 if (comptime mem.indexOfScalar(u8, "sxXeEzZ", actual_fmt[0]) != null) {558 if (comptime mem.indexOfScalar(u8, "sxXeE", actual_fmt[0]) != null) {
559 return formatText(value, actual_fmt, options, writer);559 return formatText(value, actual_fmt, options, writer);
560 }560 }
561 }561 }
...@@ -576,7 +576,7 @@ pub fn formatType(...@@ -576,7 +576,7 @@ pub fn formatType(
576 return writer.writeAll("{ ... }");576 return writer.writeAll("{ ... }");
577 }577 }
578 if (info.child == u8) {578 if (info.child == u8) {
579 if (comptime mem.indexOfScalar(u8, "sxXeEzZ", actual_fmt[0]) != null) {579 if (comptime mem.indexOfScalar(u8, "sxXeE", actual_fmt[0]) != null) {
580 return formatText(&value, actual_fmt, options, writer);580 return formatText(&value, actual_fmt, options, writer);
581 }581 }
582 }582 }
...@@ -658,8 +658,6 @@ pub fn formatIntValue(...@@ -658,8 +658,6 @@ pub fn formatIntValue(
658 } else {658 } else {
659 @compileError("Cannot print integer that is larger than 8 bits as a ascii");659 @compileError("Cannot print integer that is larger than 8 bits as a ascii");
660 }660 }
661 } else if (comptime std.mem.eql(u8, fmt, "Z")) {
662 @compileError("specifier 'Z' has been deprecated, wrap your argument in std.zig.fmtEscapes instead");
663 } else if (comptime std.mem.eql(u8, fmt, "u")) {661 } else if (comptime std.mem.eql(u8, fmt, "u")) {
664 if (@typeInfo(@TypeOf(int_value)).Int.bits <= 21) {662 if (@typeInfo(@TypeOf(int_value)).Int.bits <= 21) {
665 return formatUnicodeCodepoint(@as(u21, int_value), options, writer);663 return formatUnicodeCodepoint(@as(u21, int_value), options, writer);
...@@ -735,10 +733,6 @@ pub fn formatText(...@@ -735,10 +733,6 @@ pub fn formatText(
735 }733 }
736 }734 }
737 return;735 return;
738 } else if (comptime std.mem.eql(u8, fmt, "z")) {
739 @compileError("specifier 'z' has been deprecated, wrap your argument in std.zig.fmtId instead");
740 } else if (comptime std.mem.eql(u8, fmt, "Z")) {
741 @compileError("specifier 'Z' has been deprecated, wrap your argument in std.zig.fmtEscapes instead");
742 } else {736 } else {
743 @compileError("Unsupported format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");737 @compileError("Unsupported format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");
744 }738 }
...@@ -1988,23 +1982,34 @@ test "bytes.hex" {...@@ -1988,23 +1982,34 @@ test "bytes.hex" {
1988pub const trim = @compileError("deprecated; use std.mem.trim with std.ascii.spaces instead");1982pub const trim = @compileError("deprecated; use std.mem.trim with std.ascii.spaces instead");
1989pub const isWhiteSpace = @compileError("deprecated; use std.ascii.isSpace instead");1983pub const isWhiteSpace = @compileError("deprecated; use std.ascii.isSpace instead");
19901984
1991pub fn hexToBytes(out: []u8, input: []const u8) !void {1985/// Decodes the sequence of bytes represented by the specified string of
1992 if (out.len * 2 < input.len)1986/// hexadecimal characters.
1987/// Returns a slice of the output buffer containing the decoded bytes.
1988pub fn hexToBytes(out: []u8, input: []const u8) ![]u8 {
1989 // Expect 0 or n pairs of hexadecimal digits.
1990 if (input.len & 1 != 0)
1993 return error.InvalidLength;1991 return error.InvalidLength;
1992 if (out.len * 2 < input.len)
1993 return error.NoSpaceLeft;
19941994
1995 var in_i: usize = 0;1995 var in_i: usize = 0;
1996 while (in_i != input.len) : (in_i += 2) {1996 while (in_i < input.len) : (in_i += 2) {
1997 const hi = try charToDigit(input[in_i], 16);1997 const hi = try charToDigit(input[in_i], 16);
1998 const lo = try charToDigit(input[in_i + 1], 16);1998 const lo = try charToDigit(input[in_i + 1], 16);
1999 out[in_i / 2] = (hi << 4) | lo;1999 out[in_i / 2] = (hi << 4) | lo;
2000 }2000 }
2001
2002 return out[0 .. in_i / 2];
2001}2003}
20022004
2003test "hexToBytes" {2005test "hexToBytes" {
2004 const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";2006 var buf: [32]u8 = undefined;
2005 var pb: [32]u8 = undefined;2007 try expectFmt("90" ** 32, "{X}", .{try hexToBytes(&buf, "90" ** 32)});
2006 try hexToBytes(pb[0..], test_hex_str);2008 try expectFmt("ABCD", "{X}", .{try hexToBytes(&buf, "ABCD")});
2007 try expectFmt(test_hex_str, "{X}", .{pb});2009 try expectFmt("", "{X}", .{try hexToBytes(&buf, "")});
2010 std.testing.expectError(error.InvalidCharacter, hexToBytes(&buf, "012Z"));
2011 std.testing.expectError(error.InvalidLength, hexToBytes(&buf, "AAA"));
2012 std.testing.expectError(error.NoSpaceLeft, hexToBytes(buf[0..1], "ABAB"));
2008}2013}
20092014
2010test "formatIntValue with comptime_int" {2015test "formatIntValue with comptime_int" {
lib/std/fs.zig+1-1
...@@ -2186,7 +2186,7 @@ pub const Walker = struct {...@@ -2186,7 +2186,7 @@ pub const Walker = struct {
2186 var top = &self.stack.items[self.stack.items.len - 1];2186 var top = &self.stack.items[self.stack.items.len - 1];
2187 const dirname_len = top.dirname_len;2187 const dirname_len = top.dirname_len;
2188 if (try top.dir_it.next()) |base| {2188 if (try top.dir_it.next()) |base| {
2189 self.name_buffer.shrinkAndFree(dirname_len);2189 self.name_buffer.shrinkRetainingCapacity(dirname_len);
2190 try self.name_buffer.append(path.sep);2190 try self.name_buffer.append(path.sep);
2191 try self.name_buffer.appendSlice(base.name);2191 try self.name_buffer.appendSlice(base.name);
2192 if (base.kind == .Directory) {2192 if (base.kind == .Directory) {
lib/std/fs/file.zig+2
...@@ -587,6 +587,7 @@ pub const File = struct {...@@ -587,6 +587,7 @@ pub const File = struct {
587 }587 }
588588
589 /// See https://github.com/ziglang/zig/issues/7699589 /// See https://github.com/ziglang/zig/issues/7699
590 /// See equivalent function: `std.net.Stream.writev`.
590 pub fn writev(self: File, iovecs: []const os.iovec_const) WriteError!usize {591 pub fn writev(self: File, iovecs: []const os.iovec_const) WriteError!usize {
591 if (is_windows) {592 if (is_windows) {
592 // TODO improve this to use WriteFileScatter593 // TODO improve this to use WriteFileScatter
...@@ -605,6 +606,7 @@ pub const File = struct {...@@ -605,6 +606,7 @@ pub const File = struct {
605 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in606 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in
606 /// order to handle partial writes from the underlying OS layer.607 /// order to handle partial writes from the underlying OS layer.
607 /// See https://github.com/ziglang/zig/issues/7699608 /// See https://github.com/ziglang/zig/issues/7699
609 /// See equivalent function: `std.net.Stream.writevAll`.
608 pub fn writevAll(self: File, iovecs: []os.iovec_const) WriteError!void {610 pub fn writevAll(self: File, iovecs: []os.iovec_const) WriteError!void {
609 if (iovecs.len == 0) return;611 if (iovecs.len == 0) return;
610612
lib/std/io/reader.zig+1-1
...@@ -111,7 +111,7 @@ pub fn Reader(...@@ -111,7 +111,7 @@ pub fn Reader(
111 delimiter: u8,111 delimiter: u8,
112 max_size: usize,112 max_size: usize,
113 ) !void {113 ) !void {
114 array_list.shrinkAndFree(0);114 array_list.shrinkRetainingCapacity(0);
115 while (true) {115 while (true) {
116 var byte: u8 = try self.readByte();116 var byte: u8 = try self.readByte();
117117
lib/std/json.zig+1-1
...@@ -2018,7 +2018,7 @@ pub const Parser = struct {...@@ -2018,7 +2018,7 @@ pub const Parser = struct {
20182018
2019 pub fn reset(p: *Parser) void {2019 pub fn reset(p: *Parser) void {
2020 p.state = .Simple;2020 p.state = .Simple;
2021 p.stack.shrinkAndFree(0);2021 p.stack.shrinkRetainingCapacity(0);
2022 }2022 }
20232023
2024 pub fn parse(p: *Parser, input: []const u8) !ValueTree {2024 pub fn parse(p: *Parser, input: []const u8) !ValueTree {
lib/std/math/big/int.zig+1-1
...@@ -607,7 +607,7 @@ pub const Mutable = struct {...@@ -607,7 +607,7 @@ pub const Mutable = struct {
607 /// it will have the same length as it had when the function was called.607 /// it will have the same length as it had when the function was called.
608 pub fn gcd(rma: *Mutable, x: Const, y: Const, limbs_buffer: *std.ArrayList(Limb)) !void {608 pub fn gcd(rma: *Mutable, x: Const, y: Const, limbs_buffer: *std.ArrayList(Limb)) !void {
609 const prev_len = limbs_buffer.items.len;609 const prev_len = limbs_buffer.items.len;
610 defer limbs_buffer.shrinkAndFree(prev_len);610 defer limbs_buffer.shrinkRetainingCapacity(prev_len);
611 const x_copy = if (rma.limbs.ptr == x.limbs.ptr) blk: {611 const x_copy = if (rma.limbs.ptr == x.limbs.ptr) blk: {
612 const start = limbs_buffer.items.len;612 const start = limbs_buffer.items.len;
613 try limbs_buffer.appendSlice(x.limbs);613 try limbs_buffer.appendSlice(x.limbs);
lib/std/net.zig+39-2
...@@ -1205,13 +1205,13 @@ fn linuxLookupNameFromDnsSearch(...@@ -1205,13 +1205,13 @@ fn linuxLookupNameFromDnsSearch(
12051205
1206 var tok_it = mem.tokenize(search, " \t");1206 var tok_it = mem.tokenize(search, " \t");
1207 while (tok_it.next()) |tok| {1207 while (tok_it.next()) |tok| {
1208 canon.shrinkAndFree(canon_name.len + 1);1208 canon.shrinkRetainingCapacity(canon_name.len + 1);
1209 try canon.appendSlice(tok);1209 try canon.appendSlice(tok);
1210 try linuxLookupNameFromDns(addrs, canon, canon.items, family, rc, port);1210 try linuxLookupNameFromDns(addrs, canon, canon.items, family, rc, port);
1211 if (addrs.items.len != 0) return;1211 if (addrs.items.len != 0) return;
1212 }1212 }
12131213
1214 canon.shrinkAndFree(canon_name.len);1214 canon.shrinkRetainingCapacity(canon_name.len);
1215 return linuxLookupNameFromDns(addrs, canon, name, family, rc, port);1215 return linuxLookupNameFromDns(addrs, canon, name, family, rc, port);
1216}1216}
12171217
...@@ -1621,6 +1621,9 @@ pub const Stream = struct {...@@ -1621,6 +1621,9 @@ pub const Stream = struct {
1621 }1621 }
1622 }1622 }
16231623
1624 /// TODO in evented I/O mode, this implementation incorrectly uses the event loop's
1625 /// file system thread instead of non-blocking. It needs to be reworked to properly
1626 /// use non-blocking I/O.
1624 pub fn write(self: Stream, buffer: []const u8) WriteError!usize {1627 pub fn write(self: Stream, buffer: []const u8) WriteError!usize {
1625 if (std.Target.current.os.tag == .windows) {1628 if (std.Target.current.os.tag == .windows) {
1626 return os.windows.WriteFile(self.handle, buffer, null, io.default_mode);1629 return os.windows.WriteFile(self.handle, buffer, null, io.default_mode);
...@@ -1632,6 +1635,40 @@ pub const Stream = struct {...@@ -1632,6 +1635,40 @@ pub const Stream = struct {
1632 return os.write(self.handle, buffer);1635 return os.write(self.handle, buffer);
1633 }1636 }
1634 }1637 }
1638
1639 /// See https://github.com/ziglang/zig/issues/7699
1640 /// See equivalent function: `std.fs.File.writev`.
1641 pub fn writev(self: Stream, iovecs: []const os.iovec_const) WriteError!usize {
1642 if (std.io.is_async) {
1643 // TODO improve to actually take advantage of writev syscall, if available.
1644 if (iovecs.len == 0) return 0;
1645 const first_buffer = iovecs[0].iov_base[0..iovecs[0].iov_len];
1646 try self.write(first_buffer);
1647 return first_buffer.len;
1648 } else {
1649 return os.writev(self.handle, iovecs);
1650 }
1651 }
1652
1653 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in
1654 /// order to handle partial writes from the underlying OS layer.
1655 /// See https://github.com/ziglang/zig/issues/7699
1656 /// See equivalent function: `std.fs.File.writevAll`.
1657 pub fn writevAll(self: Stream, iovecs: []os.iovec_const) WriteError!void {
1658 if (iovecs.len == 0) return;
1659
1660 var i: usize = 0;
1661 while (true) {
1662 var amt = try self.writev(iovecs[i..]);
1663 while (amt >= iovecs[i].iov_len) {
1664 amt -= iovecs[i].iov_len;
1665 i += 1;
1666 if (i >= iovecs.len) return;
1667 }
1668 iovecs[i].iov_base += amt;
1669 iovecs[i].iov_len -= amt;
1670 }
1671 }
1635};1672};
16361673
1637pub const StreamServer = struct {1674pub const StreamServer = struct {
lib/std/os.zig+86
...@@ -1634,6 +1634,92 @@ pub fn symlinkatZ(target_path: [*:0]const u8, newdirfd: fd_t, sym_link_path: [*:...@@ -1634,6 +1634,92 @@ pub fn symlinkatZ(target_path: [*:0]const u8, newdirfd: fd_t, sym_link_path: [*:
1634 }1634 }
1635}1635}
16361636
1637pub const LinkError = UnexpectedError || error{
1638 AccessDenied,
1639 DiskQuota,
1640 PathAlreadyExists,
1641 FileSystem,
1642 SymLinkLoop,
1643 LinkQuotaExceeded,
1644 NameTooLong,
1645 FileNotFound,
1646 SystemResources,
1647 NoSpaceLeft,
1648 ReadOnlyFileSystem,
1649 NotSameFileSystem,
1650};
1651
1652pub fn linkZ(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: i32) LinkError!void {
1653 switch (errno(system.link(oldpath, newpath, flags))) {
1654 0 => return,
1655 EACCES => return error.AccessDenied,
1656 EDQUOT => return error.DiskQuota,
1657 EEXIST => return error.PathAlreadyExists,
1658 EFAULT => unreachable,
1659 EIO => return error.FileSystem,
1660 ELOOP => return error.SymLinkLoop,
1661 EMLINK => return error.LinkQuotaExceeded,
1662 ENAMETOOLONG => return error.NameTooLong,
1663 ENOENT => return error.FileNotFound,
1664 ENOMEM => return error.SystemResources,
1665 ENOSPC => return error.NoSpaceLeft,
1666 EPERM => return error.AccessDenied,
1667 EROFS => return error.ReadOnlyFileSystem,
1668 EXDEV => return error.NotSameFileSystem,
1669 EINVAL => unreachable,
1670 else => |err| return unexpectedErrno(err),
1671 }
1672}
1673
1674pub fn link(oldpath: []const u8, newpath: []const u8, flags: i32) LinkError!void {
1675 const old = try toPosixPath(oldpath);
1676 const new = try toPosixPath(newpath);
1677 return try linkZ(&old, &new, flags);
1678}
1679
1680pub const LinkatError = LinkError || error{NotDir};
1681
1682pub fn linkatZ(
1683 olddir: fd_t,
1684 oldpath: [*:0]const u8,
1685 newdir: fd_t,
1686 newpath: [*:0]const u8,
1687 flags: i32,
1688) LinkatError!void {
1689 switch (errno(system.linkat(olddir, oldpath, newdir, newpath, flags))) {
1690 0 => return,
1691 EACCES => return error.AccessDenied,
1692 EDQUOT => return error.DiskQuota,
1693 EEXIST => return error.PathAlreadyExists,
1694 EFAULT => unreachable,
1695 EIO => return error.FileSystem,
1696 ELOOP => return error.SymLinkLoop,
1697 EMLINK => return error.LinkQuotaExceeded,
1698 ENAMETOOLONG => return error.NameTooLong,
1699 ENOENT => return error.FileNotFound,
1700 ENOMEM => return error.SystemResources,
1701 ENOSPC => return error.NoSpaceLeft,
1702 ENOTDIR => return error.NotDir,
1703 EPERM => return error.AccessDenied,
1704 EROFS => return error.ReadOnlyFileSystem,
1705 EXDEV => return error.NotSameFileSystem,
1706 EINVAL => unreachable,
1707 else => |err| return unexpectedErrno(err),
1708 }
1709}
1710
1711pub fn linkat(
1712 olddir: fd_t,
1713 oldpath: []const u8,
1714 newdir: fd_t,
1715 newpath: []const u8,
1716 flags: i32,
1717) LinkatError!void {
1718 const old = try toPosixPath(oldpath);
1719 const new = try toPosixPath(newpath);
1720 return try linkatZ(olddir, &old, newdir, &new, flags);
1721}
1722
1637pub const UnlinkError = error{1723pub const UnlinkError = error{
1638 FileNotFound,1724 FileNotFound,
16391725
lib/std/os/bits/linux/arm-eabi.zig+1
...@@ -412,6 +412,7 @@ pub const SYS = extern enum(usize) {...@@ -412,6 +412,7 @@ pub const SYS = extern enum(usize) {
412 pidfd_getfd = 438,412 pidfd_getfd = 438,
413 faccessat2 = 439,413 faccessat2 = 439,
414 process_madvise = 440,414 process_madvise = 440,
415 epoll_pwait2 = 441,
415416
416 breakpoint = 0x0f0001,417 breakpoint = 0x0f0001,
417 cacheflush = 0x0f0002,418 cacheflush = 0x0f0002,
lib/std/os/bits/linux/arm64.zig+1
...@@ -313,6 +313,7 @@ pub const SYS = extern enum(usize) {...@@ -313,6 +313,7 @@ pub const SYS = extern enum(usize) {
313 pidfd_getfd = 438,313 pidfd_getfd = 438,
314 faccessat2 = 439,314 faccessat2 = 439,
315 process_madvise = 440,315 process_madvise = 440,
316 epoll_pwait2 = 441,
316317
317 _,318 _,
318};319};
lib/std/os/bits/linux/i386.zig+1
...@@ -448,6 +448,7 @@ pub const SYS = extern enum(usize) {...@@ -448,6 +448,7 @@ pub const SYS = extern enum(usize) {
448 pidfd_getfd = 438,448 pidfd_getfd = 438,
449 faccessat2 = 439,449 faccessat2 = 439,
450 process_madvise = 440,450 process_madvise = 440,
451 epoll_pwait2 = 441,
451452
452 _,453 _,
453};454};
lib/std/os/bits/linux/mips.zig+1
...@@ -430,6 +430,7 @@ pub const SYS = extern enum(usize) {...@@ -430,6 +430,7 @@ pub const SYS = extern enum(usize) {
430 pidfd_getfd = Linux + 438,430 pidfd_getfd = Linux + 438,
431 faccessat2 = Linux + 439,431 faccessat2 = Linux + 439,
432 process_madvise = Linux + 440,432 process_madvise = Linux + 440,
433 epoll_pwait2 = Linux + 441,
433434
434 _,435 _,
435};436};
lib/std/os/bits/linux/powerpc64.zig+1
...@@ -409,6 +409,7 @@ pub const SYS = extern enum(usize) {...@@ -409,6 +409,7 @@ pub const SYS = extern enum(usize) {
409 pidfd_getfd = 438,409 pidfd_getfd = 438,
410 faccessat2 = 439,410 faccessat2 = 439,
411 process_madvise = 440,411 process_madvise = 440,
412 epoll_pwait2 = 441,
412413
413 _,414 _,
414};415};
lib/std/os/bits/linux/riscv64.zig+1
...@@ -310,6 +310,7 @@ pub const SYS = extern enum(usize) {...@@ -310,6 +310,7 @@ pub const SYS = extern enum(usize) {
310 pidfd_getfd = 438,310 pidfd_getfd = 438,
311 faccessat2 = 439,311 faccessat2 = 439,
312 process_madvise = 440,312 process_madvise = 440,
313 epoll_pwait2 = 441,
313314
314 _,315 _,
315};316};
lib/std/os/bits/linux/sparc64.zig+1
...@@ -387,6 +387,7 @@ pub const SYS = extern enum(usize) {...@@ -387,6 +387,7 @@ pub const SYS = extern enum(usize) {
387 pidfd_getfd = 438,387 pidfd_getfd = 438,
388 faccessat2 = 439,388 faccessat2 = 439,
389 process_madvise = 440,389 process_madvise = 440,
390 epoll_pwait2 = 441,
390391
391 _,392 _,
392};393};
lib/std/os/bits/linux/x86_64.zig+1
...@@ -375,6 +375,7 @@ pub const SYS = extern enum(usize) {...@@ -375,6 +375,7 @@ pub const SYS = extern enum(usize) {
375 pidfd_getfd = 438,375 pidfd_getfd = 438,
376 faccessat2 = 439,376 faccessat2 = 439,
377 process_madvise = 440,377 process_madvise = 440,
378 epoll_pwait2 = 441,
378379
379 _,380 _,
380};381};
lib/std/os/linux.zig+31
...@@ -634,6 +634,37 @@ pub fn tgkill(tgid: pid_t, tid: pid_t, sig: i32) usize {...@@ -634,6 +634,37 @@ pub fn tgkill(tgid: pid_t, tid: pid_t, sig: i32) usize {
634 return syscall2(.tgkill, @bitCast(usize, @as(isize, tgid)), @bitCast(usize, @as(isize, tid)), @bitCast(usize, @as(isize, sig)));634 return syscall2(.tgkill, @bitCast(usize, @as(isize, tgid)), @bitCast(usize, @as(isize, tid)), @bitCast(usize, @as(isize, sig)));
635}635}
636636
637pub fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: i32) usize {
638 if (@hasField(SYS, "link")) {
639 return syscall3(
640 .link,
641 @ptrToInt(oldpath),
642 @ptrToInt(newpath),
643 @bitCast(usize, @as(isize, flags)),
644 );
645 } else {
646 return syscall5(
647 .linkat,
648 @bitCast(usize, @as(isize, AT_FDCWD)),
649 @ptrToInt(oldpath),
650 @bitCast(usize, @as(isize, AT_FDCWD)),
651 @ptrToInt(newpath),
652 @bitCast(usize, @as(isize, flags)),
653 );
654 }
655}
656
657pub fn linkat(oldfd: fd_t, oldpath: [*:0]const u8, newfd: fd_t, newpath: [*:0]const u8, flags: i32) usize {
658 return syscall5(
659 .linkat,
660 @bitCast(usize, @as(isize, oldfd)),
661 @ptrToInt(oldpath),
662 @bitCast(usize, @as(isize, newfd)),
663 @ptrToInt(newpath),
664 @bitCast(usize, @as(isize, flags)),
665 );
666}
667
637pub fn unlink(path: [*:0]const u8) usize {668pub fn unlink(path: [*:0]const u8) usize {
638 if (@hasField(SYS, "unlink")) {669 if (@hasField(SYS, "unlink")) {
639 return syscall1(.unlink, @ptrToInt(path));670 return syscall1(.unlink, @ptrToInt(path));
lib/std/os/test.zig+69
...@@ -189,6 +189,75 @@ fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {...@@ -189,6 +189,75 @@ fn testReadlink(target_path: []const u8, symlink_path: []const u8) !void {
189 expect(mem.eql(u8, target_path, given));189 expect(mem.eql(u8, target_path, given));
190}190}
191191
192test "link with relative paths" {
193 if (builtin.os.tag != .linux) return error.SkipZigTest;
194 var cwd = fs.cwd();
195
196 cwd.deleteFile("example.txt") catch {};
197 cwd.deleteFile("new.txt") catch {};
198
199 try cwd.writeFile("example.txt", "example");
200 try os.link("example.txt", "new.txt", 0);
201
202 const efd = try cwd.openFile("example.txt", .{});
203 defer efd.close();
204
205 const nfd = try cwd.openFile("new.txt", .{});
206 defer nfd.close();
207
208 {
209 const estat = try os.fstat(efd.handle);
210 const nstat = try os.fstat(nfd.handle);
211
212 testing.expectEqual(estat.ino, nstat.ino);
213 testing.expectEqual(@as(usize, 2), nstat.nlink);
214 }
215
216 try os.unlink("new.txt");
217
218 {
219 const estat = try os.fstat(efd.handle);
220 testing.expectEqual(@as(usize, 1), estat.nlink);
221 }
222
223 try cwd.deleteFile("example.txt");
224}
225
226test "linkat with different directories" {
227 if (builtin.os.tag != .linux) return error.SkipZigTest;
228 var cwd = fs.cwd();
229 var tmp = tmpDir(.{});
230
231 cwd.deleteFile("example.txt") catch {};
232 tmp.dir.deleteFile("new.txt") catch {};
233
234 try cwd.writeFile("example.txt", "example");
235 try os.linkat(cwd.fd, "example.txt", tmp.dir.fd, "new.txt", 0);
236
237 const efd = try cwd.openFile("example.txt", .{});
238 defer efd.close();
239
240 const nfd = try tmp.dir.openFile("new.txt", .{});
241
242 {
243 defer nfd.close();
244 const estat = try os.fstat(efd.handle);
245 const nstat = try os.fstat(nfd.handle);
246
247 testing.expectEqual(estat.ino, nstat.ino);
248 testing.expectEqual(@as(usize, 2), nstat.nlink);
249 }
250
251 try os.unlinkat(tmp.dir.fd, "new.txt", 0);
252
253 {
254 const estat = try os.fstat(efd.handle);
255 testing.expectEqual(@as(usize, 1), estat.nlink);
256 }
257
258 try cwd.deleteFile("example.txt");
259}
260
192test "fstatat" {261test "fstatat" {
193 // enable when `fstat` and `fstatat` are implemented on Windows262 // enable when `fstat` and `fstatat` are implemented on Windows
194 if (builtin.os.tag == .windows) return error.SkipZigTest;263 if (builtin.os.tag == .windows) return error.SkipZigTest;
lib/std/os/uefi.zig+14-3
...@@ -3,6 +3,8 @@...@@ -3,6 +3,8 @@
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.5// and substantial portions of the software.
6const std = @import("../std.zig");
7
6/// A protocol is an interface identified by a GUID.8/// A protocol is an interface identified by a GUID.
7pub const protocols = @import("uefi/protocols.zig");9pub const protocols = @import("uefi/protocols.zig");
810
...@@ -33,10 +35,10 @@ pub const Guid = extern struct {...@@ -33,10 +35,10 @@ pub const Guid = extern struct {
33 self: @This(),35 self: @This(),
34 comptime f: []const u8,36 comptime f: []const u8,
35 options: std.fmt.FormatOptions,37 options: std.fmt.FormatOptions,
36 out_stream: anytype,38 writer: anytype,
37 ) Errors!void {39 ) !void {
38 if (f.len == 0) {40 if (f.len == 0) {
39 return std.fmt.format(out_stream, "{x:0>8}-{x:0>4}-{x:0>4}-{x:0>2}{x:0>2}-{x:0>12}", .{41 return std.fmt.format(writer, "{x:0>8}-{x:0>4}-{x:0>4}-{x:0>2}{x:0>2}-{x:0>12}", .{
40 self.time_low,42 self.time_low,
41 self.time_mid,43 self.time_mid,
42 self.time_high_and_version,44 self.time_high_and_version,
...@@ -48,6 +50,15 @@ pub const Guid = extern struct {...@@ -48,6 +50,15 @@ pub const Guid = extern struct {
48 @compileError("Unknown format character: '" ++ f ++ "'");50 @compileError("Unknown format character: '" ++ f ++ "'");
49 }51 }
50 }52 }
53
54 pub fn eql(a: std.os.uefi.Guid, b: std.os.uefi.Guid) bool {
55 return a.time_low == b.time_low and
56 a.time_mid == b.time_mid and
57 a.time_high_and_version == b.time_high_and_version and
58 a.clock_seq_high_and_reserved == b.clock_seq_high_and_reserved and
59 a.clock_seq_low == b.clock_seq_low and
60 std.mem.eql(u8, &a.node, &b.node);
61 }
51};62};
5263
53/// An EFI Handle represents a collection of related interfaces.64/// An EFI Handle represents a collection of related interfaces.
lib/std/wasm.zig+14
...@@ -253,6 +253,20 @@ pub fn section(val: Section) u8 {...@@ -253,6 +253,20 @@ pub fn section(val: Section) u8 {
253 return @enumToInt(val);253 return @enumToInt(val);
254}254}
255255
256/// The kind of the type when importing or exporting to/from the host environment
257/// https://webassembly.github.io/spec/core/syntax/modules.html
258pub const ExternalKind = enum(u8) {
259 function,
260 table,
261 memory,
262 global,
263};
264
265/// Returns the integer value of a given `ExternalKind`
266pub fn externalKind(val: ExternalKind) u8 {
267 return @enumToInt(val);
268}
269
256// types270// types
257pub const element_type: u8 = 0x70;271pub const element_type: u8 = 0x70;
258pub const function_type: u8 = 0x60;272pub const function_type: u8 = 0x60;
lib/std/zig/parser_test.zig+1-1
...@@ -648,7 +648,7 @@ test "zig fmt: struct literal 1 element" {...@@ -648,7 +648,7 @@ test "zig fmt: struct literal 1 element" {
648 );648 );
649}649}
650650
651test "zig fmt: struct literal 1 element comma" {651test "zig fmt: Unicode code point literal larger than u8" {
652 try testCanonical(652 try testCanonical(
653 \\test {653 \\test {
654 \\ const x = X{654 \\ const x = X{
lib/std/zig/tokenizer.zig+3-3
...@@ -1535,7 +1535,7 @@ test "tokenizer - unknown length pointer and then c pointer" {...@@ -1535,7 +1535,7 @@ test "tokenizer - unknown length pointer and then c pointer" {
1535 });1535 });
1536}1536}
15371537
1538test "tokenizer - char literal with hex escape" {1538test "tokenizer - code point literal with hex escape" {
1539 testTokenize(1539 testTokenize(
1540 \\'\x1b'1540 \\'\x1b'
1541 , &.{.char_literal});1541 , &.{.char_literal});
...@@ -1544,7 +1544,7 @@ test "tokenizer - char literal with hex escape" {...@@ -1544,7 +1544,7 @@ test "tokenizer - char literal with hex escape" {
1544 , &.{ .invalid, .invalid });1544 , &.{ .invalid, .invalid });
1545}1545}
15461546
1547test "tokenizer - char literal with unicode escapes" {1547test "tokenizer - code point literal with unicode escapes" {
1548 // Valid unicode escapes1548 // Valid unicode escapes
1549 testTokenize(1549 testTokenize(
1550 \\'\u{3}'1550 \\'\u{3}'
...@@ -1594,7 +1594,7 @@ test "tokenizer - char literal with unicode escapes" {...@@ -1594,7 +1594,7 @@ test "tokenizer - char literal with unicode escapes" {
1594 , &.{ .invalid, .integer_literal, .invalid });1594 , &.{ .invalid, .integer_literal, .invalid });
1595}1595}
15961596
1597test "tokenizer - char literal with unicode code point" {1597test "tokenizer - code point literal with unicode code point" {
1598 testTokenize(1598 testTokenize(
1599 \\'💩'1599 \\'💩'
1600 , &.{.char_literal});1600 , &.{.char_literal});
src/Cache.zig+1-1
...@@ -317,7 +317,7 @@ pub const Manifest = struct {...@@ -317,7 +317,7 @@ pub const Manifest = struct {
317 cache_hash_file.stat.size = fmt.parseInt(u64, size, 10) catch return error.InvalidFormat;317 cache_hash_file.stat.size = fmt.parseInt(u64, size, 10) catch return error.InvalidFormat;
318 cache_hash_file.stat.inode = fmt.parseInt(fs.File.INode, inode, 10) catch return error.InvalidFormat;318 cache_hash_file.stat.inode = fmt.parseInt(fs.File.INode, inode, 10) catch return error.InvalidFormat;
319 cache_hash_file.stat.mtime = fmt.parseInt(i64, mtime_nsec_str, 10) catch return error.InvalidFormat;319 cache_hash_file.stat.mtime = fmt.parseInt(i64, mtime_nsec_str, 10) catch return error.InvalidFormat;
320 std.fmt.hexToBytes(&cache_hash_file.bin_digest, digest_str) catch return error.InvalidFormat;320 _ = std.fmt.hexToBytes(&cache_hash_file.bin_digest, digest_str) catch return error.InvalidFormat;
321321
322 if (file_path.len == 0) {322 if (file_path.len == 0) {
323 return error.InvalidFormat;323 return error.InvalidFormat;
src/Compilation.zig+4-2
...@@ -645,7 +645,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -645,7 +645,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
645 };645 };
646646
647 const darwin_options: DarwinOptions = if (build_options.have_llvm and comptime std.Target.current.isDarwin()) outer: {647 const darwin_options: DarwinOptions = if (build_options.have_llvm and comptime std.Target.current.isDarwin()) outer: {
648 const opts: DarwinOptions = if (use_lld and options.is_native_os and options.target.isDarwin()) inner: {648 const opts: DarwinOptions = if (use_lld and std.builtin.os.tag == .macos and options.target.isDarwin()) inner: {
649 // TODO Revisit this targeting versions lower than macOS 11 when LLVM 12 is out.649 // TODO Revisit this targeting versions lower than macOS 11 when LLVM 12 is out.
650 // See https://github.com/ziglang/zig/issues/6996650 // See https://github.com/ziglang/zig/issues/6996
651 const at_least_big_sur = options.target.os.getVersionRange().semver.min.major >= 11;651 const at_least_big_sur = options.target.os.getVersionRange().semver.min.major >= 11;
...@@ -1538,7 +1538,9 @@ pub fn getCompileLogOutput(self: *Compilation) []const u8 {...@@ -1538,7 +1538,9 @@ pub fn getCompileLogOutput(self: *Compilation) []const u8 {
1538}1538}
15391539
1540pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemory }!void {1540pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemory }!void {
1541 var progress: std.Progress = .{};1541 // If the terminal is dumb, we dont want to show the user all the
1542 // output.
1543 var progress: std.Progress = .{ .dont_print_on_dumb = true };
1542 var main_progress_node = try progress.start("", 0);1544 var main_progress_node = try progress.start("", 0);
1543 defer main_progress_node.end();1545 defer main_progress_node.end();
1544 if (self.color == .off) progress.terminal = null;1546 if (self.color == .off) progress.terminal = null;
src/codegen.zig+61-58
...@@ -944,7 +944,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -944,7 +944,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
944 /// Copies a value to a register without tracking the register. The register is not considered944 /// Copies a value to a register without tracking the register. The register is not considered
945 /// allocated. A second call to `copyToTmpRegister` may return the same register.945 /// allocated. A second call to `copyToTmpRegister` may return the same register.
946 /// This can have a side effect of spilling instructions to the stack to free up a register.946 /// This can have a side effect of spilling instructions to the stack to free up a register.
947 fn copyToTmpRegister(self: *Self, src: usize, mcv: MCValue) !Register {947 fn copyToTmpRegister(self: *Self, src: usize, ty: Type, mcv: MCValue) !Register {
948 const reg = self.findUnusedReg() orelse b: {948 const reg = self.findUnusedReg() orelse b: {
949 // We'll take over the first register. Move the instruction that was previously949 // We'll take over the first register. Move the instruction that was previously
950 // there to a stack allocation.950 // there to a stack allocation.
...@@ -961,7 +961,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -961,7 +961,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
961961
962 break :b reg;962 break :b reg;
963 };963 };
964 try self.genSetReg(src, reg, mcv);964 try self.genSetReg(src, ty, reg, mcv);
965 return reg;965 return reg;
966 }966 }
967967
...@@ -988,7 +988,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -988,7 +988,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
988988
989 break :b reg;989 break :b reg;
990 };990 };
991 try self.genSetReg(reg_owner.src, reg, mcv);991 try self.genSetReg(reg_owner.src, reg_owner.ty, reg, mcv);
992 return MCValue{ .register = reg };992 return MCValue{ .register = reg };
993 }993 }
994994
...@@ -1356,13 +1356,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1356,13 +1356,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1356 // Load immediate into register if it doesn't fit1356 // Load immediate into register if it doesn't fit
1357 // as an operand1357 // as an operand
1358 break :blk Instruction.Operand.fromU32(@intCast(u32, imm)) orelse1358 break :blk Instruction.Operand.fromU32(@intCast(u32, imm)) orelse
1359 Instruction.Operand.reg(try self.copyToTmpRegister(src, op2), Instruction.Operand.Shift.none);1359 Instruction.Operand.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), op2), Instruction.Operand.Shift.none);
1360 },1360 },
1361 .register => |reg| Instruction.Operand.reg(reg, Instruction.Operand.Shift.none),1361 .register => |reg| Instruction.Operand.reg(reg, Instruction.Operand.Shift.none),
1362 .stack_offset,1362 .stack_offset,
1363 .embedded_in_code,1363 .embedded_in_code,
1364 .memory,1364 .memory,
1365 => Instruction.Operand.reg(try self.copyToTmpRegister(src, op2), Instruction.Operand.Shift.none),1365 => Instruction.Operand.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), op2), Instruction.Operand.Shift.none),
1366 };1366 };
13671367
1368 switch (op) {1368 switch (op) {
...@@ -1448,7 +1448,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1448,7 +1448,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1448 switch (src_mcv) {1448 switch (src_mcv) {
1449 .immediate => |imm| {1449 .immediate => |imm| {
1450 if (imm > math.maxInt(u31)) {1450 if (imm > math.maxInt(u31)) {
1451 src_mcv = MCValue{ .register = try self.copyToTmpRegister(src_inst.src, src_mcv) };1451 src_mcv = MCValue{ .register = try self.copyToTmpRegister(src_inst.src, Type.initTag(.u64), src_mcv) };
1452 }1452 }
1453 },1453 },
1454 else => {},1454 else => {},
...@@ -1479,7 +1479,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1479,7 +1479,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1479 .register => |dst_reg| {1479 .register => |dst_reg| {
1480 switch (src_mcv) {1480 switch (src_mcv) {
1481 .none => unreachable,1481 .none => unreachable,
1482 .undef => try self.genSetReg(src, dst_reg, .undef),1482 .undef => try self.genSetReg(src, dst_ty, dst_reg, .undef),
1483 .dead, .unreach => unreachable,1483 .dead, .unreach => unreachable,
1484 .ptr_stack_offset => unreachable,1484 .ptr_stack_offset => unreachable,
1485 .ptr_embedded_in_code => unreachable,1485 .ptr_embedded_in_code => unreachable,
...@@ -1689,7 +1689,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1689,7 +1689,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1689 switch (mc_arg) {1689 switch (mc_arg) {
1690 .none => continue,1690 .none => continue,
1691 .register => |reg| {1691 .register => |reg| {
1692 try self.genSetReg(arg.src, reg, arg_mcv);1692 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
1693 // TODO interact with the register allocator to mark the instruction as moved.1693 // TODO interact with the register allocator to mark the instruction as moved.
1694 },1694 },
1695 .stack_offset => {1695 .stack_offset => {
...@@ -1758,7 +1758,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1758,7 +1758,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1758 else1758 else
1759 unreachable;1759 unreachable;
17601760
1761 try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr });1761 try self.genSetReg(inst.base.src, Type.initTag(.usize), .ra, .{ .memory = got_addr });
1762 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32());1762 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32());
1763 } else if (func_value.castTag(.extern_fn)) |_| {1763 } else if (func_value.castTag(.extern_fn)) |_| {
1764 return self.fail(inst.base.src, "TODO implement calling extern functions", .{});1764 return self.fail(inst.base.src, "TODO implement calling extern functions", .{});
...@@ -1831,7 +1831,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1831,7 +1831,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1831 .compare_flags_signed => unreachable,1831 .compare_flags_signed => unreachable,
1832 .compare_flags_unsigned => unreachable,1832 .compare_flags_unsigned => unreachable,
1833 .register => |reg| {1833 .register => |reg| {
1834 try self.genSetReg(arg.src, reg, arg_mcv);1834 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
1835 // TODO interact with the register allocator to mark the instruction as moved.1835 // TODO interact with the register allocator to mark the instruction as moved.
1836 },1836 },
1837 .stack_offset => {1837 .stack_offset => {
...@@ -1859,7 +1859,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1859,7 +1859,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1859 else1859 else
1860 unreachable;1860 unreachable;
18611861
1862 try self.genSetReg(inst.base.src, .lr, .{ .memory = got_addr });1862 try self.genSetReg(inst.base.src, Type.initTag(.usize), .lr, .{ .memory = got_addr });
18631863
1864 // TODO: add Instruction.supportedOn1864 // TODO: add Instruction.supportedOn
1865 // function for ARM1865 // function for ARM
...@@ -1894,7 +1894,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1894,7 +1894,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1894 .compare_flags_signed => unreachable,1894 .compare_flags_signed => unreachable,
1895 .compare_flags_unsigned => unreachable,1895 .compare_flags_unsigned => unreachable,
1896 .register => |reg| {1896 .register => |reg| {
1897 try self.genSetReg(arg.src, reg, arg_mcv);1897 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
1898 // TODO interact with the register allocator to mark the instruction as moved.1898 // TODO interact with the register allocator to mark the instruction as moved.
1899 },1899 },
1900 .stack_offset => {1900 .stack_offset => {
...@@ -1922,7 +1922,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1922,7 +1922,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1922 else1922 else
1923 unreachable;1923 unreachable;
19241924
1925 try self.genSetReg(inst.base.src, .x30, .{ .memory = got_addr });1925 try self.genSetReg(inst.base.src, Type.initTag(.usize), .x30, .{ .memory = got_addr });
19261926
1927 writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32());1927 writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32());
1928 } else if (func_value.castTag(.extern_fn)) |_| {1928 } else if (func_value.castTag(.extern_fn)) |_| {
...@@ -1945,7 +1945,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1945,7 +1945,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1945 switch (mc_arg) {1945 switch (mc_arg) {
1946 .none => continue,1946 .none => continue,
1947 .register => |reg| {1947 .register => |reg| {
1948 try self.genSetReg(arg.src, reg, arg_mcv);1948 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
1949 // TODO interact with the register allocator to mark the instruction as moved.1949 // TODO interact with the register allocator to mark the instruction as moved.
1950 },1950 },
1951 .stack_offset => {1951 .stack_offset => {
...@@ -1978,12 +1978,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1978,12 +1978,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1978 const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64);1978 const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64);
1979 switch (arch) {1979 switch (arch) {
1980 .x86_64 => {1980 .x86_64 => {
1981 try self.genSetReg(inst.base.src, .rax, .{ .memory = got_addr });1981 try self.genSetReg(inst.base.src, Type.initTag(.u32), .rax, .{ .memory = got_addr });
1982 // callq *%rax1982 // callq *%rax
1983 self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 });1983 self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 });
1984 },1984 },
1985 .aarch64 => {1985 .aarch64 => {
1986 try self.genSetReg(inst.base.src, .x30, .{ .memory = got_addr });1986 try self.genSetReg(inst.base.src, Type.initTag(.u32), .x30, .{ .memory = got_addr });
1987 // blr x301987 // blr x30
1988 writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32());1988 writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32());
1989 },1989 },
...@@ -2584,7 +2584,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2584,7 +2584,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2584 const reg = parseRegName(reg_name) orelse2584 const reg = parseRegName(reg_name) orelse
2585 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});2585 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2586 const arg = try self.resolveInst(inst.args[i]);2586 const arg = try self.resolveInst(inst.args[i]);
2587 try self.genSetReg(inst.base.src, reg, arg);2587 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);
2588 }2588 }
25892589
2590 if (mem.eql(u8, inst.asm_source, "svc #0")) {2590 if (mem.eql(u8, inst.asm_source, "svc #0")) {
...@@ -2614,7 +2614,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2614,7 +2614,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2614 const reg = parseRegName(reg_name) orelse2614 const reg = parseRegName(reg_name) orelse
2615 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});2615 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2616 const arg = try self.resolveInst(inst.args[i]);2616 const arg = try self.resolveInst(inst.args[i]);
2617 try self.genSetReg(inst.base.src, reg, arg);2617 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);
2618 }2618 }
26192619
2620 if (mem.eql(u8, inst.asm_source, "svc #0")) {2620 if (mem.eql(u8, inst.asm_source, "svc #0")) {
...@@ -2646,7 +2646,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2646,7 +2646,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2646 const reg = parseRegName(reg_name) orelse2646 const reg = parseRegName(reg_name) orelse
2647 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});2647 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2648 const arg = try self.resolveInst(inst.args[i]);2648 const arg = try self.resolveInst(inst.args[i]);
2649 try self.genSetReg(inst.base.src, reg, arg);2649 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);
2650 }2650 }
26512651
2652 if (mem.eql(u8, inst.asm_source, "ecall")) {2652 if (mem.eql(u8, inst.asm_source, "ecall")) {
...@@ -2676,7 +2676,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2676,7 +2676,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2676 const reg = parseRegName(reg_name) orelse2676 const reg = parseRegName(reg_name) orelse
2677 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});2677 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
2678 const arg = try self.resolveInst(inst.args[i]);2678 const arg = try self.resolveInst(inst.args[i]);
2679 try self.genSetReg(inst.base.src, reg, arg);2679 try self.genSetReg(inst.base.src, inst.args[i].ty, reg, arg);
2680 }2680 }
26812681
2682 if (mem.eql(u8, inst.asm_source, "syscall")) {2682 if (mem.eql(u8, inst.asm_source, "syscall")) {
...@@ -2738,7 +2738,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2738,7 +2738,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2738 fn setRegOrMem(self: *Self, src: usize, ty: Type, loc: MCValue, val: MCValue) !void {2738 fn setRegOrMem(self: *Self, src: usize, ty: Type, loc: MCValue, val: MCValue) !void {
2739 switch (loc) {2739 switch (loc) {
2740 .none => return,2740 .none => return,
2741 .register => |reg| return self.genSetReg(src, reg, val),2741 .register => |reg| return self.genSetReg(src, ty, reg, val),
2742 .stack_offset => |off| return self.genSetStack(src, ty, off, val),2742 .stack_offset => |off| return self.genSetStack(src, ty, off, val),
2743 .memory => {2743 .memory => {
2744 return self.fail(src, "TODO implement setRegOrMem for memory", .{});2744 return self.fail(src, "TODO implement setRegOrMem for memory", .{});
...@@ -2773,7 +2773,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2773,7 +2773,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2773 return self.fail(src, "TODO implement set stack variable with compare flags value (signed)", .{});2773 return self.fail(src, "TODO implement set stack variable with compare flags value (signed)", .{});
2774 },2774 },
2775 .immediate => {2775 .immediate => {
2776 const reg = try self.copyToTmpRegister(src, mcv);2776 const reg = try self.copyToTmpRegister(src, ty, mcv);
2777 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });2777 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });
2778 },2778 },
2779 .embedded_in_code => |code_offset| {2779 .embedded_in_code => |code_offset| {
...@@ -2787,7 +2787,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2787,7 +2787,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2787 1, 4 => {2787 1, 4 => {
2788 const offset = if (math.cast(u12, adj_off)) |imm| blk: {2788 const offset = if (math.cast(u12, adj_off)) |imm| blk: {
2789 break :blk Instruction.Offset.imm(imm);2789 break :blk Instruction.Offset.imm(imm);
2790 } else |_| Instruction.Offset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }), 0);2790 } else |_| Instruction.Offset.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), MCValue{ .immediate = adj_off }), 0);
2791 const str = switch (abi_size) {2791 const str = switch (abi_size) {
2792 1 => Instruction.strb,2792 1 => Instruction.strb,
2793 4 => Instruction.str,2793 4 => Instruction.str,
...@@ -2802,7 +2802,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2802,7 +2802,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2802 2 => {2802 2 => {
2803 const offset = if (adj_off <= math.maxInt(u8)) blk: {2803 const offset = if (adj_off <= math.maxInt(u8)) blk: {
2804 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));2804 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
2805 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }));2805 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), MCValue{ .immediate = adj_off }));
28062806
2807 writeInt(u32, try self.code.addManyAsArray(4), Instruction.strh(.al, reg, .fp, .{2807 writeInt(u32, try self.code.addManyAsArray(4), Instruction.strh(.al, reg, .fp, .{
2808 .offset = offset,2808 .offset = offset,
...@@ -2819,7 +2819,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2819,7 +2819,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2819 if (stack_offset == off)2819 if (stack_offset == off)
2820 return; // Copy stack variable to itself; nothing to do.2820 return; // Copy stack variable to itself; nothing to do.
28212821
2822 const reg = try self.copyToTmpRegister(src, mcv);2822 const reg = try self.copyToTmpRegister(src, ty, mcv);
2823 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });2823 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });
2824 },2824 },
2825 },2825 },
...@@ -2908,7 +2908,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2908,7 +2908,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2908 if (stack_offset == off)2908 if (stack_offset == off)
2909 return; // Copy stack variable to itself; nothing to do.2909 return; // Copy stack variable to itself; nothing to do.
29102910
2911 const reg = try self.copyToTmpRegister(src, mcv);2911 const reg = try self.copyToTmpRegister(src, ty, mcv);
2912 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });2912 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });
2913 },2913 },
2914 },2914 },
...@@ -2936,7 +2936,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2936,7 +2936,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2936 return self.fail(src, "TODO implement set stack variable with compare flags value (signed)", .{});2936 return self.fail(src, "TODO implement set stack variable with compare flags value (signed)", .{});
2937 },2937 },
2938 .immediate => {2938 .immediate => {
2939 const reg = try self.copyToTmpRegister(src, mcv);2939 const reg = try self.copyToTmpRegister(src, ty, mcv);
2940 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });2940 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });
2941 },2941 },
2942 .embedded_in_code => |code_offset| {2942 .embedded_in_code => |code_offset| {
...@@ -2951,7 +2951,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2951,7 +2951,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2951 const offset = if (math.cast(i9, adj_off)) |imm|2951 const offset = if (math.cast(i9, adj_off)) |imm|
2952 Instruction.LoadStoreOffset.imm_post_index(-imm)2952 Instruction.LoadStoreOffset.imm_post_index(-imm)
2953 else |_|2953 else |_|
2954 Instruction.LoadStoreOffset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }));2954 Instruction.LoadStoreOffset.reg(try self.copyToTmpRegister(src, Type.initTag(.u64), MCValue{ .immediate = adj_off }));
2955 const rn: Register = switch (arch) {2955 const rn: Register = switch (arch) {
2956 .aarch64, .aarch64_be => .x29,2956 .aarch64, .aarch64_be => .x29,
2957 .aarch64_32 => .w29,2957 .aarch64_32 => .w29,
...@@ -2972,7 +2972,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2972,7 +2972,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2972 if (stack_offset == off)2972 if (stack_offset == off)
2973 return; // Copy stack variable to itself; nothing to do.2973 return; // Copy stack variable to itself; nothing to do.
29742974
2975 const reg = try self.copyToTmpRegister(src, mcv);2975 const reg = try self.copyToTmpRegister(src, ty, mcv);
2976 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });2976 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });
2977 },2977 },
2978 },2978 },
...@@ -2980,7 +2980,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2980,7 +2980,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2980 }2980 }
2981 }2981 }
29822982
2983 fn genSetReg(self: *Self, src: usize, reg: Register, mcv: MCValue) InnerError!void {2983 fn genSetReg(self: *Self, src: usize, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
2984 switch (arch) {2984 switch (arch) {
2985 .arm, .armeb => switch (mcv) {2985 .arm, .armeb => switch (mcv) {
2986 .dead => unreachable,2986 .dead => unreachable,
...@@ -2991,7 +2991,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2991,7 +2991,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2991 if (!self.wantSafety())2991 if (!self.wantSafety())
2992 return; // The already existing value will do just fine.2992 return; // The already existing value will do just fine.
2993 // Write the debug undefined value.2993 // Write the debug undefined value.
2994 return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaa });2994 return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaa });
2995 },2995 },
2996 .compare_flags_unsigned,2996 .compare_flags_unsigned,
2997 .compare_flags_signed,2997 .compare_flags_signed,
...@@ -3056,21 +3056,19 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3056,21 +3056,19 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3056 .memory => |addr| {3056 .memory => |addr| {
3057 // The value is in memory at a hard-coded address.3057 // The value is in memory at a hard-coded address.
3058 // If the type is a pointer, it means the pointer address is at this memory location.3058 // If the type is a pointer, it means the pointer address is at this memory location.
3059 try self.genSetReg(src, reg, .{ .immediate = addr });3059 try self.genSetReg(src, ty, reg, .{ .immediate = addr });
3060 writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldr(.al, reg, reg, .{ .offset = Instruction.Offset.none }).toU32());3060 writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldr(.al, reg, reg, .{ .offset = Instruction.Offset.none }).toU32());
3061 },3061 },
3062 .stack_offset => |unadjusted_off| {3062 .stack_offset => |unadjusted_off| {
3063 // TODO: maybe addressing from sp instead of fp3063 // TODO: maybe addressing from sp instead of fp
3064 // TODO: supply type information to genSetReg as we do to genSetStack3064 const abi_size = ty.abiSize(self.target.*);
3065 // const abi_size = ty.abiSize(self.target.*);
3066 const abi_size = 4;
3067 const adj_off = unadjusted_off + abi_size;3065 const adj_off = unadjusted_off + abi_size;
30683066
3069 switch (abi_size) {3067 switch (abi_size) {
3070 1, 4 => {3068 1, 4 => {
3071 const offset = if (adj_off <= math.maxInt(u12)) blk: {3069 const offset = if (adj_off <= math.maxInt(u12)) blk: {
3072 break :blk Instruction.Offset.imm(@intCast(u12, adj_off));3070 break :blk Instruction.Offset.imm(@intCast(u12, adj_off));
3073 } else Instruction.Offset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }), 0);3071 } else Instruction.Offset.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), MCValue{ .immediate = adj_off }), 0);
3074 const ldr = switch (abi_size) {3072 const ldr = switch (abi_size) {
3075 1 => Instruction.ldrb,3073 1 => Instruction.ldrb,
3076 4 => Instruction.ldr,3074 4 => Instruction.ldr,
...@@ -3085,7 +3083,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3085,7 +3083,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3085 2 => {3083 2 => {
3086 const offset = if (adj_off <= math.maxInt(u8)) blk: {3084 const offset = if (adj_off <= math.maxInt(u8)) blk: {
3087 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));3085 break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
3088 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(src, MCValue{ .immediate = adj_off }));3086 } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), MCValue{ .immediate = adj_off }));
30893087
3090 writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldrh(.al, reg, .fp, .{3088 writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldrh(.al, reg, .fp, .{
3091 .offset = offset,3089 .offset = offset,
...@@ -3107,8 +3105,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3107,8 +3105,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3107 return; // The already existing value will do just fine.3105 return; // The already existing value will do just fine.
3108 // Write the debug undefined value.3106 // Write the debug undefined value.
3109 switch (reg.size()) {3107 switch (reg.size()) {
3110 32 => return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaa }),3108 32 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaa }),
3111 64 => return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),3109 64 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
3112 else => unreachable, // unexpected register size3110 else => unreachable, // unexpected register size
3113 }3111 }
3114 },3112 },
...@@ -3221,7 +3219,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3221,7 +3219,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3221 } else {3219 } else {
3222 // The value is in memory at a hard-coded address.3220 // The value is in memory at a hard-coded address.
3223 // If the type is a pointer, it means the pointer address is at this memory location.3221 // If the type is a pointer, it means the pointer address is at this memory location.
3224 try self.genSetReg(src, reg, .{ .immediate = addr });3222 try self.genSetReg(src, Type.initTag(.usize), reg, .{ .immediate = addr });
3225 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(reg, .{ .register = .{ .rn = reg } }).toU32());3223 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(reg, .{ .register = .{ .rn = reg } }).toU32());
3226 }3224 }
3227 },3225 },
...@@ -3236,7 +3234,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3236,7 +3234,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3236 if (!self.wantSafety())3234 if (!self.wantSafety())
3237 return; // The already existing value will do just fine.3235 return; // The already existing value will do just fine.
3238 // Write the debug undefined value.3236 // Write the debug undefined value.
3239 return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa });3237 return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa });
3240 },3238 },
3241 .immediate => |unsigned_x| {3239 .immediate => |unsigned_x| {
3242 const x = @bitCast(i64, unsigned_x);3240 const x = @bitCast(i64, unsigned_x);
...@@ -3261,7 +3259,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3261,7 +3259,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3261 .memory => |addr| {3259 .memory => |addr| {
3262 // The value is in memory at a hard-coded address.3260 // The value is in memory at a hard-coded address.
3263 // If the type is a pointer, it means the pointer address is at this memory location.3261 // If the type is a pointer, it means the pointer address is at this memory location.
3264 try self.genSetReg(src, reg, .{ .immediate = addr });3262 try self.genSetReg(src, ty, reg, .{ .immediate = addr });
32653263
3266 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ld(reg, 0, reg).toU32());3264 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ld(reg, 0, reg).toU32());
3267 // LOAD imm=[i12 offset = 0], rs1 =3265 // LOAD imm=[i12 offset = 0], rs1 =
...@@ -3280,10 +3278,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3280,10 +3278,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3280 return; // The already existing value will do just fine.3278 return; // The already existing value will do just fine.
3281 // Write the debug undefined value.3279 // Write the debug undefined value.
3282 switch (reg.size()) {3280 switch (reg.size()) {
3283 8 => return self.genSetReg(src, reg, .{ .immediate = 0xaa }),3281 8 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaa }),
3284 16 => return self.genSetReg(src, reg, .{ .immediate = 0xaaaa }),3282 16 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaa }),
3285 32 => return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaa }),3283 32 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaa }),
3286 64 => return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),3284 64 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
3287 else => unreachable,3285 else => unreachable,
3288 }3286 }
3289 },3287 },
...@@ -3497,7 +3495,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3497,7 +3495,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3497 assert(id3 != 4 and id3 != 5);3495 assert(id3 != 4 and id3 != 5);
34983496
3499 // Rather than duplicate the logic used for the move, we just use a self-call with a new MCValue.3497 // Rather than duplicate the logic used for the move, we just use a self-call with a new MCValue.
3500 try self.genSetReg(src, reg, MCValue{ .immediate = x });3498 try self.genSetReg(src, ty, reg, MCValue{ .immediate = x });
35013499
3502 // Now, the register contains the address of the value to load into it3500 // Now, the register contains the address of the value to load into it
3503 // Currently, we're only allowing 64-bit registers, so we need the `REX.W 8B /r` variant.3501 // Currently, we're only allowing 64-bit registers, so we need the `REX.W 8B /r` variant.
...@@ -3596,7 +3594,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3596,7 +3594,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3596 // This immediate is unsigned.3594 // This immediate is unsigned.
3597 const U = std.meta.Int(.unsigned, ti.bits - @boolToInt(ti.signedness == .signed));3595 const U = std.meta.Int(.unsigned, ti.bits - @boolToInt(ti.signedness == .signed));
3598 if (imm >= math.maxInt(U)) {3596 if (imm >= math.maxInt(U)) {
3599 return MCValue{ .register = try self.copyToTmpRegister(inst.src, mcv) };3597 return MCValue{ .register = try self.copyToTmpRegister(inst.src, Type.initTag(.usize), mcv) };
3600 }3598 }
3601 },3599 },
3602 else => {},3600 else => {},
...@@ -3710,17 +3708,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3710,17 +3708,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3710 for (param_types) |ty, i| {3708 for (param_types) |ty, i| {
3711 switch (ty.zigTypeTag()) {3709 switch (ty.zigTypeTag()) {
3712 .Bool, .Int => {3710 .Bool, .Int => {
3713 const param_size = @intCast(u32, ty.abiSize(self.target.*));3711 if (!ty.hasCodeGenBits()) {
3714 if (next_int_reg >= c_abi_int_param_regs.len) {3712 assert(cc != .C);
3715 result.args[i] = .{ .stack_offset = next_stack_offset };3713 result.args[i] = .{ .none = {} };
3716 next_stack_offset += param_size;
3717 } else {3714 } else {
3718 const aliased_reg = registerAlias(3715 const param_size = @intCast(u32, ty.abiSize(self.target.*));
3719 c_abi_int_param_regs[next_int_reg],3716 if (next_int_reg >= c_abi_int_param_regs.len) {
3720 param_size,3717 result.args[i] = .{ .stack_offset = next_stack_offset };
3721 );3718 next_stack_offset += param_size;
3722 result.args[i] = .{ .register = aliased_reg };3719 } else {
3723 next_int_reg += 1;3720 const aliased_reg = registerAlias(
3721 c_abi_int_param_regs[next_int_reg],
3722 param_size,
3723 );
3724 result.args[i] = .{ .register = aliased_reg };
3725 next_int_reg += 1;
3726 }
3724 }3727 }
3725 },3728 },
3726 else => return self.fail(src, "TODO implement function parameters of type {s}", .{@tagName(ty.zigTypeTag())}),3729 else => return self.fail(src, "TODO implement function parameters of type {s}", .{@tagName(ty.zigTypeTag())}),
src/codegen/wasm.zig+21-9
...@@ -161,15 +161,19 @@ pub const Context = struct {...@@ -161,15 +161,19 @@ pub const Context = struct {
161 pub fn gen(self: *Context) InnerError!void {161 pub fn gen(self: *Context) InnerError!void {
162 assert(self.code.items.len == 0);162 assert(self.code.items.len == 0);
163 try self.genFunctype();163 try self.genFunctype();
164 const writer = self.code.writer();
165
166 // Reserve space to write the size after generating the code as well as space for locals count
167 try self.code.resize(10);
168164
169 // Write instructions165 // Write instructions
170 // TODO: check for and handle death of instructions166 // TODO: check for and handle death of instructions
171 const tv = self.decl.typed_value.most_recent.typed_value;167 const tv = self.decl.typed_value.most_recent.typed_value;
172 const mod_fn = tv.val.castTag(.function).?.data;168 const mod_fn = blk: {
169 if (tv.val.castTag(.function)) |func| break :blk func.data;
170 if (tv.val.castTag(.extern_fn)) |ext_fn| return; // don't need codegen for extern functions
171 return self.fail(self.decl.src(), "TODO: Wasm codegen for decl type '{s}'", .{tv.ty.tag()});
172 };
173
174 // Reserve space to write the size after generating the code as well as space for locals count
175 try self.code.resize(10);
176
173 try self.genBody(mod_fn.body);177 try self.genBody(mod_fn.body);
174178
175 // finally, write our local types at the 'offset' position179 // finally, write our local types at the 'offset' position
...@@ -189,6 +193,7 @@ pub const Context = struct {...@@ -189,6 +193,7 @@ pub const Context = struct {
189 }193 }
190 }194 }
191195
196 const writer = self.code.writer();
192 try writer.writeByte(wasm.opcode(.end));197 try writer.writeByte(wasm.opcode(.end));
193198
194 // Fill in the size of the generated code to the reserved space at the199 // Fill in the size of the generated code to the reserved space at the
...@@ -239,9 +244,16 @@ pub const Context = struct {...@@ -239,9 +244,16 @@ pub const Context = struct {
239244
240 fn genCall(self: *Context, inst: *Inst.Call) InnerError!WValue {245 fn genCall(self: *Context, inst: *Inst.Call) InnerError!WValue {
241 const func_inst = inst.func.castTag(.constant).?;246 const func_inst = inst.func.castTag(.constant).?;
242 const func = func_inst.val.castTag(.function).?.data;247 const func_val = inst.func.value().?;
243 const target = func.owner_decl;248
244 const target_ty = target.typed_value.most_recent.typed_value.ty;249 const target = blk: {
250 if (func_val.castTag(.function)) |func| {
251 break :blk func.data.owner_decl;
252 } else if (func_val.castTag(.extern_fn)) |ext_fn| {
253 break :blk ext_fn.data;
254 }
255 return self.fail(inst.base.src, "Expected a function, but instead found type '{s}'", .{func_val.tag()});
256 };
245257
246 for (inst.args) |arg| {258 for (inst.args) |arg| {
247 const arg_val = self.resolveInst(arg);259 const arg_val = self.resolveInst(arg);
...@@ -495,7 +507,7 @@ pub const Context = struct {...@@ -495,7 +507,7 @@ pub const Context = struct {
495 }507 }
496508
497 fn genBr(self: *Context, br: *Inst.Br) InnerError!WValue {509 fn genBr(self: *Context, br: *Inst.Br) InnerError!WValue {
498 // of operand has codegen bits we should break with a value510 // if operand has codegen bits we should break with a value
499 if (br.operand.ty.hasCodeGenBits()) {511 if (br.operand.ty.hasCodeGenBits()) {
500 const operand = self.resolveInst(br.operand);512 const operand = self.resolveInst(br.operand);
501 try self.emitWValue(operand);513 try self.emitWValue(operand);
src/link/Wasm.zig+90-14
...@@ -33,9 +33,18 @@ base: link.File,...@@ -33,9 +33,18 @@ base: link.File,
3333
34/// List of all function Decls to be written to the output file. The index of34/// List of all function Decls to be written to the output file. The index of
35/// each Decl in this list at the time of writing the binary is used as the35/// each Decl in this list at the time of writing the binary is used as the
36/// function index.36/// function index. In the event where ext_funcs' size is not 0, the index of
37/// each function is added on top of the ext_funcs' length.
37/// TODO: can/should we access some data structure in Module directly?38/// TODO: can/should we access some data structure in Module directly?
38funcs: std.ArrayListUnmanaged(*Module.Decl) = .{},39funcs: std.ArrayListUnmanaged(*Module.Decl) = .{},
40/// List of all extern function Decls to be written to the `import` section of the
41/// wasm binary. The positin in the list defines the function index
42ext_funcs: std.ArrayListUnmanaged(*Module.Decl) = .{},
43/// When importing objects from the host environment, a name must be supplied.
44/// LLVM uses "env" by default when none is given. This would be a good default for Zig
45/// to support existing code.
46/// TODO: Allow setting this through a flag?
47host_name: []const u8 = "env",
3948
40pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Wasm {49pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Wasm {
41 assert(options.object_format == .wasm);50 assert(options.object_format == .wasm);
...@@ -76,7 +85,13 @@ pub fn deinit(self: *Wasm) void {...@@ -76,7 +85,13 @@ pub fn deinit(self: *Wasm) void {
76 decl.fn_link.wasm.?.code.deinit(self.base.allocator);85 decl.fn_link.wasm.?.code.deinit(self.base.allocator);
77 decl.fn_link.wasm.?.idx_refs.deinit(self.base.allocator);86 decl.fn_link.wasm.?.idx_refs.deinit(self.base.allocator);
78 }87 }
88 for (self.ext_funcs.items) |decl| {
89 decl.fn_link.wasm.?.functype.deinit(self.base.allocator);
90 decl.fn_link.wasm.?.code.deinit(self.base.allocator);
91 decl.fn_link.wasm.?.idx_refs.deinit(self.base.allocator);
92 }
79 self.funcs.deinit(self.base.allocator);93 self.funcs.deinit(self.base.allocator);
94 self.ext_funcs.deinit(self.base.allocator);
80}95}
8196
82// Generate code for the Decl, storing it in memory to be later written to97// Generate code for the Decl, storing it in memory to be later written to
...@@ -85,8 +100,6 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {...@@ -85,8 +100,6 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
85 const typed_value = decl.typed_value.most_recent.typed_value;100 const typed_value = decl.typed_value.most_recent.typed_value;
86 if (typed_value.ty.zigTypeTag() != .Fn)101 if (typed_value.ty.zigTypeTag() != .Fn)
87 return error.TODOImplementNonFnDeclsForWasm;102 return error.TODOImplementNonFnDeclsForWasm;
88 if (typed_value.val.tag() == .extern_fn)
89 return error.TODOImplementExternFnDeclsForWasm;
90103
91 if (decl.fn_link.wasm) |*fn_data| {104 if (decl.fn_link.wasm) |*fn_data| {
92 fn_data.functype.items.len = 0;105 fn_data.functype.items.len = 0;
...@@ -94,7 +107,12 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {...@@ -94,7 +107,12 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
94 fn_data.idx_refs.items.len = 0;107 fn_data.idx_refs.items.len = 0;
95 } else {108 } else {
96 decl.fn_link.wasm = .{};109 decl.fn_link.wasm = .{};
97 try self.funcs.append(self.base.allocator, decl);110 // dependent on function type, appends it to the correct list
111 switch (decl.typed_value.most_recent.typed_value.val.tag()) {
112 .function => try self.funcs.append(self.base.allocator, decl),
113 .extern_fn => try self.ext_funcs.append(self.base.allocator, decl),
114 else => return error.TODOImplementNonFnDeclsForWasm,
115 }
98 }116 }
99 const fn_data = &decl.fn_link.wasm.?;117 const fn_data = &decl.fn_link.wasm.?;
100118
...@@ -143,7 +161,12 @@ pub fn updateDeclExports(...@@ -143,7 +161,12 @@ pub fn updateDeclExports(
143pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {161pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
144 // TODO: remove this assert when non-function Decls are implemented162 // TODO: remove this assert when non-function Decls are implemented
145 assert(decl.typed_value.most_recent.typed_value.ty.zigTypeTag() == .Fn);163 assert(decl.typed_value.most_recent.typed_value.ty.zigTypeTag() == .Fn);
146 _ = self.funcs.swapRemove(self.getFuncidx(decl).?);164 const func_idx = self.getFuncidx(decl).?;
165 switch (decl.typed_value.most_recent.typed_value.val.tag()) {
166 .function => _ = self.funcs.swapRemove(func_idx),
167 .extern_fn => _ = self.ext_funcs.swapRemove(func_idx),
168 else => unreachable,
169 }
147 decl.fn_link.wasm.?.functype.deinit(self.base.allocator);170 decl.fn_link.wasm.?.functype.deinit(self.base.allocator);
148 decl.fn_link.wasm.?.code.deinit(self.base.allocator);171 decl.fn_link.wasm.?.code.deinit(self.base.allocator);
149 decl.fn_link.wasm.?.idx_refs.deinit(self.base.allocator);172 decl.fn_link.wasm.?.idx_refs.deinit(self.base.allocator);
...@@ -172,15 +195,46 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -172,15 +195,46 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
172 // Type section195 // Type section
173 {196 {
174 const header_offset = try reserveVecSectionHeader(file);197 const header_offset = try reserveVecSectionHeader(file);
175 for (self.funcs.items) |decl| {198
176 try file.writeAll(decl.fn_link.wasm.?.functype.items);199 // extern functions are defined in the wasm binary first through the `import`
177 }200 // section, so define their func types first
201 for (self.ext_funcs.items) |decl| try file.writeAll(decl.fn_link.wasm.?.functype.items);
202 for (self.funcs.items) |decl| try file.writeAll(decl.fn_link.wasm.?.functype.items);
203
178 try writeVecSectionHeader(204 try writeVecSectionHeader(
179 file,205 file,
180 header_offset,206 header_offset,
181 .type,207 .type,
182 @intCast(u32, (try file.getPos()) - header_offset - header_size),208 @intCast(u32, (try file.getPos()) - header_offset - header_size),
183 @intCast(u32, self.funcs.items.len),209 @intCast(u32, self.ext_funcs.items.len + self.funcs.items.len),
210 );
211 }
212
213 // Import section
214 {
215 // TODO: implement non-functions imports
216 const header_offset = try reserveVecSectionHeader(file);
217 const writer = file.writer();
218 for (self.ext_funcs.items) |decl, typeidx| {
219 try leb.writeULEB128(writer, @intCast(u32, self.host_name.len));
220 try writer.writeAll(self.host_name);
221
222 // wasm requires the length of the import name with no null-termination
223 const decl_len = mem.len(decl.name);
224 try leb.writeULEB128(writer, @intCast(u32, decl_len));
225 try writer.writeAll(decl.name[0..decl_len]);
226
227 // emit kind and the function type
228 try writer.writeByte(wasm.externalKind(.function));
229 try leb.writeULEB128(writer, @intCast(u32, typeidx));
230 }
231
232 try writeVecSectionHeader(
233 file,
234 header_offset,
235 .import,
236 @intCast(u32, (try file.getPos()) - header_offset - header_size),
237 @intCast(u32, self.ext_funcs.items.len),
184 );238 );
185 }239 }
186240
...@@ -188,7 +242,11 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -188,7 +242,11 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
188 {242 {
189 const header_offset = try reserveVecSectionHeader(file);243 const header_offset = try reserveVecSectionHeader(file);
190 const writer = file.writer();244 const writer = file.writer();
191 for (self.funcs.items) |_, typeidx| try leb.writeULEB128(writer, @intCast(u32, typeidx));245 for (self.funcs.items) |_, typeidx| {
246 const func_idx = @intCast(u32, self.getFuncIdxOffset() + typeidx);
247 try leb.writeULEB128(writer, func_idx);
248 }
249
192 try writeVecSectionHeader(250 try writeVecSectionHeader(
193 file,251 file,
194 header_offset,252 header_offset,
...@@ -212,7 +270,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {...@@ -212,7 +270,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
212 switch (exprt.exported_decl.typed_value.most_recent.typed_value.ty.zigTypeTag()) {270 switch (exprt.exported_decl.typed_value.most_recent.typed_value.ty.zigTypeTag()) {
213 .Fn => {271 .Fn => {
214 // Type of the export272 // Type of the export
215 try writer.writeByte(0x00);273 try writer.writeByte(wasm.externalKind(.function));
216 // Exported function index274 // Exported function index
217 try leb.writeULEB128(writer, self.getFuncidx(exprt.exported_decl).?);275 try leb.writeULEB128(writer, self.getFuncidx(exprt.exported_decl).?);
218 },276 },
...@@ -523,13 +581,31 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {...@@ -523,13 +581,31 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
523}581}
524582
525/// Get the current index of a given Decl in the function list583/// Get the current index of a given Decl in the function list
526/// TODO: we could maintain a hash map to potentially make this584/// This will correctly provide the index, regardless whether the function is extern or not
585/// TODO: we could maintain a hash map to potentially make this simpler
527fn getFuncidx(self: Wasm, decl: *Module.Decl) ?u32 {586fn getFuncidx(self: Wasm, decl: *Module.Decl) ?u32 {
528 return for (self.funcs.items) |func, idx| {587 var offset: u32 = 0;
529 if (func == decl) break @intCast(u32, idx);588 const slice = switch (decl.typed_value.most_recent.typed_value.val.tag()) {
589 .function => blk: {
590 // when the target is a regular function, we have to calculate
591 // the offset of where the index starts
592 offset += self.getFuncIdxOffset();
593 break :blk self.funcs.items;
594 },
595 .extern_fn => self.ext_funcs.items,
596 else => return null,
597 };
598 return for (slice) |func, idx| {
599 if (func == decl) break @intCast(u32, offset + idx);
530 } else null;600 } else null;
531}601}
532602
603/// Based on the size of `ext_funcs` returns the
604/// offset of the function indices
605fn getFuncIdxOffset(self: Wasm) u32 {
606 return @intCast(u32, self.ext_funcs.items.len);
607}
608
533fn reserveVecSectionHeader(file: fs.File) !u64 {609fn reserveVecSectionHeader(file: fs.File) !u64 {
534 // section id + fixed leb contents size + fixed leb vector length610 // section id + fixed leb contents size + fixed leb vector length
535 const header_size = 1 + 5 + 5;611 const header_size = 1 + 5 + 5;
src/stage1.zig+3-1
...@@ -278,7 +278,9 @@ export fn stage2_attach_segfault_handler() void {...@@ -278,7 +278,9 @@ export fn stage2_attach_segfault_handler() void {
278// ABI warning278// ABI warning
279export fn stage2_progress_create() *std.Progress {279export fn stage2_progress_create() *std.Progress {
280 const ptr = std.heap.c_allocator.create(std.Progress) catch @panic("out of memory");280 const ptr = std.heap.c_allocator.create(std.Progress) catch @panic("out of memory");
281 ptr.* = std.Progress{};281 // If the terminal is dumb, we dont want to show the user all the
282 // output.
283 ptr.* = std.Progress{ .dont_print_on_dumb = true };
282 return ptr;284 return ptr;
283}285}
284286
src/stage1/tokenizer.cpp+2-2
...@@ -1447,7 +1447,7 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -1447,7 +1447,7 @@ void tokenize(Buf *buf, Tokenization *out) {
1447 tokenize_error(&t, "unterminated string");1447 tokenize_error(&t, "unterminated string");
1448 break;1448 break;
1449 } else if (t.cur_tok->id == TokenIdCharLiteral) {1449 } else if (t.cur_tok->id == TokenIdCharLiteral) {
1450 tokenize_error(&t, "unterminated character literal");1450 tokenize_error(&t, "unterminated Unicode code point literal");
1451 break;1451 break;
1452 } else {1452 } else {
1453 zig_unreachable();1453 zig_unreachable();
...@@ -1456,7 +1456,7 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -1456,7 +1456,7 @@ void tokenize(Buf *buf, Tokenization *out) {
1456 case TokenizeStateCharLiteral:1456 case TokenizeStateCharLiteral:
1457 case TokenizeStateCharLiteralEnd:1457 case TokenizeStateCharLiteralEnd:
1458 case TokenizeStateCharLiteralUnicode:1458 case TokenizeStateCharLiteralUnicode:
1459 tokenize_error(&t, "unterminated character literal");1459 tokenize_error(&t, "unterminated Unicode code point literal");
1460 break;1460 break;
1461 case TokenizeStateSymbol:1461 case TokenizeStateSymbol:
1462 case TokenizeStateZero:1462 case TokenizeStateZero:
test/stage2/test.zig+22
...@@ -1397,4 +1397,26 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1397,4 +1397,26 @@ pub fn addCases(ctx: *TestContext) !void {
1397 "",1397 "",
1398 );1398 );
1399 }1399 }
1400
1401 {
1402 var case = ctx.exe("passing u0 to function", linux_x64);
1403 case.addCompareOutput(
1404 \\export fn _start() noreturn {
1405 \\ doNothing(0);
1406 \\ exit();
1407 \\}
1408 \\fn doNothing(arg: u0) void {}
1409 \\fn exit() noreturn {
1410 \\ asm volatile ("syscall"
1411 \\ :
1412 \\ : [number] "{rax}" (231),
1413 \\ [arg1] "{rdi}" (0)
1414 \\ : "rcx", "r11", "memory"
1415 \\ );
1416 \\ unreachable;
1417 \\}
1418 ,
1419 "",
1420 );
1421 }
1400}1422}