authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-24 10:44:41-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-24 10:44:41-07:00
loge86cee258cb0eefca14a94f6b3abb39e8a5f2ef9
tree6d9aa3b21685b1581787246f953db94cdb486693
parent224fbb23c44628b215662c6199dff11cc2851f04
parent8530b6b7242ebf43b5cb4ae3a2644593f4961a5e

Merge remote-tracking branch 'origin/master' into stage2-whole-file-astgen

In particular I wanted the change that makes `suspend;` illegal in the parser.

73 files changed, 1162 insertions(+), 470 deletions(-)

.gitattributes+6-6
......@@ -3,9 +3,9 @@
33langref.html.in text eol=lf
44deps/SoftFloat-3e/*.txt text eol=crlf
55
6deps/* linguist-vendored
7lib/include/* linguist-vendored
8lib/libc/* linguist-vendored
9lib/libcxx/* linguist-vendored
10lib/libcxxabi/* linguist-vendored
11lib/libunwind/* linguist-vendored
6deps/** linguist-vendored
7lib/include/** linguist-vendored
8lib/libc/** linguist-vendored
9lib/libcxx/** linguist-vendored
10lib/libcxxabi/** linguist-vendored
11lib/libunwind/** linguist-vendored
build.zig+1
......@@ -267,6 +267,7 @@ pub fn build(b: *Builder) !void {
267267 test_step.dependOn(tests.addPkgTests(b, test_filter, "lib/std/std.zig", "std", "Run the standard library tests", modes, false, skip_non_native, skip_libc, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));
268268
269269 test_step.dependOn(tests.addPkgTests(b, test_filter, "lib/std/special/compiler_rt.zig", "compiler-rt", "Run the compiler_rt tests", modes, true, skip_non_native, true, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));
270 test_step.dependOn(tests.addPkgTests(b, test_filter, "lib/std/special/c.zig", "minilibc", "Run the mini libc tests", modes, true, skip_non_native, true, is_wine_enabled, is_qemu_enabled, is_wasmtime_enabled, glibc_multi_dir));
270271
271272 test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
272273 test_step.dependOn(tests.addStandaloneTests(b, test_filter, modes));
ci/drone/linux_script+1-3
......@@ -23,13 +23,11 @@ cmake .. -DCMAKE_BUILD_TYPE=Release "-DCMAKE_INSTALL_PREFIX=$DISTDIR" -DZIG_STAT
2323
2424samu install
2525# run-translated-c tests are skipped due to: https://github.com/ziglang/zig/issues/8537
26# stage2 tests are skipped due to: https://github.com/ziglang/zig/issues/8545
2726./zig build test \
2827 -Dskip-release \
2928 -Dskip-non-native \
3029 -Dskip-compile-errors \
31 -Dskip-run-translated-c \
32 -Dskip-stage2-tests
30 -Dskip-run-translated-c
3331
3432if [ -z "$DRONE_PULL_REQUEST" ]; then
3533 mv ../LICENSE "$DISTDIR/"
doc/langref.html.in+15-7
......@@ -6509,7 +6509,7 @@ test "suspend with no resume" {
65096509
65106510fn func() void {
65116511 x += 1;
6512 suspend;
6512 suspend {}
65136513 // This line is never reached because the suspend has no matching resume.
65146514 x += 1;
65156515}
......@@ -6574,7 +6574,7 @@ fn testResumeFromSuspend(my_result: *i32) void {
65746574 resume @frame();
65756575 }
65766576 my_result.* += 1;
6577 suspend;
6577 suspend {}
65786578 my_result.* += 1;
65796579}
65806580 {#code_end#}
......@@ -6613,7 +6613,7 @@ fn amain() void {
66136613}
66146614
66156615fn func() void {
6616 suspend;
6616 suspend {}
66176617}
66186618 {#code_end#}
66196619 <p>
......@@ -6915,7 +6915,7 @@ test "async fn pointer in a struct field" {
69156915fn func(y: *i32) void {
69166916 defer y.* += 2;
69176917 y.* += 1;
6918 suspend;
6918 suspend {}
69196919}
69206920 {#code_end#}
69216921 {#header_close#}
......@@ -7498,13 +7498,13 @@ test "main" {
74987498 {#header_close#}
74997499
75007500 {#header_open|@export#}
7501 <pre>{#syntax#}@export(target: anytype, comptime options: std.builtin.ExportOptions) void{#endsyntax#}</pre>
7501 <pre>{#syntax#}@export(identifier, comptime options: std.builtin.ExportOptions) void{#endsyntax#}</pre>
75027502 <p>
75037503 Creates a symbol in the output object file.
75047504 </p>
75057505 <p>
75067506 This function can be called from a {#link|comptime#} block to conditionally export symbols.
7507 When {#syntax#}target{#endsyntax#} is a function with the C calling convention and
7507 When {#syntax#}identifier{#endsyntax#} is a function with the C calling convention and
75087508 {#syntax#}options.linkage{#endsyntax#} is {#syntax#}Strong{#endsyntax#}, this is equivalent to
75097509 the {#syntax#}export{#endsyntax#} keyword used on a function:
75107510 </p>
......@@ -7531,6 +7531,14 @@ export fn @"A function name that is a complete sentence."() void {}
75317531 {#see_also|Exporting a C Library#}
75327532 {#header_close#}
75337533
7534 {#header_open|@extern#}
7535 <pre>{#syntax#}@extern(T: type, comptime options: std.builtin.ExternOptions) *T{#endsyntax#}</pre>
7536 <p>
7537 Creates a reference to an external symbol in the output object file.
7538 </p>
7539 {#see_also|@export#}
7540 {#header_close#}
7541
75347542 {#header_open|@fence#}
75357543 <pre>{#syntax#}@fence(order: AtomicOrder){#endsyntax#}</pre>
75367544 <p>
......@@ -7640,7 +7648,7 @@ test "heap allocated frame" {
76407648}
76417649
76427650fn func() void {
7643 suspend;
7651 suspend {}
76447652}
76457653 {#code_end#}
76467654 {#header_close#}
lib/std/atomic/bool.zig+1-1
......@@ -28,7 +28,7 @@ pub const Bool = extern struct {
2828 return @atomicRmw(bool, &self.unprotected_value, .Xchg, operand, ordering);
2929 }
3030
31 pub fn load(self: *Self, comptime ordering: std.builtin.AtomicOrder) bool {
31 pub fn load(self: *const Self, comptime ordering: std.builtin.AtomicOrder) bool {
3232 switch (ordering) {
3333 .Unordered, .Monotonic, .Acquire, .SeqCst => {},
3434 else => @compileError("Invalid ordering '" ++ @tagName(ordering) ++ "' for a load operation"),
lib/std/atomic/int.zig+2-2
......@@ -31,7 +31,7 @@ pub fn Int(comptime T: type) type {
3131 return @atomicRmw(T, &self.unprotected_value, op, operand, ordering);
3232 }
3333
34 pub fn load(self: *Self, comptime ordering: builtin.AtomicOrder) T {
34 pub fn load(self: *const Self, comptime ordering: builtin.AtomicOrder) T {
3535 switch (ordering) {
3636 .Unordered, .Monotonic, .Acquire, .SeqCst => {},
3737 else => @compileError("Invalid ordering '" ++ @tagName(ordering) ++ "' for a load operation"),
......@@ -59,7 +59,7 @@ pub fn Int(comptime T: type) type {
5959 return self.rmw(.Sub, 1, .SeqCst);
6060 }
6161
62 pub fn get(self: *Self) T {
62 pub fn get(self: *const Self) T {
6363 return self.load(.SeqCst);
6464 }
6565
lib/std/build.zig+5
......@@ -1386,6 +1386,8 @@ pub const LibExeObjStep = struct {
13861386 /// safely garbage-collected during the linking phase.
13871387 link_function_sections: bool = false,
13881388
1389 linker_allow_shlib_undefined: ?bool = null,
1390
13891391 /// Uses system Wine installation to run cross compiled Windows build artifacts.
13901392 enable_wine: bool = false,
13911393
......@@ -2338,6 +2340,9 @@ pub const LibExeObjStep = struct {
23382340 if (self.link_function_sections) {
23392341 try zig_args.append("-ffunction-sections");
23402342 }
2343 if (self.linker_allow_shlib_undefined) |x| {
2344 try zig_args.append(if (x) "-fallow-shlib-undefined" else "-fno-allow-shlib-undefined");
2345 }
23412346 if (self.single_threaded) {
23422347 try zig_args.append("--single-threaded");
23432348 }
lib/std/crypto.zig+1-1
......@@ -154,7 +154,7 @@ pub const random = &@import("crypto/tlcsprng.zig").interface;
154154
155155const std = @import("std.zig");
156156
157pub const Error = @import("crypto/error.zig").Error;
157pub const errors = @import("crypto/errors.zig");
158158
159159test "crypto" {
160160 const please_windows_dont_oom = std.Target.current.os.tag == .windows;
lib/std/crypto/25519/curve25519.zig+12-8
......@@ -4,7 +4,11 @@
44// The MIT license requires this copyright notice to be included in all copies
55// and substantial portions of the software.
66const std = @import("std");
7const Error = std.crypto.Error;
7const crypto = std.crypto;
8
9const IdentityElementError = crypto.errors.IdentityElementError;
10const NonCanonicalError = crypto.errors.NonCanonicalError;
11const WeakPublicKeyError = crypto.errors.WeakPublicKeyError;
812
913/// Group operations over Curve25519.
1014pub const Curve25519 = struct {
......@@ -29,12 +33,12 @@ pub const Curve25519 = struct {
2933 pub const basePoint = Curve25519{ .x = Fe.curve25519BasePoint };
3034
3135 /// Check that the encoding of a Curve25519 point is canonical.
32 pub fn rejectNonCanonical(s: [32]u8) Error!void {
36 pub fn rejectNonCanonical(s: [32]u8) NonCanonicalError!void {
3337 return Fe.rejectNonCanonical(s, false);
3438 }
3539
3640 /// Reject the neutral element.
37 pub fn rejectIdentity(p: Curve25519) Error!void {
41 pub fn rejectIdentity(p: Curve25519) IdentityElementError!void {
3842 if (p.x.isZero()) {
3943 return error.IdentityElement;
4044 }
......@@ -45,7 +49,7 @@ pub const Curve25519 = struct {
4549 return p.dbl().dbl().dbl();
4650 }
4751
48 fn ladder(p: Curve25519, s: [32]u8, comptime bits: usize) Error!Curve25519 {
52 fn ladder(p: Curve25519, s: [32]u8, comptime bits: usize) IdentityElementError!Curve25519 {
4953 var x1 = p.x;
5054 var x2 = Fe.one;
5155 var z2 = Fe.zero;
......@@ -86,7 +90,7 @@ pub const Curve25519 = struct {
8690 /// way to use Curve25519 for a DH operation.
8791 /// Return error.IdentityElement if the resulting point is
8892 /// the identity element.
89 pub fn clampedMul(p: Curve25519, s: [32]u8) Error!Curve25519 {
93 pub fn clampedMul(p: Curve25519, s: [32]u8) IdentityElementError!Curve25519 {
9094 var t: [32]u8 = s;
9195 scalar.clamp(&t);
9296 return try ladder(p, t, 255);
......@@ -96,16 +100,16 @@ pub const Curve25519 = struct {
96100 /// Return error.IdentityElement if the resulting point is
97101 /// the identity element or error.WeakPublicKey if the public
98102 /// key is a low-order point.
99 pub fn mul(p: Curve25519, s: [32]u8) Error!Curve25519 {
103 pub fn mul(p: Curve25519, s: [32]u8) (IdentityElementError || WeakPublicKeyError)!Curve25519 {
100104 const cofactor = [_]u8{8} ++ [_]u8{0} ** 31;
101105 _ = ladder(p, cofactor, 4) catch return error.WeakPublicKey;
102106 return try ladder(p, s, 256);
103107 }
104108
105109 /// Compute the Curve25519 equivalent to an Edwards25519 point.
106 pub fn fromEdwards25519(p: std.crypto.ecc.Edwards25519) Error!Curve25519 {
110 pub fn fromEdwards25519(p: crypto.ecc.Edwards25519) IdentityElementError!Curve25519 {
107111 try p.clearCofactor().rejectIdentity();
108 const one = std.crypto.ecc.Edwards25519.Fe.one;
112 const one = crypto.ecc.Edwards25519.Fe.one;
109113 const x = one.add(p.y).mul(one.sub(p.y).invert()); // xMont=(1+yEd)/(1-yEd)
110114 return Curve25519{ .x = x };
111115 }
lib/std/crypto/25519/ed25519.zig+21-13
......@@ -8,8 +8,15 @@ const crypto = std.crypto;
88const debug = std.debug;
99const fmt = std.fmt;
1010const mem = std.mem;
11
1112const Sha512 = crypto.hash.sha2.Sha512;
12const Error = crypto.Error;
13
14const EncodingError = crypto.errors.EncodingError;
15const IdentityElementError = crypto.errors.IdentityElementError;
16const NonCanonicalError = crypto.errors.NonCanonicalError;
17const SignatureVerificationError = crypto.errors.SignatureVerificationError;
18const KeyMismatchError = crypto.errors.KeyMismatchError;
19const WeakPublicKeyError = crypto.errors.WeakPublicKeyError;
1320
1421/// Ed25519 (EdDSA) signatures.
1522pub const Ed25519 = struct {
......@@ -41,7 +48,7 @@ pub const Ed25519 = struct {
4148 ///
4249 /// For this reason, an EdDSA secret key is commonly called a seed,
4350 /// from which the actual secret is derived.
44 pub fn create(seed: ?[seed_length]u8) Error!KeyPair {
51 pub fn create(seed: ?[seed_length]u8) IdentityElementError!KeyPair {
4552 const ss = seed orelse ss: {
4653 var random_seed: [seed_length]u8 = undefined;
4754 crypto.random.bytes(&random_seed);
......@@ -51,7 +58,7 @@ pub const Ed25519 = struct {
5158 var h = Sha512.init(.{});
5259 h.update(&ss);
5360 h.final(&az);
54 const p = try Curve.basePoint.clampedMul(az[0..32].*);
61 const p = Curve.basePoint.clampedMul(az[0..32].*) catch return error.IdentityElement;
5562 var sk: [secret_length]u8 = undefined;
5663 mem.copy(u8, &sk, &ss);
5764 const pk = p.toBytes();
......@@ -72,7 +79,7 @@ pub const Ed25519 = struct {
7279 /// Sign a message using a key pair, and optional random noise.
7380 /// Having noise creates non-standard, non-deterministic signatures,
7481 /// but has been proven to increase resilience against fault attacks.
75 pub fn sign(msg: []const u8, key_pair: KeyPair, noise: ?[noise_length]u8) Error![signature_length]u8 {
82 pub fn sign(msg: []const u8, key_pair: KeyPair, noise: ?[noise_length]u8) (IdentityElementError || WeakPublicKeyError || KeyMismatchError)![signature_length]u8 {
7683 const seed = key_pair.secret_key[0..seed_length];
7784 const public_key = key_pair.secret_key[seed_length..];
7885 if (!mem.eql(u8, public_key, &key_pair.public_key)) {
......@@ -113,7 +120,7 @@ pub const Ed25519 = struct {
113120
114121 /// Verify an Ed25519 signature given a message and a public key.
115122 /// Returns error.SignatureVerificationFailed is the signature verification failed.
116 pub fn verify(sig: [signature_length]u8, msg: []const u8, public_key: [public_length]u8) Error!void {
123 pub fn verify(sig: [signature_length]u8, msg: []const u8, public_key: [public_length]u8) (SignatureVerificationError || WeakPublicKeyError || EncodingError || NonCanonicalError || IdentityElementError)!void {
117124 const r = sig[0..32];
118125 const s = sig[32..64];
119126 try Curve.scalar.rejectNonCanonical(s.*);
......@@ -122,6 +129,7 @@ pub const Ed25519 = struct {
122129 try a.rejectIdentity();
123130 try Curve.rejectNonCanonical(r.*);
124131 const expected_r = try Curve.fromBytes(r.*);
132 try expected_r.rejectIdentity();
125133
126134 var h = Sha512.init(.{});
127135 h.update(r);
......@@ -131,8 +139,7 @@ pub const Ed25519 = struct {
131139 h.final(&hram64);
132140 const hram = Curve.scalar.reduce64(hram64);
133141
134 const ah = try a.neg().mulPublic(hram);
135 const sb_ah = (try Curve.basePoint.mulPublic(s.*)).add(ah);
142 const sb_ah = try Curve.basePoint.mulDoubleBasePublic(s.*, a.neg(), hram);
136143 if (expected_r.sub(sb_ah).clearCofactor().rejectIdentity()) |_| {
137144 return error.SignatureVerificationFailed;
138145 } else |_| {}
......@@ -146,7 +153,7 @@ pub const Ed25519 = struct {
146153 };
147154
148155 /// Verify several signatures in a single operation, much faster than verifying signatures one-by-one
149 pub fn verifyBatch(comptime count: usize, signature_batch: [count]BatchElement) Error!void {
156 pub fn verifyBatch(comptime count: usize, signature_batch: [count]BatchElement) (SignatureVerificationError || IdentityElementError || WeakPublicKeyError || EncodingError || NonCanonicalError)!void {
150157 var r_batch: [count][32]u8 = undefined;
151158 var s_batch: [count][32]u8 = undefined;
152159 var a_batch: [count]Curve = undefined;
......@@ -161,6 +168,7 @@ pub const Ed25519 = struct {
161168 try a.rejectIdentity();
162169 try Curve.rejectNonCanonical(r.*);
163170 const expected_r = try Curve.fromBytes(r.*);
171 try expected_r.rejectIdentity();
164172 expected_r_batch[i] = expected_r;
165173 r_batch[i] = r.*;
166174 s_batch[i] = s.*;
......@@ -180,7 +188,7 @@ pub const Ed25519 = struct {
180188
181189 var z_batch: [count]Curve.scalar.CompressedScalar = undefined;
182190 for (z_batch) |*z| {
183 std.crypto.random.bytes(z[0..16]);
191 crypto.random.bytes(z[0..16]);
184192 mem.set(u8, z[16..], 0);
185193 }
186194
......@@ -233,8 +241,8 @@ test "ed25519 batch verification" {
233241 const key_pair = try Ed25519.KeyPair.create(null);
234242 var msg1: [32]u8 = undefined;
235243 var msg2: [32]u8 = undefined;
236 std.crypto.random.bytes(&msg1);
237 std.crypto.random.bytes(&msg2);
244 crypto.random.bytes(&msg1);
245 crypto.random.bytes(&msg2);
238246 const sig1 = try Ed25519.sign(&msg1, key_pair, null);
239247 const sig2 = try Ed25519.sign(&msg2, key_pair, null);
240248 var signature_batch = [_]Ed25519.BatchElement{
......@@ -317,13 +325,13 @@ test "ed25519 test vectors" {
317325 .msg_hex = "9bedc267423725d473888631ebf45988bad3db83851ee85c85e241a07d148b41",
318326 .public_key_hex = "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43",
319327 .sig_hex = "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03be9678ac102edcd92b0210bb34d7428d12ffc5df5f37e359941266a4e35f0f",
320 .expected = error.SignatureVerificationFailed, // 8 - non-canonical R
328 .expected = error.IdentityElement, // 8 - non-canonical R
321329 },
322330 Vec{
323331 .msg_hex = "9bedc267423725d473888631ebf45988bad3db83851ee85c85e241a07d148b41",
324332 .public_key_hex = "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43",
325333 .sig_hex = "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffca8c5b64cd208982aa38d4936621a4775aa233aa0505711d8fdcfdaa943d4908",
326 .expected = null, // 9 - non-canonical R
334 .expected = error.IdentityElement, // 9 - non-canonical R
327335 },
328336 Vec{
329337 .msg_hex = "e96b7021eb39c1a163b6da4e3093dcd3f21387da4cc4572be588fafae23c155b",
lib/std/crypto/25519/edwards25519.zig+65-18
......@@ -4,10 +4,16 @@
44// The MIT license requires this copyright notice to be included in all copies
55// and substantial portions of the software.
66const std = @import("std");
7const crypto = std.crypto;
78const debug = std.debug;
89const fmt = std.fmt;
910const mem = std.mem;
10const Error = std.crypto.Error;
11
12const EncodingError = crypto.errors.EncodingError;
13const IdentityElementError = crypto.errors.IdentityElementError;
14const NonCanonicalError = crypto.errors.NonCanonicalError;
15const NotSquareError = crypto.errors.NotSquareError;
16const WeakPublicKeyError = crypto.errors.WeakPublicKeyError;
1117
1218/// Group operations over Edwards25519.
1319pub const Edwards25519 = struct {
......@@ -26,7 +32,7 @@ pub const Edwards25519 = struct {
2632 is_base: bool = false,
2733
2834 /// Decode an Edwards25519 point from its compressed (Y+sign) coordinates.
29 pub fn fromBytes(s: [encoded_length]u8) Error!Edwards25519 {
35 pub fn fromBytes(s: [encoded_length]u8) EncodingError!Edwards25519 {
3036 const z = Fe.one;
3137 const y = Fe.fromBytes(s);
3238 var u = y.sq();
......@@ -56,7 +62,7 @@ pub const Edwards25519 = struct {
5662 }
5763
5864 /// Check that the encoding of a point is canonical.
59 pub fn rejectNonCanonical(s: [32]u8) Error!void {
65 pub fn rejectNonCanonical(s: [32]u8) NonCanonicalError!void {
6066 return Fe.rejectNonCanonical(s, true);
6167 }
6268
......@@ -81,7 +87,7 @@ pub const Edwards25519 = struct {
8187 const identityElement = Edwards25519{ .x = Fe.zero, .y = Fe.one, .z = Fe.one, .t = Fe.zero };
8288
8389 /// Reject the neutral element.
84 pub fn rejectIdentity(p: Edwards25519) Error!void {
90 pub fn rejectIdentity(p: Edwards25519) IdentityElementError!void {
8591 if (p.x.isZero()) {
8692 return error.IdentityElement;
8793 }
......@@ -177,7 +183,7 @@ pub const Edwards25519 = struct {
177183 // Based on real-world benchmarks, we only use this for multi-scalar multiplication.
178184 // NAF could be useful to half the size of precomputation tables, but we intentionally
179185 // avoid these to keep the standard library lightweight.
180 fn pcMul(pc: [9]Edwards25519, s: [32]u8, comptime vartime: bool) Error!Edwards25519 {
186 fn pcMul(pc: [9]Edwards25519, s: [32]u8, comptime vartime: bool) IdentityElementError!Edwards25519 {
181187 std.debug.assert(vartime);
182188 const e = nonAdjacentForm(s);
183189 var q = Edwards25519.identityElement;
......@@ -197,7 +203,7 @@ pub const Edwards25519 = struct {
197203 }
198204
199205 // Scalar multiplication with a 4-bit window and the first 15 multiples.
200 fn pcMul16(pc: [16]Edwards25519, s: [32]u8, comptime vartime: bool) Error!Edwards25519 {
206 fn pcMul16(pc: [16]Edwards25519, s: [32]u8, comptime vartime: bool) IdentityElementError!Edwards25519 {
201207 var q = Edwards25519.identityElement;
202208 var pos: usize = 252;
203209 while (true) : (pos -= 4) {
......@@ -232,10 +238,15 @@ pub const Edwards25519 = struct {
232238 break :pc precompute(Edwards25519.basePoint, 15);
233239 };
234240
241 const basePointPc8 = comptime pc: {
242 @setEvalBranchQuota(10000);
243 break :pc precompute(Edwards25519.basePoint, 8);
244 };
245
235246 /// Multiply an Edwards25519 point by a scalar without clamping it.
236 /// Return error.WeakPublicKey if the resulting point is
237 /// the identity element.
238 pub fn mul(p: Edwards25519, s: [32]u8) Error!Edwards25519 {
247 /// Return error.WeakPublicKey if the base generates a small-order group,
248 /// and error.IdentityElement if the result is the identity element.
249 pub fn mul(p: Edwards25519, s: [32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 {
239250 const pc = if (p.is_base) basePointPc else pc: {
240251 const xpc = precompute(p, 15);
241252 xpc[4].rejectIdentity() catch return error.WeakPublicKey;
......@@ -246,7 +257,7 @@ pub const Edwards25519 = struct {
246257
247258 /// Multiply an Edwards25519 point by a *PUBLIC* scalar *IN VARIABLE TIME*
248259 /// This can be used for signature verification.
249 pub fn mulPublic(p: Edwards25519, s: [32]u8) Error!Edwards25519 {
260 pub fn mulPublic(p: Edwards25519, s: [32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 {
250261 if (p.is_base) {
251262 return pcMul16(basePointPc, s, true);
252263 } else {
......@@ -256,14 +267,50 @@ pub const Edwards25519 = struct {
256267 }
257268 }
258269
270 /// Double-base multiplication of public parameters - Compute (p1*s1)+(p2*s2) *IN VARIABLE TIME*
271 /// This can be used for signature verification.
272 pub fn mulDoubleBasePublic(p1: Edwards25519, s1: [32]u8, p2: Edwards25519, s2: [32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 {
273 const pc1 = if (p1.is_base) basePointPc8 else pc: {
274 const xpc = precompute(p1, 8);
275 xpc[4].rejectIdentity() catch return error.WeakPublicKey;
276 break :pc xpc;
277 };
278 const pc2 = if (p2.is_base) basePointPc8 else pc: {
279 const xpc = precompute(p2, 8);
280 xpc[4].rejectIdentity() catch return error.WeakPublicKey;
281 break :pc xpc;
282 };
283 const e1 = nonAdjacentForm(s1);
284 const e2 = nonAdjacentForm(s2);
285 var q = Edwards25519.identityElement;
286 var pos: usize = 2 * 32 - 1;
287 while (true) : (pos -= 1) {
288 const slot1 = e1[pos];
289 if (slot1 > 0) {
290 q = q.add(pc1[@intCast(usize, slot1)]);
291 } else if (slot1 < 0) {
292 q = q.sub(pc1[@intCast(usize, -slot1)]);
293 }
294 const slot2 = e2[pos];
295 if (slot2 > 0) {
296 q = q.add(pc2[@intCast(usize, slot2)]);
297 } else if (slot2 < 0) {
298 q = q.sub(pc2[@intCast(usize, -slot2)]);
299 }
300 if (pos == 0) break;
301 q = q.dbl().dbl().dbl().dbl();
302 }
303 try q.rejectIdentity();
304 return q;
305 }
306
259307 /// Multiscalar multiplication *IN VARIABLE TIME* for public data
260308 /// Computes ps0*ss0 + ps1*ss1 + ps2*ss2... faster than doing many of these operations individually
261 pub fn mulMulti(comptime count: usize, ps: [count]Edwards25519, ss: [count][32]u8) Error!Edwards25519 {
309 pub fn mulMulti(comptime count: usize, ps: [count]Edwards25519, ss: [count][32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 {
262310 var pcs: [count][9]Edwards25519 = undefined;
263311 for (ps) |p, i| {
264312 if (p.is_base) {
265 @setEvalBranchQuota(10000);
266 pcs[i] = comptime precompute(Edwards25519.basePoint, 8);
313 pcs[i] = basePointPc8;
267314 } else {
268315 pcs[i] = precompute(p, 8);
269316 pcs[i][4].rejectIdentity() catch return error.WeakPublicKey;
......@@ -297,14 +344,14 @@ pub const Edwards25519 = struct {
297344 /// This is strongly recommended for DH operations.
298345 /// Return error.WeakPublicKey if the resulting point is
299346 /// the identity element.
300 pub fn clampedMul(p: Edwards25519, s: [32]u8) Error!Edwards25519 {
347 pub fn clampedMul(p: Edwards25519, s: [32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 {
301348 var t: [32]u8 = s;
302349 scalar.clamp(&t);
303350 return mul(p, t);
304351 }
305352
306353 // montgomery -- recover y = sqrt(x^3 + A*x^2 + x)
307 fn xmontToYmont(x: Fe) Error!Fe {
354 fn xmontToYmont(x: Fe) NotSquareError!Fe {
308355 var x2 = x.sq();
309356 const x3 = x.mul(x2);
310357 x2 = x2.mul32(Fe.edwards25519a_32);
......@@ -367,7 +414,7 @@ pub const Edwards25519 = struct {
367414
368415 fn stringToPoints(comptime n: usize, ctx: []const u8, s: []const u8) [n]Edwards25519 {
369416 debug.assert(n <= 2);
370 const H = std.crypto.hash.sha2.Sha512;
417 const H = crypto.hash.sha2.Sha512;
371418 const h_l: usize = 48;
372419 var xctx = ctx;
373420 var hctx: [H.digest_length]u8 = undefined;
......@@ -485,8 +532,8 @@ test "edwards25519 packing/unpacking" {
485532test "edwards25519 point addition/substraction" {
486533 var s1: [32]u8 = undefined;
487534 var s2: [32]u8 = undefined;
488 std.crypto.random.bytes(&s1);
489 std.crypto.random.bytes(&s2);
535 crypto.random.bytes(&s1);
536 crypto.random.bytes(&s2);
490537 const p = try Edwards25519.basePoint.clampedMul(s1);
491538 const q = try Edwards25519.basePoint.clampedMul(s2);
492539 const r = p.add(q).add(q).sub(q).sub(q);
lib/std/crypto/25519/field.zig+6-3
......@@ -4,9 +4,12 @@
44// The MIT license requires this copyright notice to be included in all copies
55// and substantial portions of the software.
66const std = @import("std");
7const crypto = std.crypto;
78const readIntLittle = std.mem.readIntLittle;
89const writeIntLittle = std.mem.writeIntLittle;
9const Error = std.crypto.Error;
10
11const NonCanonicalError = crypto.errors.NonCanonicalError;
12const NotSquareError = crypto.errors.NotSquareError;
1013
1114pub const Fe = struct {
1215 limbs: [5]u64,
......@@ -113,7 +116,7 @@ pub const Fe = struct {
113116 }
114117
115118 /// Reject non-canonical encodings of an element, possibly ignoring the top bit
116 pub fn rejectNonCanonical(s: [32]u8, comptime ignore_extra_bit: bool) Error!void {
119 pub fn rejectNonCanonical(s: [32]u8, comptime ignore_extra_bit: bool) NonCanonicalError!void {
117120 var c: u16 = (s[31] & 0x7f) ^ 0x7f;
118121 comptime var i = 30;
119122 inline while (i > 0) : (i -= 1) {
......@@ -413,7 +416,7 @@ pub const Fe = struct {
413416 }
414417
415418 /// Compute the square root of `x2`, returning `error.NotSquare` if `x2` was not a square
416 pub fn sqrt(x2: Fe) Error!Fe {
419 pub fn sqrt(x2: Fe) NotSquareError!Fe {
417420 var x2_copy = x2;
418421 const x = x2.uncheckedSqrt();
419422 const check = x.sq().sub(x2_copy);
lib/std/crypto/25519/ristretto255.zig+9-5
......@@ -5,7 +5,11 @@
55// and substantial portions of the software.
66const std = @import("std");
77const fmt = std.fmt;
8const Error = std.crypto.Error;
8
9const EncodingError = std.crypto.errors.EncodingError;
10const IdentityElementError = std.crypto.errors.IdentityElementError;
11const NonCanonicalError = std.crypto.errors.NonCanonicalError;
12const WeakPublicKeyError = std.crypto.errors.WeakPublicKeyError;
913
1014/// Group operations over Edwards25519.
1115pub const Ristretto255 = struct {
......@@ -35,7 +39,7 @@ pub const Ristretto255 = struct {
3539 return .{ .ratio_is_square = @boolToInt(has_m_root) | @boolToInt(has_p_root), .root = x.abs() };
3640 }
3741
38 fn rejectNonCanonical(s: [encoded_length]u8) Error!void {
42 fn rejectNonCanonical(s: [encoded_length]u8) NonCanonicalError!void {
3943 if ((s[0] & 1) != 0) {
4044 return error.NonCanonical;
4145 }
......@@ -43,7 +47,7 @@ pub const Ristretto255 = struct {
4347 }
4448
4549 /// Reject the neutral element.
46 pub fn rejectIdentity(p: Ristretto255) callconv(.Inline) Error!void {
50 pub fn rejectIdentity(p: Ristretto255) callconv(.Inline) IdentityElementError!void {
4751 return p.p.rejectIdentity();
4852 }
4953
......@@ -51,7 +55,7 @@ pub const Ristretto255 = struct {
5155 pub const basePoint = Ristretto255{ .p = Curve.basePoint };
5256
5357 /// Decode a Ristretto255 representative.
54 pub fn fromBytes(s: [encoded_length]u8) Error!Ristretto255 {
58 pub fn fromBytes(s: [encoded_length]u8) (NonCanonicalError || EncodingError)!Ristretto255 {
5559 try rejectNonCanonical(s);
5660 const s_ = Fe.fromBytes(s);
5761 const ss = s_.sq(); // s^2
......@@ -154,7 +158,7 @@ pub const Ristretto255 = struct {
154158 /// Multiply a Ristretto255 element with a scalar.
155159 /// Return error.WeakPublicKey if the resulting element is
156160 /// the identity element.
157 pub fn mul(p: Ristretto255, s: [encoded_length]u8) callconv(.Inline) Error!Ristretto255 {
161 pub fn mul(p: Ristretto255, s: [encoded_length]u8) callconv(.Inline) (IdentityElementError || WeakPublicKeyError)!Ristretto255 {
158162 return Ristretto255{ .p = try p.p.mul(s) };
159163 }
160164
lib/std/crypto/25519/scalar.zig+3-2
......@@ -5,7 +5,8 @@
55// and substantial portions of the software.
66const std = @import("std");
77const mem = std.mem;
8const Error = std.crypto.Error;
8
9const NonCanonicalError = std.crypto.errors.NonCanonicalError;
910
1011/// 2^252 + 27742317777372353535851937790883648493
1112pub const field_size = [32]u8{
......@@ -19,7 +20,7 @@ pub const CompressedScalar = [32]u8;
1920pub const zero = [_]u8{0} ** 32;
2021
2122/// Reject a scalar whose encoding is not canonical.
22pub fn rejectNonCanonical(s: [32]u8) Error!void {
23pub fn rejectNonCanonical(s: [32]u8) NonCanonicalError!void {
2324 var c: u8 = 0;
2425 var n: u8 = 1;
2526 var i: usize = 31;
lib/std/crypto/25519/x25519.zig+9-6
......@@ -9,7 +9,10 @@ const mem = std.mem;
99const fmt = std.fmt;
1010
1111const Sha512 = crypto.hash.sha2.Sha512;
12const Error = crypto.Error;
12
13const EncodingError = crypto.errors.EncodingError;
14const IdentityElementError = crypto.errors.IdentityElementError;
15const WeakPublicKeyError = crypto.errors.WeakPublicKeyError;
1316
1417/// X25519 DH function.
1518pub const X25519 = struct {
......@@ -32,7 +35,7 @@ pub const X25519 = struct {
3235 secret_key: [secret_length]u8,
3336
3437 /// Create a new key pair using an optional seed.
35 pub fn create(seed: ?[seed_length]u8) Error!KeyPair {
38 pub fn create(seed: ?[seed_length]u8) IdentityElementError!KeyPair {
3639 const sk = seed orelse sk: {
3740 var random_seed: [seed_length]u8 = undefined;
3841 crypto.random.bytes(&random_seed);
......@@ -45,7 +48,7 @@ pub const X25519 = struct {
4548 }
4649
4750 /// Create a key pair from an Ed25519 key pair
48 pub fn fromEd25519(ed25519_key_pair: crypto.sign.Ed25519.KeyPair) Error!KeyPair {
51 pub fn fromEd25519(ed25519_key_pair: crypto.sign.Ed25519.KeyPair) (IdentityElementError || EncodingError)!KeyPair {
4952 const seed = ed25519_key_pair.secret_key[0..32];
5053 var az: [Sha512.digest_length]u8 = undefined;
5154 Sha512.hash(seed, &az, .{});
......@@ -60,13 +63,13 @@ pub const X25519 = struct {
6063 };
6164
6265 /// Compute the public key for a given private key.
63 pub fn recoverPublicKey(secret_key: [secret_length]u8) Error![public_length]u8 {
66 pub fn recoverPublicKey(secret_key: [secret_length]u8) IdentityElementError![public_length]u8 {
6467 const q = try Curve.basePoint.clampedMul(secret_key);
6568 return q.toBytes();
6669 }
6770
6871 /// Compute the X25519 equivalent to an Ed25519 public eky.
69 pub fn publicKeyFromEd25519(ed25519_public_key: [crypto.sign.Ed25519.public_length]u8) Error![public_length]u8 {
72 pub fn publicKeyFromEd25519(ed25519_public_key: [crypto.sign.Ed25519.public_length]u8) (IdentityElementError || EncodingError)![public_length]u8 {
7073 const pk_ed = try crypto.ecc.Edwards25519.fromBytes(ed25519_public_key);
7174 const pk = try Curve.fromEdwards25519(pk_ed);
7275 return pk.toBytes();
......@@ -75,7 +78,7 @@ pub const X25519 = struct {
7578 /// Compute the scalar product of a public key and a secret scalar.
7679 /// Note that the output should not be used as a shared secret without
7780 /// hashing it first.
78 pub fn scalarmult(secret_key: [secret_length]u8, public_key: [public_length]u8) Error![shared_length]u8 {
81 pub fn scalarmult(secret_key: [secret_length]u8, public_key: [public_length]u8) IdentityElementError![shared_length]u8 {
7982 const q = try Curve.fromBytes(public_key).clampedMul(secret_key);
8083 return q.toBytes();
8184 }
lib/std/crypto/aegis.zig+3-3
......@@ -8,7 +8,7 @@ const std = @import("std");
88const mem = std.mem;
99const assert = std.debug.assert;
1010const AesBlock = std.crypto.core.aes.Block;
11const Error = std.crypto.Error;
11const AuthenticationError = std.crypto.errors.AuthenticationError;
1212
1313const State128L = struct {
1414 blocks: [8]AesBlock,
......@@ -137,7 +137,7 @@ pub const Aegis128L = struct {
137137 /// ad: Associated Data
138138 /// npub: public nonce
139139 /// k: private key
140 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) Error!void {
140 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) AuthenticationError!void {
141141 assert(c.len == m.len);
142142 var state = State128L.init(key, npub);
143143 var src: [32]u8 align(16) = undefined;
......@@ -299,7 +299,7 @@ pub const Aegis256 = struct {
299299 /// ad: Associated Data
300300 /// npub: public nonce
301301 /// k: private key
302 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) Error!void {
302 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) AuthenticationError!void {
303303 assert(c.len == m.len);
304304 var state = State256.init(key, npub);
305305 var src: [16]u8 align(16) = undefined;
lib/std/crypto/aes_gcm.zig+2-2
......@@ -12,7 +12,7 @@ const debug = std.debug;
1212const Ghash = std.crypto.onetimeauth.Ghash;
1313const mem = std.mem;
1414const modes = crypto.core.modes;
15const Error = crypto.Error;
15const AuthenticationError = crypto.errors.AuthenticationError;
1616
1717pub const Aes128Gcm = AesGcm(crypto.core.aes.Aes128);
1818pub const Aes256Gcm = AesGcm(crypto.core.aes.Aes256);
......@@ -60,7 +60,7 @@ fn AesGcm(comptime Aes: anytype) type {
6060 }
6161 }
6262
63 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) Error!void {
63 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) AuthenticationError!void {
6464 assert(c.len == m.len);
6565
6666 const aes = Aes.initEnc(key);
lib/std/crypto/aes_ocb.zig+2-2
......@@ -10,7 +10,7 @@ const aes = crypto.core.aes;
1010const assert = std.debug.assert;
1111const math = std.math;
1212const mem = std.mem;
13const Error = crypto.Error;
13const AuthenticationError = crypto.errors.AuthenticationError;
1414
1515pub const Aes128Ocb = AesOcb(aes.Aes128);
1616pub const Aes256Ocb = AesOcb(aes.Aes256);
......@@ -179,7 +179,7 @@ fn AesOcb(comptime Aes: anytype) type {
179179 /// ad: Associated Data
180180 /// npub: public nonce
181181 /// k: secret key
182 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) Error!void {
182 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) AuthenticationError!void {
183183 assert(c.len == m.len);
184184
185185 const aes_enc_ctx = Aes.initEnc(key);
lib/std/crypto/bcrypt.zig+6-5
......@@ -12,7 +12,8 @@ const mem = std.mem;
1212const debug = std.debug;
1313const testing = std.testing;
1414const utils = crypto.utils;
15const Error = crypto.Error;
15const EncodingError = crypto.errors.EncodingError;
16const PasswordVerificationError = crypto.errors.PasswordVerificationError;
1617
1718const salt_length: usize = 16;
1819const salt_str_length: usize = 22;
......@@ -179,7 +180,7 @@ const Codec = struct {
179180 debug.assert(j == b64.len);
180181 }
181182
182 fn decode(bin: []u8, b64: []const u8) Error!void {
183 fn decode(bin: []u8, b64: []const u8) EncodingError!void {
183184 var i: usize = 0;
184185 var j: usize = 0;
185186 while (j < bin.len) {
......@@ -204,7 +205,7 @@ const Codec = struct {
204205 }
205206};
206207
207fn strHashInternal(password: []const u8, rounds_log: u6, salt: [salt_length]u8) Error![hash_length]u8 {
208fn strHashInternal(password: []const u8, rounds_log: u6, salt: [salt_length]u8) ![hash_length]u8 {
208209 var state = State{};
209210 var password_buf: [73]u8 = undefined;
210211 const trimmed_len = math.min(password.len, password_buf.len - 1);
......@@ -252,14 +253,14 @@ fn strHashInternal(password: []const u8, rounds_log: u6, salt: [salt_length]u8)
252253/// IMPORTANT: by design, bcrypt silently truncates passwords to 72 bytes.
253254/// If this is an issue for your application, hash the password first using a function such as SHA-512,
254255/// and then use the resulting hash as the password parameter for bcrypt.
255pub fn strHash(password: []const u8, rounds_log: u6) Error![hash_length]u8 {
256pub fn strHash(password: []const u8, rounds_log: u6) ![hash_length]u8 {
256257 var salt: [salt_length]u8 = undefined;
257258 crypto.random.bytes(&salt);
258259 return strHashInternal(password, rounds_log, salt);
259260}
260261
261262/// Verify that a previously computed hash is valid for a given password.
262pub fn strVerify(h: [hash_length]u8, password: []const u8) Error!void {
263pub fn strVerify(h: [hash_length]u8, password: []const u8) (EncodingError || PasswordVerificationError)!void {
263264 if (!mem.eql(u8, "$2", h[0..2])) return error.InvalidEncoding;
264265 if (h[3] != '$' or h[6] != '$') return error.InvalidEncoding;
265266 const rounds_log_str = h[4..][0..2];
lib/std/crypto/chacha20.zig+3-3
......@@ -13,7 +13,7 @@ const testing = std.testing;
1313const maxInt = math.maxInt;
1414const Vector = std.meta.Vector;
1515const Poly1305 = std.crypto.onetimeauth.Poly1305;
16const Error = std.crypto.Error;
16const AuthenticationError = std.crypto.errors.AuthenticationError;
1717
1818/// IETF-variant of the ChaCha20 stream cipher, as designed for TLS.
1919pub const ChaCha20IETF = ChaChaIETF(20);
......@@ -521,7 +521,7 @@ fn ChaChaPoly1305(comptime rounds_nb: usize) type {
521521 /// npub: public nonce
522522 /// k: private key
523523 /// NOTE: the check of the authentication tag is currently not done in constant time
524 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) Error!void {
524 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) AuthenticationError!void {
525525 assert(c.len == m.len);
526526
527527 var polyKey = [_]u8{0} ** 32;
......@@ -583,7 +583,7 @@ fn XChaChaPoly1305(comptime rounds_nb: usize) type {
583583 /// ad: Associated Data
584584 /// npub: public nonce
585585 /// k: private key
586 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) Error!void {
586 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) AuthenticationError!void {
587587 const extended = extend(k, npub, rounds_nb);
588588 return ChaChaPoly1305(rounds_nb).decrypt(m, c, tag, ad, extended.nonce, extended.key);
589589 }
lib/std/crypto/error.zig deleted-34
......@@ -1,34 +0,0 @@
1pub const Error = error{
2 /// MAC verification failed - The tag doesn't verify for the given ciphertext and secret key
3 AuthenticationFailed,
4
5 /// The requested output length is too long for the chosen algorithm
6 OutputTooLong,
7
8 /// Finite field operation returned the identity element
9 IdentityElement,
10
11 /// Encoded input cannot be decoded
12 InvalidEncoding,
13
14 /// The signature does't verify for the given message and public key
15 SignatureVerificationFailed,
16
17 /// Both a public and secret key have been provided, but they are incompatible
18 KeyMismatch,
19
20 /// Encoded input is not in canonical form
21 NonCanonical,
22
23 /// Square root has no solutions
24 NotSquare,
25
26 /// Verification string doesn't match the provided password and parameters
27 PasswordVerificationFailed,
28
29 /// Parameters would be insecure to use
30 WeakParameters,
31
32 /// Public key would be insecure to use
33 WeakPublicKey,
34};
lib/std/crypto/errors.zig created+35
......@@ -0,0 +1,35 @@
1/// MAC verification failed - The tag doesn't verify for the given ciphertext and secret key
2pub const AuthenticationError = error{AuthenticationFailed};
3
4/// The requested output length is too long for the chosen algorithm
5pub const OutputTooLongError = error{OutputTooLong};
6
7/// Finite field operation returned the identity element
8pub const IdentityElementError = error{IdentityElement};
9
10/// Encoded input cannot be decoded
11pub const EncodingError = error{InvalidEncoding};
12
13/// The signature does't verify for the given message and public key
14pub const SignatureVerificationError = error{SignatureVerificationFailed};
15
16/// Both a public and secret key have been provided, but they are incompatible
17pub const KeyMismatchError = error{KeyMismatch};
18
19/// Encoded input is not in canonical form
20pub const NonCanonicalError = error{NonCanonical};
21
22/// Square root has no solutions
23pub const NotSquareError = error{NotSquare};
24
25/// Verification string doesn't match the provided password and parameters
26pub const PasswordVerificationError = error{PasswordVerificationFailed};
27
28/// Parameters would be insecure to use
29pub const WeakParametersError = error{WeakParameters};
30
31/// Public key would be insecure to use
32pub const WeakPublicKeyError = error{WeakPublicKey};
33
34/// Any error related to cryptography operations
35pub const Error = AuthenticationError || OutputTooLongError || IdentityElementError || EncodingError || SignatureVerificationError || KeyMismatchError || NonCanonicalError || NotSquareError || PasswordVerificationError || WeakParametersError || WeakPublicKeyError;
lib/std/crypto/gimli.zig+2-2
......@@ -20,7 +20,7 @@ const assert = std.debug.assert;
2020const testing = std.testing;
2121const htest = @import("test.zig");
2222const Vector = std.meta.Vector;
23const Error = std.crypto.Error;
23const AuthenticationError = std.crypto.errors.AuthenticationError;
2424
2525pub const State = struct {
2626 pub const BLOCKBYTES = 48;
......@@ -393,7 +393,7 @@ pub const Aead = struct {
393393 /// npub: public nonce
394394 /// k: private key
395395 /// NOTE: the check of the authentication tag is currently not done in constant time
396 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) Error!void {
396 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) AuthenticationError!void {
397397 assert(c.len == m.len);
398398
399399 var state = Aead.init(ad, npub, k);
lib/std/crypto/isap.zig+2-2
......@@ -3,7 +3,7 @@ const debug = std.debug;
33const mem = std.mem;
44const math = std.math;
55const testing = std.testing;
6const Error = std.crypto.Error;
6const AuthenticationError = std.crypto.errors.AuthenticationError;
77
88/// ISAPv2 is an authenticated encryption system hardened against side channels and fault attacks.
99/// https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/round-2/spec-doc-rnd2/isap-spec-round2.pdf
......@@ -218,7 +218,7 @@ pub const IsapA128A = struct {
218218 tag.* = mac(c, ad, npub, key);
219219 }
220220
221 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) Error!void {
221 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) AuthenticationError!void {
222222 var computed_tag = mac(c, ad, npub, key);
223223 var acc: u8 = 0;
224224 for (computed_tag) |_, j| {
lib/std/crypto/pbkdf2.zig+3-2
......@@ -7,7 +7,8 @@
77const std = @import("std");
88const mem = std.mem;
99const maxInt = std.math.maxInt;
10const Error = std.crypto.Error;
10const OutputTooLongError = std.crypto.errors.OutputTooLongError;
11const WeakParametersError = std.crypto.errors.WeakParametersError;
1112
1213// RFC 2898 Section 5.2
1314//
......@@ -55,7 +56,7 @@ const Error = std.crypto.Error;
5556/// the dk. It is common to tune this parameter to achieve approximately 100ms.
5657///
5758/// Prf: Pseudo-random function to use. A common choice is `std.crypto.auth.hmac.HmacSha256`.
58pub fn pbkdf2(dk: []u8, password: []const u8, salt: []const u8, rounds: u32, comptime Prf: type) Error!void {
59pub fn pbkdf2(dk: []u8, password: []const u8, salt: []const u8, rounds: u32, comptime Prf: type) (WeakParametersError || OutputTooLongError)!void {
5960 if (rounds < 1) return error.WeakParameters;
6061
6162 const dk_len = dk.len;
lib/std/crypto/salsa20.zig+11-8
......@@ -15,7 +15,10 @@ const Vector = std.meta.Vector;
1515const Poly1305 = crypto.onetimeauth.Poly1305;
1616const Blake2b = crypto.hash.blake2.Blake2b;
1717const X25519 = crypto.dh.X25519;
18const Error = crypto.Error;
18
19const AuthenticationError = crypto.errors.AuthenticationError;
20const IdentityElementError = crypto.errors.IdentityElementError;
21const WeakPublicKeyError = crypto.errors.WeakPublicKeyError;
1922
2023const Salsa20VecImpl = struct {
2124 const Lane = Vector(4, u32);
......@@ -399,7 +402,7 @@ pub const XSalsa20Poly1305 = struct {
399402 /// ad: Associated Data
400403 /// npub: public nonce
401404 /// k: private key
402 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) Error!void {
405 pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, k: [key_length]u8) AuthenticationError!void {
403406 debug.assert(c.len == m.len);
404407 const extended = extend(k, npub);
405408 var block0 = [_]u8{0} ** 64;
......@@ -447,7 +450,7 @@ pub const SecretBox = struct {
447450
448451 /// Verify and decrypt `c` using a nonce `npub` and a key `k`.
449452 /// `m` must be exactly `tag_length` smaller than `c`, as `c` includes an authentication tag in addition to the encrypted message.
450 pub fn open(m: []u8, c: []const u8, npub: [nonce_length]u8, k: [key_length]u8) Error!void {
453 pub fn open(m: []u8, c: []const u8, npub: [nonce_length]u8, k: [key_length]u8) AuthenticationError!void {
451454 if (c.len < tag_length) {
452455 return error.AuthenticationFailed;
453456 }
......@@ -482,20 +485,20 @@ pub const Box = struct {
482485 pub const KeyPair = X25519.KeyPair;
483486
484487 /// Compute a secret suitable for `secretbox` given a recipent's public key and a sender's secret key.
485 pub fn createSharedSecret(public_key: [public_length]u8, secret_key: [secret_length]u8) Error![shared_length]u8 {
488 pub fn createSharedSecret(public_key: [public_length]u8, secret_key: [secret_length]u8) (IdentityElementError || WeakPublicKeyError)![shared_length]u8 {
486489 const p = try X25519.scalarmult(secret_key, public_key);
487490 const zero = [_]u8{0} ** 16;
488491 return Salsa20Impl.hsalsa20(zero, p);
489492 }
490493
491494 /// Encrypt and authenticate a message using a recipient's public key `public_key` and a sender's `secret_key`.
492 pub fn seal(c: []u8, m: []const u8, npub: [nonce_length]u8, public_key: [public_length]u8, secret_key: [secret_length]u8) Error!void {
495 pub fn seal(c: []u8, m: []const u8, npub: [nonce_length]u8, public_key: [public_length]u8, secret_key: [secret_length]u8) (IdentityElementError || WeakPublicKeyError)!void {
493496 const shared_key = try createSharedSecret(public_key, secret_key);
494497 return SecretBox.seal(c, m, npub, shared_key);
495498 }
496499
497500 /// Verify and decrypt a message using a recipient's secret key `public_key` and a sender's `public_key`.
498 pub fn open(m: []u8, c: []const u8, npub: [nonce_length]u8, public_key: [public_length]u8, secret_key: [secret_length]u8) Error!void {
501 pub fn open(m: []u8, c: []const u8, npub: [nonce_length]u8, public_key: [public_length]u8, secret_key: [secret_length]u8) (IdentityElementError || WeakPublicKeyError || AuthenticationError)!void {
499502 const shared_key = try createSharedSecret(public_key, secret_key);
500503 return SecretBox.open(m, c, npub, shared_key);
501504 }
......@@ -528,7 +531,7 @@ pub const SealedBox = struct {
528531
529532 /// Encrypt a message `m` for a recipient whose public key is `public_key`.
530533 /// `c` must be `seal_length` bytes larger than `m`, so that the required metadata can be added.
531 pub fn seal(c: []u8, m: []const u8, public_key: [public_length]u8) Error!void {
534 pub fn seal(c: []u8, m: []const u8, public_key: [public_length]u8) (WeakPublicKeyError || IdentityElementError)!void {
532535 debug.assert(c.len == m.len + seal_length);
533536 var ekp = try KeyPair.create(null);
534537 const nonce = createNonce(ekp.public_key, public_key);
......@@ -539,7 +542,7 @@ pub const SealedBox = struct {
539542
540543 /// Decrypt a message using a key pair.
541544 /// `m` must be exactly `seal_length` bytes smaller than `c`, as `c` also includes metadata.
542 pub fn open(m: []u8, c: []const u8, keypair: KeyPair) Error!void {
545 pub fn open(m: []u8, c: []const u8, keypair: KeyPair) (IdentityElementError || WeakPublicKeyError || AuthenticationError)!void {
543546 if (c.len < seal_length) {
544547 return error.AuthenticationFailed;
545548 }
lib/std/event/rwlock.zig+2-2
......@@ -264,7 +264,7 @@ var shared_test_data = [1]i32{0} ** 10;
264264var shared_test_index: usize = 0;
265265var shared_count: usize = 0;
266266fn writeRunner(lock: *RwLock) callconv(.Async) void {
267 suspend; // resumed by onNextTick
267 suspend {} // resumed by onNextTick
268268
269269 var i: usize = 0;
270270 while (i < shared_test_data.len) : (i += 1) {
......@@ -281,7 +281,7 @@ fn writeRunner(lock: *RwLock) callconv(.Async) void {
281281 }
282282}
283283fn readRunner(lock: *RwLock) callconv(.Async) void {
284 suspend; // resumed by onNextTick
284 suspend {} // resumed by onNextTick
285285 std.time.sleep(1);
286286
287287 var i: usize = 0;
lib/std/math.zig-9
......@@ -1349,15 +1349,6 @@ pub fn boolMask(comptime MaskInt: type, value: bool) callconv(.Inline) MaskInt {
13491349 return @bitCast(i1, @as(u1, @boolToInt(value)));
13501350 }
13511351
1352 // At comptime, -% is disallowed on unsigned values.
1353 // So we need to jump through some hoops in that case.
1354 // This is a workaround for #7951
1355 if (@typeInfo(@TypeOf(.{value})).Struct.fields[0].is_comptime) {
1356 // Since it's comptime, we don't need this to generate nice code.
1357 // We can just do a branch here.
1358 return if (value) ~@as(MaskInt, 0) else 0;
1359 }
1360
13611352 return -%@intCast(MaskInt, @boolToInt(value));
13621353}
13631354
lib/std/math/sqrt.zig+17-3
......@@ -38,7 +38,13 @@ pub fn sqrt(x: anytype) Sqrt(@TypeOf(x)) {
3838 }
3939}
4040
41fn sqrt_int(comptime T: type, value: T) std.meta.Int(.unsigned, @typeInfo(T).Int.bits / 2) {
41fn sqrt_int(comptime T: type, value: T) Sqrt(T) {
42 switch (T) {
43 u0 => return 0,
44 u1 => return value,
45 else => {},
46 }
47
4248 var op = value;
4349 var res: T = 0;
4450 var one: T = 1 << (@typeInfo(T).Int.bits - 2);
......@@ -57,11 +63,13 @@ fn sqrt_int(comptime T: type, value: T) std.meta.Int(.unsigned, @typeInfo(T).Int
5763 one >>= 2;
5864 }
5965
60 const ResultType = std.meta.Int(.unsigned, @typeInfo(T).Int.bits / 2);
66 const ResultType = Sqrt(T);
6167 return @intCast(ResultType, res);
6268}
6369
6470test "math.sqrt_int" {
71 expect(sqrt_int(u0, 0) == 0);
72 expect(sqrt_int(u1, 1) == 1);
6573 expect(sqrt_int(u32, 3) == 1);
6674 expect(sqrt_int(u32, 4) == 2);
6775 expect(sqrt_int(u32, 5) == 2);
......@@ -73,7 +81,13 @@ test "math.sqrt_int" {
7381/// Returns the return type `sqrt` will return given an operand of type `T`.
7482pub fn Sqrt(comptime T: type) type {
7583 return switch (@typeInfo(T)) {
76 .Int => |int| std.meta.Int(.unsigned, int.bits / 2),
84 .Int => |int| {
85 return switch (int.bits) {
86 0 => u0,
87 1 => u1,
88 else => std.meta.Int(.unsigned, int.bits / 2),
89 };
90 },
7791 else => T,
7892 };
7993}
lib/std/meta.zig+15-3
......@@ -884,7 +884,7 @@ pub fn Vector(comptime len: u32, comptime child: type) type {
884884/// Given a type and value, cast the value to the type as c would.
885885/// This is for translate-c and is not intended for general use.
886886pub fn cast(comptime DestType: type, target: anytype) DestType {
887 // this function should behave like transCCast in translate-c, except it's for macros
887 // this function should behave like transCCast in translate-c, except it's for macros and enums
888888 const SourceType = @TypeOf(target);
889889 switch (@typeInfo(DestType)) {
890890 .Pointer => {
......@@ -921,9 +921,10 @@ pub fn cast(comptime DestType: type, target: anytype) DestType {
921921 }
922922 }
923923 },
924 .Enum => {
924 .Enum => |enum_type| {
925925 if (@typeInfo(SourceType) == .Int or @typeInfo(SourceType) == .ComptimeInt) {
926 return @intToEnum(DestType, target);
926 const intermediate = cast(enum_type.tag_type, target);
927 return @intToEnum(DestType, intermediate);
927928 }
928929 },
929930 .Int => {
......@@ -1011,6 +1012,17 @@ test "std.meta.cast" {
10111012 testing.expectEqual(@intToPtr(*u8, 2), cast(*u8, @intToPtr(*volatile u8, 2)));
10121013
10131014 testing.expectEqual(@intToPtr(?*c_void, 2), cast(?*c_void, @intToPtr(*u8, 2)));
1015
1016 const C_ENUM = extern enum(c_int) {
1017 A = 0,
1018 B,
1019 C,
1020 _,
1021 };
1022 testing.expectEqual(cast(C_ENUM, @as(i64, -1)), @intToEnum(C_ENUM, -1));
1023 testing.expectEqual(cast(C_ENUM, @as(i8, 1)), .B);
1024 testing.expectEqual(cast(C_ENUM, @as(u64, 1)), .B);
1025 testing.expectEqual(cast(C_ENUM, @as(u64, 42)), @intToEnum(C_ENUM, 42));
10141026}
10151027
10161028/// Given a value returns its size as C's sizeof operator would.
lib/std/os/bits/linux/powerpc.zig+1-9
......@@ -557,18 +557,10 @@ pub const kernel_stat = extern struct {
557557 size: off_t,
558558 blksize: blksize_t,
559559 blocks: blkcnt_t,
560 __atim32: timespec32,
561 __mtim32: timespec32,
562 __ctim32: timespec32,
563 __unused: [2]u32,
564560 atim: timespec,
565561 mtim: timespec,
566562 ctim: timespec,
567
568 const timespec32 = extern struct {
569 tv_sec: i32,
570 tv_nsec: i32,
571 };
563 __unused: [2]u32,
572564
573565 pub fn atime(self: @This()) timespec {
574566 return self.atim;
lib/std/os/linux.zig+49-1
......@@ -53,6 +53,7 @@ pub fn getauxval(index: usize) usize {
5353// Some architectures (and some syscalls) require 64bit parameters to be passed
5454// in a even-aligned register pair.
5555const require_aligned_register_pair =
56 std.Target.current.cpu.arch.isPPC() or
5657 std.Target.current.cpu.arch.isMIPS() or
5758 std.Target.current.cpu.arch.isARM() or
5859 std.Target.current.cpu.arch.isThumb();
......@@ -633,7 +634,7 @@ pub fn tkill(tid: pid_t, sig: i32) usize {
633634}
634635
635636pub fn tgkill(tgid: pid_t, tid: pid_t, sig: i32) usize {
636 return syscall2(.tgkill, @bitCast(usize, @as(isize, tgid)), @bitCast(usize, @as(isize, tid)), @bitCast(usize, @as(isize, sig)));
637 return syscall3(.tgkill, @bitCast(usize, @as(isize, tgid)), @bitCast(usize, @as(isize, tid)), @bitCast(usize, @as(isize, sig)));
637638}
638639
639640pub fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: i32) usize {
......@@ -1386,6 +1387,53 @@ pub fn madvise(address: [*]u8, len: usize, advice: u32) usize {
13861387 return syscall3(.madvise, @ptrToInt(address), len, advice);
13871388}
13881389
1390pub fn pidfd_open(pid: pid_t, flags: u32) usize {
1391 return syscall2(.pidfd_open, @bitCast(usize, @as(isize, pid)), flags);
1392}
1393
1394pub fn pidfd_getfd(pidfd: fd_t, targetfd: fd_t, flags: u32) usize {
1395 return syscall3(
1396 .pidfd_getfd,
1397 @bitCast(usize, @as(isize, pidfd)),
1398 @bitCast(usize, @as(isize, targetfd)),
1399 flags,
1400 );
1401}
1402
1403pub fn pidfd_send_signal(pidfd: fd_t, sig: i32, info: ?*siginfo_t, flags: u32) usize {
1404 return syscall4(
1405 .pidfd_send_signal,
1406 @bitCast(usize, @as(isize, pidfd)),
1407 @bitCast(usize, @as(isize, sig)),
1408 @ptrToInt(info),
1409 flags,
1410 );
1411}
1412
1413pub fn process_vm_readv(pid: pid_t, local: [*]const iovec, local_count: usize, remote: [*]const iovec, remote_count: usize, flags: usize) usize {
1414 return syscall6(
1415 .process_vm_readv,
1416 @bitCast(usize, @as(isize, pid)),
1417 @ptrToInt(local),
1418 local_count,
1419 @ptrToInt(remote),
1420 remote_count,
1421 flags,
1422 );
1423}
1424
1425pub fn process_vm_writev(pid: pid_t, local: [*]const iovec, local_count: usize, remote: [*]const iovec, remote_count: usize, flags: usize) usize {
1426 return syscall6(
1427 .process_vm_writev,
1428 @bitCast(usize, @as(isize, pid)),
1429 @ptrToInt(local),
1430 local_count,
1431 @ptrToInt(remote),
1432 remote_count,
1433 flags,
1434 );
1435}
1436
13891437test {
13901438 if (std.Target.current.os.tag == .linux) {
13911439 _ = @import("linux/test.zig");
lib/std/os/linux/bpf/btf.zig+1-1
......@@ -6,7 +6,7 @@
66const magic = 0xeb9f;
77const version = 1;
88
9pub const ext = @import("ext.zig");
9pub const ext = @import("btf_ext.zig");
1010
1111/// All offsets are in bytes relative to the end of this header
1212pub const Header = packed struct {
lib/std/os/windows/user32.zig+1-1
......@@ -663,7 +663,7 @@ pub fn messageBoxA(hWnd: ?HWND, lpText: [*:0]const u8, lpCaption: [*:0]const u8,
663663pub extern "user32" fn MessageBoxW(hWnd: ?HWND, lpText: [*:0]const u16, lpCaption: ?[*:0]const u16, uType: UINT) callconv(WINAPI) i32;
664664pub var pfnMessageBoxW: @TypeOf(MessageBoxW) = undefined;
665665pub fn messageBoxW(hWnd: ?HWND, lpText: [*:0]const u16, lpCaption: [*:0]const u16, uType: u32) !i32 {
666 const function = selectSymbol(pfnMessageBoxW, MessageBoxW, .win2k);
666 const function = selectSymbol(MessageBoxW, pfnMessageBoxW, .win2k);
667667 const value = function(hWnd, lpText, lpCaption, uType);
668668 if (value != 0) return value;
669669 switch (GetLastError()) {
lib/std/special/c.zig+122-29
......@@ -88,7 +88,7 @@ test "strncpy" {
8888 var s1: [9:0]u8 = undefined;
8989
9090 s1[0] = 0;
91 _ = strncpy(&s1, "foobarbaz", 9);
91 _ = strncpy(&s1, "foobarbaz", @sizeOf(@TypeOf(s1)));
9292 std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.spanZ(&s1));
9393}
9494
......@@ -242,7 +242,7 @@ export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) callconv(.C) isiz
242242 return 0;
243243}
244244
245test "test_memcmp" {
245test "memcmp" {
246246 const base_arr = &[_]u8{ 1, 1, 1 };
247247 const arr1 = &[_]u8{ 1, 1, 1 };
248248 const arr2 = &[_]u8{ 1, 0, 1 };
......@@ -266,7 +266,7 @@ export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) c
266266 return 0;
267267}
268268
269test "test_bcmp" {
269test "bcmp" {
270270 const base_arr = &[_]u8{ 1, 1, 1 };
271271 const arr1 = &[_]u8{ 1, 1, 1 };
272272 const arr2 = &[_]u8{ 1, 0, 1 };
......@@ -862,6 +862,85 @@ fn generic_fmod(comptime T: type, x: T, y: T) T {
862862 return @bitCast(T, ux);
863863}
864864
865test "fmod, fmodf" {
866 inline for ([_]type{ f32, f64 }) |T| {
867 const nan_val = math.nan(T);
868 const inf_val = math.inf(T);
869
870 std.testing.expect(isNan(generic_fmod(T, nan_val, 1.0)));
871 std.testing.expect(isNan(generic_fmod(T, 1.0, nan_val)));
872 std.testing.expect(isNan(generic_fmod(T, inf_val, 1.0)));
873 std.testing.expect(isNan(generic_fmod(T, 0.0, 0.0)));
874 std.testing.expect(isNan(generic_fmod(T, 1.0, 0.0)));
875
876 std.testing.expectEqual(@as(T, 0.0), generic_fmod(T, 0.0, 2.0));
877 std.testing.expectEqual(@as(T, -0.0), generic_fmod(T, -0.0, 2.0));
878
879 std.testing.expectEqual(@as(T, -2.0), generic_fmod(T, -32.0, 10.0));
880 std.testing.expectEqual(@as(T, -2.0), generic_fmod(T, -32.0, -10.0));
881 std.testing.expectEqual(@as(T, 2.0), generic_fmod(T, 32.0, 10.0));
882 std.testing.expectEqual(@as(T, 2.0), generic_fmod(T, 32.0, -10.0));
883 }
884}
885
886fn generic_fmin(comptime T: type, x: T, y: T) T {
887 if (isNan(x))
888 return y;
889 if (isNan(y))
890 return x;
891 return if (x < y) x else y;
892}
893
894export fn fminf(x: f32, y: f32) callconv(.C) f32 {
895 return generic_fmin(f32, x, y);
896}
897
898export fn fmin(x: f64, y: f64) callconv(.C) f64 {
899 return generic_fmin(f64, x, y);
900}
901
902test "fmin, fminf" {
903 inline for ([_]type{ f32, f64 }) |T| {
904 const nan_val = math.nan(T);
905
906 std.testing.expect(isNan(generic_fmin(T, nan_val, nan_val)));
907 std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, nan_val, 1.0));
908 std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, 1.0, nan_val));
909
910 std.testing.expectEqual(@as(T, 1.0), generic_fmin(T, 1.0, 10.0));
911 std.testing.expectEqual(@as(T, -1.0), generic_fmin(T, 1.0, -1.0));
912 }
913}
914
915fn generic_fmax(comptime T: type, x: T, y: T) T {
916 if (isNan(x))
917 return y;
918 if (isNan(y))
919 return x;
920 return if (x < y) y else x;
921}
922
923export fn fmaxf(x: f32, y: f32) callconv(.C) f32 {
924 return generic_fmax(f32, x, y);
925}
926
927export fn fmax(x: f64, y: f64) callconv(.C) f64 {
928 return generic_fmax(f64, x, y);
929}
930
931test "fmax, fmaxf" {
932 inline for ([_]type{ f32, f64 }) |T| {
933 const nan_val = math.nan(T);
934
935 std.testing.expect(isNan(generic_fmax(T, nan_val, nan_val)));
936 std.testing.expectEqual(@as(T, 1.0), generic_fmax(T, nan_val, 1.0));
937 std.testing.expectEqual(@as(T, 1.0), generic_fmax(T, 1.0, nan_val));
938
939 std.testing.expectEqual(@as(T, 10.0), generic_fmax(T, 1.0, 10.0));
940 std.testing.expectEqual(@as(T, 1.0), generic_fmax(T, 1.0, -1.0));
941 }
942}
943
865944// NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound
866945// behaviour. Most intermediate i32 values are changed to u32 where appropriate but there are
867946// potentially some edge cases remaining that are not handled in the same way.
......@@ -996,25 +1075,32 @@ export fn sqrt(x: f64) f64 {
9961075}
9971076
9981077test "sqrt" {
999 const epsilon = 0.000001;
1000
1001 std.testing.expect(sqrt(0.0) == 0.0);
1002 std.testing.expect(std.math.approxEqAbs(f64, sqrt(2.0), 1.414214, epsilon));
1003 std.testing.expect(std.math.approxEqAbs(f64, sqrt(3.6), 1.897367, epsilon));
1004 std.testing.expect(sqrt(4.0) == 2.0);
1005 std.testing.expect(std.math.approxEqAbs(f64, sqrt(7.539840), 2.745877, epsilon));
1006 std.testing.expect(std.math.approxEqAbs(f64, sqrt(19.230934), 4.385309, epsilon));
1007 std.testing.expect(sqrt(64.0) == 8.0);
1008 std.testing.expect(std.math.approxEqAbs(f64, sqrt(64.1), 8.006248, epsilon));
1009 std.testing.expect(std.math.approxEqAbs(f64, sqrt(8942.230469), 94.563367, epsilon));
1078 const V = [_]f64{
1079 0.0,
1080 4.089288054930154,
1081 7.538757127071935,
1082 8.97780793672623,
1083 5.304443821913729,
1084 5.682408965311888,
1085 0.5846878579110049,
1086 3.650338664297043,
1087 0.3178091951800732,
1088 7.1505232436382835,
1089 3.6589165881946464,
1090 };
1091
1092 // Note that @sqrt will either generate the sqrt opcode (if supported by the
1093 // target ISA) or a call to `sqrtf` otherwise.
1094 for (V) |val|
1095 std.testing.expectEqual(@sqrt(val), sqrt(val));
10101096}
10111097
10121098test "sqrt special" {
10131099 std.testing.expect(std.math.isPositiveInf(sqrt(std.math.inf(f64))));
10141100 std.testing.expect(sqrt(0.0) == 0.0);
10151101 std.testing.expect(sqrt(-0.0) == -0.0);
1016 std.testing.expect(std.math.isNan(sqrt(-1.0)));
1017 std.testing.expect(std.math.isNan(sqrt(std.math.nan(f64))));
1102 std.testing.expect(isNan(sqrt(-1.0)));
1103 std.testing.expect(isNan(sqrt(std.math.nan(f64))));
10181104}
10191105
10201106export fn sqrtf(x: f32) f32 {
......@@ -1094,23 +1180,30 @@ export fn sqrtf(x: f32) f32 {
10941180}
10951181
10961182test "sqrtf" {
1097 const epsilon = 0.000001;
1098
1099 std.testing.expect(sqrtf(0.0) == 0.0);
1100 std.testing.expect(std.math.approxEqAbs(f32, sqrtf(2.0), 1.414214, epsilon));
1101 std.testing.expect(std.math.approxEqAbs(f32, sqrtf(3.6), 1.897367, epsilon));
1102 std.testing.expect(sqrtf(4.0) == 2.0);
1103 std.testing.expect(std.math.approxEqAbs(f32, sqrtf(7.539840), 2.745877, epsilon));
1104 std.testing.expect(std.math.approxEqAbs(f32, sqrtf(19.230934), 4.385309, epsilon));
1105 std.testing.expect(sqrtf(64.0) == 8.0);
1106 std.testing.expect(std.math.approxEqAbs(f32, sqrtf(64.1), 8.006248, epsilon));
1107 std.testing.expect(std.math.approxEqAbs(f32, sqrtf(8942.230469), 94.563370, epsilon));
1183 const V = [_]f32{
1184 0.0,
1185 4.089288054930154,
1186 7.538757127071935,
1187 8.97780793672623,
1188 5.304443821913729,
1189 5.682408965311888,
1190 0.5846878579110049,
1191 3.650338664297043,
1192 0.3178091951800732,
1193 7.1505232436382835,
1194 3.6589165881946464,
1195 };
1196
1197 // Note that @sqrt will either generate the sqrt opcode (if supported by the
1198 // target ISA) or a call to `sqrtf` otherwise.
1199 for (V) |val|
1200 std.testing.expectEqual(@sqrt(val), sqrtf(val));
11081201}
11091202
11101203test "sqrtf special" {
11111204 std.testing.expect(std.math.isPositiveInf(sqrtf(std.math.inf(f32))));
11121205 std.testing.expect(sqrtf(0.0) == 0.0);
11131206 std.testing.expect(sqrtf(-0.0) == -0.0);
1114 std.testing.expect(std.math.isNan(sqrtf(-1.0)));
1115 std.testing.expect(std.math.isNan(sqrtf(std.math.nan(f32))));
1207 std.testing.expect(isNan(sqrtf(-1.0)));
1208 std.testing.expect(isNan(sqrtf(std.math.nan(f32))));
11161209}
lib/std/special/compiler_rt.zig+3-1
......@@ -116,9 +116,11 @@ comptime {
116116 @export(@import("compiler_rt/extendXfYf2.zig").__extenddftf2, .{ .name = "__extenddftf2", .linkage = linkage });
117117 @export(@import("compiler_rt/extendXfYf2.zig").__extendsftf2, .{ .name = "__extendsftf2", .linkage = linkage });
118118 @export(@import("compiler_rt/extendXfYf2.zig").__extendhfsf2, .{ .name = "__extendhfsf2", .linkage = linkage });
119 @export(@import("compiler_rt/extendXfYf2.zig").__extendhftf2, .{ .name = "__extendhftf2", .linkage = linkage });
119120
120121 @export(@import("compiler_rt/truncXfYf2.zig").__truncsfhf2, .{ .name = "__truncsfhf2", .linkage = linkage });
121122 @export(@import("compiler_rt/truncXfYf2.zig").__truncdfhf2, .{ .name = "__truncdfhf2", .linkage = linkage });
123 @export(@import("compiler_rt/truncXfYf2.zig").__trunctfhf2, .{ .name = "__trunctfhf2", .linkage = linkage });
122124 @export(@import("compiler_rt/truncXfYf2.zig").__trunctfdf2, .{ .name = "__trunctfdf2", .linkage = linkage });
123125 @export(@import("compiler_rt/truncXfYf2.zig").__trunctfsf2, .{ .name = "__trunctfsf2", .linkage = linkage });
124126
......@@ -299,7 +301,7 @@ comptime {
299301 @export(@import("compiler_rt/sparc.zig")._Qp_qtod, .{ .name = "_Qp_qtod", .linkage = linkage });
300302 }
301303
302 if (arch == .powerpc or arch.isPPC64()) {
304 if ((arch == .powerpc or arch.isPPC64()) and !is_test) {
303305 @export(@import("compiler_rt/addXf3.zig").__addtf3, .{ .name = "__addkf3", .linkage = linkage });
304306 @export(@import("compiler_rt/addXf3.zig").__subtf3, .{ .name = "__subkf3", .linkage = linkage });
305307 @export(@import("compiler_rt/mulXf3.zig").__multf3, .{ .name = "__mulkf3", .linkage = linkage });
lib/std/special/compiler_rt/extendXfYf2.zig+4
......@@ -23,6 +23,10 @@ pub fn __extendhfsf2(a: u16) callconv(.C) f32 {
2323 return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f32, f16, a });
2424}
2525
26pub fn __extendhftf2(a: u16) callconv(.C) f128 {
27 return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f128, f16, a });
28}
29
2630pub fn __aeabi_h2f(arg: u16) callconv(.AAPCS) f32 {
2731 @setRuntimeSafety(false);
2832 return @call(.{ .modifier = .always_inline }, __extendhfsf2, .{arg});
lib/std/special/compiler_rt/extendXfYf2_test.zig+48-1
......@@ -4,9 +4,10 @@
44// The MIT license requires this copyright notice to be included in all copies
55// and substantial portions of the software.
66const builtin = @import("builtin");
7const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2;
87const __extendhfsf2 = @import("extendXfYf2.zig").__extendhfsf2;
8const __extendhftf2 = @import("extendXfYf2.zig").__extendhftf2;
99const __extendsftf2 = @import("extendXfYf2.zig").__extendsftf2;
10const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2;
1011
1112fn test__extenddftf2(a: f64, expectedHi: u64, expectedLo: u64) void {
1213 const x = __extenddftf2(a);
......@@ -161,3 +162,49 @@ fn makeNaN32(rand: u32) f32 {
161162fn makeInf32() f32 {
162163 return @bitCast(f32, @as(u32, 0x7f800000));
163164}
165
166fn test__extendhftf2(a: u16, expectedHi: u64, expectedLo: u64) void {
167 const x = __extendhftf2(a);
168
169 const rep = @bitCast(u128, x);
170 const hi = @intCast(u64, rep >> 64);
171 const lo = @truncate(u64, rep);
172
173 if (hi == expectedHi and lo == expectedLo)
174 return;
175
176 // test other possible NaN representation(signal NaN)
177 if (expectedHi == 0x7fff800000000000 and expectedLo == 0x0) {
178 if ((hi & 0x7fff000000000000) == 0x7fff000000000000 and
179 ((hi & 0xffffffffffff) > 0 or lo > 0))
180 {
181 return;
182 }
183 }
184
185 @panic("__extendhftf2 test failure");
186}
187
188test "extendhftf2" {
189 // qNaN
190 test__extendhftf2(0x7e00, 0x7fff800000000000, 0x0);
191 // NaN
192 test__extendhftf2(0x7d00, 0x7fff400000000000, 0x0);
193 // inf
194 test__extendhftf2(0x7c00, 0x7fff000000000000, 0x0);
195 test__extendhftf2(0xfc00, 0xffff000000000000, 0x0);
196 // zero
197 test__extendhftf2(0x0000, 0x0000000000000000, 0x0);
198 test__extendhftf2(0x8000, 0x8000000000000000, 0x0);
199 // denormal
200 test__extendhftf2(0x0010, 0x3feb000000000000, 0x0);
201 test__extendhftf2(0x0001, 0x3fe7000000000000, 0x0);
202 test__extendhftf2(0x8001, 0xbfe7000000000000, 0x0);
203
204 // pi
205 test__extendhftf2(0x4248, 0x4000920000000000, 0x0);
206 test__extendhftf2(0xc248, 0xc000920000000000, 0x0);
207
208 test__extendhftf2(0x508c, 0x4004230000000000, 0x0);
209 test__extendhftf2(0x1bb7, 0x3ff6edc000000000, 0x0);
210}
lib/std/special/compiler_rt/truncXfYf2.zig+5-1
......@@ -13,6 +13,10 @@ pub fn __truncdfhf2(a: f64) callconv(.C) u16 {
1313 return @bitCast(u16, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f64, a }));
1414}
1515
16pub fn __trunctfhf2(a: f128) callconv(.C) u16 {
17 return @bitCast(u16, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f128, a }));
18}
19
1620pub fn __trunctfsf2(a: f128) callconv(.C) f32 {
1721 return @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f32, f128, a });
1822}
......@@ -122,7 +126,7 @@ fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t {
122126 if (shift > srcSigBits) {
123127 absResult = 0;
124128 } else {
125 const sticky: src_rep_t = significand << @intCast(SrcShift, srcBits - shift);
129 const sticky: src_rep_t = @boolToInt(significand << @intCast(SrcShift, srcBits - shift) != 0);
126130 const denormalizedSignificand: src_rep_t = significand >> @intCast(SrcShift, shift) | sticky;
127131 absResult = @intCast(dst_rep_t, denormalizedSignificand >> (srcSigBits - dstSigBits));
128132 const roundBits: src_rep_t = denormalizedSignificand & roundMask;
lib/std/special/compiler_rt/truncXfYf2_test.zig+56
......@@ -242,3 +242,59 @@ test "truncdfsf2" {
242242 // huge number becomes inf
243243 test__truncdfsf2(340282366920938463463374607431768211456.0, 0x7f800000);
244244}
245
246const __trunctfhf2 = @import("truncXfYf2.zig").__trunctfhf2;
247
248fn test__trunctfhf2(a: f128, expected: u16) void {
249 const x = __trunctfhf2(a);
250
251 const rep = @bitCast(u16, x);
252 if (rep == expected) {
253 return;
254 }
255
256 @import("std").debug.warn("got 0x{x} wanted 0x{x}\n", .{ rep, expected });
257
258 @panic("__trunctfhf2 test failure");
259}
260
261test "trunctfhf2" {
262 // qNaN
263 test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff8000000000000000000000000000)), 0x7e00);
264 // NaN
265 test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000001)), 0x7e00);
266 // inf
267 test__trunctfhf2(@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000)), 0x7c00);
268 test__trunctfhf2(-@bitCast(f128, @as(u128, 0x7fff0000000000000000000000000000)), 0xfc00);
269 // zero
270 test__trunctfhf2(0.0, 0x0);
271 test__trunctfhf2(-0.0, 0x8000);
272
273 test__trunctfhf2(3.1415926535, 0x4248);
274 test__trunctfhf2(-3.1415926535, 0xc248);
275 test__trunctfhf2(0x1.987124876876324p+100, 0x7c00);
276 test__trunctfhf2(0x1.987124876876324p+12, 0x6e62);
277 test__trunctfhf2(0x1.0p+0, 0x3c00);
278 test__trunctfhf2(0x1.0p-14, 0x0400);
279 // denormal
280 test__trunctfhf2(0x1.0p-20, 0x0010);
281 test__trunctfhf2(0x1.0p-24, 0x0001);
282 test__trunctfhf2(-0x1.0p-24, 0x8001);
283 test__trunctfhf2(0x1.5p-25, 0x0001);
284 // and back to zero
285 test__trunctfhf2(0x1.0p-25, 0x0000);
286 test__trunctfhf2(-0x1.0p-25, 0x8000);
287 // max (precise)
288 test__trunctfhf2(65504.0, 0x7bff);
289 // max (rounded)
290 test__trunctfhf2(65519.0, 0x7bff);
291 // max (to +inf)
292 test__trunctfhf2(65520.0, 0x7c00);
293 test__trunctfhf2(65536.0, 0x7c00);
294 test__trunctfhf2(-65520.0, 0xfc00);
295
296 test__trunctfhf2(0x1.23a2abb4a2ddee355f36789abcdep+5, 0x508f);
297 test__trunctfhf2(0x1.e3d3c45bd3abfd98b76a54cc321fp-9, 0x1b8f);
298 test__trunctfhf2(0x1.234eebb5faa678f4488693abcdefp+453, 0x7c00);
299 test__trunctfhf2(0x1.edcba9bb8c76a5a43dd21f334634p-43, 0x0);
300}
lib/std/target.zig+9-2
......@@ -800,6 +800,13 @@ pub const Target = struct {
800800 };
801801 }
802802
803 pub fn isPPC(arch: Arch) bool {
804 return switch (arch) {
805 .powerpc, .powerpcle => true,
806 else => false,
807 };
808 }
809
803810 pub fn isPPC64(arch: Arch) bool {
804811 return switch (arch) {
805812 .powerpc64, .powerpc64le => true,
......@@ -1184,8 +1191,8 @@ pub const Target = struct {
11841191 .mips, .mipsel => &mips.cpu.mips32,
11851192 .mips64, .mips64el => &mips.cpu.mips64,
11861193 .msp430 => &msp430.cpu.generic,
1187 .powerpc => &powerpc.cpu.ppc32,
1188 .powerpcle => &powerpc.cpu.ppc32,
1194 .powerpc => &powerpc.cpu.ppc,
1195 .powerpcle => &powerpc.cpu.ppc,
11891196 .powerpc64 => &powerpc.cpu.ppc64,
11901197 .powerpc64le => &powerpc.cpu.ppc64le,
11911198 .amdgcn => &amdgpu.cpu.generic,
lib/std/target/powerpc.zig-7
......@@ -751,13 +751,6 @@ pub const cpu = struct {
751751 .hard_float,
752752 }),
753753 };
754 pub const ppc32 = CpuModel{
755 .name = "ppc32",
756 .llvm_name = "ppc32",
757 .features = featureSet(&[_]Feature{
758 .hard_float,
759 }),
760 };
761754 pub const ppc64 = CpuModel{
762755 .name = "ppc64",
763756 .llvm_name = "ppc64",
lib/std/zig/parse.zig+2-1
......@@ -852,7 +852,7 @@ const Parser = struct {
852852 /// <- KEYWORD_comptime? VarDecl
853853 /// / KEYWORD_comptime BlockExprStatement
854854 /// / KEYWORD_nosuspend BlockExprStatement
855 /// / KEYWORD_suspend (SEMICOLON / BlockExprStatement)
855 /// / KEYWORD_suspend BlockExprStatement
856856 /// / KEYWORD_defer BlockExprStatement
857857 /// / KEYWORD_errdefer Payload? BlockExprStatement
858858 /// / IfStatement
......@@ -892,6 +892,7 @@ const Parser = struct {
892892 },
893893 .keyword_suspend => {
894894 const token = p.nextToken();
895 // TODO remove this special case when 0.9.0 is released.
895896 const block_expr: Node.Index = if (p.eatToken(.semicolon) != null)
896897 0
897898 else
lib/std/zig/parser_test.zig+54-3
......@@ -40,6 +40,21 @@ test "zig fmt: rewrite inline functions as callconv(.Inline)" {
4040 );
4141}
4242
43// TODO Remove this after zig 0.9.0 is released.
44test "zig fmt: rewrite suspend without block expression" {
45 try testTransform(
46 \\fn foo() void {
47 \\ suspend;
48 \\}
49 \\
50 ,
51 \\fn foo() void {
52 \\ suspend {}
53 \\}
54 \\
55 );
56}
57
4358test "zig fmt: simple top level comptime block" {
4459 try testCanonical(
4560 \\// line comment
......@@ -1315,6 +1330,27 @@ test "zig fmt: 'zig fmt: (off|on)' works in the middle of code" {
13151330 );
13161331}
13171332
1333test "zig fmt: 'zig fmt: on' indentation is unchanged" {
1334 try testCanonical(
1335 \\fn initOptionsAndLayouts(output: *Output, context: *Context) !void {
1336 \\ // zig fmt: off
1337 \\ try output.main_amount.init(output, "main_amount"); errdefer optput.main_amount.deinit();
1338 \\ try output.main_factor.init(output, "main_factor"); errdefer optput.main_factor.deinit();
1339 \\ try output.view_padding.init(output, "view_padding"); errdefer optput.view_padding.deinit();
1340 \\ try output.outer_padding.init(output, "outer_padding"); errdefer optput.outer_padding.deinit();
1341 \\ // zig fmt: on
1342 \\
1343 \\ // zig fmt: off
1344 \\ try output.top.init(output, .top); errdefer optput.top.deinit();
1345 \\ try output.right.init(output, .right); errdefer optput.right.deinit();
1346 \\ try output.bottom.init(output, .bottom); errdefer optput.bottom.deinit();
1347 \\ try output.left.init(output, .left); errdefer optput.left.deinit();
1348 \\ // zig fmt: on
1349 \\}
1350 \\
1351 );
1352}
1353
13181354test "zig fmt: pointer of unknown length" {
13191355 try testCanonical(
13201356 \\fn foo(ptr: [*]u8) void {}
......@@ -3644,9 +3680,9 @@ test "zig fmt: async functions" {
36443680 \\fn simpleAsyncFn() void {
36453681 \\ const a = async a.b();
36463682 \\ x += 1;
3647 \\ suspend;
3683 \\ suspend {}
36483684 \\ x += 1;
3649 \\ suspend;
3685 \\ suspend {}
36503686 \\ const p: anyframe->void = async simpleAsyncFn() catch unreachable;
36513687 \\ await p;
36523688 \\}
......@@ -5001,6 +5037,21 @@ test "recovery: invalid comptime" {
50015037 });
50025038}
50035039
5040test "recovery: missing block after suspend" {
5041 // TODO Enable this after zig 0.9.0 is released.
5042 if (true) return error.SkipZigTest;
5043
5044 try testError(
5045 \\fn foo() void {
5046 \\ suspend;
5047 \\ nosuspend;
5048 \\}
5049 , &[_]Error{
5050 .expected_block_or_expr,
5051 .expected_block_or_expr,
5052 });
5053}
5054
50045055test "recovery: missing block after for/while loops" {
50055056 try testError(
50065057 \\test "" { while (foo) }
......@@ -5144,7 +5195,7 @@ fn testError(source: []const u8, expected_errors: []const Error) !void {
51445195 var tree = try std.zig.parse(std.testing.allocator, source);
51455196 defer tree.deinit(std.testing.allocator);
51465197
5147 std.testing.expect(tree.errors.len == expected_errors.len);
5198 std.testing.expectEqual(expected_errors.len, tree.errors.len);
51485199 for (expected_errors) |expected, i| {
51495200 std.testing.expectEqual(expected, tree.errors[i].tag);
51505201 }
lib/std/zig/render.zig+8-3
......@@ -269,7 +269,12 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.I
269269 try renderToken(ais, tree, suspend_token, .space);
270270 return renderExpression(gpa, ais, tree, body, space);
271271 } else {
272 return renderToken(ais, tree, suspend_token, space);
272 // TODO remove this special case when 0.9.0 is released.
273 assert(space == .semicolon);
274 try renderToken(ais, tree, suspend_token, .space);
275 try ais.writer().writeAll("{}");
276 try ais.insertNewline();
277 return;
273278 }
274279 },
275280
......@@ -2310,9 +2315,9 @@ fn renderComments(ais: *Ais, tree: ast.Tree, start: usize, end: usize) Error!boo
23102315 // to the underlying writer, fixing up invaild whitespace.
23112316 const disabled_source = tree.source[ais.disabled_offset.?..comment_start];
23122317 try writeFixingWhitespace(ais.underlying_writer, disabled_source);
2313 ais.disabled_offset = null;
23142318 // Write with the canonical single space.
2315 try ais.writer().writeAll("// zig fmt: on\n");
2319 try ais.underlying_writer.writeAll("// zig fmt: on\n");
2320 ais.disabled_offset = null;
23162321 } else if (ais.disabled_offset == null and mem.eql(u8, comment_content, "zig fmt: off")) {
23172322 // Write with the canonical single space.
23182323 try ais.writer().writeAll("// zig fmt: off\n");
src/Compilation.zig+19-15
......@@ -2856,25 +2856,29 @@ pub fn addCCArgs(
28562856 try argv.append("-fPIC");
28572857 }
28582858 },
2859 .shared_library, .assembly, .ll, .bc, .unknown, .static_library, .object, .zig => {},
2859 .shared_library, .ll, .bc, .unknown, .static_library, .object, .zig => {},
2860 .assembly => {
2861 // Argh, why doesn't the assembler accept the list of CPU features?!
2862 // I don't see a way to do this other than hard coding everything.
2863 switch (target.cpu.arch) {
2864 .riscv32, .riscv64 => {
2865 if (std.Target.riscv.featureSetHas(target.cpu.features, .relax)) {
2866 try argv.append("-mrelax");
2867 } else {
2868 try argv.append("-mno-relax");
2869 }
2870 },
2871 else => {
2872 // TODO
2873 },
2874 }
2875 if (target.cpu.model.llvm_name) |ln|
2876 try argv.append(try std.fmt.allocPrint(arena, "-mcpu={s}", .{ln}));
2877 },
28602878 }
28612879 if (out_dep_path) |p| {
28622880 try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p });
28632881 }
2864 // Argh, why doesn't the assembler accept the list of CPU features?!
2865 // I don't see a way to do this other than hard coding everything.
2866 switch (target.cpu.arch) {
2867 .riscv32, .riscv64 => {
2868 if (std.Target.riscv.featureSetHas(target.cpu.features, .relax)) {
2869 try argv.append("-mrelax");
2870 } else {
2871 try argv.append("-mno-relax");
2872 }
2873 },
2874 else => {
2875 // TODO
2876 },
2877 }
28782882
28792883 if (target.os.tag == .freestanding) {
28802884 try argv.append("-ffreestanding");
src/codegen.zig-1
......@@ -1247,7 +1247,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
12471247 },
12481248 .stack_offset => |off| {
12491249 log.debug("reusing stack offset {} => {*}", .{ off, inst });
1250 return true;
12511250 },
12521251 else => return false,
12531252 }
src/link/MachO.zig+1-2
......@@ -645,8 +645,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
645645 break :blk true;
646646 }
647647
648 if (self.base.options.link_libcpp or
649 self.base.options.output_mode == .Lib or
648 if (self.base.options.output_mode == .Lib or
650649 self.base.options.linker_script != null)
651650 {
652651 // Fallback to LLD in this handful of cases on x86_64 only.
src/link/MachO/Archive.zig+2-3
......@@ -208,14 +208,13 @@ pub fn parseObject(self: Archive, offset: u32) !Object {
208208
209209 const object_name = try parseName(self.allocator, object_header, reader);
210210 defer self.allocator.free(object_name);
211 const object_basename = std.fs.path.basename(object_name);
212211
213 log.debug("extracting object '{s}' from archive '{s}'", .{ object_basename, self.name.? });
212 log.debug("extracting object '{s}' from archive '{s}'", .{ object_name, self.name.? });
214213
215214 const name = name: {
216215 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
217216 const path = try std.os.realpath(self.name.?, &buffer);
218 break :name try std.fmt.allocPrint(self.allocator, "{s}({s})", .{ path, object_basename });
217 break :name try std.fmt.allocPrint(self.allocator, "{s}({s})", .{ path, object_name });
219218 };
220219
221220 var object = Object.init(self.allocator);
src/link/MachO/Object.zig+43-4
......@@ -32,7 +32,9 @@ symtab_cmd_index: ?u16 = null,
3232dysymtab_cmd_index: ?u16 = null,
3333build_version_cmd_index: ?u16 = null,
3434data_in_code_cmd_index: ?u16 = null,
35
3536text_section_index: ?u16 = null,
37mod_init_func_section_index: ?u16 = null,
3638
3739// __DWARF segment sections
3840dwarf_debug_info_index: ?u16 = null,
......@@ -49,6 +51,7 @@ stabs: std.ArrayListUnmanaged(Stab) = .{},
4951tu_path: ?[]const u8 = null,
5052tu_mtime: ?u64 = null,
5153
54initializers: std.ArrayListUnmanaged(CppStatic) = .{},
5255data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
5356
5457pub const Section = struct {
......@@ -68,6 +71,11 @@ pub const Section = struct {
6871 }
6972};
7073
74const CppStatic = struct {
75 symbol: u32,
76 target_addr: u64,
77};
78
7179const Stab = struct {
7280 tag: Tag,
7381 symbol: u32,
......@@ -170,6 +178,7 @@ pub fn deinit(self: *Object) void {
170178 self.strtab.deinit(self.allocator);
171179 self.stabs.deinit(self.allocator);
172180 self.data_in_code_entries.deinit(self.allocator);
181 self.initializers.deinit(self.allocator);
173182
174183 if (self.name) |n| {
175184 self.allocator.free(n);
......@@ -216,6 +225,7 @@ pub fn parse(self: *Object) !void {
216225 try self.parseSections();
217226 if (self.symtab_cmd_index != null) try self.parseSymtab();
218227 if (self.data_in_code_cmd_index != null) try self.readDataInCode();
228 try self.parseInitializers();
219229 try self.parseDebugInfo();
220230}
221231
......@@ -250,6 +260,10 @@ pub fn readLoadCommands(self: *Object, reader: anytype) !void {
250260 if (mem.eql(u8, sectname, "__text")) {
251261 self.text_section_index = index;
252262 }
263 } else if (mem.eql(u8, segname, "__DATA")) {
264 if (mem.eql(u8, sectname, "__mod_init_func")) {
265 self.mod_init_func_section_index = index;
266 }
253267 }
254268
255269 sect.offset += offset;
......@@ -298,28 +312,53 @@ pub fn parseSections(self: *Object) !void {
298312 var section = Section{
299313 .inner = sect,
300314 .code = code,
301 .relocs = undefined,
315 .relocs = null,
302316 };
303317
304318 // Parse relocations
305 section.relocs = if (sect.nreloc > 0) relocs: {
319 if (sect.nreloc > 0) {
306320 var raw_relocs = try self.allocator.alloc(u8, @sizeOf(macho.relocation_info) * sect.nreloc);
307321 defer self.allocator.free(raw_relocs);
308322
309323 _ = try self.file.?.preadAll(raw_relocs, sect.reloff);
310324
311 break :relocs try reloc.parse(
325 section.relocs = try reloc.parse(
312326 self.allocator,
313327 self.arch.?,
314328 section.code,
315329 mem.bytesAsSlice(macho.relocation_info, raw_relocs),
316330 );
317 } else null;
331 }
318332
319333 self.sections.appendAssumeCapacity(section);
320334 }
321335}
322336
337pub fn parseInitializers(self: *Object) !void {
338 const index = self.mod_init_func_section_index orelse return;
339 const section = self.sections.items[index];
340
341 log.debug("parsing initializers in {s}", .{self.name.?});
342
343 // Parse C++ initializers
344 const relocs = section.relocs orelse unreachable;
345 try self.initializers.ensureCapacity(self.allocator, relocs.len);
346 for (relocs) |rel| {
347 self.initializers.appendAssumeCapacity(.{
348 .symbol = rel.target.symbol,
349 .target_addr = undefined,
350 });
351 }
352
353 mem.reverse(CppStatic, self.initializers.items);
354
355 for (self.initializers.items) |initializer| {
356 const sym = self.symtab.items[initializer.symbol];
357 const sym_name = self.getString(sym.n_strx);
358 log.debug(" | {s}", .{sym_name});
359 }
360}
361
323362pub fn parseSymtab(self: *Object) !void {
324363 const symtab_cmd = self.load_commands.items[self.symtab_cmd_index.?].Symtab;
325364
src/link/MachO/Symbol.zig+1-1
......@@ -52,7 +52,7 @@ pub fn isUndf(sym: macho.nlist_64) bool {
5252}
5353
5454pub fn isWeakDef(sym: macho.nlist_64) bool {
55 return sym.n_desc == macho.N_WEAK_DEF;
55 return (sym.n_desc & macho.N_WEAK_DEF) != 0;
5656}
5757
5858/// Symbol is local if it is defined and not an extern.
src/link/MachO/Zld.zig+157-67
......@@ -72,6 +72,7 @@ tlv_bss_section_index: ?u16 = null,
7272la_symbol_ptr_section_index: ?u16 = null,
7373data_section_index: ?u16 = null,
7474bss_section_index: ?u16 = null,
75common_section_index: ?u16 = null,
7576
7677symtab: std.StringArrayHashMapUnmanaged(Symbol) = .{},
7778strtab: std.ArrayListUnmanaged(u8) = .{},
......@@ -224,6 +225,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {
224225 self.allocateLinkeditSegment();
225226 try self.allocateSymbols();
226227 try self.allocateStubsAndGotEntries();
228 try self.allocateCppStatics();
227229 try self.writeStubHelperCommon();
228230 try self.resolveRelocsAndWriteSections();
229231 try self.flush();
......@@ -465,23 +467,43 @@ fn updateMetadata(self: *Zld) !void {
465467 },
466468 macho.S_ZEROFILL => {
467469 if (!mem.eql(u8, segname, "__DATA")) continue;
468 if (self.bss_section_index != null) continue;
470 if (mem.eql(u8, sectname, "__common")) {
471 if (self.common_section_index != null) continue;
469472
470 self.bss_section_index = @intCast(u16, data_seg.sections.items.len);
471 try data_seg.addSection(self.allocator, .{
472 .sectname = makeStaticString("__bss"),
473 .segname = makeStaticString("__DATA"),
474 .addr = 0,
475 .size = 0,
476 .offset = 0,
477 .@"align" = 0,
478 .reloff = 0,
479 .nreloc = 0,
480 .flags = macho.S_ZEROFILL,
481 .reserved1 = 0,
482 .reserved2 = 0,
483 .reserved3 = 0,
484 });
473 self.common_section_index = @intCast(u16, data_seg.sections.items.len);
474 try data_seg.addSection(self.allocator, .{
475 .sectname = makeStaticString("__common"),
476 .segname = makeStaticString("__DATA"),
477 .addr = 0,
478 .size = 0,
479 .offset = 0,
480 .@"align" = 0,
481 .reloff = 0,
482 .nreloc = 0,
483 .flags = macho.S_ZEROFILL,
484 .reserved1 = 0,
485 .reserved2 = 0,
486 .reserved3 = 0,
487 });
488 } else {
489 if (self.bss_section_index != null) continue;
490
491 self.bss_section_index = @intCast(u16, data_seg.sections.items.len);
492 try data_seg.addSection(self.allocator, .{
493 .sectname = makeStaticString("__bss"),
494 .segname = makeStaticString("__DATA"),
495 .addr = 0,
496 .size = 0,
497 .offset = 0,
498 .@"align" = 0,
499 .reloff = 0,
500 .nreloc = 0,
501 .flags = macho.S_ZEROFILL,
502 .reserved1 = 0,
503 .reserved2 = 0,
504 .reserved3 = 0,
505 });
506 }
485507 },
486508 macho.S_THREAD_LOCAL_VARIABLES => {
487509 if (!mem.eql(u8, segname, "__DATA")) continue;
......@@ -568,7 +590,9 @@ fn updateMetadata(self: *Zld) !void {
568590
569591 const segname = parseName(&source_sect.segname);
570592 const sectname = parseName(&source_sect.sectname);
593
571594 log.debug("section '{s}/{s}' will be unmapped", .{ segname, sectname });
595
572596 try self.unhandled_sections.putNoClobber(self.allocator, .{
573597 .object_id = object_id,
574598 .source_sect_id = source_sect_id,
......@@ -585,6 +609,7 @@ const MatchingSection = struct {
585609fn getMatchingSection(self: *Zld, section: macho.section_64) ?MatchingSection {
586610 const segname = parseName(&section.segname);
587611 const sectname = parseName(&section.sectname);
612
588613 const res: ?MatchingSection = blk: {
589614 switch (section.flags) {
590615 macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {
......@@ -612,6 +637,12 @@ fn getMatchingSection(self: *Zld, section: macho.section_64) ?MatchingSection {
612637 };
613638 },
614639 macho.S_ZEROFILL => {
640 if (mem.eql(u8, sectname, "__common")) {
641 break :blk .{
642 .seg = self.data_segment_cmd_index.?,
643 .sect = self.common_section_index.?,
644 };
645 }
615646 break :blk .{
616647 .seg = self.data_segment_cmd_index.?,
617648 .sect = self.bss_section_index.?,
......@@ -667,6 +698,7 @@ fn getMatchingSection(self: *Zld, section: macho.section_64) ?MatchingSection {
667698 },
668699 }
669700 };
701
670702 return res;
671703}
672704
......@@ -737,11 +769,12 @@ fn sortSections(self: *Zld) !void {
737769 // __DATA segment
738770 const indices = &[_]*?u16{
739771 &self.la_symbol_ptr_section_index,
740 &self.tlv_section_index,
741772 &self.data_section_index,
773 &self.tlv_section_index,
742774 &self.tlv_data_section_index,
743775 &self.tlv_bss_section_index,
744776 &self.bss_section_index,
777 &self.common_section_index,
745778 };
746779 for (indices) |maybe_index| {
747780 const new_index: u16 = if (maybe_index.*) |index| blk: {
......@@ -959,6 +992,21 @@ fn allocateStubsAndGotEntries(self: *Zld) !void {
959992 }
960993}
961994
995fn allocateCppStatics(self: *Zld) !void {
996 for (self.objects.items) |*object| {
997 for (object.initializers.items) |*initializer| {
998 const sym = object.symtab.items[initializer.symbol];
999 const sym_name = object.getString(sym.n_strx);
1000 initializer.target_addr = object.locals.get(sym_name).?.address;
1001
1002 log.debug("resolving C++ initializer '{s}' at 0x{x}", .{
1003 sym_name,
1004 initializer.target_addr,
1005 });
1006 }
1007 }
1008}
1009
9621010fn writeStubHelperCommon(self: *Zld) !void {
9631011 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
9641012 const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?];
......@@ -1236,11 +1284,12 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void {
12361284 continue;
12371285 } else if (Symbol.isGlobal(sym)) {
12381286 const sym_name = object.getString(sym.n_strx);
1287 const is_weak = Symbol.isWeakDef(sym) or Symbol.isPext(sym);
12391288 const global = self.symtab.getEntry(sym_name) orelse {
12401289 // Put new global symbol into the symbol table.
12411290 const name = try self.allocator.dupe(u8, sym_name);
12421291 try self.symtab.putNoClobber(self.allocator, name, .{
1243 .tag = if (Symbol.isWeakDef(sym)) .weak else .strong,
1292 .tag = if (is_weak) .weak else .strong,
12441293 .name = name,
12451294 .address = 0,
12461295 .section = 0,
......@@ -1251,15 +1300,20 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void {
12511300 };
12521301
12531302 switch (global.value.tag) {
1254 .weak => continue, // If symbol is weak, nothing to do.
1303 .weak => {
1304 if (is_weak) continue; // Nothing to do for weak symbol.
1305 },
12551306 .strong => {
1256 log.err("symbol '{s}' defined multiple times", .{sym_name});
1257 return error.MultipleSymbolDefinitions;
1307 if (!is_weak) {
1308 log.debug("strong symbol '{s}' defined multiple times", .{sym_name});
1309 return error.MultipleSymbolDefinitions;
1310 }
1311 continue;
12581312 },
12591313 else => {},
12601314 }
12611315
1262 global.value.tag = .strong;
1316 global.value.tag = if (is_weak) .weak else .strong;
12631317 global.value.file = object_id;
12641318 global.value.index = @intCast(u32, sym_id);
12651319 } else if (Symbol.isUndef(sym)) {
......@@ -1340,6 +1394,21 @@ fn resolveSymbols(self: *Zld) !void {
13401394 .section = 0,
13411395 .file = 0,
13421396 });
1397
1398 {
1399 log.debug("symtab", .{});
1400 for (self.symtab.items()) |sym| {
1401 switch (sym.value.tag) {
1402 .weak, .strong => {
1403 log.debug(" | {s} => {s}", .{ sym.key, self.objects.items[sym.value.file.?].name.? });
1404 },
1405 .import => {
1406 log.debug(" | {s} => libSystem.B.dylib", .{sym.key});
1407 },
1408 else => unreachable,
1409 }
1410 }
1411 }
13431412}
13441413
13451414fn resolveStubsAndGotEntries(self: *Zld) !void {
......@@ -1412,9 +1481,14 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
14121481 log.debug("relocating object {s}", .{object.name});
14131482
14141483 for (object.sections.items) |sect, source_sect_id| {
1484 if (sect.inner.flags == macho.S_MOD_INIT_FUNC_POINTERS or
1485 sect.inner.flags == macho.S_MOD_TERM_FUNC_POINTERS) continue;
1486
14151487 const segname = parseName(&sect.inner.segname);
14161488 const sectname = parseName(&sect.inner.sectname);
14171489
1490 log.debug("relocating section '{s},{s}'", .{ segname, sectname });
1491
14181492 // Get mapping
14191493 const target_mapping = self.mappings.get(.{
14201494 .object_id = @intCast(u16, object_id),
......@@ -1532,6 +1606,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
15321606 target_sect_off,
15331607 target_sect_off + sect.code.len,
15341608 });
1609
15351610 // Zero-out the space
15361611 var zeroes = try self.allocator.alloc(u8, sect.code.len);
15371612 defer self.allocator.free(zeroes);
......@@ -1571,25 +1646,33 @@ fn relocTargetAddr(self: *Zld, object_id: u16, target: reloc.Relocation.Target)
15711646 const target_sect = target_seg.sections.items[target_mapping.target_sect_id];
15721647 const target_addr = target_sect.addr + target_mapping.offset;
15731648 break :blk sym.n_value - source_sect.addr + target_addr;
1574 } else {
1575 if (self.stubs.get(sym_name)) |index| {
1576 log.debug(" | symbol stub '{s}'", .{sym_name});
1577 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1578 const stubs = segment.sections.items[self.stubs_section_index.?];
1579 break :blk stubs.addr + index * stubs.reserved2;
1580 } else if (mem.eql(u8, sym_name, "__tlv_bootstrap")) {
1581 log.debug(" | symbol '__tlv_bootstrap'", .{});
1582 const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1583 const tlv = segment.sections.items[self.tlv_section_index.?];
1584 break :blk tlv.addr;
1585 } else {
1586 const global = self.symtab.get(sym_name) orelse {
1587 log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name});
1588 return error.FailedToResolveRelocationTarget;
1589 };
1590 log.debug(" | global symbol '{s}'", .{sym_name});
1591 break :blk global.address;
1649 } else if (self.symtab.get(sym_name)) |global| {
1650 switch (global.tag) {
1651 .weak, .strong => {
1652 log.debug(" | global symbol '{s}'", .{sym_name});
1653 break :blk global.address;
1654 },
1655 .import => {
1656 if (self.stubs.get(sym_name)) |index| {
1657 log.debug(" | symbol stub '{s}'", .{sym_name});
1658 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1659 const stubs = segment.sections.items[self.stubs_section_index.?];
1660 break :blk stubs.addr + index * stubs.reserved2;
1661 } else if (mem.eql(u8, sym_name, "__tlv_bootstrap")) {
1662 log.debug(" | symbol '__tlv_bootstrap'", .{});
1663 const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1664 const tlv = segment.sections.items[self.tlv_section_index.?];
1665 break :blk tlv.addr;
1666 } else {
1667 log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name});
1668 return error.FailedToResolveRelocationTarget;
1669 }
1670 },
1671 else => unreachable,
15921672 }
1673 } else {
1674 log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name});
1675 return error.FailedToResolveRelocationTarget;
15931676 }
15941677 },
15951678 .section => |sect_id| {
......@@ -2008,6 +2091,12 @@ fn populateMetadata(self: *Zld) !void {
20082091}
20092092
20102093fn flush(self: *Zld) !void {
2094 if (self.common_section_index) |index| {
2095 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
2096 const sect = &seg.sections.items[index];
2097 sect.offset = 0;
2098 }
2099
20112100 if (self.bss_section_index) |index| {
20122101 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
20132102 const sect = &seg.sections.items[index];
......@@ -2040,6 +2129,24 @@ fn flush(self: *Zld) !void {
20402129 try self.file.?.pwriteAll(buffer, sect.offset);
20412130 }
20422131
2132 if (self.mod_init_func_section_index) |index| {
2133 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
2134 const sect = &seg.sections.items[index];
2135
2136 var initializers = std.ArrayList(u64).init(self.allocator);
2137 defer initializers.deinit();
2138
2139 // TODO sort the initializers globally
2140 for (self.objects.items) |object| {
2141 for (object.initializers.items) |initializer| {
2142 try initializers.append(initializer.target_addr);
2143 }
2144 }
2145
2146 _ = try self.file.?.pwriteAll(mem.sliceAsBytes(initializers.items), sect.offset);
2147 sect.size = @intCast(u32, initializers.items.len * @sizeOf(u64));
2148 }
2149
20432150 try self.writeGotEntries();
20442151 try self.setEntryPoint();
20452152 try self.writeRebaseInfoTable();
......@@ -2139,35 +2246,18 @@ fn writeRebaseInfoTable(self: *Zld) !void {
21392246 // TODO audit and investigate this.
21402247 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
21412248 const sect = seg.sections.items[idx];
2142 const npointers = sect.size * @sizeOf(u64);
21432249 const base_offset = sect.addr - seg.inner.vmaddr;
21442250 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);
21452251
2146 try pointers.ensureCapacity(pointers.items.len + npointers);
2147 var i: usize = 0;
2148 while (i < npointers) : (i += 1) {
2149 pointers.appendAssumeCapacity(.{
2150 .offset = base_offset + i * @sizeOf(u64),
2151 .segment_id = segment_id,
2152 });
2153 }
2154 }
2155
2156 if (self.mod_term_func_section_index) |idx| {
2157 // TODO audit and investigate this.
2158 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
2159 const sect = seg.sections.items[idx];
2160 const npointers = sect.size * @sizeOf(u64);
2161 const base_offset = sect.addr - seg.inner.vmaddr;
2162 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);
2163
2164 try pointers.ensureCapacity(pointers.items.len + npointers);
2165 var i: usize = 0;
2166 while (i < npointers) : (i += 1) {
2167 pointers.appendAssumeCapacity(.{
2168 .offset = base_offset + i * @sizeOf(u64),
2169 .segment_id = segment_id,
2170 });
2252 var index: u64 = 0;
2253 for (self.objects.items) |object| {
2254 for (object.initializers.items) |_| {
2255 try pointers.append(.{
2256 .offset = base_offset + index * @sizeOf(u64),
2257 .segment_id = segment_id,
2258 });
2259 index += 1;
2260 }
21712261 }
21722262 }
21732263
......@@ -2447,7 +2537,7 @@ fn writeDebugInfo(self: *Zld) !void {
24472537 .n_type = macho.N_OSO,
24482538 .n_sect = 0,
24492539 .n_desc = 1,
2450 .n_value = tu_mtime,
2540 .n_value = 0, //tu_mtime, TODO figure out why precalculated mtime value doesn't work
24512541 });
24522542
24532543 for (object.stabs.items) |stab| {
src/link/MachO/reloc/aarch64.zig+3-1
......@@ -226,7 +226,9 @@ pub const Parser = struct {
226226 try parser.parseTlvpLoadPageOff(rel);
227227 },
228228 .ARM64_RELOC_POINTER_TO_GOT => {
229 return error.ToDoRelocPointerToGot;
229 // TODO Handle pointer to GOT. This reloc seems to appear in
230 // __LD,__compact_unwind section which we currently don't handle.
231 log.debug("Unhandled relocation ARM64_RELOC_POINTER_TO_GOT", .{});
230232 },
231233 }
232234 }
src/main.zig+6
......@@ -355,6 +355,8 @@ const usage_build_generic =
355355 \\ -rpath [path] Add directory to the runtime library search path
356356 \\ -feach-lib-rpath Ensure adding rpath for each used dynamic library
357357 \\ -fno-each-lib-rpath Prevent adding rpath for each used dynamic library
358 \\ -fallow-shlib-undefined Allows undefined symbols in shared libraries
359 \\ -fno-allow-shlib-undefined Disallows undefined symbols in shared libraries
358360 \\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker
359361 \\ --emit-relocs Enable output of relocation sections for post build tools
360362 \\ -dynamic Force output to be dynamically linked
......@@ -988,6 +990,10 @@ fn buildOutputType(
988990 link_eh_frame_hdr = true;
989991 } else if (mem.eql(u8, arg, "--emit-relocs")) {
990992 link_emit_relocs = true;
993 } else if (mem.eql(u8, arg, "-fallow-shlib-undefined")) {
994 linker_allow_shlib_undefined = true;
995 } else if (mem.eql(u8, arg, "-fno-allow-shlib-undefined")) {
996 linker_allow_shlib_undefined = false;
991997 } else if (mem.eql(u8, arg, "-Bsymbolic")) {
992998 linker_bind_global_refs_locally = true;
993999 } else if (mem.eql(u8, arg, "--verbose-link")) {
src/register_manager.zig+74-37
......@@ -36,7 +36,7 @@ pub fn RegisterManager(
3636 }
3737
3838 fn isTracked(reg: Register) bool {
39 return std.mem.indexOfScalar(Register, callee_preserved_regs, reg) != null;
39 return reg.allocIndex() != null;
4040 }
4141
4242 fn markRegUsed(self: *Self, reg: Register) void {
......@@ -55,6 +55,7 @@ pub fn RegisterManager(
5555 self.free_registers |= @as(FreeRegInt, 1) << shift;
5656 }
5757
58 /// Returns true when this register is not tracked
5859 pub fn isRegFree(self: Self, reg: Register) bool {
5960 if (FreeRegInt == u0) return true;
6061 const index = reg.allocIndex() orelse return true;
......@@ -63,7 +64,8 @@ pub fn RegisterManager(
6364 }
6465
6566 /// Returns whether this register was allocated in the course
66 /// of this function
67 /// of this function.
68 /// Returns false when this register is not tracked
6769 pub fn isRegAllocated(self: Self, reg: Register) bool {
6870 if (FreeRegInt == u0) return false;
6971 const index = reg.allocIndex() orelse return false;
......@@ -71,57 +73,89 @@ pub fn RegisterManager(
7173 return self.allocated_registers & @as(FreeRegInt, 1) << shift != 0;
7274 }
7375
74 /// Before calling, must ensureCapacity + 1 on self.registers.
76 /// Before calling, must ensureCapacity + count on self.registers.
7577 /// Returns `null` if all registers are allocated.
76 pub fn tryAllocReg(self: *Self, inst: *ir.Inst) ?Register {
77 const free_index = @ctz(FreeRegInt, self.free_registers);
78 if (free_index >= callee_preserved_regs.len) {
78 pub fn tryAllocRegs(self: *Self, comptime count: comptime_int, insts: [count]*ir.Inst) ?[count]Register {
79 if (self.tryAllocRegsWithoutTracking(count)) |regs| {
80 for (regs) |reg, i| {
81 self.markRegUsed(reg);
82 self.registers.putAssumeCapacityNoClobber(reg, insts[i]);
83 }
84
85 return regs;
86 } else {
7987 return null;
8088 }
89 }
8190
82 // This is necessary because the return type of @ctz is 1
83 // bit longer than ShiftInt if callee_preserved_regs.len
84 // is a power of two. This int cast is always safe because
85 // free_index < callee_preserved_regs.len
86 const shift = @intCast(ShiftInt, free_index);
87 const mask = @as(FreeRegInt, 1) << shift;
88 self.free_registers &= ~mask;
89 self.allocated_registers |= mask;
91 /// Before calling, must ensureCapacity + 1 on self.registers.
92 /// Returns `null` if all registers are allocated.
93 pub fn tryAllocReg(self: *Self, inst: *ir.Inst) ?Register {
94 return if (tryAllocRegs(self, 1, .{inst})) |regs| regs[0] else null;
95 }
9096
91 const reg = callee_preserved_regs[free_index];
92 self.registers.putAssumeCapacityNoClobber(reg, inst);
93 log.debug("alloc {} => {*}", .{ reg, inst });
94 return reg;
97 /// Before calling, must ensureCapacity + count on self.registers.
98 pub fn allocRegs(self: *Self, comptime count: comptime_int, insts: [count]*ir.Inst) ![count]Register {
99 comptime assert(count > 0 and count <= callee_preserved_regs.len);
100
101 return self.tryAllocRegs(count, insts) orelse blk: {
102 // We'll take over the first count registers. Spill
103 // the instructions that were previously there to a
104 // stack allocations.
105 var regs: [count]Register = undefined;
106 std.mem.copy(Register, &regs, callee_preserved_regs[0..count]);
107
108 for (regs) |reg, i| {
109 if (self.isRegFree(reg)) {
110 self.markRegUsed(reg);
111 self.registers.putAssumeCapacityNoClobber(reg, insts[i]);
112 } else {
113 const regs_entry = self.registers.getEntry(reg).?;
114 const spilled_inst = regs_entry.value;
115 regs_entry.value = insts[i];
116 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
117 }
118 }
119
120 break :blk regs;
121 };
95122 }
96123
97124 /// Before calling, must ensureCapacity + 1 on self.registers.
98125 pub fn allocReg(self: *Self, inst: *ir.Inst) !Register {
99 return self.tryAllocReg(inst) orelse b: {
100 // We'll take over the first register. Move the instruction that was previously
101 // there to a stack allocation.
102 const reg = callee_preserved_regs[0];
103 const regs_entry = self.registers.getEntry(reg).?;
104 const spilled_inst = regs_entry.value;
105 regs_entry.value = inst;
106 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
126 return (try allocRegs(self, 1, .{inst}))[0];
127 }
107128
108 break :b reg;
109 };
129 /// Does not track the registers.
130 /// Returns `null` if not enough registers are free.
131 pub fn tryAllocRegsWithoutTracking(self: *Self, comptime count: comptime_int) ?[count]Register {
132 comptime if (callee_preserved_regs.len == 0) return null;
133 comptime assert(count > 0 and count <= callee_preserved_regs.len);
134
135 const free_registers = @popCount(FreeRegInt, self.free_registers);
136 if (free_registers < count) return null;
137
138 var regs: [count]Register = undefined;
139 var i: usize = 0;
140 for (callee_preserved_regs) |reg| {
141 if (i >= count) break;
142 if (self.isRegFree(reg)) {
143 regs[i] = reg;
144 i += 1;
145 }
146 }
147 return regs;
110148 }
111149
112150 /// Does not track the register.
113151 /// Returns `null` if all registers are allocated.
114 pub fn findUnusedReg(self: *Self) ?Register {
115 const free_index = @ctz(FreeRegInt, self.free_registers);
116 if (free_index >= callee_preserved_regs.len) {
117 return null;
118 }
119 return callee_preserved_regs[free_index];
152 pub fn tryAllocRegWithoutTracking(self: *Self) ?Register {
153 return if (tryAllocRegsWithoutTracking(self, 1)) |regs| regs[0] else null;
120154 }
121155
122156 /// Does not track the register.
123157 pub fn allocRegWithoutTracking(self: *Self) !Register {
124 return self.findUnusedReg() orelse b: {
158 return self.tryAllocRegWithoutTracking() orelse b: {
125159 // We'll take over the first register. Move the instruction that was previously
126160 // there to a stack allocation.
127161 const reg = callee_preserved_regs[0];
......@@ -190,7 +224,10 @@ pub fn RegisterManager(
190224}
191225
192226const MockRegister = enum(u2) {
193 r0, r1, r2, r3,
227 r0,
228 r1,
229 r2,
230 r3,
194231
195232 pub fn allocIndex(self: MockRegister) ?u2 {
196233 inline for (mock_callee_preserved_regs) |cpreg, i| {
......@@ -213,7 +250,7 @@ const MockFunction = struct {
213250 self.register_manager.deinit(self.allocator);
214251 self.spilled.deinit(self.allocator);
215252 }
216
253
217254 pub fn spillInstruction(self: *Self, src: LazySrcLoc, reg: MockRegister, inst: *ir.Inst) !void {
218255 try self.spilled.append(self.allocator, reg);
219256 }
src/stage1/bigfloat.cpp+3-6
......@@ -9,6 +9,7 @@
99#include "bigint.hpp"
1010#include "buffer.hpp"
1111#include "softfloat.hpp"
12#include "softfloat_ext.hpp"
1213#include "parse_f128.h"
1314#include <stdio.h>
1415#include <math.h>
......@@ -60,9 +61,7 @@ void bigfloat_init_bigint(BigFloat *dest, const BigInt *op) {
6061
6162 if (i == 0) {
6263 if (op->is_negative) {
63 float128_t zero_f128;
64 ui32_to_f128M(0, &zero_f128);
65 f128M_sub(&zero_f128, &dest->value, &dest->value);
64 f128M_neg(&dest->value, &dest->value);
6665 }
6766 return;
6867 }
......@@ -89,9 +88,7 @@ void bigfloat_add(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
8988}
9089
9190void bigfloat_negate(BigFloat *dest, const BigFloat *op) {
92 float128_t zero_f128;
93 ui32_to_f128M(0, &zero_f128);
94 f128M_sub(&zero_f128, &op->value, &dest->value);
91 f128M_neg(&op->value, &dest->value);
9592}
9693
9794void bigfloat_sub(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
src/stage1/bigint.cpp+2-2
......@@ -1446,10 +1446,10 @@ void bigint_negate(BigInt *dest, const BigInt *op) {
14461446 bigint_normalize(dest);
14471447}
14481448
1449void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count) {
1449void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed) {
14501450 BigInt zero;
14511451 bigint_init_unsigned(&zero, 0);
1452 bigint_sub_wrap(dest, &zero, op, bit_count, true);
1452 bigint_sub_wrap(dest, &zero, op, bit_count, is_signed);
14531453}
14541454
14551455void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed) {
src/stage1/bigint.hpp+1-1
......@@ -75,7 +75,7 @@ void bigint_shl_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t
7575void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2);
7676
7777void bigint_negate(BigInt *dest, const BigInt *op);
78void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count);
78void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed);
7979void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed);
8080void bigint_truncate(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed);
8181
src/stage1/codegen.cpp+4-1
......@@ -7436,7 +7436,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n
74367436 case ZigTypeIdFloat:
74377437 switch (type_entry->data.floating.bit_count) {
74387438 case 16:
7439 return LLVMConstReal(get_llvm_type(g, type_entry), zig_f16_to_double(const_val->data.x_f16));
7439 {
7440 LLVMValueRef as_int = LLVMConstInt(LLVMInt16Type(), const_val->data.x_f16.v, false);
7441 return LLVMConstBitCast(as_int, get_llvm_type(g, type_entry));
7442 }
74407443 case 32:
74417444 return LLVMConstReal(get_llvm_type(g, type_entry), const_val->data.x_f32);
74427445 case 64:
src/stage1/ir.cpp+13-20
......@@ -9534,7 +9534,7 @@ static IrInstSrc *ir_gen_nosuspend(IrBuilderSrc *irb, Scope *parent_scope, AstNo
95349534
95359535 Scope *child_scope = create_nosuspend_scope(irb->codegen, node, parent_scope);
95369536 // purposefully pass null for result_loc and let EndExpr handle it
9537 return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval, nullptr);
9537 return ir_gen_node_extra(irb, node->data.nosuspend_expr.expr, child_scope, lval, nullptr);
95389538}
95399539
95409540static IrInstSrc *ir_gen_return_from_block(IrBuilderSrc *irb, Scope *break_scope, AstNode *node, ScopeBlock *block_scope) {
......@@ -10199,14 +10199,12 @@ static IrInstSrc *ir_gen_suspend(IrBuilderSrc *irb, Scope *parent_scope, AstNode
1019910199 }
1020010200
1020110201 IrInstSrcSuspendBegin *begin = ir_build_suspend_begin_src(irb, parent_scope, node);
10202 if (node->data.suspend.block != nullptr) {
10203 ScopeSuspend *suspend_scope = create_suspend_scope(irb->codegen, node, parent_scope);
10204 Scope *child_scope = &suspend_scope->base;
10205 IrInstSrc *susp_res = ir_gen_node(irb, node->data.suspend.block, child_scope);
10206 if (susp_res == irb->codegen->invalid_inst_src)
10207 return irb->codegen->invalid_inst_src;
10208 ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.suspend.block, susp_res));
10209 }
10202 ScopeSuspend *suspend_scope = create_suspend_scope(irb->codegen, node, parent_scope);
10203 Scope *child_scope = &suspend_scope->base;
10204 IrInstSrc *susp_res = ir_gen_node(irb, node->data.suspend.block, child_scope);
10205 if (susp_res == irb->codegen->invalid_inst_src)
10206 return irb->codegen->invalid_inst_src;
10207 ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.suspend.block, susp_res));
1021010208
1021110209 return ir_mark_gen(ir_build_suspend_finish_src(irb, parent_scope, node, begin));
1021210210}
......@@ -11363,11 +11361,8 @@ static void float_negate(ZigValue *out_val, ZigValue *op) {
1136311361 } else if (op->type->id == ZigTypeIdFloat) {
1136411362 switch (op->type->data.floating.bit_count) {
1136511363 case 16:
11366 {
11367 const float16_t zero = zig_double_to_f16(0);
11368 out_val->data.x_f16 = f16_sub(zero, op->data.x_f16);
11369 return;
11370 }
11364 out_val->data.x_f16 = f16_neg(op->data.x_f16);
11365 return;
1137111366 case 32:
1137211367 out_val->data.x_f32 = -op->data.x_f32;
1137311368 return;
......@@ -11375,9 +11370,7 @@ static void float_negate(ZigValue *out_val, ZigValue *op) {
1137511370 out_val->data.x_f64 = -op->data.x_f64;
1137611371 return;
1137711372 case 128:
11378 float128_t zero_f128;
11379 ui32_to_f128M(0, &zero_f128);
11380 f128M_sub(&zero_f128, &op->data.x_f128, &out_val->data.x_f128);
11373 f128M_neg(&op->data.x_f128, &out_val->data.x_f128);
1138111374 return;
1138211375 default:
1138311376 zig_unreachable();
......@@ -21665,8 +21658,8 @@ static ErrorMsg *ir_eval_negation_scalar(IrAnalyze *ira, IrInst* source_instr, Z
2166521658{
2166621659 bool is_float = (scalar_type->id == ZigTypeIdFloat || scalar_type->id == ZigTypeIdComptimeFloat);
2166721660
21668 bool ok_type = ((scalar_type->id == ZigTypeIdInt && scalar_type->data.integral.is_signed) ||
21669 scalar_type->id == ZigTypeIdComptimeInt || (is_float && !is_wrap_op));
21661 bool ok_type = scalar_type->id == ZigTypeIdInt || scalar_type->id == ZigTypeIdComptimeInt ||
21662 (is_float && !is_wrap_op);
2167021663
2167121664 if (!ok_type) {
2167221665 const char *fmt = is_wrap_op ? "invalid wrapping negation type: '%s'" : "invalid negation type: '%s'";
......@@ -21677,7 +21670,7 @@ static ErrorMsg *ir_eval_negation_scalar(IrAnalyze *ira, IrInst* source_instr, Z
2167721670 float_negate(scalar_out_val, operand_val);
2167821671 } else if (is_wrap_op) {
2167921672 bigint_negate_wrap(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint,
21680 scalar_type->data.integral.bit_count);
21673 scalar_type->data.integral.bit_count, scalar_type->data.integral.is_signed);
2168121674 } else {
2168221675 bigint_negate(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint);
2168321676 }
src/stage1/parser.cpp+1-4
......@@ -946,10 +946,7 @@ static AstNode *ast_parse_statement(ParseContext *pc) {
946946
947947 Token *suspend = eat_token_if(pc, TokenIdKeywordSuspend);
948948 if (suspend != nullptr) {
949 AstNode *statement = nullptr;
950 if (eat_token_if(pc, TokenIdSemicolon) == nullptr)
951 statement = ast_expect(pc, ast_parse_block_expr_statement);
952
949 AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement);
953950 AstNode *res = ast_create_node(pc, NodeTypeSuspend, suspend);
954951 res->data.suspend.block = statement;
955952 return res;
src/stage1/softfloat_ext.cpp+31-7
......@@ -1,17 +1,21 @@
11#include "softfloat_ext.hpp"
2#include "zigendian.h"
23
34extern "C" {
45 #include "softfloat.h"
56}
67
78void f128M_abs(const float128_t *aPtr, float128_t *zPtr) {
8 float128_t zero_float;
9 ui32_to_f128M(0, &zero_float);
10 if (f128M_lt(aPtr, &zero_float)) {
11 f128M_sub(&zero_float, aPtr, zPtr);
12 } else {
13 *zPtr = *aPtr;
14 }
9 // Clear the sign bit.
10#if ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN
11 zPtr->v[1] = aPtr->v[1] & ~(UINT64_C(1) << 63);
12 zPtr->v[0] = aPtr->v[0];
13#elif ZIG_BYTE_ORDER == ZIG_BIG_ENDIAN
14 zPtr->v[0] = aPtr->v[0] & ~(UINT64_C(1) << 63);
15 zPtr->v[1] = aPtr->v[1];
16#else
17#error Unsupported endian
18#endif
1519}
1620
1721void f128M_trunc(const float128_t *aPtr, float128_t *zPtr) {
......@@ -22,4 +26,24 @@ void f128M_trunc(const float128_t *aPtr, float128_t *zPtr) {
2226 } else {
2327 f128M_roundToInt(aPtr, softfloat_round_min, false, zPtr);
2428 }
29}
30
31float16_t f16_neg(const float16_t a) {
32 union { uint16_t ui; float16_t f; } uA;
33 // Toggle the sign bit.
34 uA.ui = a.v ^ (UINT16_C(1) << 15);
35 return uA.f;
36}
37
38void f128M_neg(const float128_t *aPtr, float128_t *zPtr) {
39 // Toggle the sign bit.
40#if ZIG_BYTE_ORDER == ZIG_LITTLE_ENDIAN
41 zPtr->v[1] = aPtr->v[1] ^ (UINT64_C(1) << 63);
42 zPtr->v[0] = aPtr->v[0];
43#elif ZIG_BYTE_ORDER == ZIG_BIG_ENDIAN
44 zPtr->v[0] = aPtr->v[0] ^ (UINT64_C(1) << 63);
45 zPtr->v[1] = aPtr->v[1];
46#else
47#error Unsupported endian
48#endif
2549}
\ No newline at end of file
src/stage1/softfloat_ext.hpp+3
......@@ -5,5 +5,8 @@
55
66void f128M_abs(const float128_t *aPtr, float128_t *zPtr);
77void f128M_trunc(const float128_t *aPtr, float128_t *zPtr);
8void f128M_neg(const float128_t *aPtr, float128_t *zPtr);
9
10float16_t f16_neg(const float16_t a);
811
912#endif
\ No newline at end of file
src/translate_c.zig+10-6
......@@ -1353,10 +1353,14 @@ fn transCreatePointerArithmeticSignedOp(
13531353
13541354 const bitcast_node = try usizeCastForWrappingPtrArithmetic(c.arena, rhs_node);
13551355
1356 const arith_args = .{ .lhs = lhs_node, .rhs = bitcast_node };
1357 const arith_node = try if (is_add) Tag.add.create(c.arena, arith_args) else Tag.sub.create(c.arena, arith_args);
1358
1359 return maybeSuppressResult(c, scope, result_used, arith_node);
1356 return transCreateNodeInfixOp(
1357 c,
1358 scope,
1359 if (is_add) .add else .sub,
1360 lhs_node,
1361 bitcast_node,
1362 result_used,
1363 );
13601364}
13611365
13621366fn transBinaryOperator(
......@@ -2161,8 +2165,8 @@ fn transCCast(
21612165 return Tag.as.create(c.arena, .{ .lhs = dst_node, .rhs = bool_to_int });
21622166 }
21632167 if (cIsEnum(dst_type)) {
2164 // @intToEnum(dest_type, val)
2165 return Tag.int_to_enum.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
2168 // import("std").meta.cast(dest_type, val)
2169 return Tag.std_meta_cast.create(c.arena, .{ .lhs = dst_node, .rhs = expr });
21662170 }
21672171 if (cIsEnum(src_type) and !cIsEnum(dst_type)) {
21682172 // @enumToInt(val)
src/translate_c/ast.zig+3-3
......@@ -1665,7 +1665,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
16651665 },
16661666 .array_access => {
16671667 const payload = node.castTag(.array_access).?.data;
1668 const lhs = try renderNode(c, payload.lhs);
1668 const lhs = try renderNodeGrouped(c, payload.lhs);
16691669 const l_bracket = try c.addToken(.l_bracket, "[");
16701670 const index_expr = try renderNode(c, payload.rhs);
16711671 _ = try c.addToken(.r_bracket, "]");
......@@ -1728,7 +1728,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
17281728 },
17291729 .field_access => {
17301730 const payload = node.castTag(.field_access).?.data;
1731 const lhs = try renderNode(c, payload.lhs);
1731 const lhs = try renderNodeGrouped(c, payload.lhs);
17321732 return renderFieldAccess(c, lhs, payload.field_name);
17331733 },
17341734 .@"struct", .@"union" => return renderRecord(c, node),
......@@ -2073,7 +2073,7 @@ fn renderNullSentinelArrayType(c: *Context, len: usize, elem_type: Node) !NodeIn
20732073 .main_token = l_bracket,
20742074 .data = .{
20752075 .lhs = len_expr,
2076 .rhs = try c.addExtra(std.zig.ast.Node.ArrayTypeSentinel {
2076 .rhs = try c.addExtra(std.zig.ast.Node.ArrayTypeSentinel{
20772077 .sentinel = sentinel_expr,
20782078 .elem_type = elem_type_expr,
20792079 }),
test/compile_errors.zig+7-7
......@@ -1021,7 +1021,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
10211021 \\export fn entry() void {
10221022 \\ nosuspend {
10231023 \\ const bar = async foo();
1024 \\ suspend;
1024 \\ suspend {}
10251025 \\ resume bar;
10261026 \\ }
10271027 \\}
......@@ -2120,7 +2120,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
21202120 \\ non_async_fn = func;
21212121 \\}
21222122 \\fn func() void {
2123 \\ suspend;
2123 \\ suspend {}
21242124 \\}
21252125 , &[_][]const u8{
21262126 "tmp.zig:5:1: error: 'func' cannot be async",
......@@ -2198,7 +2198,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
21982198 \\ var x: anyframe = &f;
21992199 \\}
22002200 \\fn func() void {
2201 \\ suspend;
2201 \\ suspend {}
22022202 \\}
22032203 , &[_][]const u8{
22042204 "tmp.zig:3:12: error: expected type 'anyframe', found '*const @Frame(func)'",
......@@ -2231,10 +2231,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
22312231 \\ frame = async bar();
22322232 \\}
22332233 \\fn foo() void {
2234 \\ suspend;
2234 \\ suspend {}
22352235 \\}
22362236 \\fn bar() void {
2237 \\ suspend;
2237 \\ suspend {}
22382238 \\}
22392239 , &[_][]const u8{
22402240 "tmp.zig:3:13: error: expected type '*@Frame(bar)', found '*@Frame(foo)'",
......@@ -2269,7 +2269,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
22692269 \\ var result = await frame;
22702270 \\}
22712271 \\fn func() void {
2272 \\ suspend;
2272 \\ suspend {}
22732273 \\}
22742274 , &[_][]const u8{
22752275 "tmp.zig:1:1: error: function with calling convention 'C' cannot be async",
......@@ -2347,7 +2347,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
23472347 \\ bar();
23482348 \\}
23492349 \\fn bar() void {
2350 \\ suspend;
2350 \\ suspend {}
23512351 \\}
23522352 , &[_][]const u8{
23532353 "tmp.zig:1:1: error: function with calling convention 'C' cannot be async",
test/run_translated_c.zig+23
......@@ -1453,4 +1453,27 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
14531453 \\ return 0;
14541454 \\}
14551455 , "");
1456
1457 cases.add("Cast to enum from larger integral type. Issue #6011",
1458 \\#include <stdint.h>
1459 \\#include <stdlib.h>
1460 \\enum Foo { A, B, C };
1461 \\static inline enum Foo do_stuff(void) {
1462 \\ int64_t i = 1;
1463 \\ return (enum Foo)i;
1464 \\}
1465 \\int main(void) {
1466 \\ if (do_stuff() != B) abort();
1467 \\ return 0;
1468 \\}
1469 , "");
1470
1471 cases.add("Render array LHS as grouped node if necessary",
1472 \\#include <stdlib.h>
1473 \\int main(void) {
1474 \\ int arr[] = {40, 41, 42, 43};
1475 \\ if ((arr + 1)[1] != 42) abort();
1476 \\ return 0;
1477 \\}
1478 , "");
14561479}
test/runtime_safety.zig+17-17
......@@ -13,7 +13,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
1313
1414 cases.addRuntimeSafety("switch on corrupted enum value",
1515 \\const std = @import("std");
16 ++ check_panic_msg ++
16 ++ check_panic_msg ++
1717 \\const E = enum(u32) {
1818 \\ X = 1,
1919 \\};
......@@ -28,7 +28,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
2828
2929 cases.addRuntimeSafety("switch on corrupted union value",
3030 \\const std = @import("std");
31 ++ check_panic_msg ++
31 ++ check_panic_msg ++
3232 \\const U = union(enum(u32)) {
3333 \\ X: u8,
3434 \\};
......@@ -54,7 +54,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
5454
5555 cases.addRuntimeSafety("@tagName on corrupted enum value",
5656 \\const std = @import("std");
57 ++ check_panic_msg ++
57 ++ check_panic_msg ++
5858 \\const E = enum(u32) {
5959 \\ X = 1,
6060 \\};
......@@ -67,7 +67,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
6767
6868 cases.addRuntimeSafety("@tagName on corrupted union value",
6969 \\const std = @import("std");
70 ++ check_panic_msg ++
70 ++ check_panic_msg ++
7171 \\const U = union(enum(u32)) {
7272 \\ X: u8,
7373 \\};
......@@ -92,7 +92,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
9292
9393 cases.addRuntimeSafety("slicing operator with sentinel",
9494 \\const std = @import("std");
95 ++ check_panic_msg ++
95 ++ check_panic_msg ++
9696 \\pub fn main() void {
9797 \\ var buf = [4]u8{'a','b','c',0};
9898 \\ const slice = buf[0..4 :0];
......@@ -100,7 +100,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
100100 );
101101 cases.addRuntimeSafety("slicing operator with sentinel",
102102 \\const std = @import("std");
103 ++ check_panic_msg ++
103 ++ check_panic_msg ++
104104 \\pub fn main() void {
105105 \\ var buf = [4]u8{'a','b','c',0};
106106 \\ const slice = buf[0..:0];
......@@ -108,7 +108,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
108108 );
109109 cases.addRuntimeSafety("slicing operator with sentinel",
110110 \\const std = @import("std");
111 ++ check_panic_msg ++
111 ++ check_panic_msg ++
112112 \\pub fn main() void {
113113 \\ var buf_zero = [0]u8{};
114114 \\ const slice = buf_zero[0..0 :0];
......@@ -116,7 +116,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
116116 );
117117 cases.addRuntimeSafety("slicing operator with sentinel",
118118 \\const std = @import("std");
119 ++ check_panic_msg ++
119 ++ check_panic_msg ++
120120 \\pub fn main() void {
121121 \\ var buf_zero = [0]u8{};
122122 \\ const slice = buf_zero[0..:0];
......@@ -124,7 +124,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
124124 );
125125 cases.addRuntimeSafety("slicing operator with sentinel",
126126 \\const std = @import("std");
127 ++ check_panic_msg ++
127 ++ check_panic_msg ++
128128 \\pub fn main() void {
129129 \\ var buf_sentinel = [2:0]u8{'a','b'};
130130 \\ @ptrCast(*[3]u8, &buf_sentinel)[2] = 0;
......@@ -133,7 +133,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
133133 );
134134 cases.addRuntimeSafety("slicing operator with sentinel",
135135 \\const std = @import("std");
136 ++ check_panic_msg ++
136 ++ check_panic_msg ++
137137 \\pub fn main() void {
138138 \\ var buf_slice: []const u8 = &[3]u8{ 'a', 'b', 0 };
139139 \\ const slice = buf_slice[0..3 :0];
......@@ -141,7 +141,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
141141 );
142142 cases.addRuntimeSafety("slicing operator with sentinel",
143143 \\const std = @import("std");
144 ++ check_panic_msg ++
144 ++ check_panic_msg ++
145145 \\pub fn main() void {
146146 \\ var buf_slice: []const u8 = &[3]u8{ 'a', 'b', 0 };
147147 \\ const slice = buf_slice[0.. :0];
......@@ -367,7 +367,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
367367 \\}
368368 \\fn add(a: i32, b: i32) i32 {
369369 \\ if (a > 100) {
370 \\ suspend;
370 \\ suspend {}
371371 \\ }
372372 \\ return a + b;
373373 \\}
......@@ -407,7 +407,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
407407 \\ var frame = @asyncCall(&bytes, {}, ptr, .{});
408408 \\}
409409 \\fn other() callconv(.Async) void {
410 \\ suspend;
410 \\ suspend {}
411411 \\}
412412 );
413413
......@@ -424,7 +424,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
424424 \\ await frame;
425425 \\}
426426 \\fn other() void {
427 \\ suspend;
427 \\ suspend {}
428428 \\}
429429 );
430430
......@@ -440,7 +440,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
440440 \\ other();
441441 \\}
442442 \\fn other() void {
443 \\ suspend;
443 \\ suspend {}
444444 \\}
445445 );
446446
......@@ -454,7 +454,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
454454 \\ resume p; //bad
455455 \\}
456456 \\fn suspendOnce() void {
457 \\ suspend;
457 \\ suspend {}
458458 \\}
459459 );
460460
......@@ -1019,7 +1019,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
10191019 \\}
10201020 \\
10211021 \\fn failing() anyerror!void {
1022 \\ suspend;
1022 \\ suspend {}
10231023 \\ return second();
10241024 \\}
10251025 \\
test/stage1/behavior/async_fn.zig+42-42
......@@ -18,9 +18,9 @@ test "simple coroutine suspend and resume" {
1818}
1919fn simpleAsyncFn() void {
2020 global_x += 1;
21 suspend;
21 suspend {}
2222 global_x += 1;
23 suspend;
23 suspend {}
2424 global_x += 1;
2525}
2626
......@@ -34,7 +34,7 @@ test "pass parameter to coroutine" {
3434}
3535fn simpleAsyncFnWithArg(delta: i32) void {
3636 global_y += delta;
37 suspend;
37 suspend {}
3838 global_y += delta;
3939}
4040
......@@ -50,7 +50,7 @@ test "suspend at end of function" {
5050
5151 fn suspendAtEnd() void {
5252 x += 1;
53 suspend;
53 suspend {}
5454 }
5555 };
5656 S.doTheTest();
......@@ -74,11 +74,11 @@ test "local variable in async function" {
7474
7575 fn add(a: i32, b: i32) void {
7676 var accum: i32 = 0;
77 suspend;
77 suspend {}
7878 accum += a;
79 suspend;
79 suspend {}
8080 accum += b;
81 suspend;
81 suspend {}
8282 x = accum;
8383 }
8484 };
......@@ -102,7 +102,7 @@ test "calling an inferred async function" {
102102 }
103103 fn other() void {
104104 other_frame = @frame();
105 suspend;
105 suspend {}
106106 x += 1;
107107 }
108108 };
......@@ -129,7 +129,7 @@ test "@frameSize" {
129129 }
130130 fn other(param: i32) void {
131131 var local: i32 = undefined;
132 suspend;
132 suspend {}
133133 }
134134 };
135135 S.doTheTest();
......@@ -269,7 +269,7 @@ test "async function with dot syntax" {
269269 var y: i32 = 1;
270270 fn foo() callconv(.Async) void {
271271 y += 1;
272 suspend;
272 suspend {}
273273 }
274274 };
275275 const p = async S.foo();
......@@ -298,7 +298,7 @@ fn doTheAwait(f: anyframe->void) void {
298298fn simpleAsyncFn2(y: *i32) callconv(.Async) void {
299299 defer y.* += 2;
300300 y.* += 1;
301 suspend;
301 suspend {}
302302}
303303
304304test "@asyncCall with return type" {
......@@ -312,7 +312,7 @@ test "@asyncCall with return type" {
312312
313313 fn afunc() i32 {
314314 global_frame = @frame();
315 suspend;
315 suspend {}
316316 return 1234;
317317 }
318318 };
......@@ -348,7 +348,7 @@ test "async fn with inferred error set" {
348348
349349 fn failing() !void {
350350 global_frame = @frame();
351 suspend;
351 suspend {}
352352 return error.Fail;
353353 }
354354 };
......@@ -375,7 +375,7 @@ fn nonFailing() (anyframe->anyerror!void) {
375375 return &Static.frame;
376376}
377377fn suspendThenFail() callconv(.Async) anyerror!void {
378 suspend;
378 suspend {}
379379 return error.Fail;
380380}
381381fn printTrace(p: anyframe->(anyerror!void)) callconv(.Async) void {
......@@ -400,7 +400,7 @@ fn testBreakFromSuspend(my_result: *i32) callconv(.Async) void {
400400 resume @frame();
401401 }
402402 my_result.* += 1;
403 suspend;
403 suspend {}
404404 my_result.* += 1;
405405}
406406
......@@ -421,7 +421,7 @@ test "heap allocated async function frame" {
421421
422422 fn someFunc() void {
423423 x += 1;
424 suspend;
424 suspend {}
425425 x += 1;
426426 }
427427 };
......@@ -454,7 +454,7 @@ test "async function call return value" {
454454
455455 fn other(x: i32, y: i32) Point {
456456 frame = @frame();
457 suspend;
457 suspend {}
458458 return Point{
459459 .x = x,
460460 .y = y,
......@@ -487,7 +487,7 @@ test "suspension points inside branching control flow" {
487487
488488 fn func(b: bool) void {
489489 while (b) {
490 suspend;
490 suspend {}
491491 result += 1;
492492 }
493493 }
......@@ -541,7 +541,7 @@ test "pass string literal to async function" {
541541
542542 fn hello(msg: []const u8) void {
543543 frame = @frame();
544 suspend;
544 suspend {}
545545 expectEqualStrings("hello", msg);
546546 ok = true;
547547 }
......@@ -566,7 +566,7 @@ test "await inside an errdefer" {
566566
567567 fn func() void {
568568 frame = @frame();
569 suspend;
569 suspend {}
570570 }
571571 };
572572 S.doTheTest();
......@@ -590,7 +590,7 @@ test "try in an async function with error union and non-zero-bit payload" {
590590
591591 fn theProblem() ![]u8 {
592592 frame = @frame();
593 suspend;
593 suspend {}
594594 const result = try other();
595595 return result;
596596 }
......@@ -622,7 +622,7 @@ test "returning a const error from async function" {
622622
623623 fn fetchUrl(unused: i32, url: []const u8) ![]u8 {
624624 frame = @frame();
625 suspend;
625 suspend {}
626626 ok = true;
627627 return error.OutOfMemory;
628628 }
......@@ -967,7 +967,7 @@ test "@asyncCall with comptime-known function, but not awaited directly" {
967967
968968 fn failing() !void {
969969 global_frame = @frame();
970 suspend;
970 suspend {}
971971 return error.Fail;
972972 }
973973 };
......@@ -977,7 +977,7 @@ test "@asyncCall with comptime-known function, but not awaited directly" {
977977test "@asyncCall with actual frame instead of byte buffer" {
978978 const S = struct {
979979 fn func() i32 {
980 suspend;
980 suspend {}
981981 return 1234;
982982 }
983983 };
......@@ -993,7 +993,7 @@ test "@asyncCall using the result location inside the frame" {
993993 fn simple2(y: *i32) callconv(.Async) i32 {
994994 defer y.* += 2;
995995 y.* += 1;
996 suspend;
996 suspend {}
997997 return 1234;
998998 }
999999 fn getAnswer(f: anyframe->i32, out: *i32) void {
......@@ -1095,7 +1095,7 @@ test "nosuspend function call" {
10951095 }
10961096 fn add(a: i32, b: i32) i32 {
10971097 if (a > 100) {
1098 suspend;
1098 suspend {}
10991099 }
11001100 return a + b;
11011101 }
......@@ -1170,7 +1170,7 @@ test "suspend in for loop" {
11701170 global_frame = @frame();
11711171 var sum: u32 = 0;
11721172 for (stuff) |x| {
1173 suspend;
1173 suspend {}
11741174 sum += x;
11751175 }
11761176 global_frame = null;
......@@ -1197,7 +1197,7 @@ test "suspend in while loop" {
11971197 global_frame = @frame();
11981198 defer global_frame = null;
11991199 while (stuff) |val| {
1200 suspend;
1200 suspend {}
12011201 return val;
12021202 }
12031203 return 0;
......@@ -1206,7 +1206,7 @@ test "suspend in while loop" {
12061206 global_frame = @frame();
12071207 defer global_frame = null;
12081208 while (stuff) |val| {
1209 suspend;
1209 suspend {}
12101210 return val;
12111211 } else |err| {
12121212 return 0;
......@@ -1339,7 +1339,7 @@ test "async function passed 0-bit arg after non-0-bit arg" {
13391339
13401340 fn bar(x: i32, args: anytype) anyerror!void {
13411341 global_frame = @frame();
1342 suspend;
1342 suspend {}
13431343 global_int = x;
13441344 }
13451345 };
......@@ -1361,7 +1361,7 @@ test "async function passed align(16) arg after align(8) arg" {
13611361 fn bar(x: u64, args: anytype) anyerror!void {
13621362 expect(x == 10);
13631363 global_frame = @frame();
1364 suspend;
1364 suspend {}
13651365 global_int = args[0];
13661366 }
13671367 };
......@@ -1383,7 +1383,7 @@ test "async function call resolves target fn frame, comptime func" {
13831383
13841384 fn bar() anyerror!void {
13851385 global_frame = @frame();
1386 suspend;
1386 suspend {}
13871387 global_int += 1;
13881388 }
13891389 };
......@@ -1406,7 +1406,7 @@ test "async function call resolves target fn frame, runtime func" {
14061406
14071407 fn bar() anyerror!void {
14081408 global_frame = @frame();
1409 suspend;
1409 suspend {}
14101410 global_int += 1;
14111411 }
14121412 };
......@@ -1430,7 +1430,7 @@ test "properly spill optional payload capture value" {
14301430
14311431 fn bar() void {
14321432 global_frame = @frame();
1433 suspend;
1433 suspend {}
14341434 global_int += 1;
14351435 }
14361436 };
......@@ -1466,13 +1466,13 @@ test "handle defer interfering with return value spill" {
14661466
14671467 fn bar() anyerror!void {
14681468 global_frame1 = @frame();
1469 suspend;
1469 suspend {}
14701470 return error.Bad;
14711471 }
14721472
14731473 fn baz() void {
14741474 global_frame2 = @frame();
1475 suspend;
1475 suspend {}
14761476 baz_happened = true;
14771477 }
14781478 };
......@@ -1497,7 +1497,7 @@ test "take address of temporary async frame" {
14971497
14981498 fn foo(arg: i32) i32 {
14991499 global_frame = @frame();
1500 suspend;
1500 suspend {}
15011501 return arg + 1234;
15021502 }
15031503
......@@ -1520,7 +1520,7 @@ test "nosuspend await" {
15201520
15211521 fn foo(want_suspend: bool) i32 {
15221522 if (want_suspend) {
1523 suspend;
1523 suspend {}
15241524 }
15251525 return 42;
15261526 }
......@@ -1569,11 +1569,11 @@ test "nosuspend on async function calls" {
15691569// };
15701570// const S1 = struct {
15711571// fn c() S0 {
1572// suspend;
1572// suspend {}
15731573// return S0{};
15741574// }
15751575// fn d() !S0 {
1576// suspend;
1576// suspend {}
15771577// return S0{};
15781578// }
15791579// };
......@@ -1591,11 +1591,11 @@ test "nosuspend resume async function calls" {
15911591 };
15921592 const S1 = struct {
15931593 fn c() S0 {
1594 suspend;
1594 suspend {}
15951595 return S0{};
15961596 }
15971597 fn d() !S0 {
1598 suspend;
1598 suspend {}
15991599 return S0{};
16001600 }
16011601 };
test/stage1/behavior/math.zig+31-4
......@@ -229,16 +229,26 @@ fn testSignedWrappingEval(x: i32) void {
229229 expect(max_val == maxInt(i32));
230230}
231231
232test "negation wrapping" {
233 testNegationWrappingEval(minInt(i16));
234 comptime testNegationWrappingEval(minInt(i16));
232test "signed negation wrapping" {
233 testSignedNegationWrappingEval(minInt(i16));
234 comptime testSignedNegationWrappingEval(minInt(i16));
235235}
236fn testNegationWrappingEval(x: i16) void {
236fn testSignedNegationWrappingEval(x: i16) void {
237237 expect(x == -32768);
238238 const neg = -%x;
239239 expect(neg == -32768);
240240}
241241
242test "unsigned negation wrapping" {
243 testUnsignedNegationWrappingEval(1);
244 comptime testUnsignedNegationWrappingEval(1);
245}
246fn testUnsignedNegationWrappingEval(x: u16) void {
247 expect(x == 1);
248 const neg = -%x;
249 expect(neg == maxInt(u16));
250}
251
242252test "unsigned 64-bit division" {
243253 test_u64_div();
244254 comptime test_u64_div();
......@@ -843,3 +853,20 @@ test "compare undefined literal with comptime_int" {
843853 x = true;
844854 expect(x);
845855}
856
857test "signed zeros are represented properly" {
858 const S = struct {
859 fn doTheTest() void {
860 inline for ([_]type{ f16, f32, f64, f128 }) |T| {
861 const ST = std.meta.Int(.unsigned, @typeInfo(T).Float.bits);
862 var as_fp_val = -@as(T, 0.0);
863 var as_uint_val = @bitCast(ST, as_fp_val);
864 // Ensure the sign bit is set.
865 expect(as_uint_val >> (@typeInfo(T).Float.bits - 1) == 1);
866 }
867 }
868 };
869
870 S.doTheTest();
871 comptime S.doTheTest();
872}
test/tests.zig+16
......@@ -212,6 +212,22 @@ const test_targets = blk: {
212212 // .link_libc = true,
213213 //},
214214
215 TestTarget{
216 .target = .{
217 .cpu_arch = .powerpc,
218 .os_tag = .linux,
219 .abi = .none,
220 },
221 },
222 TestTarget{
223 .target = .{
224 .cpu_arch = .powerpc,
225 .os_tag = .linux,
226 .abi = .musl,
227 },
228 .link_libc = true,
229 },
230
215231 TestTarget{
216232 .target = .{
217233 .cpu_arch = .riscv64,
test/translate_c.zig+20-4
......@@ -3,6 +3,22 @@ const std = @import("std");
33const CrossTarget = std.zig.CrossTarget;
44
55pub fn addCases(cases: *tests.TranslateCContext) void {
6 cases.add("field access is grouped if necessary",
7 \\unsigned long foo(unsigned long x) {
8 \\ return ((union{unsigned long _x}){x})._x;
9 \\}
10 , &[_][]const u8{
11 \\pub export fn foo(arg_x: c_ulong) c_ulong {
12 \\ var x = arg_x;
13 \\ const union_unnamed_1 = extern union {
14 \\ _x: c_ulong,
15 \\ };
16 \\ return (union_unnamed_1{
17 \\ ._x = x,
18 \\ })._x;
19 \\}
20 });
21
622 cases.add("unnamed child types of typedef receive typedef's name",
723 \\typedef enum {
824 \\ FooA,
......@@ -111,7 +127,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
111127 \\ const A = @enumToInt(enum_Foo.A);
112128 \\ const B = @enumToInt(enum_Foo.B);
113129 \\ const C = @enumToInt(enum_Foo.C);
114 \\ var a: enum_Foo = @intToEnum(enum_Foo, B);
130 \\ var a: enum_Foo = @import("std").meta.cast(enum_Foo, B);
115131 \\ {
116132 \\ const enum_Foo = extern enum(c_int) {
117133 \\ A,
......@@ -122,7 +138,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
122138 \\ const A_2 = @enumToInt(enum_Foo.A);
123139 \\ const B_3 = @enumToInt(enum_Foo.B);
124140 \\ const C_4 = @enumToInt(enum_Foo.C);
125 \\ var a_5: enum_Foo = @intToEnum(enum_Foo, B_3);
141 \\ var a_5: enum_Foo = @import("std").meta.cast(enum_Foo, B_3);
126142 \\ }
127143 \\}
128144 });
......@@ -1676,7 +1692,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
16761692 \\pub const e = @enumToInt(enum_unnamed_1.e);
16771693 \\pub const f = @enumToInt(enum_unnamed_1.f);
16781694 \\pub const g = @enumToInt(enum_unnamed_1.g);
1679 \\pub export var h: enum_unnamed_1 = @intToEnum(enum_unnamed_1, e);
1695 \\pub export var h: enum_unnamed_1 = @import("std").meta.cast(enum_unnamed_1, e);
16801696 \\const enum_unnamed_2 = extern enum(c_int) {
16811697 \\ i,
16821698 \\ j,
......@@ -2308,7 +2324,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
23082324 \\ var a = arg_a;
23092325 \\ var b = arg_b;
23102326 \\ var c = arg_c;
2311 \\ var d: enum_Foo = @intToEnum(enum_Foo, FooA);
2327 \\ var d: enum_Foo = @import("std").meta.cast(enum_Foo, FooA);
23122328 \\ var e: c_int = @boolToInt((a != 0) and (b != 0));
23132329 \\ var f: c_int = @boolToInt((b != 0) and (c != null));
23142330 \\ var g: c_int = @boolToInt((a != 0) and (c != null));
tools/update_cpu_features.zig+6
......@@ -663,6 +663,12 @@ const llvm_targets = [_]LlvmTarget{
663663 .zig_name = "powerpc",
664664 .llvm_name = "PowerPC",
665665 .td_name = "PPC.td",
666 .feature_overrides = &.{
667 .{
668 .llvm_name = "ppc32",
669 .omit = true,
670 },
671 },
666672 },
667673 .{
668674 .zig_name = "riscv",