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 {
310310 <p>
311311 The two arguments passed to the <code>stdout.print()</code> function, <code>"Hello, {s}!\n"</code>
312312 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#}
314314 substitution in the <code>print</code> function. The curly-braces inside of the first argument
315315 are substituted with the compile-time known value inside of the second argument
316316 (known as an {#link|anonymous struct literal|Anonymous Struct Literals#}). The <code>\n</code>
......@@ -682,18 +682,31 @@ pub fn main() void {
682682 </div>
683683 {#see_also|Optionals|undefined#}
684684 {#header_close#}
685 {#header_open|String Literals and Character Literals#}
685 {#header_open|String Literals and Unicode Code Point Literals#}
686686 <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.
688688 The type of string literals encodes both the length, and the fact that they are null-terminated,
689689 and thus they can be {#link|coerced|Type Coercion#} to both {#link|Slices#} and
690690 {#link|Null-Terminated Pointers|Sentinel-Terminated Pointers#}.
691691 Dereferencing string literals converts them to {#link|Arrays#}.
692692 </p>
693693 <p>
694 Character literals have type {#syntax#}comptime_int{#endsyntax#}, the same as
694 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
695702 {#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.
697710 </p>
698711 {#code_begin|test#}
699712const expect = @import("std").testing.expect;
......@@ -709,6 +722,7 @@ test "string literals" {
709722 expect('\u{1f4a9}' == 128169);
710723 expect('💯' == 128175);
711724 expect(mem.eql(u8, "hello", "h\x65llo"));
725 expect("\xff"[0] == 0xff); // non-UTF-8 strings are possible with \xNN notation.
712726}
713727 {#code_end#}
714728 {#see_also|Arrays|Zig Test|Source Encoding#}
......@@ -749,11 +763,11 @@ test "string literals" {
749763 </tr>
750764 <tr>
751765 <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>
753767 </tr>
754768 <tr>
755769 <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>
757771 </tr>
758772 </table>
759773 </div>
......@@ -7414,7 +7428,7 @@ test "main" {
74147428 This function returns a compile time constant pointer to null-terminated,
74157429 fixed-size array with length equal to the byte count of the file given by
74167430 {#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#}
74187432 with the file contents.
74197433 </p>
74207434 <p>
lib/std/Progress.zig+17-1
......@@ -25,6 +25,13 @@ terminal: ?std.fs.File = undefined,
2525/// Whether the terminal supports ANSI escape codes.
2626supports_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
2835root: Node = undefined,
2936
3037/// 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) !*
141148 self.supports_ansi_escape_codes = true;
142149 } else if (std.builtin.os.tag == .windows and stderr.isTty()) {
143150 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;
144154 }
145155 self.root = Node{
146156 .context = self,
......@@ -178,6 +188,8 @@ pub fn refresh(self: *Progress) void {
178188}
179189
180190fn 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;
181193 const file = self.terminal orelse return;
182194
183195 const prev_columns_written = self.columns_written;
......@@ -226,7 +238,11 @@ fn refreshWithHeldLock(self: *Progress) void {
226238
227239 if (windows.kernel32.SetConsoleCursorPosition(file.handle, cursor_pos) != windows.TRUE)
228240 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
231247 self.columns_written = 0;
232248 }
lib/std/Thread/Semaphore.zig+1-1
......@@ -13,7 +13,7 @@ cond: Condition = .{},
1313//! It is OK to initialize this field to any value.
1414permits: usize = 0,
1515
16const RwLock = @This();
16const Semaphore = @This();
1717const std = @import("../std.zig");
1818const Mutex = std.Thread.Mutex;
1919const Condition = std.Thread.Condition;
lib/std/build.zig+46-5
......@@ -543,7 +543,7 @@ pub const Builder = struct {
543543 .Scalar => |s| {
544544 const n = std.fmt.parseInt(T, s, 10) catch |err| switch (err) {
545545 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) });
547547 self.markInvalidUserInput();
548548 return null;
549549 },
......@@ -1308,6 +1308,12 @@ const BuildOptionArtifactArg = struct {
13081308 artifact: *LibExeObjStep,
13091309};
13101310
1311const BuildOptionWriteFileArg = struct {
1312 name: []const u8,
1313 write_file: *WriteFileStep,
1314 basename: []const u8,
1315};
1316
13111317pub const LibExeObjStep = struct {
13121318 step: Step,
13131319 builder: *Builder,
......@@ -1355,6 +1361,7 @@ pub const LibExeObjStep = struct {
13551361 packages: ArrayList(Pkg),
13561362 build_options_contents: std.ArrayList(u8),
13571363 build_options_artifact_args: std.ArrayList(BuildOptionArtifactArg),
1364 build_options_write_file_args: std.ArrayList(BuildOptionWriteFileArg),
13581365
13591366 object_src: []const u8,
13601367
......@@ -1515,6 +1522,7 @@ pub const LibExeObjStep = struct {
15151522 .object_src = undefined,
15161523 .build_options_contents = std.ArrayList(u8).init(builder.allocator),
15171524 .build_options_artifact_args = std.ArrayList(BuildOptionArtifactArg).init(builder.allocator),
1525 .build_options_write_file_args = std.ArrayList(BuildOptionWriteFileArg).init(builder.allocator),
15181526 .c_std = Builder.CStd.C99,
15191527 .override_lib_dir = null,
15201528 .main_pkg_path = null,
......@@ -2008,6 +2016,23 @@ pub const LibExeObjStep = struct {
20082016 self.step.dependOn(&artifact.step);
20092017 }
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
20112036 pub fn addSystemIncludeDir(self: *LibExeObjStep, path: []const u8) void {
20122037 self.include_dirs.append(IncludeDir{ .RawPathSystem = self.builder.dupe(path) }) catch unreachable;
20132038 }
......@@ -2228,11 +2253,27 @@ pub const LibExeObjStep = struct {
22282253 }
22292254 }
22302255
2231 if (self.build_options_contents.items.len > 0 or self.build_options_artifact_args.items.len > 0) {
2232 // Render build artifact options at the last minute, now that the path is known.
2256 if (self.build_options_contents.items.len > 0 or
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.
22332264 for (self.build_options_artifact_args.items) |item| {
2234 const out = self.build_options_contents.writer();
2235 out.print("pub const {s}: []const u8 = \"{}\";\n", .{ item.name, std.zig.fmtEscapes(item.artifact.getOutputPath()) }) catch unreachable;
2265 self.addBuildOption(
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 );
22362277 }
22372278
22382279 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)
100100pub 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;
101101pub extern "c" fn munmap(addr: *align(page_size) c_void, len: usize) c_int;
102102pub 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;
103105pub extern "c" fn unlink(path: [*:0]const u8) c_int;
104106pub extern "c" fn unlinkat(dirfd: fd_t, path: [*:0]const u8, flags: c_uint) c_int;
105107pub 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 {
207207
208208test "ed25519 key pair creation" {
209209 var seed: [32]u8 = undefined;
210 try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
210 _ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
211211 const key_pair = try Ed25519.KeyPair.create(seed);
212212 var buf: [256]u8 = undefined;
213213 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{key_pair.secret_key}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
......@@ -216,7 +216,7 @@ test "ed25519 key pair creation" {
216216
217217test "ed25519 signature" {
218218 var seed: [32]u8 = undefined;
219 try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
219 _ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
220220 const key_pair = try Ed25519.KeyPair.create(seed);
221221
222222 const sig = try Ed25519.sign("test", key_pair, null);
......@@ -339,11 +339,11 @@ test "ed25519 test vectors" {
339339 };
340340 for (entries) |entry, i| {
341341 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);
343343 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);
345345 var sig: [64]u8 = undefined;
346 try fmt.hexToBytes(&sig, entry.sig_hex);
346 _ = try fmt.hexToBytes(&sig, entry.sig_hex);
347347 if (entry.expected) |error_type| {
348348 std.testing.expectError(error_type, Ed25519.verify(sig, &msg, public_key));
349349 } else {
lib/std/crypto/25519/ristretto255.zig+1-1
......@@ -173,7 +173,7 @@ test "ristretto255" {
173173 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{p.toBytes()}), "E2F2AE0A6ABC4E71A884A961C500515F58E30B6AA582DD8DB6A65945E08D2D76");
174174
175175 var r: [Ristretto255.encoded_length]u8 = undefined;
176 try fmt.hexToBytes(r[0..], "6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919");
176 _ = try fmt.hexToBytes(r[0..], "6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919");
177177 var q = try Ristretto255.fromBytes(r);
178178 q = q.dbl().add(p);
179179 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");
8585test "x25519 public key calculation from secret key" {
8686 var sk: [32]u8 = undefined;
8787 var pk_expected: [32]u8 = undefined;
88 try fmt.hexToBytes(sk[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
89 try fmt.hexToBytes(pk_expected[0..], "f1814f0e8ff1043d8a44d25babff3cedcae6c22c3edaa48f857ae70de2baae50");
88 _ = try fmt.hexToBytes(sk[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
89 _ = try fmt.hexToBytes(pk_expected[0..], "f1814f0e8ff1043d8a44d25babff3cedcae6c22c3edaa48f857ae70de2baae50");
9090 const pk_calculated = try X25519.recoverPublicKey(sk);
9191 std.testing.expectEqual(pk_calculated, pk_expected);
9292}
lib/std/crypto/aes.zig+4-4
......@@ -122,11 +122,11 @@ test "expand 128-bit key" {
122122 var exp: [16]u8 = undefined;
123123
124124 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]);
126126 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
127127 }
128128 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]);
130130 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
131131 }
132132}
......@@ -144,11 +144,11 @@ test "expand 256-bit key" {
144144 var exp: [16]u8 = undefined;
145145
146146 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]);
148148 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
149149 }
150150 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]);
152152 testing.expectEqualSlices(u8, &exp, &round_key.toBytes());
153153 }
154154}
lib/std/crypto/blake3.zig+1-1
......@@ -663,7 +663,7 @@ fn testBlake3(hasher: *Blake3, input_len: usize, expected_hex: [262]u8) void {
663663
664664 // Compare to expected value
665665 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;
667667 testing.expectEqual(actual_bytes, expected_bytes);
668668
669669 // 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 {
270270test "hash" {
271271 // a test vector (30) from NIST KAT submission.
272272 var msg: [58 / 2]u8 = undefined;
273 try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C");
273 _ = try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C");
274274 var md: [32]u8 = undefined;
275275 hash(&md, &msg, .{});
276276 htest.assertEqual("1C9A03DC6A5DDC5444CFC6F4B154CFF5CF081633B2CEA4D7D0AE7CCFED5AAA44", &md);
......@@ -278,7 +278,7 @@ test "hash" {
278278
279279test "hash test vector 17" {
280280 var msg: [32 / 2]u8 = undefined;
281 try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F");
281 _ = try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F");
282282 var md: [32]u8 = undefined;
283283 hash(&md, &msg, .{});
284284 htest.assertEqual("404C130AF1B9023A7908200919F690FFBB756D5176E056FFDE320016A37C7282", &md);
......@@ -286,7 +286,7 @@ test "hash test vector 17" {
286286
287287test "hash test vector 33" {
288288 var msg: [32]u8 = undefined;
289 try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
289 _ = try std.fmt.hexToBytes(&msg, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
290290 var md: [32]u8 = undefined;
291291 hash(&md, &msg, .{});
292292 htest.assertEqual("A8F4FA28708BDA7EFB4C1914CA4AFA9E475B82D588D36504F87DBB0ED9AB3C4B", &md);
......@@ -436,9 +436,9 @@ pub const Aead = struct {
436436
437437test "cipher" {
438438 var key: [32]u8 = undefined;
439 try std.fmt.hexToBytes(&key, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
439 _ = try std.fmt.hexToBytes(&key, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
440440 var nonce: [16]u8 = undefined;
441 try std.fmt.hexToBytes(&nonce, "000102030405060708090A0B0C0D0E0F");
441 _ = try std.fmt.hexToBytes(&nonce, "000102030405060708090A0B0C0D0E0F");
442442 { // test vector (1) from NIST KAT submission.
443443 const ad: [0]u8 = undefined;
444444 const pt: [0]u8 = undefined;
......@@ -456,7 +456,7 @@ test "cipher" {
456456 { // test vector (34) from NIST KAT submission.
457457 const ad: [0]u8 = undefined;
458458 var pt: [2 / 2]u8 = undefined;
459 try std.fmt.hexToBytes(&pt, "00");
459 _ = try std.fmt.hexToBytes(&pt, "00");
460460
461461 var ct: [pt.len]u8 = undefined;
462462 var tag: [16]u8 = undefined;
......@@ -470,9 +470,9 @@ test "cipher" {
470470 }
471471 { // test vector (106) from NIST KAT submission.
472472 var ad: [12 / 2]u8 = undefined;
473 try std.fmt.hexToBytes(&ad, "000102030405");
473 _ = try std.fmt.hexToBytes(&ad, "000102030405");
474474 var pt: [6 / 2]u8 = undefined;
475 try std.fmt.hexToBytes(&pt, "000102");
475 _ = try std.fmt.hexToBytes(&pt, "000102");
476476
477477 var ct: [pt.len]u8 = undefined;
478478 var tag: [16]u8 = undefined;
......@@ -486,9 +486,9 @@ test "cipher" {
486486 }
487487 { // test vector (790) from NIST KAT submission.
488488 var ad: [60 / 2]u8 = undefined;
489 try std.fmt.hexToBytes(&ad, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D");
489 _ = try std.fmt.hexToBytes(&ad, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D");
490490 var pt: [46 / 2]u8 = undefined;
491 try std.fmt.hexToBytes(&pt, "000102030405060708090A0B0C0D0E0F10111213141516");
491 _ = try std.fmt.hexToBytes(&pt, "000102030405060708090A0B0C0D0E0F10111213141516");
492492
493493 var ct: [pt.len]u8 = undefined;
494494 var tag: [16]u8 = undefined;
......@@ -503,7 +503,7 @@ test "cipher" {
503503 { // test vector (1057) from NIST KAT submission.
504504 const ad: [0]u8 = undefined;
505505 var pt: [64 / 2]u8 = undefined;
506 try std.fmt.hexToBytes(&pt, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
506 _ = try std.fmt.hexToBytes(&pt, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F");
507507
508508 var ct: [pt.len]u8 = undefined;
509509 var tag: [16]u8 = undefined;
lib/std/event/loop.zig+4-5
......@@ -440,13 +440,11 @@ pub const Loop = struct {
440440 .overlapped = ResumeNode.overlapped_init,
441441 },
442442 };
443 var need_to_delete = false;
443 var need_to_delete = true;
444444 defer if (need_to_delete) self.linuxRemoveFd(fd);
445445
446446 suspend {
447 if (self.linuxAddFd(fd, &resume_node.base, flags)) |_| {
448 need_to_delete = true;
449 } else |err| switch (err) {
447 self.linuxAddFd(fd, &resume_node.base, flags) catch |err| switch (err) {
450448 error.FileDescriptorNotRegistered => unreachable,
451449 error.OperationCausesCircularLoop => unreachable,
452450 error.FileDescriptorIncompatibleWithEpoll => unreachable,
......@@ -456,6 +454,7 @@ pub const Loop = struct {
456454 error.UserResourceLimitReached,
457455 error.Unexpected,
458456 => {
457 need_to_delete = false;
459458 // Fall back to a blocking poll(). Ideally this codepath is never hit, since
460459 // epoll should be just fine. But this is better than incorrect behavior.
461460 var poll_flags: i16 = 0;
......@@ -479,7 +478,7 @@ pub const Loop = struct {
479478 };
480479 resume @frame();
481480 },
482 }
481 };
483482 }
484483 }
485484
lib/std/fifo.zig+7-3
......@@ -44,6 +44,8 @@ pub fn LinearFifo(
4444 count: usize,
4545
4646 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
4850 // Type of Self argument for slice operations.
4951 // If buffer is inline (Static) then we need to ensure we haven't
......@@ -153,7 +155,7 @@ pub fn LinearFifo(
153155 var start = self.head + offset;
154156 if (start >= self.buf.len) {
155157 start -= self.buf.len;
156 return self.buf[start .. self.count - offset];
158 return self.buf[start .. start + (self.count - offset)];
157159 } else {
158160 const end = math.min(self.head + self.count, self.buf.len);
159161 return self.buf[start..end];
......@@ -228,7 +230,7 @@ pub fn LinearFifo(
228230 return self.read(dest);
229231 }
230232
231 pub fn reader(self: *Self) std.io.Reader(*Self, error{}, readFn) {
233 pub fn reader(self: *Self) Reader {
232234 return .{ .context = self };
233235 }
234236
......@@ -318,7 +320,7 @@ pub fn LinearFifo(
318320 return bytes.len;
319321 }
320322
321 pub fn writer(self: *Self) std.io.Writer(*Self, error{OutOfMemory}, appendWrite) {
323 pub fn writer(self: *Self) Writer {
322324 return .{ .context = self };
323325 }
324326
......@@ -427,6 +429,8 @@ test "LinearFifo(u8, .Dynamic)" {
427429 fifo.writeAssumeCapacity("6<chars<11");
428430 testing.expectEqualSlices(u8, "HELLO6<char", fifo.readableSlice(0));
429431 testing.expectEqualSlices(u8, "s<11", fifo.readableSlice(11));
432 testing.expectEqualSlices(u8, "11", fifo.readableSlice(13));
433 testing.expectEqualSlices(u8, "", fifo.readableSlice(15));
430434 fifo.discard(11);
431435 testing.expectEqualSlices(u8, "s<11", fifo.readableSlice(0));
432436 fifo.discard(4);
lib/std/fmt.zig+22-17
......@@ -524,7 +524,7 @@ pub fn formatType(
524524 if (actual_fmt.len == 0)
525525 @compileError("cannot format array ref without a specifier (i.e. {s} or {*})");
526526 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) {
528528 return formatText(value, actual_fmt, options, writer);
529529 }
530530 }
......@@ -542,7 +542,7 @@ pub fn formatType(
542542 return formatType(mem.span(value), actual_fmt, options, writer, max_depth);
543543 }
544544 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) {
546546 return formatText(mem.span(value), actual_fmt, options, writer);
547547 }
548548 }
......@@ -555,7 +555,7 @@ pub fn formatType(
555555 return writer.writeAll("{ ... }");
556556 }
557557 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) {
559559 return formatText(value, actual_fmt, options, writer);
560560 }
561561 }
......@@ -576,7 +576,7 @@ pub fn formatType(
576576 return writer.writeAll("{ ... }");
577577 }
578578 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) {
580580 return formatText(&value, actual_fmt, options, writer);
581581 }
582582 }
......@@ -658,8 +658,6 @@ pub fn formatIntValue(
658658 } else {
659659 @compileError("Cannot print integer that is larger than 8 bits as a ascii");
660660 }
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");
663661 } else if (comptime std.mem.eql(u8, fmt, "u")) {
664662 if (@typeInfo(@TypeOf(int_value)).Int.bits <= 21) {
665663 return formatUnicodeCodepoint(@as(u21, int_value), options, writer);
......@@ -735,10 +733,6 @@ pub fn formatText(
735733 }
736734 }
737735 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");
742736 } else {
743737 @compileError("Unsupported format string '" ++ fmt ++ "' for type '" ++ @typeName(@TypeOf(value)) ++ "'");
744738 }
......@@ -1988,23 +1982,34 @@ test "bytes.hex" {
19881982pub const trim = @compileError("deprecated; use std.mem.trim with std.ascii.spaces instead");
19891983pub const isWhiteSpace = @compileError("deprecated; use std.ascii.isSpace instead");
19901984
1991pub fn hexToBytes(out: []u8, input: []const u8) !void {
1992 if (out.len * 2 < input.len)
1985/// Decodes the sequence of bytes represented by the specified string of
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)
19931991 return error.InvalidLength;
1992 if (out.len * 2 < input.len)
1993 return error.NoSpaceLeft;
19941994
19951995 var in_i: usize = 0;
1996 while (in_i != input.len) : (in_i += 2) {
1996 while (in_i < input.len) : (in_i += 2) {
19971997 const hi = try charToDigit(input[in_i], 16);
19981998 const lo = try charToDigit(input[in_i + 1], 16);
19991999 out[in_i / 2] = (hi << 4) | lo;
20002000 }
2001
2002 return out[0 .. in_i / 2];
20012003}
20022004
20032005test "hexToBytes" {
2004 const test_hex_str = "909A312BB12ED1F819B3521AC4C1E896F2160507FFC1C8381E3B07BB16BD1706";
2005 var pb: [32]u8 = undefined;
2006 try hexToBytes(pb[0..], test_hex_str);
2007 try expectFmt(test_hex_str, "{X}", .{pb});
2006 var buf: [32]u8 = undefined;
2007 try expectFmt("90" ** 32, "{X}", .{try hexToBytes(&buf, "90" ** 32)});
2008 try expectFmt("ABCD", "{X}", .{try hexToBytes(&buf, "ABCD")});
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"));
20082013}
20092014
20102015test "formatIntValue with comptime_int" {
lib/std/fs.zig+1-1
......@@ -2186,7 +2186,7 @@ pub const Walker = struct {
21862186 var top = &self.stack.items[self.stack.items.len - 1];
21872187 const dirname_len = top.dirname_len;
21882188 if (try top.dir_it.next()) |base| {
2189 self.name_buffer.shrinkAndFree(dirname_len);
2189 self.name_buffer.shrinkRetainingCapacity(dirname_len);
21902190 try self.name_buffer.append(path.sep);
21912191 try self.name_buffer.appendSlice(base.name);
21922192 if (base.kind == .Directory) {
lib/std/fs/file.zig+2
......@@ -587,6 +587,7 @@ pub const File = struct {
587587 }
588588
589589 /// See https://github.com/ziglang/zig/issues/7699
590 /// See equivalent function: `std.net.Stream.writev`.
590591 pub fn writev(self: File, iovecs: []const os.iovec_const) WriteError!usize {
591592 if (is_windows) {
592593 // TODO improve this to use WriteFileScatter
......@@ -605,6 +606,7 @@ pub const File = struct {
605606 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in
606607 /// order to handle partial writes from the underlying OS layer.
607608 /// See https://github.com/ziglang/zig/issues/7699
609 /// See equivalent function: `std.net.Stream.writevAll`.
608610 pub fn writevAll(self: File, iovecs: []os.iovec_const) WriteError!void {
609611 if (iovecs.len == 0) return;
610612
lib/std/io/reader.zig+1-1
......@@ -111,7 +111,7 @@ pub fn Reader(
111111 delimiter: u8,
112112 max_size: usize,
113113 ) !void {
114 array_list.shrinkAndFree(0);
114 array_list.shrinkRetainingCapacity(0);
115115 while (true) {
116116 var byte: u8 = try self.readByte();
117117
lib/std/json.zig+1-1
......@@ -2018,7 +2018,7 @@ pub const Parser = struct {
20182018
20192019 pub fn reset(p: *Parser) void {
20202020 p.state = .Simple;
2021 p.stack.shrinkAndFree(0);
2021 p.stack.shrinkRetainingCapacity(0);
20222022 }
20232023
20242024 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 {
607607 /// it will have the same length as it had when the function was called.
608608 pub fn gcd(rma: *Mutable, x: Const, y: Const, limbs_buffer: *std.ArrayList(Limb)) !void {
609609 const prev_len = limbs_buffer.items.len;
610 defer limbs_buffer.shrinkAndFree(prev_len);
610 defer limbs_buffer.shrinkRetainingCapacity(prev_len);
611611 const x_copy = if (rma.limbs.ptr == x.limbs.ptr) blk: {
612612 const start = limbs_buffer.items.len;
613613 try limbs_buffer.appendSlice(x.limbs);
lib/std/net.zig+39-2
......@@ -1205,13 +1205,13 @@ fn linuxLookupNameFromDnsSearch(
12051205
12061206 var tok_it = mem.tokenize(search, " \t");
12071207 while (tok_it.next()) |tok| {
1208 canon.shrinkAndFree(canon_name.len + 1);
1208 canon.shrinkRetainingCapacity(canon_name.len + 1);
12091209 try canon.appendSlice(tok);
12101210 try linuxLookupNameFromDns(addrs, canon, canon.items, family, rc, port);
12111211 if (addrs.items.len != 0) return;
12121212 }
12131213
1214 canon.shrinkAndFree(canon_name.len);
1214 canon.shrinkRetainingCapacity(canon_name.len);
12151215 return linuxLookupNameFromDns(addrs, canon, name, family, rc, port);
12161216}
12171217
......@@ -1621,6 +1621,9 @@ pub const Stream = struct {
16211621 }
16221622 }
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.
16241627 pub fn write(self: Stream, buffer: []const u8) WriteError!usize {
16251628 if (std.Target.current.os.tag == .windows) {
16261629 return os.windows.WriteFile(self.handle, buffer, null, io.default_mode);
......@@ -1632,6 +1635,40 @@ pub const Stream = struct {
16321635 return os.write(self.handle, buffer);
16331636 }
16341637 }
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 }
16351672};
16361673
16371674pub 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: [*:
16341634 }
16351635}
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
16371723pub const UnlinkError = error{
16381724 FileNotFound,
16391725
lib/std/os/bits/linux/arm-eabi.zig+1
......@@ -412,6 +412,7 @@ pub const SYS = extern enum(usize) {
412412 pidfd_getfd = 438,
413413 faccessat2 = 439,
414414 process_madvise = 440,
415 epoll_pwait2 = 441,
415416
416417 breakpoint = 0x0f0001,
417418 cacheflush = 0x0f0002,
lib/std/os/bits/linux/arm64.zig+1
......@@ -313,6 +313,7 @@ pub const SYS = extern enum(usize) {
313313 pidfd_getfd = 438,
314314 faccessat2 = 439,
315315 process_madvise = 440,
316 epoll_pwait2 = 441,
316317
317318 _,
318319};
lib/std/os/bits/linux/i386.zig+1
......@@ -448,6 +448,7 @@ pub const SYS = extern enum(usize) {
448448 pidfd_getfd = 438,
449449 faccessat2 = 439,
450450 process_madvise = 440,
451 epoll_pwait2 = 441,
451452
452453 _,
453454};
lib/std/os/bits/linux/mips.zig+1
......@@ -430,6 +430,7 @@ pub const SYS = extern enum(usize) {
430430 pidfd_getfd = Linux + 438,
431431 faccessat2 = Linux + 439,
432432 process_madvise = Linux + 440,
433 epoll_pwait2 = Linux + 441,
433434
434435 _,
435436};
lib/std/os/bits/linux/powerpc64.zig+1
......@@ -409,6 +409,7 @@ pub const SYS = extern enum(usize) {
409409 pidfd_getfd = 438,
410410 faccessat2 = 439,
411411 process_madvise = 440,
412 epoll_pwait2 = 441,
412413
413414 _,
414415};
lib/std/os/bits/linux/riscv64.zig+1
......@@ -310,6 +310,7 @@ pub const SYS = extern enum(usize) {
310310 pidfd_getfd = 438,
311311 faccessat2 = 439,
312312 process_madvise = 440,
313 epoll_pwait2 = 441,
313314
314315 _,
315316};
lib/std/os/bits/linux/sparc64.zig+1
......@@ -387,6 +387,7 @@ pub const SYS = extern enum(usize) {
387387 pidfd_getfd = 438,
388388 faccessat2 = 439,
389389 process_madvise = 440,
390 epoll_pwait2 = 441,
390391
391392 _,
392393};
lib/std/os/bits/linux/x86_64.zig+1
......@@ -375,6 +375,7 @@ pub const SYS = extern enum(usize) {
375375 pidfd_getfd = 438,
376376 faccessat2 = 439,
377377 process_madvise = 440,
378 epoll_pwait2 = 441,
378379
379380 _,
380381};
lib/std/os/linux.zig+31
......@@ -634,6 +634,37 @@ pub fn tgkill(tgid: pid_t, tid: pid_t, sig: i32) usize {
634634 return syscall2(.tgkill, @bitCast(usize, @as(isize, tgid)), @bitCast(usize, @as(isize, tid)), @bitCast(usize, @as(isize, sig)));
635635}
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
637668pub fn unlink(path: [*:0]const u8) usize {
638669 if (@hasField(SYS, "unlink")) {
639670 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 {
189189 expect(mem.eql(u8, target_path, given));
190190}
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
192261test "fstatat" {
193262 // enable when `fstat` and `fstatat` are implemented on Windows
194263 if (builtin.os.tag == .windows) return error.SkipZigTest;
lib/std/os/uefi.zig+14-3
......@@ -3,6 +3,8 @@
33// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
44// The MIT license requires this copyright notice to be included in all copies
55// and substantial portions of the software.
6const std = @import("../std.zig");
7
68/// A protocol is an interface identified by a GUID.
79pub const protocols = @import("uefi/protocols.zig");
810
......@@ -33,10 +35,10 @@ pub const Guid = extern struct {
3335 self: @This(),
3436 comptime f: []const u8,
3537 options: std.fmt.FormatOptions,
36 out_stream: anytype,
37 ) Errors!void {
38 writer: anytype,
39 ) !void {
3840 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}", .{
4042 self.time_low,
4143 self.time_mid,
4244 self.time_high_and_version,
......@@ -48,6 +50,15 @@ pub const Guid = extern struct {
4850 @compileError("Unknown format character: '" ++ f ++ "'");
4951 }
5052 }
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 }
5162};
5263
5364/// An EFI Handle represents a collection of related interfaces.
lib/std/wasm.zig+14
......@@ -253,6 +253,20 @@ pub fn section(val: Section) u8 {
253253 return @enumToInt(val);
254254}
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
256270// types
257271pub const element_type: u8 = 0x70;
258272pub const function_type: u8 = 0x60;
lib/std/zig/parser_test.zig+1-1
......@@ -648,7 +648,7 @@ test "zig fmt: struct literal 1 element" {
648648 );
649649}
650650
651test "zig fmt: struct literal 1 element comma" {
651test "zig fmt: Unicode code point literal larger than u8" {
652652 try testCanonical(
653653 \\test {
654654 \\ const x = X{
lib/std/zig/tokenizer.zig+3-3
......@@ -1535,7 +1535,7 @@ test "tokenizer - unknown length pointer and then c pointer" {
15351535 });
15361536}
15371537
1538test "tokenizer - char literal with hex escape" {
1538test "tokenizer - code point literal with hex escape" {
15391539 testTokenize(
15401540 \\'\x1b'
15411541 , &.{.char_literal});
......@@ -1544,7 +1544,7 @@ test "tokenizer - char literal with hex escape" {
15441544 , &.{ .invalid, .invalid });
15451545}
15461546
1547test "tokenizer - char literal with unicode escapes" {
1547test "tokenizer - code point literal with unicode escapes" {
15481548 // Valid unicode escapes
15491549 testTokenize(
15501550 \\'\u{3}'
......@@ -1594,7 +1594,7 @@ test "tokenizer - char literal with unicode escapes" {
15941594 , &.{ .invalid, .integer_literal, .invalid });
15951595}
15961596
1597test "tokenizer - char literal with unicode code point" {
1597test "tokenizer - code point literal with unicode code point" {
15981598 testTokenize(
15991599 \\'💩'
16001600 , &.{.char_literal});
src/Cache.zig+1-1
......@@ -317,7 +317,7 @@ pub const Manifest = struct {
317317 cache_hash_file.stat.size = fmt.parseInt(u64, size, 10) catch return error.InvalidFormat;
318318 cache_hash_file.stat.inode = fmt.parseInt(fs.File.INode, inode, 10) catch return error.InvalidFormat;
319319 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
322322 if (file_path.len == 0) {
323323 return error.InvalidFormat;
src/Compilation.zig+4-2
......@@ -645,7 +645,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
645645 };
646646
647647 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: {
649649 // TODO Revisit this targeting versions lower than macOS 11 when LLVM 12 is out.
650650 // See https://github.com/ziglang/zig/issues/6996
651651 const at_least_big_sur = options.target.os.getVersionRange().semver.min.major >= 11;
......@@ -1538,7 +1538,9 @@ pub fn getCompileLogOutput(self: *Compilation) []const u8 {
15381538}
15391539
15401540pub 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 };
15421544 var main_progress_node = try progress.start("", 0);
15431545 defer main_progress_node.end();
15441546 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 {
944944 /// Copies a value to a register without tracking the register. The register is not considered
945945 /// allocated. A second call to `copyToTmpRegister` may return the same register.
946946 /// 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 {
948948 const reg = self.findUnusedReg() orelse b: {
949949 // We'll take over the first register. Move the instruction that was previously
950950 // there to a stack allocation.
......@@ -961,7 +961,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
961961
962962 break :b reg;
963963 };
964 try self.genSetReg(src, reg, mcv);
964 try self.genSetReg(src, ty, reg, mcv);
965965 return reg;
966966 }
967967
......@@ -988,7 +988,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
988988
989989 break :b reg;
990990 };
991 try self.genSetReg(reg_owner.src, reg, mcv);
991 try self.genSetReg(reg_owner.src, reg_owner.ty, reg, mcv);
992992 return MCValue{ .register = reg };
993993 }
994994
......@@ -1356,13 +1356,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
13561356 // Load immediate into register if it doesn't fit
13571357 // as an operand
13581358 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);
13601360 },
13611361 .register => |reg| Instruction.Operand.reg(reg, Instruction.Operand.Shift.none),
13621362 .stack_offset,
13631363 .embedded_in_code,
13641364 .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),
13661366 };
13671367
13681368 switch (op) {
......@@ -1448,7 +1448,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
14481448 switch (src_mcv) {
14491449 .immediate => |imm| {
14501450 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) };
14521452 }
14531453 },
14541454 else => {},
......@@ -1479,7 +1479,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
14791479 .register => |dst_reg| {
14801480 switch (src_mcv) {
14811481 .none => unreachable,
1482 .undef => try self.genSetReg(src, dst_reg, .undef),
1482 .undef => try self.genSetReg(src, dst_ty, dst_reg, .undef),
14831483 .dead, .unreach => unreachable,
14841484 .ptr_stack_offset => unreachable,
14851485 .ptr_embedded_in_code => unreachable,
......@@ -1689,7 +1689,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
16891689 switch (mc_arg) {
16901690 .none => continue,
16911691 .register => |reg| {
1692 try self.genSetReg(arg.src, reg, arg_mcv);
1692 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
16931693 // TODO interact with the register allocator to mark the instruction as moved.
16941694 },
16951695 .stack_offset => {
......@@ -1758,7 +1758,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
17581758 else
17591759 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 });
17621762 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32());
17631763 } else if (func_value.castTag(.extern_fn)) |_| {
17641764 return self.fail(inst.base.src, "TODO implement calling extern functions", .{});
......@@ -1831,7 +1831,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
18311831 .compare_flags_signed => unreachable,
18321832 .compare_flags_unsigned => unreachable,
18331833 .register => |reg| {
1834 try self.genSetReg(arg.src, reg, arg_mcv);
1834 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
18351835 // TODO interact with the register allocator to mark the instruction as moved.
18361836 },
18371837 .stack_offset => {
......@@ -1859,7 +1859,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
18591859 else
18601860 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
18641864 // TODO: add Instruction.supportedOn
18651865 // function for ARM
......@@ -1894,7 +1894,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
18941894 .compare_flags_signed => unreachable,
18951895 .compare_flags_unsigned => unreachable,
18961896 .register => |reg| {
1897 try self.genSetReg(arg.src, reg, arg_mcv);
1897 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
18981898 // TODO interact with the register allocator to mark the instruction as moved.
18991899 },
19001900 .stack_offset => {
......@@ -1922,7 +1922,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
19221922 else
19231923 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
19271927 writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32());
19281928 } else if (func_value.castTag(.extern_fn)) |_| {
......@@ -1945,7 +1945,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
19451945 switch (mc_arg) {
19461946 .none => continue,
19471947 .register => |reg| {
1948 try self.genSetReg(arg.src, reg, arg_mcv);
1948 try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
19491949 // TODO interact with the register allocator to mark the instruction as moved.
19501950 },
19511951 .stack_offset => {
......@@ -1978,12 +1978,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
19781978 const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64);
19791979 switch (arch) {
19801980 .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 });
19821982 // callq *%rax
19831983 self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 });
19841984 },
19851985 .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 });
19871987 // blr x30
19881988 writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32());
19891989 },
......@@ -2584,7 +2584,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
25842584 const reg = parseRegName(reg_name) orelse
25852585 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
25862586 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);
25882588 }
25892589
25902590 if (mem.eql(u8, inst.asm_source, "svc #0")) {
......@@ -2614,7 +2614,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
26142614 const reg = parseRegName(reg_name) orelse
26152615 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
26162616 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);
26182618 }
26192619
26202620 if (mem.eql(u8, inst.asm_source, "svc #0")) {
......@@ -2646,7 +2646,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
26462646 const reg = parseRegName(reg_name) orelse
26472647 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
26482648 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);
26502650 }
26512651
26522652 if (mem.eql(u8, inst.asm_source, "ecall")) {
......@@ -2676,7 +2676,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
26762676 const reg = parseRegName(reg_name) orelse
26772677 return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
26782678 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);
26802680 }
26812681
26822682 if (mem.eql(u8, inst.asm_source, "syscall")) {
......@@ -2738,7 +2738,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27382738 fn setRegOrMem(self: *Self, src: usize, ty: Type, loc: MCValue, val: MCValue) !void {
27392739 switch (loc) {
27402740 .none => return,
2741 .register => |reg| return self.genSetReg(src, reg, val),
2741 .register => |reg| return self.genSetReg(src, ty, reg, val),
27422742 .stack_offset => |off| return self.genSetStack(src, ty, off, val),
27432743 .memory => {
27442744 return self.fail(src, "TODO implement setRegOrMem for memory", .{});
......@@ -2773,7 +2773,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27732773 return self.fail(src, "TODO implement set stack variable with compare flags value (signed)", .{});
27742774 },
27752775 .immediate => {
2776 const reg = try self.copyToTmpRegister(src, mcv);
2776 const reg = try self.copyToTmpRegister(src, ty, mcv);
27772777 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });
27782778 },
27792779 .embedded_in_code => |code_offset| {
......@@ -2787,7 +2787,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
27872787 1, 4 => {
27882788 const offset = if (math.cast(u12, adj_off)) |imm| blk: {
27892789 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);
27912791 const str = switch (abi_size) {
27922792 1 => Instruction.strb,
27932793 4 => Instruction.str,
......@@ -2802,7 +2802,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
28022802 2 => {
28032803 const offset = if (adj_off <= math.maxInt(u8)) blk: {
28042804 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
28072807 writeInt(u32, try self.code.addManyAsArray(4), Instruction.strh(.al, reg, .fp, .{
28082808 .offset = offset,
......@@ -2819,7 +2819,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
28192819 if (stack_offset == off)
28202820 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);
28232823 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });
28242824 },
28252825 },
......@@ -2908,7 +2908,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
29082908 if (stack_offset == off)
29092909 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);
29122912 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });
29132913 },
29142914 },
......@@ -2936,7 +2936,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
29362936 return self.fail(src, "TODO implement set stack variable with compare flags value (signed)", .{});
29372937 },
29382938 .immediate => {
2939 const reg = try self.copyToTmpRegister(src, mcv);
2939 const reg = try self.copyToTmpRegister(src, ty, mcv);
29402940 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });
29412941 },
29422942 .embedded_in_code => |code_offset| {
......@@ -2951,7 +2951,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
29512951 const offset = if (math.cast(i9, adj_off)) |imm|
29522952 Instruction.LoadStoreOffset.imm_post_index(-imm)
29532953 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 }));
29552955 const rn: Register = switch (arch) {
29562956 .aarch64, .aarch64_be => .x29,
29572957 .aarch64_32 => .w29,
......@@ -2972,7 +2972,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
29722972 if (stack_offset == off)
29732973 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);
29762976 return self.genSetStack(src, ty, stack_offset, MCValue{ .register = reg });
29772977 },
29782978 },
......@@ -2980,7 +2980,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
29802980 }
29812981 }
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 {
29842984 switch (arch) {
29852985 .arm, .armeb => switch (mcv) {
29862986 .dead => unreachable,
......@@ -2991,7 +2991,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
29912991 if (!self.wantSafety())
29922992 return; // The already existing value will do just fine.
29932993 // Write the debug undefined value.
2994 return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaa });
2994 return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaa });
29952995 },
29962996 .compare_flags_unsigned,
29972997 .compare_flags_signed,
......@@ -3056,21 +3056,19 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
30563056 .memory => |addr| {
30573057 // The value is in memory at a hard-coded address.
30583058 // 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 });
30603060 writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldr(.al, reg, reg, .{ .offset = Instruction.Offset.none }).toU32());
30613061 },
30623062 .stack_offset => |unadjusted_off| {
30633063 // TODO: maybe addressing from sp instead of fp
3064 // TODO: supply type information to genSetReg as we do to genSetStack
3065 // const abi_size = ty.abiSize(self.target.*);
3066 const abi_size = 4;
3064 const abi_size = ty.abiSize(self.target.*);
30673065 const adj_off = unadjusted_off + abi_size;
30683066
30693067 switch (abi_size) {
30703068 1, 4 => {
30713069 const offset = if (adj_off <= math.maxInt(u12)) blk: {
30723070 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);
30743072 const ldr = switch (abi_size) {
30753073 1 => Instruction.ldrb,
30763074 4 => Instruction.ldr,
......@@ -3085,7 +3083,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
30853083 2 => {
30863084 const offset = if (adj_off <= math.maxInt(u8)) blk: {
30873085 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
30903088 writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldrh(.al, reg, .fp, .{
30913089 .offset = offset,
......@@ -3107,8 +3105,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
31073105 return; // The already existing value will do just fine.
31083106 // Write the debug undefined value.
31093107 switch (reg.size()) {
3110 32 => return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaa }),
3111 64 => return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
3108 32 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaa }),
3109 64 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
31123110 else => unreachable, // unexpected register size
31133111 }
31143112 },
......@@ -3221,7 +3219,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
32213219 } else {
32223220 // The value is in memory at a hard-coded address.
32233221 // 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 });
32253223 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(reg, .{ .register = .{ .rn = reg } }).toU32());
32263224 }
32273225 },
......@@ -3236,7 +3234,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
32363234 if (!self.wantSafety())
32373235 return; // The already existing value will do just fine.
32383236 // Write the debug undefined value.
3239 return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa });
3237 return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa });
32403238 },
32413239 .immediate => |unsigned_x| {
32423240 const x = @bitCast(i64, unsigned_x);
......@@ -3261,7 +3259,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
32613259 .memory => |addr| {
32623260 // The value is in memory at a hard-coded address.
32633261 // 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
32663264 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ld(reg, 0, reg).toU32());
32673265 // LOAD imm=[i12 offset = 0], rs1 =
......@@ -3280,10 +3278,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
32803278 return; // The already existing value will do just fine.
32813279 // Write the debug undefined value.
32823280 switch (reg.size()) {
3283 8 => return self.genSetReg(src, reg, .{ .immediate = 0xaa }),
3284 16 => return self.genSetReg(src, reg, .{ .immediate = 0xaaaa }),
3285 32 => return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaa }),
3286 64 => return self.genSetReg(src, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
3281 8 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaa }),
3282 16 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaa }),
3283 32 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaa }),
3284 64 => return self.genSetReg(src, ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }),
32873285 else => unreachable,
32883286 }
32893287 },
......@@ -3497,7 +3495,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
34973495 assert(id3 != 4 and id3 != 5);
34983496
34993497 // 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
35023500 // Now, the register contains the address of the value to load into it
35033501 // 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 {
35963594 // This immediate is unsigned.
35973595 const U = std.meta.Int(.unsigned, ti.bits - @boolToInt(ti.signedness == .signed));
35983596 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) };
36003598 }
36013599 },
36023600 else => {},
......@@ -3710,17 +3708,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
37103708 for (param_types) |ty, i| {
37113709 switch (ty.zigTypeTag()) {
37123710 .Bool, .Int => {
3713 const param_size = @intCast(u32, ty.abiSize(self.target.*));
3714 if (next_int_reg >= c_abi_int_param_regs.len) {
3715 result.args[i] = .{ .stack_offset = next_stack_offset };
3716 next_stack_offset += param_size;
3711 if (!ty.hasCodeGenBits()) {
3712 assert(cc != .C);
3713 result.args[i] = .{ .none = {} };
37173714 } else {
3718 const aliased_reg = registerAlias(
3719 c_abi_int_param_regs[next_int_reg],
3720 param_size,
3721 );
3722 result.args[i] = .{ .register = aliased_reg };
3723 next_int_reg += 1;
3715 const param_size = @intCast(u32, ty.abiSize(self.target.*));
3716 if (next_int_reg >= c_abi_int_param_regs.len) {
3717 result.args[i] = .{ .stack_offset = next_stack_offset };
3718 next_stack_offset += param_size;
3719 } else {
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 }
37243727 }
37253728 },
37263729 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 {
161161 pub fn gen(self: *Context) InnerError!void {
162162 assert(self.code.items.len == 0);
163163 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
169165 // Write instructions
170166 // TODO: check for and handle death of instructions
171167 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
173177 try self.genBody(mod_fn.body);
174178
175179 // finally, write our local types at the 'offset' position
......@@ -189,6 +193,7 @@ pub const Context = struct {
189193 }
190194 }
191195
196 const writer = self.code.writer();
192197 try writer.writeByte(wasm.opcode(.end));
193198
194199 // Fill in the size of the generated code to the reserved space at the
......@@ -239,9 +244,16 @@ pub const Context = struct {
239244
240245 fn genCall(self: *Context, inst: *Inst.Call) InnerError!WValue {
241246 const func_inst = inst.func.castTag(.constant).?;
242 const func = func_inst.val.castTag(.function).?.data;
243 const target = func.owner_decl;
244 const target_ty = target.typed_value.most_recent.typed_value.ty;
247 const func_val = inst.func.value().?;
248
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
246258 for (inst.args) |arg| {
247259 const arg_val = self.resolveInst(arg);
......@@ -495,7 +507,7 @@ pub const Context = struct {
495507 }
496508
497509 fn genBr(self: *Context, br: *Inst.Br) InnerError!WValue {
498 // of operand has codegen bits we should break with a value
510 // if operand has codegen bits we should break with a value
499511 if (br.operand.ty.hasCodeGenBits()) {
500512 const operand = self.resolveInst(br.operand);
501513 try self.emitWValue(operand);
src/link/Wasm.zig+90-14
......@@ -33,9 +33,18 @@ base: link.File,
3333
3434/// List of all function Decls to be written to the output file. The index of
3535/// 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.
3738/// TODO: can/should we access some data structure in Module directly?
3839funcs: 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
4049pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Wasm {
4150 assert(options.object_format == .wasm);
......@@ -76,7 +85,13 @@ pub fn deinit(self: *Wasm) void {
7685 decl.fn_link.wasm.?.code.deinit(self.base.allocator);
7786 decl.fn_link.wasm.?.idx_refs.deinit(self.base.allocator);
7887 }
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 }
7993 self.funcs.deinit(self.base.allocator);
94 self.ext_funcs.deinit(self.base.allocator);
8095}
8196
8297// 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 {
85100 const typed_value = decl.typed_value.most_recent.typed_value;
86101 if (typed_value.ty.zigTypeTag() != .Fn)
87102 return error.TODOImplementNonFnDeclsForWasm;
88 if (typed_value.val.tag() == .extern_fn)
89 return error.TODOImplementExternFnDeclsForWasm;
90103
91104 if (decl.fn_link.wasm) |*fn_data| {
92105 fn_data.functype.items.len = 0;
......@@ -94,7 +107,12 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
94107 fn_data.idx_refs.items.len = 0;
95108 } else {
96109 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 }
98116 }
99117 const fn_data = &decl.fn_link.wasm.?;
100118
......@@ -143,7 +161,12 @@ pub fn updateDeclExports(
143161pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
144162 // TODO: remove this assert when non-function Decls are implemented
145163 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 }
147170 decl.fn_link.wasm.?.functype.deinit(self.base.allocator);
148171 decl.fn_link.wasm.?.code.deinit(self.base.allocator);
149172 decl.fn_link.wasm.?.idx_refs.deinit(self.base.allocator);
......@@ -172,15 +195,46 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
172195 // Type section
173196 {
174197 const header_offset = try reserveVecSectionHeader(file);
175 for (self.funcs.items) |decl| {
176 try file.writeAll(decl.fn_link.wasm.?.functype.items);
177 }
198
199 // extern functions are defined in the wasm binary first through the `import`
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
178204 try writeVecSectionHeader(
179205 file,
180206 header_offset,
181207 .type,
182208 @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),
184238 );
185239 }
186240
......@@ -188,7 +242,11 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
188242 {
189243 const header_offset = try reserveVecSectionHeader(file);
190244 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
192250 try writeVecSectionHeader(
193251 file,
194252 header_offset,
......@@ -212,7 +270,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
212270 switch (exprt.exported_decl.typed_value.most_recent.typed_value.ty.zigTypeTag()) {
213271 .Fn => {
214272 // Type of the export
215 try writer.writeByte(0x00);
273 try writer.writeByte(wasm.externalKind(.function));
216274 // Exported function index
217275 try leb.writeULEB128(writer, self.getFuncidx(exprt.exported_decl).?);
218276 },
......@@ -523,13 +581,31 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
523581}
524582
525583/// Get the current index of a given Decl in the function list
526/// TODO: we could maintain a hash map to potentially make this
584/// 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
527586fn getFuncidx(self: Wasm, decl: *Module.Decl) ?u32 {
528 return for (self.funcs.items) |func, idx| {
529 if (func == decl) break @intCast(u32, idx);
587 var offset: u32 = 0;
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);
530600 } else null;
531601}
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
533609fn reserveVecSectionHeader(file: fs.File) !u64 {
534610 // section id + fixed leb contents size + fixed leb vector length
535611 const header_size = 1 + 5 + 5;
src/stage1.zig+3-1
......@@ -278,7 +278,9 @@ export fn stage2_attach_segfault_handler() void {
278278// ABI warning
279279export fn stage2_progress_create() *std.Progress {
280280 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 };
282284 return ptr;
283285}
284286
src/stage1/tokenizer.cpp+2-2
......@@ -1447,7 +1447,7 @@ void tokenize(Buf *buf, Tokenization *out) {
14471447 tokenize_error(&t, "unterminated string");
14481448 break;
14491449 } else if (t.cur_tok->id == TokenIdCharLiteral) {
1450 tokenize_error(&t, "unterminated character literal");
1450 tokenize_error(&t, "unterminated Unicode code point literal");
14511451 break;
14521452 } else {
14531453 zig_unreachable();
......@@ -1456,7 +1456,7 @@ void tokenize(Buf *buf, Tokenization *out) {
14561456 case TokenizeStateCharLiteral:
14571457 case TokenizeStateCharLiteralEnd:
14581458 case TokenizeStateCharLiteralUnicode:
1459 tokenize_error(&t, "unterminated character literal");
1459 tokenize_error(&t, "unterminated Unicode code point literal");
14601460 break;
14611461 case TokenizeStateSymbol:
14621462 case TokenizeStateZero:
test/stage2/test.zig+22
......@@ -1397,4 +1397,26 @@ pub fn addCases(ctx: *TestContext) !void {
13971397 "",
13981398 );
13991399 }
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 }
14001422}