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