| author | |
| committer | |
| log | e86cee258cb0eefca14a94f6b3abb39e8a5f2ef9 |
| tree | 6d9aa3b21685b1581787246f953db94cdb486693 |
| parent | 224fbb23c44628b215662c6199dff11cc2851f04 |
| parent | 8530b6b7242ebf43b5cb4ae3a2644593f4961a5e |
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 @@ |
| 3 | 3 | langref.html.in text eol=lf |
| 4 | 4 | deps/SoftFloat-3e/*.txt text eol=crlf |
| 5 | 5 | |
| 6 | deps/* linguist-vendored | |
| 7 | lib/include/* linguist-vendored | |
| 8 | lib/libc/* linguist-vendored | |
| 9 | lib/libcxx/* linguist-vendored | |
| 10 | lib/libcxxabi/* linguist-vendored | |
| 11 | lib/libunwind/* linguist-vendored | |
| 6 | deps/** linguist-vendored | |
| 7 | lib/include/** linguist-vendored | |
| 8 | lib/libc/** linguist-vendored | |
| 9 | lib/libcxx/** linguist-vendored | |
| 10 | lib/libcxxabi/** linguist-vendored | |
| 11 | lib/libunwind/** linguist-vendored |
build.zig+1| ... | ... | @@ -267,6 +267,7 @@ pub fn build(b: *Builder) !void { |
| 267 | 267 | 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)); |
| 268 | 268 | |
| 269 | 269 | 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)); | |
| 270 | 271 | |
| 271 | 272 | test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes)); |
| 272 | 273 | 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 |
| 23 | 23 | |
| 24 | 24 | samu install |
| 25 | 25 | # 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 | |
| 27 | 26 | ./zig build test \ |
| 28 | 27 | -Dskip-release \ |
| 29 | 28 | -Dskip-non-native \ |
| 30 | 29 | -Dskip-compile-errors \ |
| 31 | -Dskip-run-translated-c \ | |
| 32 | -Dskip-stage2-tests | |
| 30 | -Dskip-run-translated-c | |
| 33 | 31 | |
| 34 | 32 | if [ -z "$DRONE_PULL_REQUEST" ]; then |
| 35 | 33 | mv ../LICENSE "$DISTDIR/" |
doc/langref.html.in+15-7| ... | ... | @@ -6509,7 +6509,7 @@ test "suspend with no resume" { |
| 6509 | 6509 | |
| 6510 | 6510 | fn func() void { |
| 6511 | 6511 | x += 1; |
| 6512 | suspend; | |
| 6512 | suspend {} | |
| 6513 | 6513 | // This line is never reached because the suspend has no matching resume. |
| 6514 | 6514 | x += 1; |
| 6515 | 6515 | } |
| ... | ... | @@ -6574,7 +6574,7 @@ fn testResumeFromSuspend(my_result: *i32) void { |
| 6574 | 6574 | resume @frame(); |
| 6575 | 6575 | } |
| 6576 | 6576 | my_result.* += 1; |
| 6577 | suspend; | |
| 6577 | suspend {} | |
| 6578 | 6578 | my_result.* += 1; |
| 6579 | 6579 | } |
| 6580 | 6580 | {#code_end#} |
| ... | ... | @@ -6613,7 +6613,7 @@ fn amain() void { |
| 6613 | 6613 | } |
| 6614 | 6614 | |
| 6615 | 6615 | fn func() void { |
| 6616 | suspend; | |
| 6616 | suspend {} | |
| 6617 | 6617 | } |
| 6618 | 6618 | {#code_end#} |
| 6619 | 6619 | <p> |
| ... | ... | @@ -6915,7 +6915,7 @@ test "async fn pointer in a struct field" { |
| 6915 | 6915 | fn func(y: *i32) void { |
| 6916 | 6916 | defer y.* += 2; |
| 6917 | 6917 | y.* += 1; |
| 6918 | suspend; | |
| 6918 | suspend {} | |
| 6919 | 6919 | } |
| 6920 | 6920 | {#code_end#} |
| 6921 | 6921 | {#header_close#} |
| ... | ... | @@ -7498,13 +7498,13 @@ test "main" { |
| 7498 | 7498 | {#header_close#} |
| 7499 | 7499 | |
| 7500 | 7500 | {#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> | |
| 7502 | 7502 | <p> |
| 7503 | 7503 | Creates a symbol in the output object file. |
| 7504 | 7504 | </p> |
| 7505 | 7505 | <p> |
| 7506 | 7506 | 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 | |
| 7508 | 7508 | {#syntax#}options.linkage{#endsyntax#} is {#syntax#}Strong{#endsyntax#}, this is equivalent to |
| 7509 | 7509 | the {#syntax#}export{#endsyntax#} keyword used on a function: |
| 7510 | 7510 | </p> |
| ... | ... | @@ -7531,6 +7531,14 @@ export fn @"A function name that is a complete sentence."() void {} |
| 7531 | 7531 | {#see_also|Exporting a C Library#} |
| 7532 | 7532 | {#header_close#} |
| 7533 | 7533 | |
| 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 | ||
| 7534 | 7542 | {#header_open|@fence#} |
| 7535 | 7543 | <pre>{#syntax#}@fence(order: AtomicOrder){#endsyntax#}</pre> |
| 7536 | 7544 | <p> |
| ... | ... | @@ -7640,7 +7648,7 @@ test "heap allocated frame" { |
| 7640 | 7648 | } |
| 7641 | 7649 | |
| 7642 | 7650 | fn func() void { |
| 7643 | suspend; | |
| 7651 | suspend {} | |
| 7644 | 7652 | } |
| 7645 | 7653 | {#code_end#} |
| 7646 | 7654 | {#header_close#} |
lib/std/atomic/bool.zig+1-1| ... | ... | @@ -28,7 +28,7 @@ pub const Bool = extern struct { |
| 28 | 28 | return @atomicRmw(bool, &self.unprotected_value, .Xchg, operand, ordering); |
| 29 | 29 | } |
| 30 | 30 | |
| 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 { | |
| 32 | 32 | switch (ordering) { |
| 33 | 33 | .Unordered, .Monotonic, .Acquire, .SeqCst => {}, |
| 34 | 34 | 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 { |
| 31 | 31 | return @atomicRmw(T, &self.unprotected_value, op, operand, ordering); |
| 32 | 32 | } |
| 33 | 33 | |
| 34 | pub fn load(self: *Self, comptime ordering: builtin.AtomicOrder) T { | |
| 34 | pub fn load(self: *const Self, comptime ordering: builtin.AtomicOrder) T { | |
| 35 | 35 | switch (ordering) { |
| 36 | 36 | .Unordered, .Monotonic, .Acquire, .SeqCst => {}, |
| 37 | 37 | else => @compileError("Invalid ordering '" ++ @tagName(ordering) ++ "' for a load operation"), |
| ... | ... | @@ -59,7 +59,7 @@ pub fn Int(comptime T: type) type { |
| 59 | 59 | return self.rmw(.Sub, 1, .SeqCst); |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | pub fn get(self: *Self) T { | |
| 62 | pub fn get(self: *const Self) T { | |
| 63 | 63 | return self.load(.SeqCst); |
| 64 | 64 | } |
| 65 | 65 |
lib/std/build.zig+5| ... | ... | @@ -1386,6 +1386,8 @@ pub const LibExeObjStep = struct { |
| 1386 | 1386 | /// safely garbage-collected during the linking phase. |
| 1387 | 1387 | link_function_sections: bool = false, |
| 1388 | 1388 | |
| 1389 | linker_allow_shlib_undefined: ?bool = null, | |
| 1390 | ||
| 1389 | 1391 | /// Uses system Wine installation to run cross compiled Windows build artifacts. |
| 1390 | 1392 | enable_wine: bool = false, |
| 1391 | 1393 | |
| ... | ... | @@ -2338,6 +2340,9 @@ pub const LibExeObjStep = struct { |
| 2338 | 2340 | if (self.link_function_sections) { |
| 2339 | 2341 | try zig_args.append("-ffunction-sections"); |
| 2340 | 2342 | } |
| 2343 | if (self.linker_allow_shlib_undefined) |x| { | |
| 2344 | try zig_args.append(if (x) "-fallow-shlib-undefined" else "-fno-allow-shlib-undefined"); | |
| 2345 | } | |
| 2341 | 2346 | if (self.single_threaded) { |
| 2342 | 2347 | try zig_args.append("--single-threaded"); |
| 2343 | 2348 | } |
lib/std/crypto.zig+1-1| ... | ... | @@ -154,7 +154,7 @@ pub const random = &@import("crypto/tlcsprng.zig").interface; |
| 154 | 154 | |
| 155 | 155 | const std = @import("std.zig"); |
| 156 | 156 | |
| 157 | pub const Error = @import("crypto/error.zig").Error; | |
| 157 | pub const errors = @import("crypto/errors.zig"); | |
| 158 | 158 | |
| 159 | 159 | test "crypto" { |
| 160 | 160 | const please_windows_dont_oom = std.Target.current.os.tag == .windows; |
lib/std/crypto/25519/curve25519.zig+12-8| ... | ... | @@ -4,7 +4,11 @@ |
| 4 | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | 5 | // and substantial portions of the software. |
| 6 | 6 | const std = @import("std"); |
| 7 | const Error = std.crypto.Error; | |
| 7 | const crypto = std.crypto; | |
| 8 | ||
| 9 | const IdentityElementError = crypto.errors.IdentityElementError; | |
| 10 | const NonCanonicalError = crypto.errors.NonCanonicalError; | |
| 11 | const WeakPublicKeyError = crypto.errors.WeakPublicKeyError; | |
| 8 | 12 | |
| 9 | 13 | /// Group operations over Curve25519. |
| 10 | 14 | pub const Curve25519 = struct { |
| ... | ... | @@ -29,12 +33,12 @@ pub const Curve25519 = struct { |
| 29 | 33 | pub const basePoint = Curve25519{ .x = Fe.curve25519BasePoint }; |
| 30 | 34 | |
| 31 | 35 | /// 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 { | |
| 33 | 37 | return Fe.rejectNonCanonical(s, false); |
| 34 | 38 | } |
| 35 | 39 | |
| 36 | 40 | /// Reject the neutral element. |
| 37 | pub fn rejectIdentity(p: Curve25519) Error!void { | |
| 41 | pub fn rejectIdentity(p: Curve25519) IdentityElementError!void { | |
| 38 | 42 | if (p.x.isZero()) { |
| 39 | 43 | return error.IdentityElement; |
| 40 | 44 | } |
| ... | ... | @@ -45,7 +49,7 @@ pub const Curve25519 = struct { |
| 45 | 49 | return p.dbl().dbl().dbl(); |
| 46 | 50 | } |
| 47 | 51 | |
| 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 { | |
| 49 | 53 | var x1 = p.x; |
| 50 | 54 | var x2 = Fe.one; |
| 51 | 55 | var z2 = Fe.zero; |
| ... | ... | @@ -86,7 +90,7 @@ pub const Curve25519 = struct { |
| 86 | 90 | /// way to use Curve25519 for a DH operation. |
| 87 | 91 | /// Return error.IdentityElement if the resulting point is |
| 88 | 92 | /// 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 { | |
| 90 | 94 | var t: [32]u8 = s; |
| 91 | 95 | scalar.clamp(&t); |
| 92 | 96 | return try ladder(p, t, 255); |
| ... | ... | @@ -96,16 +100,16 @@ pub const Curve25519 = struct { |
| 96 | 100 | /// Return error.IdentityElement if the resulting point is |
| 97 | 101 | /// the identity element or error.WeakPublicKey if the public |
| 98 | 102 | /// 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 { | |
| 100 | 104 | const cofactor = [_]u8{8} ++ [_]u8{0} ** 31; |
| 101 | 105 | _ = ladder(p, cofactor, 4) catch return error.WeakPublicKey; |
| 102 | 106 | return try ladder(p, s, 256); |
| 103 | 107 | } |
| 104 | 108 | |
| 105 | 109 | /// 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 { | |
| 107 | 111 | try p.clearCofactor().rejectIdentity(); |
| 108 | const one = std.crypto.ecc.Edwards25519.Fe.one; | |
| 112 | const one = crypto.ecc.Edwards25519.Fe.one; | |
| 109 | 113 | const x = one.add(p.y).mul(one.sub(p.y).invert()); // xMont=(1+yEd)/(1-yEd) |
| 110 | 114 | return Curve25519{ .x = x }; |
| 111 | 115 | } |
lib/std/crypto/25519/ed25519.zig+21-13| ... | ... | @@ -8,8 +8,15 @@ const crypto = std.crypto; |
| 8 | 8 | const debug = std.debug; |
| 9 | 9 | const fmt = std.fmt; |
| 10 | 10 | const mem = std.mem; |
| 11 | ||
| 11 | 12 | const Sha512 = crypto.hash.sha2.Sha512; |
| 12 | const Error = crypto.Error; | |
| 13 | ||
| 14 | const EncodingError = crypto.errors.EncodingError; | |
| 15 | const IdentityElementError = crypto.errors.IdentityElementError; | |
| 16 | const NonCanonicalError = crypto.errors.NonCanonicalError; | |
| 17 | const SignatureVerificationError = crypto.errors.SignatureVerificationError; | |
| 18 | const KeyMismatchError = crypto.errors.KeyMismatchError; | |
| 19 | const WeakPublicKeyError = crypto.errors.WeakPublicKeyError; | |
| 13 | 20 | |
| 14 | 21 | /// Ed25519 (EdDSA) signatures. |
| 15 | 22 | pub const Ed25519 = struct { |
| ... | ... | @@ -41,7 +48,7 @@ pub const Ed25519 = struct { |
| 41 | 48 | /// |
| 42 | 49 | /// For this reason, an EdDSA secret key is commonly called a seed, |
| 43 | 50 | /// 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 { | |
| 45 | 52 | const ss = seed orelse ss: { |
| 46 | 53 | var random_seed: [seed_length]u8 = undefined; |
| 47 | 54 | crypto.random.bytes(&random_seed); |
| ... | ... | @@ -51,7 +58,7 @@ pub const Ed25519 = struct { |
| 51 | 58 | var h = Sha512.init(.{}); |
| 52 | 59 | h.update(&ss); |
| 53 | 60 | 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; | |
| 55 | 62 | var sk: [secret_length]u8 = undefined; |
| 56 | 63 | mem.copy(u8, &sk, &ss); |
| 57 | 64 | const pk = p.toBytes(); |
| ... | ... | @@ -72,7 +79,7 @@ pub const Ed25519 = struct { |
| 72 | 79 | /// Sign a message using a key pair, and optional random noise. |
| 73 | 80 | /// Having noise creates non-standard, non-deterministic signatures, |
| 74 | 81 | /// 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 { | |
| 76 | 83 | const seed = key_pair.secret_key[0..seed_length]; |
| 77 | 84 | const public_key = key_pair.secret_key[seed_length..]; |
| 78 | 85 | if (!mem.eql(u8, public_key, &key_pair.public_key)) { |
| ... | ... | @@ -113,7 +120,7 @@ pub const Ed25519 = struct { |
| 113 | 120 | |
| 114 | 121 | /// Verify an Ed25519 signature given a message and a public key. |
| 115 | 122 | /// 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 { | |
| 117 | 124 | const r = sig[0..32]; |
| 118 | 125 | const s = sig[32..64]; |
| 119 | 126 | try Curve.scalar.rejectNonCanonical(s.*); |
| ... | ... | @@ -122,6 +129,7 @@ pub const Ed25519 = struct { |
| 122 | 129 | try a.rejectIdentity(); |
| 123 | 130 | try Curve.rejectNonCanonical(r.*); |
| 124 | 131 | const expected_r = try Curve.fromBytes(r.*); |
| 132 | try expected_r.rejectIdentity(); | |
| 125 | 133 | |
| 126 | 134 | var h = Sha512.init(.{}); |
| 127 | 135 | h.update(r); |
| ... | ... | @@ -131,8 +139,7 @@ pub const Ed25519 = struct { |
| 131 | 139 | h.final(&hram64); |
| 132 | 140 | const hram = Curve.scalar.reduce64(hram64); |
| 133 | 141 | |
| 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); | |
| 136 | 143 | if (expected_r.sub(sb_ah).clearCofactor().rejectIdentity()) |_| { |
| 137 | 144 | return error.SignatureVerificationFailed; |
| 138 | 145 | } else |_| {} |
| ... | ... | @@ -146,7 +153,7 @@ pub const Ed25519 = struct { |
| 146 | 153 | }; |
| 147 | 154 | |
| 148 | 155 | /// 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 { | |
| 150 | 157 | var r_batch: [count][32]u8 = undefined; |
| 151 | 158 | var s_batch: [count][32]u8 = undefined; |
| 152 | 159 | var a_batch: [count]Curve = undefined; |
| ... | ... | @@ -161,6 +168,7 @@ pub const Ed25519 = struct { |
| 161 | 168 | try a.rejectIdentity(); |
| 162 | 169 | try Curve.rejectNonCanonical(r.*); |
| 163 | 170 | const expected_r = try Curve.fromBytes(r.*); |
| 171 | try expected_r.rejectIdentity(); | |
| 164 | 172 | expected_r_batch[i] = expected_r; |
| 165 | 173 | r_batch[i] = r.*; |
| 166 | 174 | s_batch[i] = s.*; |
| ... | ... | @@ -180,7 +188,7 @@ pub const Ed25519 = struct { |
| 180 | 188 | |
| 181 | 189 | var z_batch: [count]Curve.scalar.CompressedScalar = undefined; |
| 182 | 190 | for (z_batch) |*z| { |
| 183 | std.crypto.random.bytes(z[0..16]); | |
| 191 | crypto.random.bytes(z[0..16]); | |
| 184 | 192 | mem.set(u8, z[16..], 0); |
| 185 | 193 | } |
| 186 | 194 | |
| ... | ... | @@ -233,8 +241,8 @@ test "ed25519 batch verification" { |
| 233 | 241 | const key_pair = try Ed25519.KeyPair.create(null); |
| 234 | 242 | var msg1: [32]u8 = undefined; |
| 235 | 243 | 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); | |
| 238 | 246 | const sig1 = try Ed25519.sign(&msg1, key_pair, null); |
| 239 | 247 | const sig2 = try Ed25519.sign(&msg2, key_pair, null); |
| 240 | 248 | var signature_batch = [_]Ed25519.BatchElement{ |
| ... | ... | @@ -317,13 +325,13 @@ test "ed25519 test vectors" { |
| 317 | 325 | .msg_hex = "9bedc267423725d473888631ebf45988bad3db83851ee85c85e241a07d148b41", |
| 318 | 326 | .public_key_hex = "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43", |
| 319 | 327 | .sig_hex = "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03be9678ac102edcd92b0210bb34d7428d12ffc5df5f37e359941266a4e35f0f", |
| 320 | .expected = error.SignatureVerificationFailed, // 8 - non-canonical R | |
| 328 | .expected = error.IdentityElement, // 8 - non-canonical R | |
| 321 | 329 | }, |
| 322 | 330 | Vec{ |
| 323 | 331 | .msg_hex = "9bedc267423725d473888631ebf45988bad3db83851ee85c85e241a07d148b41", |
| 324 | 332 | .public_key_hex = "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43", |
| 325 | 333 | .sig_hex = "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffca8c5b64cd208982aa38d4936621a4775aa233aa0505711d8fdcfdaa943d4908", |
| 326 | .expected = null, // 9 - non-canonical R | |
| 334 | .expected = error.IdentityElement, // 9 - non-canonical R | |
| 327 | 335 | }, |
| 328 | 336 | Vec{ |
| 329 | 337 | .msg_hex = "e96b7021eb39c1a163b6da4e3093dcd3f21387da4cc4572be588fafae23c155b", |
lib/std/crypto/25519/edwards25519.zig+65-18| ... | ... | @@ -4,10 +4,16 @@ |
| 4 | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | 5 | // and substantial portions of the software. |
| 6 | 6 | const std = @import("std"); |
| 7 | const crypto = std.crypto; | |
| 7 | 8 | const debug = std.debug; |
| 8 | 9 | const fmt = std.fmt; |
| 9 | 10 | const mem = std.mem; |
| 10 | const Error = std.crypto.Error; | |
| 11 | ||
| 12 | const EncodingError = crypto.errors.EncodingError; | |
| 13 | const IdentityElementError = crypto.errors.IdentityElementError; | |
| 14 | const NonCanonicalError = crypto.errors.NonCanonicalError; | |
| 15 | const NotSquareError = crypto.errors.NotSquareError; | |
| 16 | const WeakPublicKeyError = crypto.errors.WeakPublicKeyError; | |
| 11 | 17 | |
| 12 | 18 | /// Group operations over Edwards25519. |
| 13 | 19 | pub const Edwards25519 = struct { |
| ... | ... | @@ -26,7 +32,7 @@ pub const Edwards25519 = struct { |
| 26 | 32 | is_base: bool = false, |
| 27 | 33 | |
| 28 | 34 | /// 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 { | |
| 30 | 36 | const z = Fe.one; |
| 31 | 37 | const y = Fe.fromBytes(s); |
| 32 | 38 | var u = y.sq(); |
| ... | ... | @@ -56,7 +62,7 @@ pub const Edwards25519 = struct { |
| 56 | 62 | } |
| 57 | 63 | |
| 58 | 64 | /// 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 { | |
| 60 | 66 | return Fe.rejectNonCanonical(s, true); |
| 61 | 67 | } |
| 62 | 68 | |
| ... | ... | @@ -81,7 +87,7 @@ pub const Edwards25519 = struct { |
| 81 | 87 | const identityElement = Edwards25519{ .x = Fe.zero, .y = Fe.one, .z = Fe.one, .t = Fe.zero }; |
| 82 | 88 | |
| 83 | 89 | /// Reject the neutral element. |
| 84 | pub fn rejectIdentity(p: Edwards25519) Error!void { | |
| 90 | pub fn rejectIdentity(p: Edwards25519) IdentityElementError!void { | |
| 85 | 91 | if (p.x.isZero()) { |
| 86 | 92 | return error.IdentityElement; |
| 87 | 93 | } |
| ... | ... | @@ -177,7 +183,7 @@ pub const Edwards25519 = struct { |
| 177 | 183 | // Based on real-world benchmarks, we only use this for multi-scalar multiplication. |
| 178 | 184 | // NAF could be useful to half the size of precomputation tables, but we intentionally |
| 179 | 185 | // 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 { | |
| 181 | 187 | std.debug.assert(vartime); |
| 182 | 188 | const e = nonAdjacentForm(s); |
| 183 | 189 | var q = Edwards25519.identityElement; |
| ... | ... | @@ -197,7 +203,7 @@ pub const Edwards25519 = struct { |
| 197 | 203 | } |
| 198 | 204 | |
| 199 | 205 | // 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 { | |
| 201 | 207 | var q = Edwards25519.identityElement; |
| 202 | 208 | var pos: usize = 252; |
| 203 | 209 | while (true) : (pos -= 4) { |
| ... | ... | @@ -232,10 +238,15 @@ pub const Edwards25519 = struct { |
| 232 | 238 | break :pc precompute(Edwards25519.basePoint, 15); |
| 233 | 239 | }; |
| 234 | 240 | |
| 241 | const basePointPc8 = comptime pc: { | |
| 242 | @setEvalBranchQuota(10000); | |
| 243 | break :pc precompute(Edwards25519.basePoint, 8); | |
| 244 | }; | |
| 245 | ||
| 235 | 246 | /// 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 { | |
| 239 | 250 | const pc = if (p.is_base) basePointPc else pc: { |
| 240 | 251 | const xpc = precompute(p, 15); |
| 241 | 252 | xpc[4].rejectIdentity() catch return error.WeakPublicKey; |
| ... | ... | @@ -246,7 +257,7 @@ pub const Edwards25519 = struct { |
| 246 | 257 | |
| 247 | 258 | /// Multiply an Edwards25519 point by a *PUBLIC* scalar *IN VARIABLE TIME* |
| 248 | 259 | /// 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 { | |
| 250 | 261 | if (p.is_base) { |
| 251 | 262 | return pcMul16(basePointPc, s, true); |
| 252 | 263 | } else { |
| ... | ... | @@ -256,14 +267,50 @@ pub const Edwards25519 = struct { |
| 256 | 267 | } |
| 257 | 268 | } |
| 258 | 269 | |
| 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 | ||
| 259 | 307 | /// Multiscalar multiplication *IN VARIABLE TIME* for public data |
| 260 | 308 | /// 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 { | |
| 262 | 310 | var pcs: [count][9]Edwards25519 = undefined; |
| 263 | 311 | for (ps) |p, i| { |
| 264 | 312 | if (p.is_base) { |
| 265 | @setEvalBranchQuota(10000); | |
| 266 | pcs[i] = comptime precompute(Edwards25519.basePoint, 8); | |
| 313 | pcs[i] = basePointPc8; | |
| 267 | 314 | } else { |
| 268 | 315 | pcs[i] = precompute(p, 8); |
| 269 | 316 | pcs[i][4].rejectIdentity() catch return error.WeakPublicKey; |
| ... | ... | @@ -297,14 +344,14 @@ pub const Edwards25519 = struct { |
| 297 | 344 | /// This is strongly recommended for DH operations. |
| 298 | 345 | /// Return error.WeakPublicKey if the resulting point is |
| 299 | 346 | /// 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 { | |
| 301 | 348 | var t: [32]u8 = s; |
| 302 | 349 | scalar.clamp(&t); |
| 303 | 350 | return mul(p, t); |
| 304 | 351 | } |
| 305 | 352 | |
| 306 | 353 | // montgomery -- recover y = sqrt(x^3 + A*x^2 + x) |
| 307 | fn xmontToYmont(x: Fe) Error!Fe { | |
| 354 | fn xmontToYmont(x: Fe) NotSquareError!Fe { | |
| 308 | 355 | var x2 = x.sq(); |
| 309 | 356 | const x3 = x.mul(x2); |
| 310 | 357 | x2 = x2.mul32(Fe.edwards25519a_32); |
| ... | ... | @@ -367,7 +414,7 @@ pub const Edwards25519 = struct { |
| 367 | 414 | |
| 368 | 415 | fn stringToPoints(comptime n: usize, ctx: []const u8, s: []const u8) [n]Edwards25519 { |
| 369 | 416 | debug.assert(n <= 2); |
| 370 | const H = std.crypto.hash.sha2.Sha512; | |
| 417 | const H = crypto.hash.sha2.Sha512; | |
| 371 | 418 | const h_l: usize = 48; |
| 372 | 419 | var xctx = ctx; |
| 373 | 420 | var hctx: [H.digest_length]u8 = undefined; |
| ... | ... | @@ -485,8 +532,8 @@ test "edwards25519 packing/unpacking" { |
| 485 | 532 | test "edwards25519 point addition/substraction" { |
| 486 | 533 | var s1: [32]u8 = undefined; |
| 487 | 534 | 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); | |
| 490 | 537 | const p = try Edwards25519.basePoint.clampedMul(s1); |
| 491 | 538 | const q = try Edwards25519.basePoint.clampedMul(s2); |
| 492 | 539 | const r = p.add(q).add(q).sub(q).sub(q); |
lib/std/crypto/25519/field.zig+6-3| ... | ... | @@ -4,9 +4,12 @@ |
| 4 | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | 5 | // and substantial portions of the software. |
| 6 | 6 | const std = @import("std"); |
| 7 | const crypto = std.crypto; | |
| 7 | 8 | const readIntLittle = std.mem.readIntLittle; |
| 8 | 9 | const writeIntLittle = std.mem.writeIntLittle; |
| 9 | const Error = std.crypto.Error; | |
| 10 | ||
| 11 | const NonCanonicalError = crypto.errors.NonCanonicalError; | |
| 12 | const NotSquareError = crypto.errors.NotSquareError; | |
| 10 | 13 | |
| 11 | 14 | pub const Fe = struct { |
| 12 | 15 | limbs: [5]u64, |
| ... | ... | @@ -113,7 +116,7 @@ pub const Fe = struct { |
| 113 | 116 | } |
| 114 | 117 | |
| 115 | 118 | /// 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 { | |
| 117 | 120 | var c: u16 = (s[31] & 0x7f) ^ 0x7f; |
| 118 | 121 | comptime var i = 30; |
| 119 | 122 | inline while (i > 0) : (i -= 1) { |
| ... | ... | @@ -413,7 +416,7 @@ pub const Fe = struct { |
| 413 | 416 | } |
| 414 | 417 | |
| 415 | 418 | /// 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 { | |
| 417 | 420 | var x2_copy = x2; |
| 418 | 421 | const x = x2.uncheckedSqrt(); |
| 419 | 422 | const check = x.sq().sub(x2_copy); |
lib/std/crypto/25519/ristretto255.zig+9-5| ... | ... | @@ -5,7 +5,11 @@ |
| 5 | 5 | // and substantial portions of the software. |
| 6 | 6 | const std = @import("std"); |
| 7 | 7 | const fmt = std.fmt; |
| 8 | const Error = std.crypto.Error; | |
| 8 | ||
| 9 | const EncodingError = std.crypto.errors.EncodingError; | |
| 10 | const IdentityElementError = std.crypto.errors.IdentityElementError; | |
| 11 | const NonCanonicalError = std.crypto.errors.NonCanonicalError; | |
| 12 | const WeakPublicKeyError = std.crypto.errors.WeakPublicKeyError; | |
| 9 | 13 | |
| 10 | 14 | /// Group operations over Edwards25519. |
| 11 | 15 | pub const Ristretto255 = struct { |
| ... | ... | @@ -35,7 +39,7 @@ pub const Ristretto255 = struct { |
| 35 | 39 | return .{ .ratio_is_square = @boolToInt(has_m_root) | @boolToInt(has_p_root), .root = x.abs() }; |
| 36 | 40 | } |
| 37 | 41 | |
| 38 | fn rejectNonCanonical(s: [encoded_length]u8) Error!void { | |
| 42 | fn rejectNonCanonical(s: [encoded_length]u8) NonCanonicalError!void { | |
| 39 | 43 | if ((s[0] & 1) != 0) { |
| 40 | 44 | return error.NonCanonical; |
| 41 | 45 | } |
| ... | ... | @@ -43,7 +47,7 @@ pub const Ristretto255 = struct { |
| 43 | 47 | } |
| 44 | 48 | |
| 45 | 49 | /// Reject the neutral element. |
| 46 | pub fn rejectIdentity(p: Ristretto255) callconv(.Inline) Error!void { | |
| 50 | pub fn rejectIdentity(p: Ristretto255) callconv(.Inline) IdentityElementError!void { | |
| 47 | 51 | return p.p.rejectIdentity(); |
| 48 | 52 | } |
| 49 | 53 | |
| ... | ... | @@ -51,7 +55,7 @@ pub const Ristretto255 = struct { |
| 51 | 55 | pub const basePoint = Ristretto255{ .p = Curve.basePoint }; |
| 52 | 56 | |
| 53 | 57 | /// 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 { | |
| 55 | 59 | try rejectNonCanonical(s); |
| 56 | 60 | const s_ = Fe.fromBytes(s); |
| 57 | 61 | const ss = s_.sq(); // s^2 |
| ... | ... | @@ -154,7 +158,7 @@ pub const Ristretto255 = struct { |
| 154 | 158 | /// Multiply a Ristretto255 element with a scalar. |
| 155 | 159 | /// Return error.WeakPublicKey if the resulting element is |
| 156 | 160 | /// 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 { | |
| 158 | 162 | return Ristretto255{ .p = try p.p.mul(s) }; |
| 159 | 163 | } |
| 160 | 164 |
lib/std/crypto/25519/scalar.zig+3-2| ... | ... | @@ -5,7 +5,8 @@ |
| 5 | 5 | // and substantial portions of the software. |
| 6 | 6 | const std = @import("std"); |
| 7 | 7 | const mem = std.mem; |
| 8 | const Error = std.crypto.Error; | |
| 8 | ||
| 9 | const NonCanonicalError = std.crypto.errors.NonCanonicalError; | |
| 9 | 10 | |
| 10 | 11 | /// 2^252 + 27742317777372353535851937790883648493 |
| 11 | 12 | pub const field_size = [32]u8{ |
| ... | ... | @@ -19,7 +20,7 @@ pub const CompressedScalar = [32]u8; |
| 19 | 20 | pub const zero = [_]u8{0} ** 32; |
| 20 | 21 | |
| 21 | 22 | /// Reject a scalar whose encoding is not canonical. |
| 22 | pub fn rejectNonCanonical(s: [32]u8) Error!void { | |
| 23 | pub fn rejectNonCanonical(s: [32]u8) NonCanonicalError!void { | |
| 23 | 24 | var c: u8 = 0; |
| 24 | 25 | var n: u8 = 1; |
| 25 | 26 | var i: usize = 31; |
lib/std/crypto/25519/x25519.zig+9-6| ... | ... | @@ -9,7 +9,10 @@ const mem = std.mem; |
| 9 | 9 | const fmt = std.fmt; |
| 10 | 10 | |
| 11 | 11 | const Sha512 = crypto.hash.sha2.Sha512; |
| 12 | const Error = crypto.Error; | |
| 12 | ||
| 13 | const EncodingError = crypto.errors.EncodingError; | |
| 14 | const IdentityElementError = crypto.errors.IdentityElementError; | |
| 15 | const WeakPublicKeyError = crypto.errors.WeakPublicKeyError; | |
| 13 | 16 | |
| 14 | 17 | /// X25519 DH function. |
| 15 | 18 | pub const X25519 = struct { |
| ... | ... | @@ -32,7 +35,7 @@ pub const X25519 = struct { |
| 32 | 35 | secret_key: [secret_length]u8, |
| 33 | 36 | |
| 34 | 37 | /// 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 { | |
| 36 | 39 | const sk = seed orelse sk: { |
| 37 | 40 | var random_seed: [seed_length]u8 = undefined; |
| 38 | 41 | crypto.random.bytes(&random_seed); |
| ... | ... | @@ -45,7 +48,7 @@ pub const X25519 = struct { |
| 45 | 48 | } |
| 46 | 49 | |
| 47 | 50 | /// 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 { | |
| 49 | 52 | const seed = ed25519_key_pair.secret_key[0..32]; |
| 50 | 53 | var az: [Sha512.digest_length]u8 = undefined; |
| 51 | 54 | Sha512.hash(seed, &az, .{}); |
| ... | ... | @@ -60,13 +63,13 @@ pub const X25519 = struct { |
| 60 | 63 | }; |
| 61 | 64 | |
| 62 | 65 | /// 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 { | |
| 64 | 67 | const q = try Curve.basePoint.clampedMul(secret_key); |
| 65 | 68 | return q.toBytes(); |
| 66 | 69 | } |
| 67 | 70 | |
| 68 | 71 | /// 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 { | |
| 70 | 73 | const pk_ed = try crypto.ecc.Edwards25519.fromBytes(ed25519_public_key); |
| 71 | 74 | const pk = try Curve.fromEdwards25519(pk_ed); |
| 72 | 75 | return pk.toBytes(); |
| ... | ... | @@ -75,7 +78,7 @@ pub const X25519 = struct { |
| 75 | 78 | /// Compute the scalar product of a public key and a secret scalar. |
| 76 | 79 | /// Note that the output should not be used as a shared secret without |
| 77 | 80 | /// 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 { | |
| 79 | 82 | const q = try Curve.fromBytes(public_key).clampedMul(secret_key); |
| 80 | 83 | return q.toBytes(); |
| 81 | 84 | } |
lib/std/crypto/aegis.zig+3-3| ... | ... | @@ -8,7 +8,7 @@ const std = @import("std"); |
| 8 | 8 | const mem = std.mem; |
| 9 | 9 | const assert = std.debug.assert; |
| 10 | 10 | const AesBlock = std.crypto.core.aes.Block; |
| 11 | const Error = std.crypto.Error; | |
| 11 | const AuthenticationError = std.crypto.errors.AuthenticationError; | |
| 12 | 12 | |
| 13 | 13 | const State128L = struct { |
| 14 | 14 | blocks: [8]AesBlock, |
| ... | ... | @@ -137,7 +137,7 @@ pub const Aegis128L = struct { |
| 137 | 137 | /// ad: Associated Data |
| 138 | 138 | /// npub: public nonce |
| 139 | 139 | /// 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 { | |
| 141 | 141 | assert(c.len == m.len); |
| 142 | 142 | var state = State128L.init(key, npub); |
| 143 | 143 | var src: [32]u8 align(16) = undefined; |
| ... | ... | @@ -299,7 +299,7 @@ pub const Aegis256 = struct { |
| 299 | 299 | /// ad: Associated Data |
| 300 | 300 | /// npub: public nonce |
| 301 | 301 | /// 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 { | |
| 303 | 303 | assert(c.len == m.len); |
| 304 | 304 | var state = State256.init(key, npub); |
| 305 | 305 | var src: [16]u8 align(16) = undefined; |
lib/std/crypto/aes_gcm.zig+2-2| ... | ... | @@ -12,7 +12,7 @@ const debug = std.debug; |
| 12 | 12 | const Ghash = std.crypto.onetimeauth.Ghash; |
| 13 | 13 | const mem = std.mem; |
| 14 | 14 | const modes = crypto.core.modes; |
| 15 | const Error = crypto.Error; | |
| 15 | const AuthenticationError = crypto.errors.AuthenticationError; | |
| 16 | 16 | |
| 17 | 17 | pub const Aes128Gcm = AesGcm(crypto.core.aes.Aes128); |
| 18 | 18 | pub const Aes256Gcm = AesGcm(crypto.core.aes.Aes256); |
| ... | ... | @@ -60,7 +60,7 @@ fn AesGcm(comptime Aes: anytype) type { |
| 60 | 60 | } |
| 61 | 61 | } |
| 62 | 62 | |
| 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 { | |
| 64 | 64 | assert(c.len == m.len); |
| 65 | 65 | |
| 66 | 66 | const aes = Aes.initEnc(key); |
lib/std/crypto/aes_ocb.zig+2-2| ... | ... | @@ -10,7 +10,7 @@ const aes = crypto.core.aes; |
| 10 | 10 | const assert = std.debug.assert; |
| 11 | 11 | const math = std.math; |
| 12 | 12 | const mem = std.mem; |
| 13 | const Error = crypto.Error; | |
| 13 | const AuthenticationError = crypto.errors.AuthenticationError; | |
| 14 | 14 | |
| 15 | 15 | pub const Aes128Ocb = AesOcb(aes.Aes128); |
| 16 | 16 | pub const Aes256Ocb = AesOcb(aes.Aes256); |
| ... | ... | @@ -179,7 +179,7 @@ fn AesOcb(comptime Aes: anytype) type { |
| 179 | 179 | /// ad: Associated Data |
| 180 | 180 | /// npub: public nonce |
| 181 | 181 | /// 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 { | |
| 183 | 183 | assert(c.len == m.len); |
| 184 | 184 | |
| 185 | 185 | const aes_enc_ctx = Aes.initEnc(key); |
lib/std/crypto/bcrypt.zig+6-5| ... | ... | @@ -12,7 +12,8 @@ const mem = std.mem; |
| 12 | 12 | const debug = std.debug; |
| 13 | 13 | const testing = std.testing; |
| 14 | 14 | const utils = crypto.utils; |
| 15 | const Error = crypto.Error; | |
| 15 | const EncodingError = crypto.errors.EncodingError; | |
| 16 | const PasswordVerificationError = crypto.errors.PasswordVerificationError; | |
| 16 | 17 | |
| 17 | 18 | const salt_length: usize = 16; |
| 18 | 19 | const salt_str_length: usize = 22; |
| ... | ... | @@ -179,7 +180,7 @@ const Codec = struct { |
| 179 | 180 | debug.assert(j == b64.len); |
| 180 | 181 | } |
| 181 | 182 | |
| 182 | fn decode(bin: []u8, b64: []const u8) Error!void { | |
| 183 | fn decode(bin: []u8, b64: []const u8) EncodingError!void { | |
| 183 | 184 | var i: usize = 0; |
| 184 | 185 | var j: usize = 0; |
| 185 | 186 | while (j < bin.len) { |
| ... | ... | @@ -204,7 +205,7 @@ const Codec = struct { |
| 204 | 205 | } |
| 205 | 206 | }; |
| 206 | 207 | |
| 207 | fn strHashInternal(password: []const u8, rounds_log: u6, salt: [salt_length]u8) Error![hash_length]u8 { | |
| 208 | fn strHashInternal(password: []const u8, rounds_log: u6, salt: [salt_length]u8) ![hash_length]u8 { | |
| 208 | 209 | var state = State{}; |
| 209 | 210 | var password_buf: [73]u8 = undefined; |
| 210 | 211 | 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) |
| 252 | 253 | /// IMPORTANT: by design, bcrypt silently truncates passwords to 72 bytes. |
| 253 | 254 | /// If this is an issue for your application, hash the password first using a function such as SHA-512, |
| 254 | 255 | /// and then use the resulting hash as the password parameter for bcrypt. |
| 255 | pub fn strHash(password: []const u8, rounds_log: u6) Error![hash_length]u8 { | |
| 256 | pub fn strHash(password: []const u8, rounds_log: u6) ![hash_length]u8 { | |
| 256 | 257 | var salt: [salt_length]u8 = undefined; |
| 257 | 258 | crypto.random.bytes(&salt); |
| 258 | 259 | return strHashInternal(password, rounds_log, salt); |
| 259 | 260 | } |
| 260 | 261 | |
| 261 | 262 | /// Verify that a previously computed hash is valid for a given password. |
| 262 | pub fn strVerify(h: [hash_length]u8, password: []const u8) Error!void { | |
| 263 | pub fn strVerify(h: [hash_length]u8, password: []const u8) (EncodingError || PasswordVerificationError)!void { | |
| 263 | 264 | if (!mem.eql(u8, "$2", h[0..2])) return error.InvalidEncoding; |
| 264 | 265 | if (h[3] != '$' or h[6] != '$') return error.InvalidEncoding; |
| 265 | 266 | const rounds_log_str = h[4..][0..2]; |
lib/std/crypto/chacha20.zig+3-3| ... | ... | @@ -13,7 +13,7 @@ const testing = std.testing; |
| 13 | 13 | const maxInt = math.maxInt; |
| 14 | 14 | const Vector = std.meta.Vector; |
| 15 | 15 | const Poly1305 = std.crypto.onetimeauth.Poly1305; |
| 16 | const Error = std.crypto.Error; | |
| 16 | const AuthenticationError = std.crypto.errors.AuthenticationError; | |
| 17 | 17 | |
| 18 | 18 | /// IETF-variant of the ChaCha20 stream cipher, as designed for TLS. |
| 19 | 19 | pub const ChaCha20IETF = ChaChaIETF(20); |
| ... | ... | @@ -521,7 +521,7 @@ fn ChaChaPoly1305(comptime rounds_nb: usize) type { |
| 521 | 521 | /// npub: public nonce |
| 522 | 522 | /// k: private key |
| 523 | 523 | /// 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 { | |
| 525 | 525 | assert(c.len == m.len); |
| 526 | 526 | |
| 527 | 527 | var polyKey = [_]u8{0} ** 32; |
| ... | ... | @@ -583,7 +583,7 @@ fn XChaChaPoly1305(comptime rounds_nb: usize) type { |
| 583 | 583 | /// ad: Associated Data |
| 584 | 584 | /// npub: public nonce |
| 585 | 585 | /// 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 { | |
| 587 | 587 | const extended = extend(k, npub, rounds_nb); |
| 588 | 588 | return ChaChaPoly1305(rounds_nb).decrypt(m, c, tag, ad, extended.nonce, extended.key); |
| 589 | 589 | } |
lib/std/crypto/error.zig deleted-34| ... | ... | @@ -1,34 +0,0 @@ |
| 1 | pub 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 | |
| 2 | pub const AuthenticationError = error{AuthenticationFailed}; | |
| 3 | ||
| 4 | /// The requested output length is too long for the chosen algorithm | |
| 5 | pub const OutputTooLongError = error{OutputTooLong}; | |
| 6 | ||
| 7 | /// Finite field operation returned the identity element | |
| 8 | pub const IdentityElementError = error{IdentityElement}; | |
| 9 | ||
| 10 | /// Encoded input cannot be decoded | |
| 11 | pub const EncodingError = error{InvalidEncoding}; | |
| 12 | ||
| 13 | /// The signature does't verify for the given message and public key | |
| 14 | pub const SignatureVerificationError = error{SignatureVerificationFailed}; | |
| 15 | ||
| 16 | /// Both a public and secret key have been provided, but they are incompatible | |
| 17 | pub const KeyMismatchError = error{KeyMismatch}; | |
| 18 | ||
| 19 | /// Encoded input is not in canonical form | |
| 20 | pub const NonCanonicalError = error{NonCanonical}; | |
| 21 | ||
| 22 | /// Square root has no solutions | |
| 23 | pub const NotSquareError = error{NotSquare}; | |
| 24 | ||
| 25 | /// Verification string doesn't match the provided password and parameters | |
| 26 | pub const PasswordVerificationError = error{PasswordVerificationFailed}; | |
| 27 | ||
| 28 | /// Parameters would be insecure to use | |
| 29 | pub const WeakParametersError = error{WeakParameters}; | |
| 30 | ||
| 31 | /// Public key would be insecure to use | |
| 32 | pub const WeakPublicKeyError = error{WeakPublicKey}; | |
| 33 | ||
| 34 | /// Any error related to cryptography operations | |
| 35 | pub 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; |
| 20 | 20 | const testing = std.testing; |
| 21 | 21 | const htest = @import("test.zig"); |
| 22 | 22 | const Vector = std.meta.Vector; |
| 23 | const Error = std.crypto.Error; | |
| 23 | const AuthenticationError = std.crypto.errors.AuthenticationError; | |
| 24 | 24 | |
| 25 | 25 | pub const State = struct { |
| 26 | 26 | pub const BLOCKBYTES = 48; |
| ... | ... | @@ -393,7 +393,7 @@ pub const Aead = struct { |
| 393 | 393 | /// npub: public nonce |
| 394 | 394 | /// k: private key |
| 395 | 395 | /// 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 { | |
| 397 | 397 | assert(c.len == m.len); |
| 398 | 398 | |
| 399 | 399 | var state = Aead.init(ad, npub, k); |
lib/std/crypto/isap.zig+2-2| ... | ... | @@ -3,7 +3,7 @@ const debug = std.debug; |
| 3 | 3 | const mem = std.mem; |
| 4 | 4 | const math = std.math; |
| 5 | 5 | const testing = std.testing; |
| 6 | const Error = std.crypto.Error; | |
| 6 | const AuthenticationError = std.crypto.errors.AuthenticationError; | |
| 7 | 7 | |
| 8 | 8 | /// ISAPv2 is an authenticated encryption system hardened against side channels and fault attacks. |
| 9 | 9 | /// 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 { |
| 218 | 218 | tag.* = mac(c, ad, npub, key); |
| 219 | 219 | } |
| 220 | 220 | |
| 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 { | |
| 222 | 222 | var computed_tag = mac(c, ad, npub, key); |
| 223 | 223 | var acc: u8 = 0; |
| 224 | 224 | for (computed_tag) |_, j| { |
lib/std/crypto/pbkdf2.zig+3-2| ... | ... | @@ -7,7 +7,8 @@ |
| 7 | 7 | const std = @import("std"); |
| 8 | 8 | const mem = std.mem; |
| 9 | 9 | const maxInt = std.math.maxInt; |
| 10 | const Error = std.crypto.Error; | |
| 10 | const OutputTooLongError = std.crypto.errors.OutputTooLongError; | |
| 11 | const WeakParametersError = std.crypto.errors.WeakParametersError; | |
| 11 | 12 | |
| 12 | 13 | // RFC 2898 Section 5.2 |
| 13 | 14 | // |
| ... | ... | @@ -55,7 +56,7 @@ const Error = std.crypto.Error; |
| 55 | 56 | /// the dk. It is common to tune this parameter to achieve approximately 100ms. |
| 56 | 57 | /// |
| 57 | 58 | /// Prf: Pseudo-random function to use. A common choice is `std.crypto.auth.hmac.HmacSha256`. |
| 58 | pub fn pbkdf2(dk: []u8, password: []const u8, salt: []const u8, rounds: u32, comptime Prf: type) Error!void { | |
| 59 | pub fn pbkdf2(dk: []u8, password: []const u8, salt: []const u8, rounds: u32, comptime Prf: type) (WeakParametersError || OutputTooLongError)!void { | |
| 59 | 60 | if (rounds < 1) return error.WeakParameters; |
| 60 | 61 | |
| 61 | 62 | const dk_len = dk.len; |
lib/std/crypto/salsa20.zig+11-8| ... | ... | @@ -15,7 +15,10 @@ const Vector = std.meta.Vector; |
| 15 | 15 | const Poly1305 = crypto.onetimeauth.Poly1305; |
| 16 | 16 | const Blake2b = crypto.hash.blake2.Blake2b; |
| 17 | 17 | const X25519 = crypto.dh.X25519; |
| 18 | const Error = crypto.Error; | |
| 18 | ||
| 19 | const AuthenticationError = crypto.errors.AuthenticationError; | |
| 20 | const IdentityElementError = crypto.errors.IdentityElementError; | |
| 21 | const WeakPublicKeyError = crypto.errors.WeakPublicKeyError; | |
| 19 | 22 | |
| 20 | 23 | const Salsa20VecImpl = struct { |
| 21 | 24 | const Lane = Vector(4, u32); |
| ... | ... | @@ -399,7 +402,7 @@ pub const XSalsa20Poly1305 = struct { |
| 399 | 402 | /// ad: Associated Data |
| 400 | 403 | /// npub: public nonce |
| 401 | 404 | /// 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 { | |
| 403 | 406 | debug.assert(c.len == m.len); |
| 404 | 407 | const extended = extend(k, npub); |
| 405 | 408 | var block0 = [_]u8{0} ** 64; |
| ... | ... | @@ -447,7 +450,7 @@ pub const SecretBox = struct { |
| 447 | 450 | |
| 448 | 451 | /// Verify and decrypt `c` using a nonce `npub` and a key `k`. |
| 449 | 452 | /// `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 { | |
| 451 | 454 | if (c.len < tag_length) { |
| 452 | 455 | return error.AuthenticationFailed; |
| 453 | 456 | } |
| ... | ... | @@ -482,20 +485,20 @@ pub const Box = struct { |
| 482 | 485 | pub const KeyPair = X25519.KeyPair; |
| 483 | 486 | |
| 484 | 487 | /// 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 { | |
| 486 | 489 | const p = try X25519.scalarmult(secret_key, public_key); |
| 487 | 490 | const zero = [_]u8{0} ** 16; |
| 488 | 491 | return Salsa20Impl.hsalsa20(zero, p); |
| 489 | 492 | } |
| 490 | 493 | |
| 491 | 494 | /// 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 { | |
| 493 | 496 | const shared_key = try createSharedSecret(public_key, secret_key); |
| 494 | 497 | return SecretBox.seal(c, m, npub, shared_key); |
| 495 | 498 | } |
| 496 | 499 | |
| 497 | 500 | /// 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 { | |
| 499 | 502 | const shared_key = try createSharedSecret(public_key, secret_key); |
| 500 | 503 | return SecretBox.open(m, c, npub, shared_key); |
| 501 | 504 | } |
| ... | ... | @@ -528,7 +531,7 @@ pub const SealedBox = struct { |
| 528 | 531 | |
| 529 | 532 | /// Encrypt a message `m` for a recipient whose public key is `public_key`. |
| 530 | 533 | /// `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 { | |
| 532 | 535 | debug.assert(c.len == m.len + seal_length); |
| 533 | 536 | var ekp = try KeyPair.create(null); |
| 534 | 537 | const nonce = createNonce(ekp.public_key, public_key); |
| ... | ... | @@ -539,7 +542,7 @@ pub const SealedBox = struct { |
| 539 | 542 | |
| 540 | 543 | /// Decrypt a message using a key pair. |
| 541 | 544 | /// `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 { | |
| 543 | 546 | if (c.len < seal_length) { |
| 544 | 547 | return error.AuthenticationFailed; |
| 545 | 548 | } |
lib/std/event/rwlock.zig+2-2| ... | ... | @@ -264,7 +264,7 @@ var shared_test_data = [1]i32{0} ** 10; |
| 264 | 264 | var shared_test_index: usize = 0; |
| 265 | 265 | var shared_count: usize = 0; |
| 266 | 266 | fn writeRunner(lock: *RwLock) callconv(.Async) void { |
| 267 | suspend; // resumed by onNextTick | |
| 267 | suspend {} // resumed by onNextTick | |
| 268 | 268 | |
| 269 | 269 | var i: usize = 0; |
| 270 | 270 | while (i < shared_test_data.len) : (i += 1) { |
| ... | ... | @@ -281,7 +281,7 @@ fn writeRunner(lock: *RwLock) callconv(.Async) void { |
| 281 | 281 | } |
| 282 | 282 | } |
| 283 | 283 | fn readRunner(lock: *RwLock) callconv(.Async) void { |
| 284 | suspend; // resumed by onNextTick | |
| 284 | suspend {} // resumed by onNextTick | |
| 285 | 285 | std.time.sleep(1); |
| 286 | 286 | |
| 287 | 287 | var i: usize = 0; |
lib/std/math.zig-9| ... | ... | @@ -1349,15 +1349,6 @@ pub fn boolMask(comptime MaskInt: type, value: bool) callconv(.Inline) MaskInt { |
| 1349 | 1349 | return @bitCast(i1, @as(u1, @boolToInt(value))); |
| 1350 | 1350 | } |
| 1351 | 1351 | |
| 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 | ||
| 1361 | 1352 | return -%@intCast(MaskInt, @boolToInt(value)); |
| 1362 | 1353 | } |
| 1363 | 1354 |
lib/std/math/sqrt.zig+17-3| ... | ... | @@ -38,7 +38,13 @@ pub fn sqrt(x: anytype) Sqrt(@TypeOf(x)) { |
| 38 | 38 | } |
| 39 | 39 | } |
| 40 | 40 | |
| 41 | fn sqrt_int(comptime T: type, value: T) std.meta.Int(.unsigned, @typeInfo(T).Int.bits / 2) { | |
| 41 | fn sqrt_int(comptime T: type, value: T) Sqrt(T) { | |
| 42 | switch (T) { | |
| 43 | u0 => return 0, | |
| 44 | u1 => return value, | |
| 45 | else => {}, | |
| 46 | } | |
| 47 | ||
| 42 | 48 | var op = value; |
| 43 | 49 | var res: T = 0; |
| 44 | 50 | 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 |
| 57 | 63 | one >>= 2; |
| 58 | 64 | } |
| 59 | 65 | |
| 60 | const ResultType = std.meta.Int(.unsigned, @typeInfo(T).Int.bits / 2); | |
| 66 | const ResultType = Sqrt(T); | |
| 61 | 67 | return @intCast(ResultType, res); |
| 62 | 68 | } |
| 63 | 69 | |
| 64 | 70 | test "math.sqrt_int" { |
| 71 | expect(sqrt_int(u0, 0) == 0); | |
| 72 | expect(sqrt_int(u1, 1) == 1); | |
| 65 | 73 | expect(sqrt_int(u32, 3) == 1); |
| 66 | 74 | expect(sqrt_int(u32, 4) == 2); |
| 67 | 75 | expect(sqrt_int(u32, 5) == 2); |
| ... | ... | @@ -73,7 +81,13 @@ test "math.sqrt_int" { |
| 73 | 81 | /// Returns the return type `sqrt` will return given an operand of type `T`. |
| 74 | 82 | pub fn Sqrt(comptime T: type) type { |
| 75 | 83 | 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 | }, | |
| 77 | 91 | else => T, |
| 78 | 92 | }; |
| 79 | 93 | } |
lib/std/meta.zig+15-3| ... | ... | @@ -884,7 +884,7 @@ pub fn Vector(comptime len: u32, comptime child: type) type { |
| 884 | 884 | /// Given a type and value, cast the value to the type as c would. |
| 885 | 885 | /// This is for translate-c and is not intended for general use. |
| 886 | 886 | pub 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 | |
| 888 | 888 | const SourceType = @TypeOf(target); |
| 889 | 889 | switch (@typeInfo(DestType)) { |
| 890 | 890 | .Pointer => { |
| ... | ... | @@ -921,9 +921,10 @@ pub fn cast(comptime DestType: type, target: anytype) DestType { |
| 921 | 921 | } |
| 922 | 922 | } |
| 923 | 923 | }, |
| 924 | .Enum => { | |
| 924 | .Enum => |enum_type| { | |
| 925 | 925 | 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); | |
| 927 | 928 | } |
| 928 | 929 | }, |
| 929 | 930 | .Int => { |
| ... | ... | @@ -1011,6 +1012,17 @@ test "std.meta.cast" { |
| 1011 | 1012 | testing.expectEqual(@intToPtr(*u8, 2), cast(*u8, @intToPtr(*volatile u8, 2))); |
| 1012 | 1013 | |
| 1013 | 1014 | 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)); | |
| 1014 | 1026 | } |
| 1015 | 1027 | |
| 1016 | 1028 | /// 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 { |
| 557 | 557 | size: off_t, |
| 558 | 558 | blksize: blksize_t, |
| 559 | 559 | blocks: blkcnt_t, |
| 560 | __atim32: timespec32, | |
| 561 | __mtim32: timespec32, | |
| 562 | __ctim32: timespec32, | |
| 563 | __unused: [2]u32, | |
| 564 | 560 | atim: timespec, |
| 565 | 561 | mtim: timespec, |
| 566 | 562 | ctim: timespec, |
| 567 | ||
| 568 | const timespec32 = extern struct { | |
| 569 | tv_sec: i32, | |
| 570 | tv_nsec: i32, | |
| 571 | }; | |
| 563 | __unused: [2]u32, | |
| 572 | 564 | |
| 573 | 565 | pub fn atime(self: @This()) timespec { |
| 574 | 566 | return self.atim; |
lib/std/os/linux.zig+49-1| ... | ... | @@ -53,6 +53,7 @@ pub fn getauxval(index: usize) usize { |
| 53 | 53 | // Some architectures (and some syscalls) require 64bit parameters to be passed |
| 54 | 54 | // in a even-aligned register pair. |
| 55 | 55 | const require_aligned_register_pair = |
| 56 | std.Target.current.cpu.arch.isPPC() or | |
| 56 | 57 | std.Target.current.cpu.arch.isMIPS() or |
| 57 | 58 | std.Target.current.cpu.arch.isARM() or |
| 58 | 59 | std.Target.current.cpu.arch.isThumb(); |
| ... | ... | @@ -633,7 +634,7 @@ pub fn tkill(tid: pid_t, sig: i32) usize { |
| 633 | 634 | } |
| 634 | 635 | |
| 635 | 636 | pub 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))); | |
| 637 | 638 | } |
| 638 | 639 | |
| 639 | 640 | pub 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 { |
| 1386 | 1387 | return syscall3(.madvise, @ptrToInt(address), len, advice); |
| 1387 | 1388 | } |
| 1388 | 1389 | |
| 1390 | pub fn pidfd_open(pid: pid_t, flags: u32) usize { | |
| 1391 | return syscall2(.pidfd_open, @bitCast(usize, @as(isize, pid)), flags); | |
| 1392 | } | |
| 1393 | ||
| 1394 | pub 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 | ||
| 1403 | pub 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 | ||
| 1413 | pub 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 | ||
| 1425 | pub 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 | ||
| 1389 | 1437 | test { |
| 1390 | 1438 | if (std.Target.current.os.tag == .linux) { |
| 1391 | 1439 | _ = @import("linux/test.zig"); |
lib/std/os/linux/bpf/btf.zig+1-1| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | const magic = 0xeb9f; |
| 7 | 7 | const version = 1; |
| 8 | 8 | |
| 9 | pub const ext = @import("ext.zig"); | |
| 9 | pub const ext = @import("btf_ext.zig"); | |
| 10 | 10 | |
| 11 | 11 | /// All offsets are in bytes relative to the end of this header |
| 12 | 12 | pub 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, |
| 663 | 663 | pub extern "user32" fn MessageBoxW(hWnd: ?HWND, lpText: [*:0]const u16, lpCaption: ?[*:0]const u16, uType: UINT) callconv(WINAPI) i32; |
| 664 | 664 | pub var pfnMessageBoxW: @TypeOf(MessageBoxW) = undefined; |
| 665 | 665 | pub 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); | |
| 667 | 667 | const value = function(hWnd, lpText, lpCaption, uType); |
| 668 | 668 | if (value != 0) return value; |
| 669 | 669 | switch (GetLastError()) { |
lib/std/special/c.zig+122-29| ... | ... | @@ -88,7 +88,7 @@ test "strncpy" { |
| 88 | 88 | var s1: [9:0]u8 = undefined; |
| 89 | 89 | |
| 90 | 90 | s1[0] = 0; |
| 91 | _ = strncpy(&s1, "foobarbaz", 9); | |
| 91 | _ = strncpy(&s1, "foobarbaz", @sizeOf(@TypeOf(s1))); | |
| 92 | 92 | std.testing.expectEqualSlices(u8, "foobarbaz", std.mem.spanZ(&s1)); |
| 93 | 93 | } |
| 94 | 94 | |
| ... | ... | @@ -242,7 +242,7 @@ export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) callconv(.C) isiz |
| 242 | 242 | return 0; |
| 243 | 243 | } |
| 244 | 244 | |
| 245 | test "test_memcmp" { | |
| 245 | test "memcmp" { | |
| 246 | 246 | const base_arr = &[_]u8{ 1, 1, 1 }; |
| 247 | 247 | const arr1 = &[_]u8{ 1, 1, 1 }; |
| 248 | 248 | const arr2 = &[_]u8{ 1, 0, 1 }; |
| ... | ... | @@ -266,7 +266,7 @@ export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) c |
| 266 | 266 | return 0; |
| 267 | 267 | } |
| 268 | 268 | |
| 269 | test "test_bcmp" { | |
| 269 | test "bcmp" { | |
| 270 | 270 | const base_arr = &[_]u8{ 1, 1, 1 }; |
| 271 | 271 | const arr1 = &[_]u8{ 1, 1, 1 }; |
| 272 | 272 | const arr2 = &[_]u8{ 1, 0, 1 }; |
| ... | ... | @@ -862,6 +862,85 @@ fn generic_fmod(comptime T: type, x: T, y: T) T { |
| 862 | 862 | return @bitCast(T, ux); |
| 863 | 863 | } |
| 864 | 864 | |
| 865 | test "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 | ||
| 886 | fn 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 | ||
| 894 | export fn fminf(x: f32, y: f32) callconv(.C) f32 { | |
| 895 | return generic_fmin(f32, x, y); | |
| 896 | } | |
| 897 | ||
| 898 | export fn fmin(x: f64, y: f64) callconv(.C) f64 { | |
| 899 | return generic_fmin(f64, x, y); | |
| 900 | } | |
| 901 | ||
| 902 | test "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 | ||
| 915 | fn 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 | ||
| 923 | export fn fmaxf(x: f32, y: f32) callconv(.C) f32 { | |
| 924 | return generic_fmax(f32, x, y); | |
| 925 | } | |
| 926 | ||
| 927 | export fn fmax(x: f64, y: f64) callconv(.C) f64 { | |
| 928 | return generic_fmax(f64, x, y); | |
| 929 | } | |
| 930 | ||
| 931 | test "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 | ||
| 865 | 944 | // NOTE: The original code is full of implicit signed -> unsigned assumptions and u32 wraparound |
| 866 | 945 | // behaviour. Most intermediate i32 values are changed to u32 where appropriate but there are |
| 867 | 946 | // potentially some edge cases remaining that are not handled in the same way. |
| ... | ... | @@ -996,25 +1075,32 @@ export fn sqrt(x: f64) f64 { |
| 996 | 1075 | } |
| 997 | 1076 | |
| 998 | 1077 | test "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)); | |
| 1010 | 1096 | } |
| 1011 | 1097 | |
| 1012 | 1098 | test "sqrt special" { |
| 1013 | 1099 | std.testing.expect(std.math.isPositiveInf(sqrt(std.math.inf(f64)))); |
| 1014 | 1100 | std.testing.expect(sqrt(0.0) == 0.0); |
| 1015 | 1101 | 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)))); | |
| 1018 | 1104 | } |
| 1019 | 1105 | |
| 1020 | 1106 | export fn sqrtf(x: f32) f32 { |
| ... | ... | @@ -1094,23 +1180,30 @@ export fn sqrtf(x: f32) f32 { |
| 1094 | 1180 | } |
| 1095 | 1181 | |
| 1096 | 1182 | test "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)); | |
| 1108 | 1201 | } |
| 1109 | 1202 | |
| 1110 | 1203 | test "sqrtf special" { |
| 1111 | 1204 | std.testing.expect(std.math.isPositiveInf(sqrtf(std.math.inf(f32)))); |
| 1112 | 1205 | std.testing.expect(sqrtf(0.0) == 0.0); |
| 1113 | 1206 | 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)))); | |
| 1116 | 1209 | } |
lib/std/special/compiler_rt.zig+3-1| ... | ... | @@ -116,9 +116,11 @@ comptime { |
| 116 | 116 | @export(@import("compiler_rt/extendXfYf2.zig").__extenddftf2, .{ .name = "__extenddftf2", .linkage = linkage }); |
| 117 | 117 | @export(@import("compiler_rt/extendXfYf2.zig").__extendsftf2, .{ .name = "__extendsftf2", .linkage = linkage }); |
| 118 | 118 | @export(@import("compiler_rt/extendXfYf2.zig").__extendhfsf2, .{ .name = "__extendhfsf2", .linkage = linkage }); |
| 119 | @export(@import("compiler_rt/extendXfYf2.zig").__extendhftf2, .{ .name = "__extendhftf2", .linkage = linkage }); | |
| 119 | 120 | |
| 120 | 121 | @export(@import("compiler_rt/truncXfYf2.zig").__truncsfhf2, .{ .name = "__truncsfhf2", .linkage = linkage }); |
| 121 | 122 | @export(@import("compiler_rt/truncXfYf2.zig").__truncdfhf2, .{ .name = "__truncdfhf2", .linkage = linkage }); |
| 123 | @export(@import("compiler_rt/truncXfYf2.zig").__trunctfhf2, .{ .name = "__trunctfhf2", .linkage = linkage }); | |
| 122 | 124 | @export(@import("compiler_rt/truncXfYf2.zig").__trunctfdf2, .{ .name = "__trunctfdf2", .linkage = linkage }); |
| 123 | 125 | @export(@import("compiler_rt/truncXfYf2.zig").__trunctfsf2, .{ .name = "__trunctfsf2", .linkage = linkage }); |
| 124 | 126 | |
| ... | ... | @@ -299,7 +301,7 @@ comptime { |
| 299 | 301 | @export(@import("compiler_rt/sparc.zig")._Qp_qtod, .{ .name = "_Qp_qtod", .linkage = linkage }); |
| 300 | 302 | } |
| 301 | 303 | |
| 302 | if (arch == .powerpc or arch.isPPC64()) { | |
| 304 | if ((arch == .powerpc or arch.isPPC64()) and !is_test) { | |
| 303 | 305 | @export(@import("compiler_rt/addXf3.zig").__addtf3, .{ .name = "__addkf3", .linkage = linkage }); |
| 304 | 306 | @export(@import("compiler_rt/addXf3.zig").__subtf3, .{ .name = "__subkf3", .linkage = linkage }); |
| 305 | 307 | @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 { |
| 23 | 23 | return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f32, f16, a }); |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | pub fn __extendhftf2(a: u16) callconv(.C) f128 { | |
| 27 | return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f128, f16, a }); | |
| 28 | } | |
| 29 | ||
| 26 | 30 | pub fn __aeabi_h2f(arg: u16) callconv(.AAPCS) f32 { |
| 27 | 31 | @setRuntimeSafety(false); |
| 28 | 32 | return @call(.{ .modifier = .always_inline }, __extendhfsf2, .{arg}); |
lib/std/special/compiler_rt/extendXfYf2_test.zig+48-1| ... | ... | @@ -4,9 +4,10 @@ |
| 4 | 4 | // The MIT license requires this copyright notice to be included in all copies |
| 5 | 5 | // and substantial portions of the software. |
| 6 | 6 | const builtin = @import("builtin"); |
| 7 | const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2; | |
| 8 | 7 | const __extendhfsf2 = @import("extendXfYf2.zig").__extendhfsf2; |
| 8 | const __extendhftf2 = @import("extendXfYf2.zig").__extendhftf2; | |
| 9 | 9 | const __extendsftf2 = @import("extendXfYf2.zig").__extendsftf2; |
| 10 | const __extenddftf2 = @import("extendXfYf2.zig").__extenddftf2; | |
| 10 | 11 | |
| 11 | 12 | fn test__extenddftf2(a: f64, expectedHi: u64, expectedLo: u64) void { |
| 12 | 13 | const x = __extenddftf2(a); |
| ... | ... | @@ -161,3 +162,49 @@ fn makeNaN32(rand: u32) f32 { |
| 161 | 162 | fn makeInf32() f32 { |
| 162 | 163 | return @bitCast(f32, @as(u32, 0x7f800000)); |
| 163 | 164 | } |
| 165 | ||
| 166 | fn 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 | ||
| 188 | test "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 { |
| 13 | 13 | return @bitCast(u16, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f64, a })); |
| 14 | 14 | } |
| 15 | 15 | |
| 16 | pub fn __trunctfhf2(a: f128) callconv(.C) u16 { | |
| 17 | return @bitCast(u16, @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f16, f128, a })); | |
| 18 | } | |
| 19 | ||
| 16 | 20 | pub fn __trunctfsf2(a: f128) callconv(.C) f32 { |
| 17 | 21 | return @call(.{ .modifier = .always_inline }, truncXfYf2, .{ f32, f128, a }); |
| 18 | 22 | } |
| ... | ... | @@ -122,7 +126,7 @@ fn truncXfYf2(comptime dst_t: type, comptime src_t: type, a: src_t) dst_t { |
| 122 | 126 | if (shift > srcSigBits) { |
| 123 | 127 | absResult = 0; |
| 124 | 128 | } 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); | |
| 126 | 130 | const denormalizedSignificand: src_rep_t = significand >> @intCast(SrcShift, shift) | sticky; |
| 127 | 131 | absResult = @intCast(dst_rep_t, denormalizedSignificand >> (srcSigBits - dstSigBits)); |
| 128 | 132 | const roundBits: src_rep_t = denormalizedSignificand & roundMask; |
lib/std/special/compiler_rt/truncXfYf2_test.zig+56| ... | ... | @@ -242,3 +242,59 @@ test "truncdfsf2" { |
| 242 | 242 | // huge number becomes inf |
| 243 | 243 | test__truncdfsf2(340282366920938463463374607431768211456.0, 0x7f800000); |
| 244 | 244 | } |
| 245 | ||
| 246 | const __trunctfhf2 = @import("truncXfYf2.zig").__trunctfhf2; | |
| 247 | ||
| 248 | fn 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 | ||
| 261 | test "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 { |
| 800 | 800 | }; |
| 801 | 801 | } |
| 802 | 802 | |
| 803 | pub fn isPPC(arch: Arch) bool { | |
| 804 | return switch (arch) { | |
| 805 | .powerpc, .powerpcle => true, | |
| 806 | else => false, | |
| 807 | }; | |
| 808 | } | |
| 809 | ||
| 803 | 810 | pub fn isPPC64(arch: Arch) bool { |
| 804 | 811 | return switch (arch) { |
| 805 | 812 | .powerpc64, .powerpc64le => true, |
| ... | ... | @@ -1184,8 +1191,8 @@ pub const Target = struct { |
| 1184 | 1191 | .mips, .mipsel => &mips.cpu.mips32, |
| 1185 | 1192 | .mips64, .mips64el => &mips.cpu.mips64, |
| 1186 | 1193 | .msp430 => &msp430.cpu.generic, |
| 1187 | .powerpc => &powerpc.cpu.ppc32, | |
| 1188 | .powerpcle => &powerpc.cpu.ppc32, | |
| 1194 | .powerpc => &powerpc.cpu.ppc, | |
| 1195 | .powerpcle => &powerpc.cpu.ppc, | |
| 1189 | 1196 | .powerpc64 => &powerpc.cpu.ppc64, |
| 1190 | 1197 | .powerpc64le => &powerpc.cpu.ppc64le, |
| 1191 | 1198 | .amdgcn => &amdgpu.cpu.generic, |
lib/std/target/powerpc.zig-7| ... | ... | @@ -751,13 +751,6 @@ pub const cpu = struct { |
| 751 | 751 | .hard_float, |
| 752 | 752 | }), |
| 753 | 753 | }; |
| 754 | pub const ppc32 = CpuModel{ | |
| 755 | .name = "ppc32", | |
| 756 | .llvm_name = "ppc32", | |
| 757 | .features = featureSet(&[_]Feature{ | |
| 758 | .hard_float, | |
| 759 | }), | |
| 760 | }; | |
| 761 | 754 | pub const ppc64 = CpuModel{ |
| 762 | 755 | .name = "ppc64", |
| 763 | 756 | .llvm_name = "ppc64", |
lib/std/zig/parse.zig+2-1| ... | ... | @@ -852,7 +852,7 @@ const Parser = struct { |
| 852 | 852 | /// <- KEYWORD_comptime? VarDecl |
| 853 | 853 | /// / KEYWORD_comptime BlockExprStatement |
| 854 | 854 | /// / KEYWORD_nosuspend BlockExprStatement |
| 855 | /// / KEYWORD_suspend (SEMICOLON / BlockExprStatement) | |
| 855 | /// / KEYWORD_suspend BlockExprStatement | |
| 856 | 856 | /// / KEYWORD_defer BlockExprStatement |
| 857 | 857 | /// / KEYWORD_errdefer Payload? BlockExprStatement |
| 858 | 858 | /// / IfStatement |
| ... | ... | @@ -892,6 +892,7 @@ const Parser = struct { |
| 892 | 892 | }, |
| 893 | 893 | .keyword_suspend => { |
| 894 | 894 | const token = p.nextToken(); |
| 895 | // TODO remove this special case when 0.9.0 is released. | |
| 895 | 896 | const block_expr: Node.Index = if (p.eatToken(.semicolon) != null) |
| 896 | 897 | 0 |
| 897 | 898 | else |
lib/std/zig/parser_test.zig+54-3| ... | ... | @@ -40,6 +40,21 @@ test "zig fmt: rewrite inline functions as callconv(.Inline)" { |
| 40 | 40 | ); |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | // TODO Remove this after zig 0.9.0 is released. | |
| 44 | test "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 | ||
| 43 | 58 | test "zig fmt: simple top level comptime block" { |
| 44 | 59 | try testCanonical( |
| 45 | 60 | \\// line comment |
| ... | ... | @@ -1315,6 +1330,27 @@ test "zig fmt: 'zig fmt: (off|on)' works in the middle of code" { |
| 1315 | 1330 | ); |
| 1316 | 1331 | } |
| 1317 | 1332 | |
| 1333 | test "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 | ||
| 1318 | 1354 | test "zig fmt: pointer of unknown length" { |
| 1319 | 1355 | try testCanonical( |
| 1320 | 1356 | \\fn foo(ptr: [*]u8) void {} |
| ... | ... | @@ -3644,9 +3680,9 @@ test "zig fmt: async functions" { |
| 3644 | 3680 | \\fn simpleAsyncFn() void { |
| 3645 | 3681 | \\ const a = async a.b(); |
| 3646 | 3682 | \\ x += 1; |
| 3647 | \\ suspend; | |
| 3683 | \\ suspend {} | |
| 3648 | 3684 | \\ x += 1; |
| 3649 | \\ suspend; | |
| 3685 | \\ suspend {} | |
| 3650 | 3686 | \\ const p: anyframe->void = async simpleAsyncFn() catch unreachable; |
| 3651 | 3687 | \\ await p; |
| 3652 | 3688 | \\} |
| ... | ... | @@ -5001,6 +5037,21 @@ test "recovery: invalid comptime" { |
| 5001 | 5037 | }); |
| 5002 | 5038 | } |
| 5003 | 5039 | |
| 5040 | test "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 | ||
| 5004 | 5055 | test "recovery: missing block after for/while loops" { |
| 5005 | 5056 | try testError( |
| 5006 | 5057 | \\test "" { while (foo) } |
| ... | ... | @@ -5144,7 +5195,7 @@ fn testError(source: []const u8, expected_errors: []const Error) !void { |
| 5144 | 5195 | var tree = try std.zig.parse(std.testing.allocator, source); |
| 5145 | 5196 | defer tree.deinit(std.testing.allocator); |
| 5146 | 5197 | |
| 5147 | std.testing.expect(tree.errors.len == expected_errors.len); | |
| 5198 | std.testing.expectEqual(expected_errors.len, tree.errors.len); | |
| 5148 | 5199 | for (expected_errors) |expected, i| { |
| 5149 | 5200 | std.testing.expectEqual(expected, tree.errors[i].tag); |
| 5150 | 5201 | } |
lib/std/zig/render.zig+8-3| ... | ... | @@ -269,7 +269,12 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.I |
| 269 | 269 | try renderToken(ais, tree, suspend_token, .space); |
| 270 | 270 | return renderExpression(gpa, ais, tree, body, space); |
| 271 | 271 | } 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; | |
| 273 | 278 | } |
| 274 | 279 | }, |
| 275 | 280 | |
| ... | ... | @@ -2310,9 +2315,9 @@ fn renderComments(ais: *Ais, tree: ast.Tree, start: usize, end: usize) Error!boo |
| 2310 | 2315 | // to the underlying writer, fixing up invaild whitespace. |
| 2311 | 2316 | const disabled_source = tree.source[ais.disabled_offset.?..comment_start]; |
| 2312 | 2317 | try writeFixingWhitespace(ais.underlying_writer, disabled_source); |
| 2313 | ais.disabled_offset = null; | |
| 2314 | 2318 | // 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; | |
| 2316 | 2321 | } else if (ais.disabled_offset == null and mem.eql(u8, comment_content, "zig fmt: off")) { |
| 2317 | 2322 | // Write with the canonical single space. |
| 2318 | 2323 | try ais.writer().writeAll("// zig fmt: off\n"); |
src/Compilation.zig+19-15| ... | ... | @@ -2856,25 +2856,29 @@ pub fn addCCArgs( |
| 2856 | 2856 | try argv.append("-fPIC"); |
| 2857 | 2857 | } |
| 2858 | 2858 | }, |
| 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 | }, | |
| 2860 | 2878 | } |
| 2861 | 2879 | if (out_dep_path) |p| { |
| 2862 | 2880 | try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p }); |
| 2863 | 2881 | } |
| 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 | } | |
| 2878 | 2882 | |
| 2879 | 2883 | if (target.os.tag == .freestanding) { |
| 2880 | 2884 | try argv.append("-ffreestanding"); |
src/codegen.zig-1| ... | ... | @@ -1247,7 +1247,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1247 | 1247 | }, |
| 1248 | 1248 | .stack_offset => |off| { |
| 1249 | 1249 | log.debug("reusing stack offset {} => {*}", .{ off, inst }); |
| 1250 | return true; | |
| 1251 | 1250 | }, |
| 1252 | 1251 | else => return false, |
| 1253 | 1252 | } |
src/link/MachO.zig+1-2| ... | ... | @@ -645,8 +645,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 645 | 645 | break :blk true; |
| 646 | 646 | } |
| 647 | 647 | |
| 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 | |
| 650 | 649 | self.base.options.linker_script != null) |
| 651 | 650 | { |
| 652 | 651 | // 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 { |
| 208 | 208 | |
| 209 | 209 | const object_name = try parseName(self.allocator, object_header, reader); |
| 210 | 210 | defer self.allocator.free(object_name); |
| 211 | const object_basename = std.fs.path.basename(object_name); | |
| 212 | 211 | |
| 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.? }); | |
| 214 | 213 | |
| 215 | 214 | const name = name: { |
| 216 | 215 | var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; |
| 217 | 216 | 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 }); | |
| 219 | 218 | }; |
| 220 | 219 | |
| 221 | 220 | var object = Object.init(self.allocator); |
src/link/MachO/Object.zig+43-4| ... | ... | @@ -32,7 +32,9 @@ symtab_cmd_index: ?u16 = null, |
| 32 | 32 | dysymtab_cmd_index: ?u16 = null, |
| 33 | 33 | build_version_cmd_index: ?u16 = null, |
| 34 | 34 | data_in_code_cmd_index: ?u16 = null, |
| 35 | ||
| 35 | 36 | text_section_index: ?u16 = null, |
| 37 | mod_init_func_section_index: ?u16 = null, | |
| 36 | 38 | |
| 37 | 39 | // __DWARF segment sections |
| 38 | 40 | dwarf_debug_info_index: ?u16 = null, |
| ... | ... | @@ -49,6 +51,7 @@ stabs: std.ArrayListUnmanaged(Stab) = .{}, |
| 49 | 51 | tu_path: ?[]const u8 = null, |
| 50 | 52 | tu_mtime: ?u64 = null, |
| 51 | 53 | |
| 54 | initializers: std.ArrayListUnmanaged(CppStatic) = .{}, | |
| 52 | 55 | data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{}, |
| 53 | 56 | |
| 54 | 57 | pub const Section = struct { |
| ... | ... | @@ -68,6 +71,11 @@ pub const Section = struct { |
| 68 | 71 | } |
| 69 | 72 | }; |
| 70 | 73 | |
| 74 | const CppStatic = struct { | |
| 75 | symbol: u32, | |
| 76 | target_addr: u64, | |
| 77 | }; | |
| 78 | ||
| 71 | 79 | const Stab = struct { |
| 72 | 80 | tag: Tag, |
| 73 | 81 | symbol: u32, |
| ... | ... | @@ -170,6 +178,7 @@ pub fn deinit(self: *Object) void { |
| 170 | 178 | self.strtab.deinit(self.allocator); |
| 171 | 179 | self.stabs.deinit(self.allocator); |
| 172 | 180 | self.data_in_code_entries.deinit(self.allocator); |
| 181 | self.initializers.deinit(self.allocator); | |
| 173 | 182 | |
| 174 | 183 | if (self.name) |n| { |
| 175 | 184 | self.allocator.free(n); |
| ... | ... | @@ -216,6 +225,7 @@ pub fn parse(self: *Object) !void { |
| 216 | 225 | try self.parseSections(); |
| 217 | 226 | if (self.symtab_cmd_index != null) try self.parseSymtab(); |
| 218 | 227 | if (self.data_in_code_cmd_index != null) try self.readDataInCode(); |
| 228 | try self.parseInitializers(); | |
| 219 | 229 | try self.parseDebugInfo(); |
| 220 | 230 | } |
| 221 | 231 | |
| ... | ... | @@ -250,6 +260,10 @@ pub fn readLoadCommands(self: *Object, reader: anytype) !void { |
| 250 | 260 | if (mem.eql(u8, sectname, "__text")) { |
| 251 | 261 | self.text_section_index = index; |
| 252 | 262 | } |
| 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 | } | |
| 253 | 267 | } |
| 254 | 268 | |
| 255 | 269 | sect.offset += offset; |
| ... | ... | @@ -298,28 +312,53 @@ pub fn parseSections(self: *Object) !void { |
| 298 | 312 | var section = Section{ |
| 299 | 313 | .inner = sect, |
| 300 | 314 | .code = code, |
| 301 | .relocs = undefined, | |
| 315 | .relocs = null, | |
| 302 | 316 | }; |
| 303 | 317 | |
| 304 | 318 | // Parse relocations |
| 305 | section.relocs = if (sect.nreloc > 0) relocs: { | |
| 319 | if (sect.nreloc > 0) { | |
| 306 | 320 | var raw_relocs = try self.allocator.alloc(u8, @sizeOf(macho.relocation_info) * sect.nreloc); |
| 307 | 321 | defer self.allocator.free(raw_relocs); |
| 308 | 322 | |
| 309 | 323 | _ = try self.file.?.preadAll(raw_relocs, sect.reloff); |
| 310 | 324 | |
| 311 | break :relocs try reloc.parse( | |
| 325 | section.relocs = try reloc.parse( | |
| 312 | 326 | self.allocator, |
| 313 | 327 | self.arch.?, |
| 314 | 328 | section.code, |
| 315 | 329 | mem.bytesAsSlice(macho.relocation_info, raw_relocs), |
| 316 | 330 | ); |
| 317 | } else null; | |
| 331 | } | |
| 318 | 332 | |
| 319 | 333 | self.sections.appendAssumeCapacity(section); |
| 320 | 334 | } |
| 321 | 335 | } |
| 322 | 336 | |
| 337 | pub 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 | ||
| 323 | 362 | pub fn parseSymtab(self: *Object) !void { |
| 324 | 363 | const symtab_cmd = self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 325 | 364 |
src/link/MachO/Symbol.zig+1-1| ... | ... | @@ -52,7 +52,7 @@ pub fn isUndf(sym: macho.nlist_64) bool { |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | 54 | pub 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; | |
| 56 | 56 | } |
| 57 | 57 | |
| 58 | 58 | /// 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, |
| 72 | 72 | la_symbol_ptr_section_index: ?u16 = null, |
| 73 | 73 | data_section_index: ?u16 = null, |
| 74 | 74 | bss_section_index: ?u16 = null, |
| 75 | common_section_index: ?u16 = null, | |
| 75 | 76 | |
| 76 | 77 | symtab: std.StringArrayHashMapUnmanaged(Symbol) = .{}, |
| 77 | 78 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| ... | ... | @@ -224,6 +225,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { |
| 224 | 225 | self.allocateLinkeditSegment(); |
| 225 | 226 | try self.allocateSymbols(); |
| 226 | 227 | try self.allocateStubsAndGotEntries(); |
| 228 | try self.allocateCppStatics(); | |
| 227 | 229 | try self.writeStubHelperCommon(); |
| 228 | 230 | try self.resolveRelocsAndWriteSections(); |
| 229 | 231 | try self.flush(); |
| ... | ... | @@ -465,23 +467,43 @@ fn updateMetadata(self: *Zld) !void { |
| 465 | 467 | }, |
| 466 | 468 | macho.S_ZEROFILL => { |
| 467 | 469 | 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; | |
| 469 | 472 | |
| 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 | } | |
| 485 | 507 | }, |
| 486 | 508 | macho.S_THREAD_LOCAL_VARIABLES => { |
| 487 | 509 | if (!mem.eql(u8, segname, "__DATA")) continue; |
| ... | ... | @@ -568,7 +590,9 @@ fn updateMetadata(self: *Zld) !void { |
| 568 | 590 | |
| 569 | 591 | const segname = parseName(&source_sect.segname); |
| 570 | 592 | const sectname = parseName(&source_sect.sectname); |
| 593 | ||
| 571 | 594 | log.debug("section '{s}/{s}' will be unmapped", .{ segname, sectname }); |
| 595 | ||
| 572 | 596 | try self.unhandled_sections.putNoClobber(self.allocator, .{ |
| 573 | 597 | .object_id = object_id, |
| 574 | 598 | .source_sect_id = source_sect_id, |
| ... | ... | @@ -585,6 +609,7 @@ const MatchingSection = struct { |
| 585 | 609 | fn getMatchingSection(self: *Zld, section: macho.section_64) ?MatchingSection { |
| 586 | 610 | const segname = parseName(&section.segname); |
| 587 | 611 | const sectname = parseName(&section.sectname); |
| 612 | ||
| 588 | 613 | const res: ?MatchingSection = blk: { |
| 589 | 614 | switch (section.flags) { |
| 590 | 615 | 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 { |
| 612 | 637 | }; |
| 613 | 638 | }, |
| 614 | 639 | 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 | } | |
| 615 | 646 | break :blk .{ |
| 616 | 647 | .seg = self.data_segment_cmd_index.?, |
| 617 | 648 | .sect = self.bss_section_index.?, |
| ... | ... | @@ -667,6 +698,7 @@ fn getMatchingSection(self: *Zld, section: macho.section_64) ?MatchingSection { |
| 667 | 698 | }, |
| 668 | 699 | } |
| 669 | 700 | }; |
| 701 | ||
| 670 | 702 | return res; |
| 671 | 703 | } |
| 672 | 704 | |
| ... | ... | @@ -737,11 +769,12 @@ fn sortSections(self: *Zld) !void { |
| 737 | 769 | // __DATA segment |
| 738 | 770 | const indices = &[_]*?u16{ |
| 739 | 771 | &self.la_symbol_ptr_section_index, |
| 740 | &self.tlv_section_index, | |
| 741 | 772 | &self.data_section_index, |
| 773 | &self.tlv_section_index, | |
| 742 | 774 | &self.tlv_data_section_index, |
| 743 | 775 | &self.tlv_bss_section_index, |
| 744 | 776 | &self.bss_section_index, |
| 777 | &self.common_section_index, | |
| 745 | 778 | }; |
| 746 | 779 | for (indices) |maybe_index| { |
| 747 | 780 | const new_index: u16 = if (maybe_index.*) |index| blk: { |
| ... | ... | @@ -959,6 +992,21 @@ fn allocateStubsAndGotEntries(self: *Zld) !void { |
| 959 | 992 | } |
| 960 | 993 | } |
| 961 | 994 | |
| 995 | fn 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 | ||
| 962 | 1010 | fn writeStubHelperCommon(self: *Zld) !void { |
| 963 | 1011 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 964 | 1012 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| ... | ... | @@ -1236,11 +1284,12 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void { |
| 1236 | 1284 | continue; |
| 1237 | 1285 | } else if (Symbol.isGlobal(sym)) { |
| 1238 | 1286 | const sym_name = object.getString(sym.n_strx); |
| 1287 | const is_weak = Symbol.isWeakDef(sym) or Symbol.isPext(sym); | |
| 1239 | 1288 | const global = self.symtab.getEntry(sym_name) orelse { |
| 1240 | 1289 | // Put new global symbol into the symbol table. |
| 1241 | 1290 | const name = try self.allocator.dupe(u8, sym_name); |
| 1242 | 1291 | try self.symtab.putNoClobber(self.allocator, name, .{ |
| 1243 | .tag = if (Symbol.isWeakDef(sym)) .weak else .strong, | |
| 1292 | .tag = if (is_weak) .weak else .strong, | |
| 1244 | 1293 | .name = name, |
| 1245 | 1294 | .address = 0, |
| 1246 | 1295 | .section = 0, |
| ... | ... | @@ -1251,15 +1300,20 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void { |
| 1251 | 1300 | }; |
| 1252 | 1301 | |
| 1253 | 1302 | 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 | }, | |
| 1255 | 1306 | .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; | |
| 1258 | 1312 | }, |
| 1259 | 1313 | else => {}, |
| 1260 | 1314 | } |
| 1261 | 1315 | |
| 1262 | global.value.tag = .strong; | |
| 1316 | global.value.tag = if (is_weak) .weak else .strong; | |
| 1263 | 1317 | global.value.file = object_id; |
| 1264 | 1318 | global.value.index = @intCast(u32, sym_id); |
| 1265 | 1319 | } else if (Symbol.isUndef(sym)) { |
| ... | ... | @@ -1340,6 +1394,21 @@ fn resolveSymbols(self: *Zld) !void { |
| 1340 | 1394 | .section = 0, |
| 1341 | 1395 | .file = 0, |
| 1342 | 1396 | }); |
| 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 | } | |
| 1343 | 1412 | } |
| 1344 | 1413 | |
| 1345 | 1414 | fn resolveStubsAndGotEntries(self: *Zld) !void { |
| ... | ... | @@ -1412,9 +1481,14 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1412 | 1481 | log.debug("relocating object {s}", .{object.name}); |
| 1413 | 1482 | |
| 1414 | 1483 | 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 | ||
| 1415 | 1487 | const segname = parseName(&sect.inner.segname); |
| 1416 | 1488 | const sectname = parseName(&sect.inner.sectname); |
| 1417 | 1489 | |
| 1490 | log.debug("relocating section '{s},{s}'", .{ segname, sectname }); | |
| 1491 | ||
| 1418 | 1492 | // Get mapping |
| 1419 | 1493 | const target_mapping = self.mappings.get(.{ |
| 1420 | 1494 | .object_id = @intCast(u16, object_id), |
| ... | ... | @@ -1532,6 +1606,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1532 | 1606 | target_sect_off, |
| 1533 | 1607 | target_sect_off + sect.code.len, |
| 1534 | 1608 | }); |
| 1609 | ||
| 1535 | 1610 | // Zero-out the space |
| 1536 | 1611 | var zeroes = try self.allocator.alloc(u8, sect.code.len); |
| 1537 | 1612 | defer self.allocator.free(zeroes); |
| ... | ... | @@ -1571,25 +1646,33 @@ fn relocTargetAddr(self: *Zld, object_id: u16, target: reloc.Relocation.Target) |
| 1571 | 1646 | const target_sect = target_seg.sections.items[target_mapping.target_sect_id]; |
| 1572 | 1647 | const target_addr = target_sect.addr + target_mapping.offset; |
| 1573 | 1648 | 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, | |
| 1592 | 1672 | } |
| 1673 | } else { | |
| 1674 | log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name}); | |
| 1675 | return error.FailedToResolveRelocationTarget; | |
| 1593 | 1676 | } |
| 1594 | 1677 | }, |
| 1595 | 1678 | .section => |sect_id| { |
| ... | ... | @@ -2008,6 +2091,12 @@ fn populateMetadata(self: *Zld) !void { |
| 2008 | 2091 | } |
| 2009 | 2092 | |
| 2010 | 2093 | fn 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 | ||
| 2011 | 2100 | if (self.bss_section_index) |index| { |
| 2012 | 2101 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2013 | 2102 | const sect = &seg.sections.items[index]; |
| ... | ... | @@ -2040,6 +2129,24 @@ fn flush(self: *Zld) !void { |
| 2040 | 2129 | try self.file.?.pwriteAll(buffer, sect.offset); |
| 2041 | 2130 | } |
| 2042 | 2131 | |
| 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 | ||
| 2043 | 2150 | try self.writeGotEntries(); |
| 2044 | 2151 | try self.setEntryPoint(); |
| 2045 | 2152 | try self.writeRebaseInfoTable(); |
| ... | ... | @@ -2139,35 +2246,18 @@ fn writeRebaseInfoTable(self: *Zld) !void { |
| 2139 | 2246 | // TODO audit and investigate this. |
| 2140 | 2247 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2141 | 2248 | const sect = seg.sections.items[idx]; |
| 2142 | const npointers = sect.size * @sizeOf(u64); | |
| 2143 | 2249 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 2144 | 2250 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); |
| 2145 | 2251 | |
| 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 | } | |
| 2171 | 2261 | } |
| 2172 | 2262 | } |
| 2173 | 2263 | |
| ... | ... | @@ -2447,7 +2537,7 @@ fn writeDebugInfo(self: *Zld) !void { |
| 2447 | 2537 | .n_type = macho.N_OSO, |
| 2448 | 2538 | .n_sect = 0, |
| 2449 | 2539 | .n_desc = 1, |
| 2450 | .n_value = tu_mtime, | |
| 2540 | .n_value = 0, //tu_mtime, TODO figure out why precalculated mtime value doesn't work | |
| 2451 | 2541 | }); |
| 2452 | 2542 | |
| 2453 | 2543 | for (object.stabs.items) |stab| { |
src/link/MachO/reloc/aarch64.zig+3-1| ... | ... | @@ -226,7 +226,9 @@ pub const Parser = struct { |
| 226 | 226 | try parser.parseTlvpLoadPageOff(rel); |
| 227 | 227 | }, |
| 228 | 228 | .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", .{}); | |
| 230 | 232 | }, |
| 231 | 233 | } |
| 232 | 234 | } |
src/main.zig+6| ... | ... | @@ -355,6 +355,8 @@ const usage_build_generic = |
| 355 | 355 | \\ -rpath [path] Add directory to the runtime library search path |
| 356 | 356 | \\ -feach-lib-rpath Ensure adding rpath for each used dynamic library |
| 357 | 357 | \\ -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 | |
| 358 | 360 | \\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker |
| 359 | 361 | \\ --emit-relocs Enable output of relocation sections for post build tools |
| 360 | 362 | \\ -dynamic Force output to be dynamically linked |
| ... | ... | @@ -988,6 +990,10 @@ fn buildOutputType( |
| 988 | 990 | link_eh_frame_hdr = true; |
| 989 | 991 | } else if (mem.eql(u8, arg, "--emit-relocs")) { |
| 990 | 992 | 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; | |
| 991 | 997 | } else if (mem.eql(u8, arg, "-Bsymbolic")) { |
| 992 | 998 | linker_bind_global_refs_locally = true; |
| 993 | 999 | } else if (mem.eql(u8, arg, "--verbose-link")) { |
src/register_manager.zig+74-37| ... | ... | @@ -36,7 +36,7 @@ pub fn RegisterManager( |
| 36 | 36 | } |
| 37 | 37 | |
| 38 | 38 | fn isTracked(reg: Register) bool { |
| 39 | return std.mem.indexOfScalar(Register, callee_preserved_regs, reg) != null; | |
| 39 | return reg.allocIndex() != null; | |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | 42 | fn markRegUsed(self: *Self, reg: Register) void { |
| ... | ... | @@ -55,6 +55,7 @@ pub fn RegisterManager( |
| 55 | 55 | self.free_registers |= @as(FreeRegInt, 1) << shift; |
| 56 | 56 | } |
| 57 | 57 | |
| 58 | /// Returns true when this register is not tracked | |
| 58 | 59 | pub fn isRegFree(self: Self, reg: Register) bool { |
| 59 | 60 | if (FreeRegInt == u0) return true; |
| 60 | 61 | const index = reg.allocIndex() orelse return true; |
| ... | ... | @@ -63,7 +64,8 @@ pub fn RegisterManager( |
| 63 | 64 | } |
| 64 | 65 | |
| 65 | 66 | /// 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 | |
| 67 | 69 | pub fn isRegAllocated(self: Self, reg: Register) bool { |
| 68 | 70 | if (FreeRegInt == u0) return false; |
| 69 | 71 | const index = reg.allocIndex() orelse return false; |
| ... | ... | @@ -71,57 +73,89 @@ pub fn RegisterManager( |
| 71 | 73 | return self.allocated_registers & @as(FreeRegInt, 1) << shift != 0; |
| 72 | 74 | } |
| 73 | 75 | |
| 74 | /// Before calling, must ensureCapacity + 1 on self.registers. | |
| 76 | /// Before calling, must ensureCapacity + count on self.registers. | |
| 75 | 77 | /// 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 { | |
| 79 | 87 | return null; |
| 80 | 88 | } |
| 89 | } | |
| 81 | 90 | |
| 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 | } | |
| 90 | 96 | |
| 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 | }; | |
| 95 | 122 | } |
| 96 | 123 | |
| 97 | 124 | /// Before calling, must ensureCapacity + 1 on self.registers. |
| 98 | 125 | 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 | } | |
| 107 | 128 | |
| 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; | |
| 110 | 148 | } |
| 111 | 149 | |
| 112 | 150 | /// Does not track the register. |
| 113 | 151 | /// 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; | |
| 120 | 154 | } |
| 121 | 155 | |
| 122 | 156 | /// Does not track the register. |
| 123 | 157 | pub fn allocRegWithoutTracking(self: *Self) !Register { |
| 124 | return self.findUnusedReg() orelse b: { | |
| 158 | return self.tryAllocRegWithoutTracking() orelse b: { | |
| 125 | 159 | // We'll take over the first register. Move the instruction that was previously |
| 126 | 160 | // there to a stack allocation. |
| 127 | 161 | const reg = callee_preserved_regs[0]; |
| ... | ... | @@ -190,7 +224,10 @@ pub fn RegisterManager( |
| 190 | 224 | } |
| 191 | 225 | |
| 192 | 226 | const MockRegister = enum(u2) { |
| 193 | r0, r1, r2, r3, | |
| 227 | r0, | |
| 228 | r1, | |
| 229 | r2, | |
| 230 | r3, | |
| 194 | 231 | |
| 195 | 232 | pub fn allocIndex(self: MockRegister) ?u2 { |
| 196 | 233 | inline for (mock_callee_preserved_regs) |cpreg, i| { |
| ... | ... | @@ -213,7 +250,7 @@ const MockFunction = struct { |
| 213 | 250 | self.register_manager.deinit(self.allocator); |
| 214 | 251 | self.spilled.deinit(self.allocator); |
| 215 | 252 | } |
| 216 | ||
| 253 | ||
| 217 | 254 | pub fn spillInstruction(self: *Self, src: LazySrcLoc, reg: MockRegister, inst: *ir.Inst) !void { |
| 218 | 255 | try self.spilled.append(self.allocator, reg); |
| 219 | 256 | } |
src/stage1/bigfloat.cpp+3-6| ... | ... | @@ -9,6 +9,7 @@ |
| 9 | 9 | #include "bigint.hpp" |
| 10 | 10 | #include "buffer.hpp" |
| 11 | 11 | #include "softfloat.hpp" |
| 12 | #include "softfloat_ext.hpp" | |
| 12 | 13 | #include "parse_f128.h" |
| 13 | 14 | #include <stdio.h> |
| 14 | 15 | #include <math.h> |
| ... | ... | @@ -60,9 +61,7 @@ void bigfloat_init_bigint(BigFloat *dest, const BigInt *op) { |
| 60 | 61 | |
| 61 | 62 | if (i == 0) { |
| 62 | 63 | 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); | |
| 66 | 65 | } |
| 67 | 66 | return; |
| 68 | 67 | } |
| ... | ... | @@ -89,9 +88,7 @@ void bigfloat_add(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) { |
| 89 | 88 | } |
| 90 | 89 | |
| 91 | 90 | void 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); | |
| 95 | 92 | } |
| 96 | 93 | |
| 97 | 94 | void 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) { |
| 1446 | 1446 | bigint_normalize(dest); |
| 1447 | 1447 | } |
| 1448 | 1448 | |
| 1449 | void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count) { | |
| 1449 | void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed) { | |
| 1450 | 1450 | BigInt zero; |
| 1451 | 1451 | 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); | |
| 1453 | 1453 | } |
| 1454 | 1454 | |
| 1455 | 1455 | void 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 |
| 75 | 75 | void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2); |
| 76 | 76 | |
| 77 | 77 | void bigint_negate(BigInt *dest, const BigInt *op); |
| 78 | void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count); | |
| 78 | void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed); | |
| 79 | 79 | void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed); |
| 80 | 80 | void bigint_truncate(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed); |
| 81 | 81 |
src/stage1/codegen.cpp+4-1| ... | ... | @@ -7436,7 +7436,10 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n |
| 7436 | 7436 | case ZigTypeIdFloat: |
| 7437 | 7437 | switch (type_entry->data.floating.bit_count) { |
| 7438 | 7438 | 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 | } | |
| 7440 | 7443 | case 32: |
| 7441 | 7444 | return LLVMConstReal(get_llvm_type(g, type_entry), const_val->data.x_f32); |
| 7442 | 7445 | case 64: |
src/stage1/ir.cpp+13-20| ... | ... | @@ -9534,7 +9534,7 @@ static IrInstSrc *ir_gen_nosuspend(IrBuilderSrc *irb, Scope *parent_scope, AstNo |
| 9534 | 9534 | |
| 9535 | 9535 | Scope *child_scope = create_nosuspend_scope(irb->codegen, node, parent_scope); |
| 9536 | 9536 | // 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); | |
| 9538 | 9538 | } |
| 9539 | 9539 | |
| 9540 | 9540 | static 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 |
| 10199 | 10199 | } |
| 10200 | 10200 | |
| 10201 | 10201 | 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)); | |
| 10210 | 10208 | |
| 10211 | 10209 | return ir_mark_gen(ir_build_suspend_finish_src(irb, parent_scope, node, begin)); |
| 10212 | 10210 | } |
| ... | ... | @@ -11363,11 +11361,8 @@ static void float_negate(ZigValue *out_val, ZigValue *op) { |
| 11363 | 11361 | } else if (op->type->id == ZigTypeIdFloat) { |
| 11364 | 11362 | switch (op->type->data.floating.bit_count) { |
| 11365 | 11363 | 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; | |
| 11371 | 11366 | case 32: |
| 11372 | 11367 | out_val->data.x_f32 = -op->data.x_f32; |
| 11373 | 11368 | return; |
| ... | ... | @@ -11375,9 +11370,7 @@ static void float_negate(ZigValue *out_val, ZigValue *op) { |
| 11375 | 11370 | out_val->data.x_f64 = -op->data.x_f64; |
| 11376 | 11371 | return; |
| 11377 | 11372 | 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); | |
| 11381 | 11374 | return; |
| 11382 | 11375 | default: |
| 11383 | 11376 | zig_unreachable(); |
| ... | ... | @@ -21665,8 +21658,8 @@ static ErrorMsg *ir_eval_negation_scalar(IrAnalyze *ira, IrInst* source_instr, Z |
| 21665 | 21658 | { |
| 21666 | 21659 | bool is_float = (scalar_type->id == ZigTypeIdFloat || scalar_type->id == ZigTypeIdComptimeFloat); |
| 21667 | 21660 | |
| 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); | |
| 21670 | 21663 | |
| 21671 | 21664 | if (!ok_type) { |
| 21672 | 21665 | 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 |
| 21677 | 21670 | float_negate(scalar_out_val, operand_val); |
| 21678 | 21671 | } else if (is_wrap_op) { |
| 21679 | 21672 | 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); | |
| 21681 | 21674 | } else { |
| 21682 | 21675 | bigint_negate(&scalar_out_val->data.x_bigint, &operand_val->data.x_bigint); |
| 21683 | 21676 | } |
src/stage1/parser.cpp+1-4| ... | ... | @@ -946,10 +946,7 @@ static AstNode *ast_parse_statement(ParseContext *pc) { |
| 946 | 946 | |
| 947 | 947 | Token *suspend = eat_token_if(pc, TokenIdKeywordSuspend); |
| 948 | 948 | 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); | |
| 953 | 950 | AstNode *res = ast_create_node(pc, NodeTypeSuspend, suspend); |
| 954 | 951 | res->data.suspend.block = statement; |
| 955 | 952 | return res; |
src/stage1/softfloat_ext.cpp+31-7| ... | ... | @@ -1,17 +1,21 @@ |
| 1 | 1 | #include "softfloat_ext.hpp" |
| 2 | #include "zigendian.h" | |
| 2 | 3 | |
| 3 | 4 | extern "C" { |
| 4 | 5 | #include "softfloat.h" |
| 5 | 6 | } |
| 6 | 7 | |
| 7 | 8 | void 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 | |
| 15 | 19 | } |
| 16 | 20 | |
| 17 | 21 | void f128M_trunc(const float128_t *aPtr, float128_t *zPtr) { |
| ... | ... | @@ -22,4 +26,24 @@ void f128M_trunc(const float128_t *aPtr, float128_t *zPtr) { |
| 22 | 26 | } else { |
| 23 | 27 | f128M_roundToInt(aPtr, softfloat_round_min, false, zPtr); |
| 24 | 28 | } |
| 29 | } | |
| 30 | ||
| 31 | float16_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 | ||
| 38 | void 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 | |
| 25 | 49 | } |
| \ No newline at end of file |
src/stage1/softfloat_ext.hpp+3| ... | ... | @@ -5,5 +5,8 @@ |
| 5 | 5 | |
| 6 | 6 | void f128M_abs(const float128_t *aPtr, float128_t *zPtr); |
| 7 | 7 | void f128M_trunc(const float128_t *aPtr, float128_t *zPtr); |
| 8 | void f128M_neg(const float128_t *aPtr, float128_t *zPtr); | |
| 9 | ||
| 10 | float16_t f16_neg(const float16_t a); | |
| 8 | 11 | |
| 9 | 12 | #endif |
| \ No newline at end of file |
src/translate_c.zig+10-6| ... | ... | @@ -1353,10 +1353,14 @@ fn transCreatePointerArithmeticSignedOp( |
| 1353 | 1353 | |
| 1354 | 1354 | const bitcast_node = try usizeCastForWrappingPtrArithmetic(c.arena, rhs_node); |
| 1355 | 1355 | |
| 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 | ); | |
| 1360 | 1364 | } |
| 1361 | 1365 | |
| 1362 | 1366 | fn transBinaryOperator( |
| ... | ... | @@ -2161,8 +2165,8 @@ fn transCCast( |
| 2161 | 2165 | return Tag.as.create(c.arena, .{ .lhs = dst_node, .rhs = bool_to_int }); |
| 2162 | 2166 | } |
| 2163 | 2167 | 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 }); | |
| 2166 | 2170 | } |
| 2167 | 2171 | if (cIsEnum(src_type) and !cIsEnum(dst_type)) { |
| 2168 | 2172 | // @enumToInt(val) |
src/translate_c/ast.zig+3-3| ... | ... | @@ -1665,7 +1665,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 1665 | 1665 | }, |
| 1666 | 1666 | .array_access => { |
| 1667 | 1667 | const payload = node.castTag(.array_access).?.data; |
| 1668 | const lhs = try renderNode(c, payload.lhs); | |
| 1668 | const lhs = try renderNodeGrouped(c, payload.lhs); | |
| 1669 | 1669 | const l_bracket = try c.addToken(.l_bracket, "["); |
| 1670 | 1670 | const index_expr = try renderNode(c, payload.rhs); |
| 1671 | 1671 | _ = try c.addToken(.r_bracket, "]"); |
| ... | ... | @@ -1728,7 +1728,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 1728 | 1728 | }, |
| 1729 | 1729 | .field_access => { |
| 1730 | 1730 | const payload = node.castTag(.field_access).?.data; |
| 1731 | const lhs = try renderNode(c, payload.lhs); | |
| 1731 | const lhs = try renderNodeGrouped(c, payload.lhs); | |
| 1732 | 1732 | return renderFieldAccess(c, lhs, payload.field_name); |
| 1733 | 1733 | }, |
| 1734 | 1734 | .@"struct", .@"union" => return renderRecord(c, node), |
| ... | ... | @@ -2073,7 +2073,7 @@ fn renderNullSentinelArrayType(c: *Context, len: usize, elem_type: Node) !NodeIn |
| 2073 | 2073 | .main_token = l_bracket, |
| 2074 | 2074 | .data = .{ |
| 2075 | 2075 | .lhs = len_expr, |
| 2076 | .rhs = try c.addExtra(std.zig.ast.Node.ArrayTypeSentinel { | |
| 2076 | .rhs = try c.addExtra(std.zig.ast.Node.ArrayTypeSentinel{ | |
| 2077 | 2077 | .sentinel = sentinel_expr, |
| 2078 | 2078 | .elem_type = elem_type_expr, |
| 2079 | 2079 | }), |
test/compile_errors.zig+7-7| ... | ... | @@ -1021,7 +1021,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1021 | 1021 | \\export fn entry() void { |
| 1022 | 1022 | \\ nosuspend { |
| 1023 | 1023 | \\ const bar = async foo(); |
| 1024 | \\ suspend; | |
| 1024 | \\ suspend {} | |
| 1025 | 1025 | \\ resume bar; |
| 1026 | 1026 | \\ } |
| 1027 | 1027 | \\} |
| ... | ... | @@ -2120,7 +2120,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 2120 | 2120 | \\ non_async_fn = func; |
| 2121 | 2121 | \\} |
| 2122 | 2122 | \\fn func() void { |
| 2123 | \\ suspend; | |
| 2123 | \\ suspend {} | |
| 2124 | 2124 | \\} |
| 2125 | 2125 | , &[_][]const u8{ |
| 2126 | 2126 | "tmp.zig:5:1: error: 'func' cannot be async", |
| ... | ... | @@ -2198,7 +2198,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 2198 | 2198 | \\ var x: anyframe = &f; |
| 2199 | 2199 | \\} |
| 2200 | 2200 | \\fn func() void { |
| 2201 | \\ suspend; | |
| 2201 | \\ suspend {} | |
| 2202 | 2202 | \\} |
| 2203 | 2203 | , &[_][]const u8{ |
| 2204 | 2204 | "tmp.zig:3:12: error: expected type 'anyframe', found '*const @Frame(func)'", |
| ... | ... | @@ -2231,10 +2231,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 2231 | 2231 | \\ frame = async bar(); |
| 2232 | 2232 | \\} |
| 2233 | 2233 | \\fn foo() void { |
| 2234 | \\ suspend; | |
| 2234 | \\ suspend {} | |
| 2235 | 2235 | \\} |
| 2236 | 2236 | \\fn bar() void { |
| 2237 | \\ suspend; | |
| 2237 | \\ suspend {} | |
| 2238 | 2238 | \\} |
| 2239 | 2239 | , &[_][]const u8{ |
| 2240 | 2240 | "tmp.zig:3:13: error: expected type '*@Frame(bar)', found '*@Frame(foo)'", |
| ... | ... | @@ -2269,7 +2269,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 2269 | 2269 | \\ var result = await frame; |
| 2270 | 2270 | \\} |
| 2271 | 2271 | \\fn func() void { |
| 2272 | \\ suspend; | |
| 2272 | \\ suspend {} | |
| 2273 | 2273 | \\} |
| 2274 | 2274 | , &[_][]const u8{ |
| 2275 | 2275 | "tmp.zig:1:1: error: function with calling convention 'C' cannot be async", |
| ... | ... | @@ -2347,7 +2347,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 2347 | 2347 | \\ bar(); |
| 2348 | 2348 | \\} |
| 2349 | 2349 | \\fn bar() void { |
| 2350 | \\ suspend; | |
| 2350 | \\ suspend {} | |
| 2351 | 2351 | \\} |
| 2352 | 2352 | , &[_][]const u8{ |
| 2353 | 2353 | "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 { |
| 1453 | 1453 | \\ return 0; |
| 1454 | 1454 | \\} |
| 1455 | 1455 | , ""); |
| 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 | , ""); | |
| 1456 | 1479 | } |
test/runtime_safety.zig+17-17| ... | ... | @@ -13,7 +13,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 13 | 13 | |
| 14 | 14 | cases.addRuntimeSafety("switch on corrupted enum value", |
| 15 | 15 | \\const std = @import("std"); |
| 16 | ++ check_panic_msg ++ | |
| 16 | ++ check_panic_msg ++ | |
| 17 | 17 | \\const E = enum(u32) { |
| 18 | 18 | \\ X = 1, |
| 19 | 19 | \\}; |
| ... | ... | @@ -28,7 +28,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 28 | 28 | |
| 29 | 29 | cases.addRuntimeSafety("switch on corrupted union value", |
| 30 | 30 | \\const std = @import("std"); |
| 31 | ++ check_panic_msg ++ | |
| 31 | ++ check_panic_msg ++ | |
| 32 | 32 | \\const U = union(enum(u32)) { |
| 33 | 33 | \\ X: u8, |
| 34 | 34 | \\}; |
| ... | ... | @@ -54,7 +54,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 54 | 54 | |
| 55 | 55 | cases.addRuntimeSafety("@tagName on corrupted enum value", |
| 56 | 56 | \\const std = @import("std"); |
| 57 | ++ check_panic_msg ++ | |
| 57 | ++ check_panic_msg ++ | |
| 58 | 58 | \\const E = enum(u32) { |
| 59 | 59 | \\ X = 1, |
| 60 | 60 | \\}; |
| ... | ... | @@ -67,7 +67,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 67 | 67 | |
| 68 | 68 | cases.addRuntimeSafety("@tagName on corrupted union value", |
| 69 | 69 | \\const std = @import("std"); |
| 70 | ++ check_panic_msg ++ | |
| 70 | ++ check_panic_msg ++ | |
| 71 | 71 | \\const U = union(enum(u32)) { |
| 72 | 72 | \\ X: u8, |
| 73 | 73 | \\}; |
| ... | ... | @@ -92,7 +92,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 92 | 92 | |
| 93 | 93 | cases.addRuntimeSafety("slicing operator with sentinel", |
| 94 | 94 | \\const std = @import("std"); |
| 95 | ++ check_panic_msg ++ | |
| 95 | ++ check_panic_msg ++ | |
| 96 | 96 | \\pub fn main() void { |
| 97 | 97 | \\ var buf = [4]u8{'a','b','c',0}; |
| 98 | 98 | \\ const slice = buf[0..4 :0]; |
| ... | ... | @@ -100,7 +100,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 100 | 100 | ); |
| 101 | 101 | cases.addRuntimeSafety("slicing operator with sentinel", |
| 102 | 102 | \\const std = @import("std"); |
| 103 | ++ check_panic_msg ++ | |
| 103 | ++ check_panic_msg ++ | |
| 104 | 104 | \\pub fn main() void { |
| 105 | 105 | \\ var buf = [4]u8{'a','b','c',0}; |
| 106 | 106 | \\ const slice = buf[0..:0]; |
| ... | ... | @@ -108,7 +108,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 108 | 108 | ); |
| 109 | 109 | cases.addRuntimeSafety("slicing operator with sentinel", |
| 110 | 110 | \\const std = @import("std"); |
| 111 | ++ check_panic_msg ++ | |
| 111 | ++ check_panic_msg ++ | |
| 112 | 112 | \\pub fn main() void { |
| 113 | 113 | \\ var buf_zero = [0]u8{}; |
| 114 | 114 | \\ const slice = buf_zero[0..0 :0]; |
| ... | ... | @@ -116,7 +116,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 116 | 116 | ); |
| 117 | 117 | cases.addRuntimeSafety("slicing operator with sentinel", |
| 118 | 118 | \\const std = @import("std"); |
| 119 | ++ check_panic_msg ++ | |
| 119 | ++ check_panic_msg ++ | |
| 120 | 120 | \\pub fn main() void { |
| 121 | 121 | \\ var buf_zero = [0]u8{}; |
| 122 | 122 | \\ const slice = buf_zero[0..:0]; |
| ... | ... | @@ -124,7 +124,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 124 | 124 | ); |
| 125 | 125 | cases.addRuntimeSafety("slicing operator with sentinel", |
| 126 | 126 | \\const std = @import("std"); |
| 127 | ++ check_panic_msg ++ | |
| 127 | ++ check_panic_msg ++ | |
| 128 | 128 | \\pub fn main() void { |
| 129 | 129 | \\ var buf_sentinel = [2:0]u8{'a','b'}; |
| 130 | 130 | \\ @ptrCast(*[3]u8, &buf_sentinel)[2] = 0; |
| ... | ... | @@ -133,7 +133,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 133 | 133 | ); |
| 134 | 134 | cases.addRuntimeSafety("slicing operator with sentinel", |
| 135 | 135 | \\const std = @import("std"); |
| 136 | ++ check_panic_msg ++ | |
| 136 | ++ check_panic_msg ++ | |
| 137 | 137 | \\pub fn main() void { |
| 138 | 138 | \\ var buf_slice: []const u8 = &[3]u8{ 'a', 'b', 0 }; |
| 139 | 139 | \\ const slice = buf_slice[0..3 :0]; |
| ... | ... | @@ -141,7 +141,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 141 | 141 | ); |
| 142 | 142 | cases.addRuntimeSafety("slicing operator with sentinel", |
| 143 | 143 | \\const std = @import("std"); |
| 144 | ++ check_panic_msg ++ | |
| 144 | ++ check_panic_msg ++ | |
| 145 | 145 | \\pub fn main() void { |
| 146 | 146 | \\ var buf_slice: []const u8 = &[3]u8{ 'a', 'b', 0 }; |
| 147 | 147 | \\ const slice = buf_slice[0.. :0]; |
| ... | ... | @@ -367,7 +367,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 367 | 367 | \\} |
| 368 | 368 | \\fn add(a: i32, b: i32) i32 { |
| 369 | 369 | \\ if (a > 100) { |
| 370 | \\ suspend; | |
| 370 | \\ suspend {} | |
| 371 | 371 | \\ } |
| 372 | 372 | \\ return a + b; |
| 373 | 373 | \\} |
| ... | ... | @@ -407,7 +407,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 407 | 407 | \\ var frame = @asyncCall(&bytes, {}, ptr, .{}); |
| 408 | 408 | \\} |
| 409 | 409 | \\fn other() callconv(.Async) void { |
| 410 | \\ suspend; | |
| 410 | \\ suspend {} | |
| 411 | 411 | \\} |
| 412 | 412 | ); |
| 413 | 413 | |
| ... | ... | @@ -424,7 +424,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 424 | 424 | \\ await frame; |
| 425 | 425 | \\} |
| 426 | 426 | \\fn other() void { |
| 427 | \\ suspend; | |
| 427 | \\ suspend {} | |
| 428 | 428 | \\} |
| 429 | 429 | ); |
| 430 | 430 | |
| ... | ... | @@ -440,7 +440,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 440 | 440 | \\ other(); |
| 441 | 441 | \\} |
| 442 | 442 | \\fn other() void { |
| 443 | \\ suspend; | |
| 443 | \\ suspend {} | |
| 444 | 444 | \\} |
| 445 | 445 | ); |
| 446 | 446 | |
| ... | ... | @@ -454,7 +454,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 454 | 454 | \\ resume p; //bad |
| 455 | 455 | \\} |
| 456 | 456 | \\fn suspendOnce() void { |
| 457 | \\ suspend; | |
| 457 | \\ suspend {} | |
| 458 | 458 | \\} |
| 459 | 459 | ); |
| 460 | 460 | |
| ... | ... | @@ -1019,7 +1019,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { |
| 1019 | 1019 | \\} |
| 1020 | 1020 | \\ |
| 1021 | 1021 | \\fn failing() anyerror!void { |
| 1022 | \\ suspend; | |
| 1022 | \\ suspend {} | |
| 1023 | 1023 | \\ return second(); |
| 1024 | 1024 | \\} |
| 1025 | 1025 | \\ |
test/stage1/behavior/async_fn.zig+42-42| ... | ... | @@ -18,9 +18,9 @@ test "simple coroutine suspend and resume" { |
| 18 | 18 | } |
| 19 | 19 | fn simpleAsyncFn() void { |
| 20 | 20 | global_x += 1; |
| 21 | suspend; | |
| 21 | suspend {} | |
| 22 | 22 | global_x += 1; |
| 23 | suspend; | |
| 23 | suspend {} | |
| 24 | 24 | global_x += 1; |
| 25 | 25 | } |
| 26 | 26 | |
| ... | ... | @@ -34,7 +34,7 @@ test "pass parameter to coroutine" { |
| 34 | 34 | } |
| 35 | 35 | fn simpleAsyncFnWithArg(delta: i32) void { |
| 36 | 36 | global_y += delta; |
| 37 | suspend; | |
| 37 | suspend {} | |
| 38 | 38 | global_y += delta; |
| 39 | 39 | } |
| 40 | 40 | |
| ... | ... | @@ -50,7 +50,7 @@ test "suspend at end of function" { |
| 50 | 50 | |
| 51 | 51 | fn suspendAtEnd() void { |
| 52 | 52 | x += 1; |
| 53 | suspend; | |
| 53 | suspend {} | |
| 54 | 54 | } |
| 55 | 55 | }; |
| 56 | 56 | S.doTheTest(); |
| ... | ... | @@ -74,11 +74,11 @@ test "local variable in async function" { |
| 74 | 74 | |
| 75 | 75 | fn add(a: i32, b: i32) void { |
| 76 | 76 | var accum: i32 = 0; |
| 77 | suspend; | |
| 77 | suspend {} | |
| 78 | 78 | accum += a; |
| 79 | suspend; | |
| 79 | suspend {} | |
| 80 | 80 | accum += b; |
| 81 | suspend; | |
| 81 | suspend {} | |
| 82 | 82 | x = accum; |
| 83 | 83 | } |
| 84 | 84 | }; |
| ... | ... | @@ -102,7 +102,7 @@ test "calling an inferred async function" { |
| 102 | 102 | } |
| 103 | 103 | fn other() void { |
| 104 | 104 | other_frame = @frame(); |
| 105 | suspend; | |
| 105 | suspend {} | |
| 106 | 106 | x += 1; |
| 107 | 107 | } |
| 108 | 108 | }; |
| ... | ... | @@ -129,7 +129,7 @@ test "@frameSize" { |
| 129 | 129 | } |
| 130 | 130 | fn other(param: i32) void { |
| 131 | 131 | var local: i32 = undefined; |
| 132 | suspend; | |
| 132 | suspend {} | |
| 133 | 133 | } |
| 134 | 134 | }; |
| 135 | 135 | S.doTheTest(); |
| ... | ... | @@ -269,7 +269,7 @@ test "async function with dot syntax" { |
| 269 | 269 | var y: i32 = 1; |
| 270 | 270 | fn foo() callconv(.Async) void { |
| 271 | 271 | y += 1; |
| 272 | suspend; | |
| 272 | suspend {} | |
| 273 | 273 | } |
| 274 | 274 | }; |
| 275 | 275 | const p = async S.foo(); |
| ... | ... | @@ -298,7 +298,7 @@ fn doTheAwait(f: anyframe->void) void { |
| 298 | 298 | fn simpleAsyncFn2(y: *i32) callconv(.Async) void { |
| 299 | 299 | defer y.* += 2; |
| 300 | 300 | y.* += 1; |
| 301 | suspend; | |
| 301 | suspend {} | |
| 302 | 302 | } |
| 303 | 303 | |
| 304 | 304 | test "@asyncCall with return type" { |
| ... | ... | @@ -312,7 +312,7 @@ test "@asyncCall with return type" { |
| 312 | 312 | |
| 313 | 313 | fn afunc() i32 { |
| 314 | 314 | global_frame = @frame(); |
| 315 | suspend; | |
| 315 | suspend {} | |
| 316 | 316 | return 1234; |
| 317 | 317 | } |
| 318 | 318 | }; |
| ... | ... | @@ -348,7 +348,7 @@ test "async fn with inferred error set" { |
| 348 | 348 | |
| 349 | 349 | fn failing() !void { |
| 350 | 350 | global_frame = @frame(); |
| 351 | suspend; | |
| 351 | suspend {} | |
| 352 | 352 | return error.Fail; |
| 353 | 353 | } |
| 354 | 354 | }; |
| ... | ... | @@ -375,7 +375,7 @@ fn nonFailing() (anyframe->anyerror!void) { |
| 375 | 375 | return &Static.frame; |
| 376 | 376 | } |
| 377 | 377 | fn suspendThenFail() callconv(.Async) anyerror!void { |
| 378 | suspend; | |
| 378 | suspend {} | |
| 379 | 379 | return error.Fail; |
| 380 | 380 | } |
| 381 | 381 | fn printTrace(p: anyframe->(anyerror!void)) callconv(.Async) void { |
| ... | ... | @@ -400,7 +400,7 @@ fn testBreakFromSuspend(my_result: *i32) callconv(.Async) void { |
| 400 | 400 | resume @frame(); |
| 401 | 401 | } |
| 402 | 402 | my_result.* += 1; |
| 403 | suspend; | |
| 403 | suspend {} | |
| 404 | 404 | my_result.* += 1; |
| 405 | 405 | } |
| 406 | 406 | |
| ... | ... | @@ -421,7 +421,7 @@ test "heap allocated async function frame" { |
| 421 | 421 | |
| 422 | 422 | fn someFunc() void { |
| 423 | 423 | x += 1; |
| 424 | suspend; | |
| 424 | suspend {} | |
| 425 | 425 | x += 1; |
| 426 | 426 | } |
| 427 | 427 | }; |
| ... | ... | @@ -454,7 +454,7 @@ test "async function call return value" { |
| 454 | 454 | |
| 455 | 455 | fn other(x: i32, y: i32) Point { |
| 456 | 456 | frame = @frame(); |
| 457 | suspend; | |
| 457 | suspend {} | |
| 458 | 458 | return Point{ |
| 459 | 459 | .x = x, |
| 460 | 460 | .y = y, |
| ... | ... | @@ -487,7 +487,7 @@ test "suspension points inside branching control flow" { |
| 487 | 487 | |
| 488 | 488 | fn func(b: bool) void { |
| 489 | 489 | while (b) { |
| 490 | suspend; | |
| 490 | suspend {} | |
| 491 | 491 | result += 1; |
| 492 | 492 | } |
| 493 | 493 | } |
| ... | ... | @@ -541,7 +541,7 @@ test "pass string literal to async function" { |
| 541 | 541 | |
| 542 | 542 | fn hello(msg: []const u8) void { |
| 543 | 543 | frame = @frame(); |
| 544 | suspend; | |
| 544 | suspend {} | |
| 545 | 545 | expectEqualStrings("hello", msg); |
| 546 | 546 | ok = true; |
| 547 | 547 | } |
| ... | ... | @@ -566,7 +566,7 @@ test "await inside an errdefer" { |
| 566 | 566 | |
| 567 | 567 | fn func() void { |
| 568 | 568 | frame = @frame(); |
| 569 | suspend; | |
| 569 | suspend {} | |
| 570 | 570 | } |
| 571 | 571 | }; |
| 572 | 572 | S.doTheTest(); |
| ... | ... | @@ -590,7 +590,7 @@ test "try in an async function with error union and non-zero-bit payload" { |
| 590 | 590 | |
| 591 | 591 | fn theProblem() ![]u8 { |
| 592 | 592 | frame = @frame(); |
| 593 | suspend; | |
| 593 | suspend {} | |
| 594 | 594 | const result = try other(); |
| 595 | 595 | return result; |
| 596 | 596 | } |
| ... | ... | @@ -622,7 +622,7 @@ test "returning a const error from async function" { |
| 622 | 622 | |
| 623 | 623 | fn fetchUrl(unused: i32, url: []const u8) ![]u8 { |
| 624 | 624 | frame = @frame(); |
| 625 | suspend; | |
| 625 | suspend {} | |
| 626 | 626 | ok = true; |
| 627 | 627 | return error.OutOfMemory; |
| 628 | 628 | } |
| ... | ... | @@ -967,7 +967,7 @@ test "@asyncCall with comptime-known function, but not awaited directly" { |
| 967 | 967 | |
| 968 | 968 | fn failing() !void { |
| 969 | 969 | global_frame = @frame(); |
| 970 | suspend; | |
| 970 | suspend {} | |
| 971 | 971 | return error.Fail; |
| 972 | 972 | } |
| 973 | 973 | }; |
| ... | ... | @@ -977,7 +977,7 @@ test "@asyncCall with comptime-known function, but not awaited directly" { |
| 977 | 977 | test "@asyncCall with actual frame instead of byte buffer" { |
| 978 | 978 | const S = struct { |
| 979 | 979 | fn func() i32 { |
| 980 | suspend; | |
| 980 | suspend {} | |
| 981 | 981 | return 1234; |
| 982 | 982 | } |
| 983 | 983 | }; |
| ... | ... | @@ -993,7 +993,7 @@ test "@asyncCall using the result location inside the frame" { |
| 993 | 993 | fn simple2(y: *i32) callconv(.Async) i32 { |
| 994 | 994 | defer y.* += 2; |
| 995 | 995 | y.* += 1; |
| 996 | suspend; | |
| 996 | suspend {} | |
| 997 | 997 | return 1234; |
| 998 | 998 | } |
| 999 | 999 | fn getAnswer(f: anyframe->i32, out: *i32) void { |
| ... | ... | @@ -1095,7 +1095,7 @@ test "nosuspend function call" { |
| 1095 | 1095 | } |
| 1096 | 1096 | fn add(a: i32, b: i32) i32 { |
| 1097 | 1097 | if (a > 100) { |
| 1098 | suspend; | |
| 1098 | suspend {} | |
| 1099 | 1099 | } |
| 1100 | 1100 | return a + b; |
| 1101 | 1101 | } |
| ... | ... | @@ -1170,7 +1170,7 @@ test "suspend in for loop" { |
| 1170 | 1170 | global_frame = @frame(); |
| 1171 | 1171 | var sum: u32 = 0; |
| 1172 | 1172 | for (stuff) |x| { |
| 1173 | suspend; | |
| 1173 | suspend {} | |
| 1174 | 1174 | sum += x; |
| 1175 | 1175 | } |
| 1176 | 1176 | global_frame = null; |
| ... | ... | @@ -1197,7 +1197,7 @@ test "suspend in while loop" { |
| 1197 | 1197 | global_frame = @frame(); |
| 1198 | 1198 | defer global_frame = null; |
| 1199 | 1199 | while (stuff) |val| { |
| 1200 | suspend; | |
| 1200 | suspend {} | |
| 1201 | 1201 | return val; |
| 1202 | 1202 | } |
| 1203 | 1203 | return 0; |
| ... | ... | @@ -1206,7 +1206,7 @@ test "suspend in while loop" { |
| 1206 | 1206 | global_frame = @frame(); |
| 1207 | 1207 | defer global_frame = null; |
| 1208 | 1208 | while (stuff) |val| { |
| 1209 | suspend; | |
| 1209 | suspend {} | |
| 1210 | 1210 | return val; |
| 1211 | 1211 | } else |err| { |
| 1212 | 1212 | return 0; |
| ... | ... | @@ -1339,7 +1339,7 @@ test "async function passed 0-bit arg after non-0-bit arg" { |
| 1339 | 1339 | |
| 1340 | 1340 | fn bar(x: i32, args: anytype) anyerror!void { |
| 1341 | 1341 | global_frame = @frame(); |
| 1342 | suspend; | |
| 1342 | suspend {} | |
| 1343 | 1343 | global_int = x; |
| 1344 | 1344 | } |
| 1345 | 1345 | }; |
| ... | ... | @@ -1361,7 +1361,7 @@ test "async function passed align(16) arg after align(8) arg" { |
| 1361 | 1361 | fn bar(x: u64, args: anytype) anyerror!void { |
| 1362 | 1362 | expect(x == 10); |
| 1363 | 1363 | global_frame = @frame(); |
| 1364 | suspend; | |
| 1364 | suspend {} | |
| 1365 | 1365 | global_int = args[0]; |
| 1366 | 1366 | } |
| 1367 | 1367 | }; |
| ... | ... | @@ -1383,7 +1383,7 @@ test "async function call resolves target fn frame, comptime func" { |
| 1383 | 1383 | |
| 1384 | 1384 | fn bar() anyerror!void { |
| 1385 | 1385 | global_frame = @frame(); |
| 1386 | suspend; | |
| 1386 | suspend {} | |
| 1387 | 1387 | global_int += 1; |
| 1388 | 1388 | } |
| 1389 | 1389 | }; |
| ... | ... | @@ -1406,7 +1406,7 @@ test "async function call resolves target fn frame, runtime func" { |
| 1406 | 1406 | |
| 1407 | 1407 | fn bar() anyerror!void { |
| 1408 | 1408 | global_frame = @frame(); |
| 1409 | suspend; | |
| 1409 | suspend {} | |
| 1410 | 1410 | global_int += 1; |
| 1411 | 1411 | } |
| 1412 | 1412 | }; |
| ... | ... | @@ -1430,7 +1430,7 @@ test "properly spill optional payload capture value" { |
| 1430 | 1430 | |
| 1431 | 1431 | fn bar() void { |
| 1432 | 1432 | global_frame = @frame(); |
| 1433 | suspend; | |
| 1433 | suspend {} | |
| 1434 | 1434 | global_int += 1; |
| 1435 | 1435 | } |
| 1436 | 1436 | }; |
| ... | ... | @@ -1466,13 +1466,13 @@ test "handle defer interfering with return value spill" { |
| 1466 | 1466 | |
| 1467 | 1467 | fn bar() anyerror!void { |
| 1468 | 1468 | global_frame1 = @frame(); |
| 1469 | suspend; | |
| 1469 | suspend {} | |
| 1470 | 1470 | return error.Bad; |
| 1471 | 1471 | } |
| 1472 | 1472 | |
| 1473 | 1473 | fn baz() void { |
| 1474 | 1474 | global_frame2 = @frame(); |
| 1475 | suspend; | |
| 1475 | suspend {} | |
| 1476 | 1476 | baz_happened = true; |
| 1477 | 1477 | } |
| 1478 | 1478 | }; |
| ... | ... | @@ -1497,7 +1497,7 @@ test "take address of temporary async frame" { |
| 1497 | 1497 | |
| 1498 | 1498 | fn foo(arg: i32) i32 { |
| 1499 | 1499 | global_frame = @frame(); |
| 1500 | suspend; | |
| 1500 | suspend {} | |
| 1501 | 1501 | return arg + 1234; |
| 1502 | 1502 | } |
| 1503 | 1503 | |
| ... | ... | @@ -1520,7 +1520,7 @@ test "nosuspend await" { |
| 1520 | 1520 | |
| 1521 | 1521 | fn foo(want_suspend: bool) i32 { |
| 1522 | 1522 | if (want_suspend) { |
| 1523 | suspend; | |
| 1523 | suspend {} | |
| 1524 | 1524 | } |
| 1525 | 1525 | return 42; |
| 1526 | 1526 | } |
| ... | ... | @@ -1569,11 +1569,11 @@ test "nosuspend on async function calls" { |
| 1569 | 1569 | // }; |
| 1570 | 1570 | // const S1 = struct { |
| 1571 | 1571 | // fn c() S0 { |
| 1572 | // suspend; | |
| 1572 | // suspend {} | |
| 1573 | 1573 | // return S0{}; |
| 1574 | 1574 | // } |
| 1575 | 1575 | // fn d() !S0 { |
| 1576 | // suspend; | |
| 1576 | // suspend {} | |
| 1577 | 1577 | // return S0{}; |
| 1578 | 1578 | // } |
| 1579 | 1579 | // }; |
| ... | ... | @@ -1591,11 +1591,11 @@ test "nosuspend resume async function calls" { |
| 1591 | 1591 | }; |
| 1592 | 1592 | const S1 = struct { |
| 1593 | 1593 | fn c() S0 { |
| 1594 | suspend; | |
| 1594 | suspend {} | |
| 1595 | 1595 | return S0{}; |
| 1596 | 1596 | } |
| 1597 | 1597 | fn d() !S0 { |
| 1598 | suspend; | |
| 1598 | suspend {} | |
| 1599 | 1599 | return S0{}; |
| 1600 | 1600 | } |
| 1601 | 1601 | }; |
test/stage1/behavior/math.zig+31-4| ... | ... | @@ -229,16 +229,26 @@ fn testSignedWrappingEval(x: i32) void { |
| 229 | 229 | expect(max_val == maxInt(i32)); |
| 230 | 230 | } |
| 231 | 231 | |
| 232 | test "negation wrapping" { | |
| 233 | testNegationWrappingEval(minInt(i16)); | |
| 234 | comptime testNegationWrappingEval(minInt(i16)); | |
| 232 | test "signed negation wrapping" { | |
| 233 | testSignedNegationWrappingEval(minInt(i16)); | |
| 234 | comptime testSignedNegationWrappingEval(minInt(i16)); | |
| 235 | 235 | } |
| 236 | fn testNegationWrappingEval(x: i16) void { | |
| 236 | fn testSignedNegationWrappingEval(x: i16) void { | |
| 237 | 237 | expect(x == -32768); |
| 238 | 238 | const neg = -%x; |
| 239 | 239 | expect(neg == -32768); |
| 240 | 240 | } |
| 241 | 241 | |
| 242 | test "unsigned negation wrapping" { | |
| 243 | testUnsignedNegationWrappingEval(1); | |
| 244 | comptime testUnsignedNegationWrappingEval(1); | |
| 245 | } | |
| 246 | fn testUnsignedNegationWrappingEval(x: u16) void { | |
| 247 | expect(x == 1); | |
| 248 | const neg = -%x; | |
| 249 | expect(neg == maxInt(u16)); | |
| 250 | } | |
| 251 | ||
| 242 | 252 | test "unsigned 64-bit division" { |
| 243 | 253 | test_u64_div(); |
| 244 | 254 | comptime test_u64_div(); |
| ... | ... | @@ -843,3 +853,20 @@ test "compare undefined literal with comptime_int" { |
| 843 | 853 | x = true; |
| 844 | 854 | expect(x); |
| 845 | 855 | } |
| 856 | ||
| 857 | test "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: { |
| 212 | 212 | // .link_libc = true, |
| 213 | 213 | //}, |
| 214 | 214 | |
| 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 | ||
| 215 | 231 | TestTarget{ |
| 216 | 232 | .target = .{ |
| 217 | 233 | .cpu_arch = .riscv64, |
test/translate_c.zig+20-4| ... | ... | @@ -3,6 +3,22 @@ const std = @import("std"); |
| 3 | 3 | const CrossTarget = std.zig.CrossTarget; |
| 4 | 4 | |
| 5 | 5 | pub 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 | ||
| 6 | 22 | cases.add("unnamed child types of typedef receive typedef's name", |
| 7 | 23 | \\typedef enum { |
| 8 | 24 | \\ FooA, |
| ... | ... | @@ -111,7 +127,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 111 | 127 | \\ const A = @enumToInt(enum_Foo.A); |
| 112 | 128 | \\ const B = @enumToInt(enum_Foo.B); |
| 113 | 129 | \\ 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); | |
| 115 | 131 | \\ { |
| 116 | 132 | \\ const enum_Foo = extern enum(c_int) { |
| 117 | 133 | \\ A, |
| ... | ... | @@ -122,7 +138,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 122 | 138 | \\ const A_2 = @enumToInt(enum_Foo.A); |
| 123 | 139 | \\ const B_3 = @enumToInt(enum_Foo.B); |
| 124 | 140 | \\ 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); | |
| 126 | 142 | \\ } |
| 127 | 143 | \\} |
| 128 | 144 | }); |
| ... | ... | @@ -1676,7 +1692,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1676 | 1692 | \\pub const e = @enumToInt(enum_unnamed_1.e); |
| 1677 | 1693 | \\pub const f = @enumToInt(enum_unnamed_1.f); |
| 1678 | 1694 | \\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); | |
| 1680 | 1696 | \\const enum_unnamed_2 = extern enum(c_int) { |
| 1681 | 1697 | \\ i, |
| 1682 | 1698 | \\ j, |
| ... | ... | @@ -2308,7 +2324,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 2308 | 2324 | \\ var a = arg_a; |
| 2309 | 2325 | \\ var b = arg_b; |
| 2310 | 2326 | \\ 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); | |
| 2312 | 2328 | \\ var e: c_int = @boolToInt((a != 0) and (b != 0)); |
| 2313 | 2329 | \\ var f: c_int = @boolToInt((b != 0) and (c != null)); |
| 2314 | 2330 | \\ var g: c_int = @boolToInt((a != 0) and (c != null)); |
tools/update_cpu_features.zig+6| ... | ... | @@ -663,6 +663,12 @@ const llvm_targets = [_]LlvmTarget{ |
| 663 | 663 | .zig_name = "powerpc", |
| 664 | 664 | .llvm_name = "PowerPC", |
| 665 | 665 | .td_name = "PPC.td", |
| 666 | .feature_overrides = &.{ | |
| 667 | .{ | |
| 668 | .llvm_name = "ppc32", | |
| 669 | .omit = true, | |
| 670 | }, | |
| 671 | }, | |
| 666 | 672 | }, |
| 667 | 673 | .{ |
| 668 | 674 | .zig_name = "riscv", |