| author | |
| committer | |
| log | 584cb2e4fb67eb95a8c9d790f807235c8088bd76 |
| tree | 26e1a211055647edf04734ce0d10ff5f762df31c |
| parent | 24215df8c56ba64e624487f914513212e3e747e9 |
| parent | bee7db77fe65802a41f2812caac4faa7dcb8acd3 |
45 files changed, 824 insertions(+), 170 deletions(-)
doc/langref.html.in+2-2| ... | ... | @@ -933,8 +933,8 @@ const assert = std.debug.assert; |
| 933 | 933 | threadlocal var x: i32 = 1234; |
| 934 | 934 | |
| 935 | 935 | test "thread local storage" { |
| 936 | const thread1 = try std.Thread.spawn({}, testTls); | |
| 937 | const thread2 = try std.Thread.spawn({}, testTls); | |
| 936 | const thread1 = try std.Thread.spawn(testTls, {}); | |
| 937 | const thread2 = try std.Thread.spawn(testTls, {}); | |
| 938 | 938 | testTls({}); |
| 939 | 939 | thread1.wait(); |
| 940 | 940 | thread2.wait(); |
lib/std/Thread.zig+20-6| ... | ... | @@ -165,18 +165,32 @@ pub const SpawnError = error{ |
| 165 | 165 | Unexpected, |
| 166 | 166 | }; |
| 167 | 167 | |
| 168 | /// caller must call wait on the returned thread | |
| 169 | /// fn startFn(@TypeOf(context)) T | |
| 170 | /// where T is u8, noreturn, void, or !void | |
| 171 | /// caller must call wait on the returned thread | |
| 172 | pub fn spawn(context: anytype, comptime startFn: anytype) SpawnError!*Thread { | |
| 168 | // Given `T`, the type of the thread startFn, extract the expected type for the | |
| 169 | // context parameter. | |
| 170 | fn SpawnContextType(comptime T: type) type { | |
| 171 | const TI = @typeInfo(T); | |
| 172 | if (TI != .Fn) | |
| 173 | @compileError("expected function type, found " ++ @typeName(T)); | |
| 174 | ||
| 175 | if (TI.Fn.args.len != 1) | |
| 176 | @compileError("expected function with single argument, found " ++ @typeName(T)); | |
| 177 | ||
| 178 | return TI.Fn.args[0].arg_type orelse | |
| 179 | @compileError("cannot use a generic function as thread startFn"); | |
| 180 | } | |
| 181 | ||
| 182 | /// Spawns a new thread executing startFn, returning an handle for it. | |
| 183 | /// Caller must call wait on the returned thread. | |
| 184 | /// The `startFn` function must take a single argument of type T and return a | |
| 185 | /// value of type u8, noreturn, void or !void. | |
| 186 | /// The `context` parameter is of type T and is passed to the spawned thread. | |
| 187 | pub fn spawn(comptime startFn: anytype, context: SpawnContextType(@TypeOf(startFn))) SpawnError!*Thread { | |
| 173 | 188 | if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode"); |
| 174 | 189 | // TODO compile-time call graph analysis to determine stack upper bound |
| 175 | 190 | // https://github.com/ziglang/zig/issues/157 |
| 176 | 191 | const default_stack_size = 16 * 1024 * 1024; |
| 177 | 192 | |
| 178 | 193 | const Context = @TypeOf(context); |
| 179 | comptime assert(@typeInfo(@TypeOf(startFn)).Fn.args[0].arg_type.? == Context); | |
| 180 | 194 | |
| 181 | 195 | if (std.Target.current.os.tag == .windows) { |
| 182 | 196 | const WinThread = struct { |
lib/std/Thread/AutoResetEvent.zig+2-2| ... | ... | @@ -220,8 +220,8 @@ test "basic usage" { |
| 220 | 220 | }; |
| 221 | 221 | |
| 222 | 222 | var context = Context{}; |
| 223 | const send_thread = try std.Thread.spawn(&context, Context.sender); | |
| 224 | const recv_thread = try std.Thread.spawn(&context, Context.receiver); | |
| 223 | const send_thread = try std.Thread.spawn(Context.sender, &context); | |
| 224 | const recv_thread = try std.Thread.spawn(Context.receiver, &context); | |
| 225 | 225 | |
| 226 | 226 | send_thread.wait(); |
| 227 | 227 | recv_thread.wait(); |
lib/std/Thread/Mutex.zig+1-1| ... | ... | @@ -299,7 +299,7 @@ test "basic usage" { |
| 299 | 299 | const thread_count = 10; |
| 300 | 300 | var threads: [thread_count]*std.Thread = undefined; |
| 301 | 301 | for (threads) |*t| { |
| 302 | t.* = try std.Thread.spawn(&context, worker); | |
| 302 | t.* = try std.Thread.spawn(worker, &context); | |
| 303 | 303 | } |
| 304 | 304 | for (threads) |t| |
| 305 | 305 | t.wait(); |
lib/std/Thread/ResetEvent.zig+2-2| ... | ... | @@ -281,7 +281,7 @@ test "basic usage" { |
| 281 | 281 | var context: Context = undefined; |
| 282 | 282 | try context.init(); |
| 283 | 283 | defer context.deinit(); |
| 284 | const receiver = try std.Thread.spawn(&context, Context.receiver); | |
| 284 | const receiver = try std.Thread.spawn(Context.receiver, &context); | |
| 285 | 285 | defer receiver.wait(); |
| 286 | 286 | context.sender(); |
| 287 | 287 | |
| ... | ... | @@ -290,7 +290,7 @@ test "basic usage" { |
| 290 | 290 | // https://github.com/ziglang/zig/issues/7009 |
| 291 | 291 | var timed = Context.init(); |
| 292 | 292 | defer timed.deinit(); |
| 293 | const sleeper = try std.Thread.spawn(&timed, Context.sleeper); | |
| 293 | const sleeper = try std.Thread.spawn(Context.sleeper, &timed); | |
| 294 | 294 | defer sleeper.wait(); |
| 295 | 295 | try timed.timedWaiter(); |
| 296 | 296 | } |
lib/std/Thread/StaticResetEvent.zig+2-2| ... | ... | @@ -379,7 +379,7 @@ test "basic usage" { |
| 379 | 379 | }; |
| 380 | 380 | |
| 381 | 381 | var context = Context{}; |
| 382 | const receiver = try std.Thread.spawn(&context, Context.receiver); | |
| 382 | const receiver = try std.Thread.spawn(Context.receiver, &context); | |
| 383 | 383 | defer receiver.wait(); |
| 384 | 384 | context.sender(); |
| 385 | 385 | |
| ... | ... | @@ -388,7 +388,7 @@ test "basic usage" { |
| 388 | 388 | // https://github.com/ziglang/zig/issues/7009 |
| 389 | 389 | var timed = Context.init(); |
| 390 | 390 | defer timed.deinit(); |
| 391 | const sleeper = try std.Thread.spawn(&timed, Context.sleeper); | |
| 391 | const sleeper = try std.Thread.spawn(Context.sleeper, &timed); | |
| 392 | 392 | defer sleeper.wait(); |
| 393 | 393 | try timed.timedWaiter(); |
| 394 | 394 | } |
lib/std/atomic/queue.zig+2-2| ... | ... | @@ -216,11 +216,11 @@ test "std.atomic.Queue" { |
| 216 | 216 | |
| 217 | 217 | var putters: [put_thread_count]*std.Thread = undefined; |
| 218 | 218 | for (putters) |*t| { |
| 219 | t.* = try std.Thread.spawn(&context, startPuts); | |
| 219 | t.* = try std.Thread.spawn(startPuts, &context); | |
| 220 | 220 | } |
| 221 | 221 | var getters: [put_thread_count]*std.Thread = undefined; |
| 222 | 222 | for (getters) |*t| { |
| 223 | t.* = try std.Thread.spawn(&context, startGets); | |
| 223 | t.* = try std.Thread.spawn(startGets, &context); | |
| 224 | 224 | } |
| 225 | 225 | |
| 226 | 226 | for (putters) |t| |
lib/std/atomic/stack.zig+2-2| ... | ... | @@ -123,11 +123,11 @@ test "std.atomic.stack" { |
| 123 | 123 | } else { |
| 124 | 124 | var putters: [put_thread_count]*std.Thread = undefined; |
| 125 | 125 | for (putters) |*t| { |
| 126 | t.* = try std.Thread.spawn(&context, startPuts); | |
| 126 | t.* = try std.Thread.spawn(startPuts, &context); | |
| 127 | 127 | } |
| 128 | 128 | var getters: [put_thread_count]*std.Thread = undefined; |
| 129 | 129 | for (getters) |*t| { |
| 130 | t.* = try std.Thread.spawn(&context, startGets); | |
| 130 | t.* = try std.Thread.spawn(startGets, &context); | |
| 131 | 131 | } |
| 132 | 132 | |
| 133 | 133 | for (putters) |t| |
lib/std/buf_set.zig+1-1| ... | ... | @@ -32,7 +32,7 @@ pub const BufSet = struct { |
| 32 | 32 | if (self.hash_map.get(key) == null) { |
| 33 | 33 | const key_copy = try self.copy(key); |
| 34 | 34 | errdefer self.free(key_copy); |
| 35 | _ = try self.hash_map.put(key_copy, {}); | |
| 35 | try self.hash_map.put(key_copy, {}); | |
| 36 | 36 | } |
| 37 | 37 | } |
| 38 | 38 |
lib/std/build.zig+2-2| ... | ... | @@ -790,7 +790,7 @@ pub const Builder = struct { |
| 790 | 790 | var list = ArrayList([]const u8).init(self.allocator); |
| 791 | 791 | list.append(s) catch unreachable; |
| 792 | 792 | list.append(value) catch unreachable; |
| 793 | _ = self.user_input_options.put(name, UserInputOption{ | |
| 793 | self.user_input_options.put(name, UserInputOption{ | |
| 794 | 794 | .name = name, |
| 795 | 795 | .value = UserValue{ .List = list }, |
| 796 | 796 | .used = false, |
| ... | ... | @@ -799,7 +799,7 @@ pub const Builder = struct { |
| 799 | 799 | UserValue.List => |*list| { |
| 800 | 800 | // append to the list |
| 801 | 801 | list.append(value) catch unreachable; |
| 802 | _ = self.user_input_options.put(name, UserInputOption{ | |
| 802 | self.user_input_options.put(name, UserInputOption{ | |
| 803 | 803 | .name = name, |
| 804 | 804 | .value = UserValue{ .List = list.* }, |
| 805 | 805 | .used = false, |
lib/std/c/builtins.zig+6| ... | ... | @@ -182,3 +182,9 @@ pub fn __builtin_memcpy( |
| 182 | 182 | @memcpy(dst_cast, src_cast, len); |
| 183 | 183 | return dst; |
| 184 | 184 | } |
| 185 | ||
| 186 | /// The return value of __builtin_expect is `expr`. `c` is the expected value | |
| 187 | /// of `expr` and is used as a hint to the compiler in C. Here it is unused. | |
| 188 | pub fn __builtin_expect(expr: c_long, c: c_long) callconv(.Inline) c_long { | |
| 189 | return expr; | |
| 190 | } |
lib/std/crypto.zig+8-22| ... | ... | @@ -16,6 +16,11 @@ pub const aead = struct { |
| 16 | 16 | pub const Aes256Gcm = @import("crypto/aes_gcm.zig").Aes256Gcm; |
| 17 | 17 | }; |
| 18 | 18 | |
| 19 | pub const aes_ocb = struct { | |
| 20 | pub const Aes128Ocb = @import("crypto/aes_ocb.zig").Aes128Ocb; | |
| 21 | pub const Aes256Ocb = @import("crypto/aes_ocb.zig").Aes256Ocb; | |
| 22 | }; | |
| 23 | ||
| 19 | 24 | pub const Gimli = @import("crypto/gimli.zig").Aead; |
| 20 | 25 | |
| 21 | 26 | pub const chacha_poly = struct { |
| ... | ... | @@ -157,30 +162,11 @@ test "crypto" { |
| 157 | 162 | } |
| 158 | 163 | } |
| 159 | 164 | |
| 160 | _ = @import("crypto/aes.zig"); | |
| 161 | _ = @import("crypto/bcrypt.zig"); | |
| 165 | _ = @import("crypto/aegis.zig"); | |
| 166 | _ = @import("crypto/aes_gcm.zig"); | |
| 167 | _ = @import("crypto/aes_ocb.zig"); | |
| 162 | 168 | _ = @import("crypto/blake2.zig"); |
| 163 | _ = @import("crypto/blake3.zig"); | |
| 164 | 169 | _ = @import("crypto/chacha20.zig"); |
| 165 | _ = @import("crypto/gimli.zig"); | |
| 166 | _ = @import("crypto/hmac.zig"); | |
| 167 | _ = @import("crypto/isap.zig"); | |
| 168 | _ = @import("crypto/md5.zig"); | |
| 169 | _ = @import("crypto/modes.zig"); | |
| 170 | _ = @import("crypto/pbkdf2.zig"); | |
| 171 | _ = @import("crypto/poly1305.zig"); | |
| 172 | _ = @import("crypto/sha1.zig"); | |
| 173 | _ = @import("crypto/sha2.zig"); | |
| 174 | _ = @import("crypto/sha3.zig"); | |
| 175 | _ = @import("crypto/salsa20.zig"); | |
| 176 | _ = @import("crypto/siphash.zig"); | |
| 177 | _ = @import("crypto/25519/curve25519.zig"); | |
| 178 | _ = @import("crypto/25519/ed25519.zig"); | |
| 179 | _ = @import("crypto/25519/edwards25519.zig"); | |
| 180 | _ = @import("crypto/25519/field.zig"); | |
| 181 | _ = @import("crypto/25519/scalar.zig"); | |
| 182 | _ = @import("crypto/25519/x25519.zig"); | |
| 183 | _ = @import("crypto/25519/ristretto255.zig"); | |
| 184 | 170 | } |
| 185 | 171 | |
| 186 | 172 | test "CSPRNG" { |
lib/std/crypto/aes/aesni.zig+2-8| ... | ... | @@ -313,10 +313,7 @@ pub fn AesEncryptCtx(comptime Aes: type) type { |
| 313 | 313 | inline while (i < rounds) : (i += 1) { |
| 314 | 314 | ts = Block.parallel.encryptWide(count, ts, round_keys[i]); |
| 315 | 315 | } |
| 316 | i = 1; | |
| 317 | inline while (i < count) : (i += 1) { | |
| 318 | ts = Block.parallel.encryptLastWide(count, ts, round_keys[i]); | |
| 319 | } | |
| 316 | ts = Block.parallel.encryptLastWide(count, ts, round_keys[i]); | |
| 320 | 317 | j = 0; |
| 321 | 318 | inline while (j < count) : (j += 1) { |
| 322 | 319 | dst[16 * j .. 16 * j + 16].* = ts[j].toBytes(); |
| ... | ... | @@ -392,10 +389,7 @@ pub fn AesDecryptCtx(comptime Aes: type) type { |
| 392 | 389 | inline while (i < rounds) : (i += 1) { |
| 393 | 390 | ts = Block.parallel.decryptWide(count, ts, inv_round_keys[i]); |
| 394 | 391 | } |
| 395 | i = 1; | |
| 396 | inline while (i < count) : (i += 1) { | |
| 397 | ts = Block.parallel.decryptLastWide(count, ts, inv_round_keys[i]); | |
| 398 | } | |
| 392 | ts = Block.parallel.decryptLastWide(count, ts, inv_round_keys[i]); | |
| 399 | 393 | j = 0; |
| 400 | 394 | inline while (j < count) : (j += 1) { |
| 401 | 395 | dst[16 * j .. 16 * j + 16].* = ts[j].toBytes(); |
lib/std/crypto/aes/armcrypto.zig+2-8| ... | ... | @@ -364,10 +364,7 @@ pub fn AesEncryptCtx(comptime Aes: type) type { |
| 364 | 364 | inline while (i < rounds) : (i += 1) { |
| 365 | 365 | ts = Block.parallel.encryptWide(count, ts, round_keys[i]); |
| 366 | 366 | } |
| 367 | i = 1; | |
| 368 | inline while (i < count) : (i += 1) { | |
| 369 | ts = Block.parallel.encryptLastWide(count, ts, round_keys[i]); | |
| 370 | } | |
| 367 | ts = Block.parallel.encryptLastWide(count, ts, round_keys[i]); | |
| 371 | 368 | j = 0; |
| 372 | 369 | inline while (j < count) : (j += 1) { |
| 373 | 370 | dst[16 * j .. 16 * j + 16].* = ts[j].toBytes(); |
| ... | ... | @@ -443,10 +440,7 @@ pub fn AesDecryptCtx(comptime Aes: type) type { |
| 443 | 440 | inline while (i < rounds) : (i += 1) { |
| 444 | 441 | ts = Block.parallel.decryptWide(count, ts, inv_round_keys[i]); |
| 445 | 442 | } |
| 446 | i = 1; | |
| 447 | inline while (i < count) : (i += 1) { | |
| 448 | ts = Block.parallel.decryptLastWide(count, ts, inv_round_keys[i]); | |
| 449 | } | |
| 443 | ts = Block.parallel.decryptLastWide(count, ts, inv_round_keys[i]); | |
| 450 | 444 | j = 0; |
| 451 | 445 | inline while (j < count) : (j += 1) { |
| 452 | 446 | dst[16 * j .. 16 * j + 16].* = ts[j].toBytes(); |
lib/std/crypto/aes_ocb.zig created+343| ... | ... | @@ -0,0 +1,343 @@ |
| 1 | // SPDX-License-Identifier: MIT | |
| 2 | // Copyright (c) 2015-2021 Zig Contributors | |
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | |
| 4 | // The MIT license requires this copyright notice to be included in all copies | |
| 5 | // and substantial portions of the software. | |
| 6 | ||
| 7 | const std = @import("std"); | |
| 8 | const crypto = std.crypto; | |
| 9 | const aes = crypto.core.aes; | |
| 10 | const assert = std.debug.assert; | |
| 11 | const math = std.math; | |
| 12 | const mem = std.mem; | |
| 13 | ||
| 14 | pub const Aes128Ocb = AesOcb(aes.Aes128); | |
| 15 | pub const Aes256Ocb = AesOcb(aes.Aes256); | |
| 16 | ||
| 17 | const Block = [16]u8; | |
| 18 | ||
| 19 | /// AES-OCB (RFC 7253 - https://competitions.cr.yp.to/round3/ocbv11.pdf) | |
| 20 | fn AesOcb(comptime Aes: anytype) type { | |
| 21 | const EncryptCtx = aes.AesEncryptCtx(Aes); | |
| 22 | const DecryptCtx = aes.AesDecryptCtx(Aes); | |
| 23 | ||
| 24 | return struct { | |
| 25 | pub const key_length = Aes.key_bits / 8; | |
| 26 | pub const nonce_length: usize = 12; | |
| 27 | pub const tag_length: usize = 16; | |
| 28 | ||
| 29 | const Lx = struct { | |
| 30 | star: Block align(16), | |
| 31 | dol: Block align(16), | |
| 32 | table: [56]Block align(16) = undefined, | |
| 33 | upto: usize, | |
| 34 | ||
| 35 | fn double(l: Block) callconv(.Inline) Block { | |
| 36 | const l_ = mem.readIntBig(u128, &l); | |
| 37 | const l_2 = (l_ << 1) ^ (0x87 & -%(l_ >> 127)); | |
| 38 | var l2: Block = undefined; | |
| 39 | mem.writeIntBig(u128, &l2, l_2); | |
| 40 | return l2; | |
| 41 | } | |
| 42 | ||
| 43 | fn precomp(lx: *Lx, upto: usize) []const Block { | |
| 44 | const table = &lx.table; | |
| 45 | assert(upto < table.len); | |
| 46 | var i = lx.upto; | |
| 47 | while (i + 1 <= upto) : (i += 1) { | |
| 48 | table[i + 1] = double(table[i]); | |
| 49 | } | |
| 50 | lx.upto = upto; | |
| 51 | return lx.table[0 .. upto + 1]; | |
| 52 | } | |
| 53 | ||
| 54 | fn init(aes_enc_ctx: EncryptCtx) Lx { | |
| 55 | const zeros = [_]u8{0} ** 16; | |
| 56 | var star: Block = undefined; | |
| 57 | aes_enc_ctx.encrypt(&star, &zeros); | |
| 58 | const dol = double(star); | |
| 59 | var lx = Lx{ .star = star, .dol = dol, .upto = 0 }; | |
| 60 | lx.table[0] = double(dol); | |
| 61 | return lx; | |
| 62 | } | |
| 63 | }; | |
| 64 | ||
| 65 | fn hash(aes_enc_ctx: EncryptCtx, lx: *Lx, a: []const u8) Block { | |
| 66 | const full_blocks: usize = a.len / 16; | |
| 67 | const x_max = if (full_blocks > 0) math.log2_int(usize, full_blocks) else 0; | |
| 68 | const lt = lx.precomp(x_max); | |
| 69 | var sum = [_]u8{0} ** 16; | |
| 70 | var offset = [_]u8{0} ** 16; | |
| 71 | var i: usize = 0; | |
| 72 | while (i < full_blocks) : (i += 1) { | |
| 73 | xorWith(&offset, lt[@ctz(usize, i + 1)]); | |
| 74 | var e = xorBlocks(offset, a[i * 16 ..][0..16].*); | |
| 75 | aes_enc_ctx.encrypt(&e, &e); | |
| 76 | xorWith(&sum, e); | |
| 77 | } | |
| 78 | const leftover = a.len % 16; | |
| 79 | if (leftover > 0) { | |
| 80 | xorWith(&offset, lx.star); | |
| 81 | var padded = [_]u8{0} ** 16; | |
| 82 | mem.copy(u8, padded[0..leftover], a[i * 16 ..][0..leftover]); | |
| 83 | padded[leftover] = 1; | |
| 84 | var e = xorBlocks(offset, padded); | |
| 85 | aes_enc_ctx.encrypt(&e, &e); | |
| 86 | xorWith(&sum, e); | |
| 87 | } | |
| 88 | return sum; | |
| 89 | } | |
| 90 | ||
| 91 | fn getOffset(aes_enc_ctx: EncryptCtx, npub: [nonce_length]u8) Block { | |
| 92 | var nx = [_]u8{0} ** 16; | |
| 93 | nx[0] = @intCast(u8, @truncate(u7, tag_length * 8) << 1); | |
| 94 | nx[16 - nonce_length - 1] = 1; | |
| 95 | mem.copy(u8, nx[16 - nonce_length ..], &npub); | |
| 96 | ||
| 97 | const bottom = @truncate(u6, nx[15]); | |
| 98 | nx[15] &= 0xc0; | |
| 99 | var ktop_: Block = undefined; | |
| 100 | aes_enc_ctx.encrypt(&ktop_, &nx); | |
| 101 | const ktop = mem.readIntBig(u128, &ktop_); | |
| 102 | var stretch = (@as(u192, ktop) << 64) | @as(u192, @truncate(u64, ktop >> 64) ^ @truncate(u64, ktop >> 56)); | |
| 103 | var offset: Block = undefined; | |
| 104 | mem.writeIntBig(u128, &offset, @truncate(u128, stretch >> (64 - @as(u7, bottom)))); | |
| 105 | return offset; | |
| 106 | } | |
| 107 | ||
| 108 | const has_aesni = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .aes); | |
| 109 | const has_armaes = comptime std.Target.aarch64.featureSetHas(std.Target.current.cpu.features, .aes); | |
| 110 | const wb: usize = if ((std.Target.current.cpu.arch == .x86_64 and has_aesni) or (std.Target.current.cpu.arch == .aarch64 and has_armaes)) 4 else 0; | |
| 111 | ||
| 112 | /// c: ciphertext: output buffer should be of size m.len | |
| 113 | /// tag: authentication tag: output MAC | |
| 114 | /// m: message | |
| 115 | /// ad: Associated Data | |
| 116 | /// npub: public nonce | |
| 117 | /// k: secret key | |
| 118 | pub fn encrypt(c: []u8, tag: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) void { | |
| 119 | assert(c.len == m.len); | |
| 120 | ||
| 121 | const aes_enc_ctx = Aes.initEnc(key); | |
| 122 | const full_blocks: usize = m.len / 16; | |
| 123 | const x_max = if (full_blocks > 0) math.log2_int(usize, full_blocks) else 0; | |
| 124 | var lx = Lx.init(aes_enc_ctx); | |
| 125 | const lt = lx.precomp(x_max); | |
| 126 | ||
| 127 | var offset = getOffset(aes_enc_ctx, npub); | |
| 128 | var sum = [_]u8{0} ** 16; | |
| 129 | var i: usize = 0; | |
| 130 | ||
| 131 | while (wb > 0 and i + wb <= full_blocks) : (i += wb) { | |
| 132 | var offsets: [wb]Block align(16) = undefined; | |
| 133 | var es: [16 * wb]u8 align(16) = undefined; | |
| 134 | var j: usize = 0; | |
| 135 | while (j < wb) : (j += 1) { | |
| 136 | xorWith(&offset, lt[@ctz(usize, i + 1 + j)]); | |
| 137 | offsets[j] = offset; | |
| 138 | const p = m[(i + j) * 16 ..][0..16].*; | |
| 139 | mem.copy(u8, es[j * 16 ..][0..16], &xorBlocks(p, offsets[j])); | |
| 140 | xorWith(&sum, p); | |
| 141 | } | |
| 142 | aes_enc_ctx.encryptWide(wb, &es, &es); | |
| 143 | j = 0; | |
| 144 | while (j < wb) : (j += 1) { | |
| 145 | const e = es[j * 16 ..][0..16].*; | |
| 146 | mem.copy(u8, c[(i + j) * 16 ..][0..16], &xorBlocks(e, offsets[j])); | |
| 147 | } | |
| 148 | } | |
| 149 | while (i < full_blocks) : (i += 1) { | |
| 150 | xorWith(&offset, lt[@ctz(usize, i + 1)]); | |
| 151 | const p = m[i * 16 ..][0..16].*; | |
| 152 | var e = xorBlocks(p, offset); | |
| 153 | aes_enc_ctx.encrypt(&e, &e); | |
| 154 | mem.copy(u8, c[i * 16 ..][0..16], &xorBlocks(e, offset)); | |
| 155 | xorWith(&sum, p); | |
| 156 | } | |
| 157 | const leftover = m.len % 16; | |
| 158 | if (leftover > 0) { | |
| 159 | xorWith(&offset, lx.star); | |
| 160 | var pad = offset; | |
| 161 | aes_enc_ctx.encrypt(&pad, &pad); | |
| 162 | for (m[i * 16 ..]) |x, j| { | |
| 163 | c[i * 16 + j] = pad[j] ^ x; | |
| 164 | } | |
| 165 | var e = [_]u8{0} ** 16; | |
| 166 | mem.copy(u8, e[0..leftover], m[i * 16 ..][0..leftover]); | |
| 167 | e[leftover] = 0x80; | |
| 168 | xorWith(&sum, e); | |
| 169 | } | |
| 170 | var e = xorBlocks(xorBlocks(sum, offset), lx.dol); | |
| 171 | aes_enc_ctx.encrypt(&e, &e); | |
| 172 | tag.* = xorBlocks(e, hash(aes_enc_ctx, &lx, ad)); | |
| 173 | } | |
| 174 | ||
| 175 | /// m: message: output buffer should be of size c.len | |
| 176 | /// c: ciphertext | |
| 177 | /// tag: authentication tag | |
| 178 | /// ad: Associated Data | |
| 179 | /// npub: public nonce | |
| 180 | /// k: secret key | |
| 181 | pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) !void { | |
| 182 | assert(c.len == m.len); | |
| 183 | ||
| 184 | const aes_enc_ctx = Aes.initEnc(key); | |
| 185 | const aes_dec_ctx = DecryptCtx.initFromEnc(aes_enc_ctx); | |
| 186 | const full_blocks: usize = m.len / 16; | |
| 187 | const x_max = if (full_blocks > 0) math.log2_int(usize, full_blocks) else 0; | |
| 188 | var lx = Lx.init(aes_enc_ctx); | |
| 189 | const lt = lx.precomp(x_max); | |
| 190 | ||
| 191 | var offset = getOffset(aes_enc_ctx, npub); | |
| 192 | var sum = [_]u8{0} ** 16; | |
| 193 | var i: usize = 0; | |
| 194 | ||
| 195 | while (wb > 0 and i + wb <= full_blocks) : (i += wb) { | |
| 196 | var offsets: [wb]Block align(16) = undefined; | |
| 197 | var es: [16 * wb]u8 align(16) = undefined; | |
| 198 | var j: usize = 0; | |
| 199 | while (j < wb) : (j += 1) { | |
| 200 | xorWith(&offset, lt[@ctz(usize, i + 1 + j)]); | |
| 201 | offsets[j] = offset; | |
| 202 | const q = c[(i + j) * 16 ..][0..16].*; | |
| 203 | mem.copy(u8, es[j * 16 ..][0..16], &xorBlocks(q, offsets[j])); | |
| 204 | } | |
| 205 | aes_dec_ctx.decryptWide(wb, &es, &es); | |
| 206 | j = 0; | |
| 207 | while (j < wb) : (j += 1) { | |
| 208 | const p = xorBlocks(es[j * 16 ..][0..16].*, offsets[j]); | |
| 209 | mem.copy(u8, m[(i + j) * 16 ..][0..16], &p); | |
| 210 | xorWith(&sum, p); | |
| 211 | } | |
| 212 | } | |
| 213 | while (i < full_blocks) : (i += 1) { | |
| 214 | xorWith(&offset, lt[@ctz(usize, i + 1)]); | |
| 215 | const q = c[i * 16 ..][0..16].*; | |
| 216 | var e = xorBlocks(q, offset); | |
| 217 | aes_dec_ctx.decrypt(&e, &e); | |
| 218 | const p = xorBlocks(e, offset); | |
| 219 | mem.copy(u8, m[i * 16 ..][0..16], &p); | |
| 220 | xorWith(&sum, p); | |
| 221 | } | |
| 222 | const leftover = m.len % 16; | |
| 223 | if (leftover > 0) { | |
| 224 | xorWith(&offset, lx.star); | |
| 225 | var pad = offset; | |
| 226 | aes_enc_ctx.encrypt(&pad, &pad); | |
| 227 | for (c[i * 16 ..]) |x, j| { | |
| 228 | m[i * 16 + j] = pad[j] ^ x; | |
| 229 | } | |
| 230 | var e = [_]u8{0} ** 16; | |
| 231 | mem.copy(u8, e[0..leftover], m[i * 16 ..][0..leftover]); | |
| 232 | e[leftover] = 0x80; | |
| 233 | xorWith(&sum, e); | |
| 234 | } | |
| 235 | var e = xorBlocks(xorBlocks(sum, offset), lx.dol); | |
| 236 | aes_enc_ctx.encrypt(&e, &e); | |
| 237 | var computed_tag = xorBlocks(e, hash(aes_enc_ctx, &lx, ad)); | |
| 238 | const verify = crypto.utils.timingSafeEql([tag_length]u8, computed_tag, tag); | |
| 239 | crypto.utils.secureZero(u8, &computed_tag); | |
| 240 | if (!verify) { | |
| 241 | return error.AuthenticationFailed; | |
| 242 | } | |
| 243 | } | |
| 244 | }; | |
| 245 | } | |
| 246 | ||
| 247 | fn xorBlocks(x: Block, y: Block) callconv(.Inline) Block { | |
| 248 | var z: Block = x; | |
| 249 | for (z) |*v, i| { | |
| 250 | v.* = x[i] ^ y[i]; | |
| 251 | } | |
| 252 | return z; | |
| 253 | } | |
| 254 | ||
| 255 | fn xorWith(x: *Block, y: Block) callconv(.Inline) void { | |
| 256 | for (x) |*v, i| { | |
| 257 | v.* ^= y[i]; | |
| 258 | } | |
| 259 | } | |
| 260 | ||
| 261 | const hexToBytes = std.fmt.hexToBytes; | |
| 262 | ||
| 263 | test "AesOcb test vector 1" { | |
| 264 | var k: [Aes128Ocb.key_length]u8 = undefined; | |
| 265 | var nonce: [Aes128Ocb.nonce_length]u8 = undefined; | |
| 266 | var tag: [Aes128Ocb.tag_length]u8 = undefined; | |
| 267 | _ = try hexToBytes(&k, "000102030405060708090A0B0C0D0E0F"); | |
| 268 | _ = try hexToBytes(&nonce, "BBAA99887766554433221100"); | |
| 269 | ||
| 270 | var c: [0]u8 = undefined; | |
| 271 | Aes128Ocb.encrypt(&c, &tag, "", "", nonce, k); | |
| 272 | ||
| 273 | var expected_c: [c.len]u8 = undefined; | |
| 274 | var expected_tag: [tag.len]u8 = undefined; | |
| 275 | _ = try hexToBytes(&expected_tag, "785407BFFFC8AD9EDCC5520AC9111EE6"); | |
| 276 | ||
| 277 | var m: [0]u8 = undefined; | |
| 278 | try Aes128Ocb.decrypt(&m, "", tag, "", nonce, k); | |
| 279 | } | |
| 280 | ||
| 281 | test "AesOcb test vector 2" { | |
| 282 | var k: [Aes128Ocb.key_length]u8 = undefined; | |
| 283 | var nonce: [Aes128Ocb.nonce_length]u8 = undefined; | |
| 284 | var tag: [Aes128Ocb.tag_length]u8 = undefined; | |
| 285 | var ad: [40]u8 = undefined; | |
| 286 | _ = try hexToBytes(&k, "000102030405060708090A0B0C0D0E0F"); | |
| 287 | _ = try hexToBytes(&ad, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627"); | |
| 288 | _ = try hexToBytes(&nonce, "BBAA9988776655443322110E"); | |
| 289 | ||
| 290 | var c: [0]u8 = undefined; | |
| 291 | Aes128Ocb.encrypt(&c, &tag, "", &ad, nonce, k); | |
| 292 | ||
| 293 | var expected_tag: [tag.len]u8 = undefined; | |
| 294 | _ = try hexToBytes(&expected_tag, "C5CD9D1850C141E358649994EE701B68"); | |
| 295 | ||
| 296 | var m: [0]u8 = undefined; | |
| 297 | try Aes128Ocb.decrypt(&m, &c, tag, &ad, nonce, k); | |
| 298 | } | |
| 299 | ||
| 300 | test "AesOcb test vector 3" { | |
| 301 | var k: [Aes128Ocb.key_length]u8 = undefined; | |
| 302 | var nonce: [Aes128Ocb.nonce_length]u8 = undefined; | |
| 303 | var tag: [Aes128Ocb.tag_length]u8 = undefined; | |
| 304 | var m: [40]u8 = undefined; | |
| 305 | var c: [m.len]u8 = undefined; | |
| 306 | _ = try hexToBytes(&k, "000102030405060708090A0B0C0D0E0F"); | |
| 307 | _ = try hexToBytes(&m, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627"); | |
| 308 | _ = try hexToBytes(&nonce, "BBAA9988776655443322110F"); | |
| 309 | ||
| 310 | Aes128Ocb.encrypt(&c, &tag, &m, "", nonce, k); | |
| 311 | ||
| 312 | var expected_c: [c.len]u8 = undefined; | |
| 313 | var expected_tag: [tag.len]u8 = undefined; | |
| 314 | _ = try hexToBytes(&expected_tag, "479AD363AC366B95A98CA5F3000B1479"); | |
| 315 | _ = try hexToBytes(&expected_c, "4412923493C57D5DE0D700F753CCE0D1D2D95060122E9F15A5DDBFC5787E50B5CC55EE507BCB084E"); | |
| 316 | ||
| 317 | var m2: [m.len]u8 = undefined; | |
| 318 | try Aes128Ocb.decrypt(&m2, &c, tag, "", nonce, k); | |
| 319 | assert(mem.eql(u8, &m, &m2)); | |
| 320 | } | |
| 321 | ||
| 322 | test "AesOcb test vector 4" { | |
| 323 | var k: [Aes128Ocb.key_length]u8 = undefined; | |
| 324 | var nonce: [Aes128Ocb.nonce_length]u8 = undefined; | |
| 325 | var tag: [Aes128Ocb.tag_length]u8 = undefined; | |
| 326 | var m: [40]u8 = undefined; | |
| 327 | var ad = m; | |
| 328 | var c: [m.len]u8 = undefined; | |
| 329 | _ = try hexToBytes(&k, "000102030405060708090A0B0C0D0E0F"); | |
| 330 | _ = try hexToBytes(&m, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627"); | |
| 331 | _ = try hexToBytes(&nonce, "BBAA99887766554433221104"); | |
| 332 | ||
| 333 | Aes128Ocb.encrypt(&c, &tag, &m, &ad, nonce, k); | |
| 334 | ||
| 335 | var expected_c: [c.len]u8 = undefined; | |
| 336 | var expected_tag: [tag.len]u8 = undefined; | |
| 337 | _ = try hexToBytes(&expected_tag, "3AD7A4FF3835B8C5701C1CCEC8FC3358"); | |
| 338 | _ = try hexToBytes(&expected_c, "571D535B60B277188BE5147170A9A22C"); | |
| 339 | ||
| 340 | var m2: [m.len]u8 = undefined; | |
| 341 | try Aes128Ocb.decrypt(&m2, &c, tag, &ad, nonce, k); | |
| 342 | assert(mem.eql(u8, &m, &m2)); | |
| 343 | } |
lib/std/crypto/benchmark.zig+11-9| ... | ... | @@ -208,6 +208,8 @@ const aeads = [_]Crypto{ |
| 208 | 208 | Crypto{ .ty = crypto.aead.aegis.Aegis256, .name = "aegis-256" }, |
| 209 | 209 | Crypto{ .ty = crypto.aead.aes_gcm.Aes128Gcm, .name = "aes128-gcm" }, |
| 210 | 210 | Crypto{ .ty = crypto.aead.aes_gcm.Aes256Gcm, .name = "aes256-gcm" }, |
| 211 | Crypto{ .ty = crypto.aead.aes_ocb.Aes128Ocb, .name = "aes128-ocb" }, | |
| 212 | Crypto{ .ty = crypto.aead.aes_ocb.Aes256Ocb, .name = "aes256-ocb" }, | |
| 211 | 213 | Crypto{ .ty = crypto.aead.isap.IsapA128A, .name = "isapa128a" }, |
| 212 | 214 | }; |
| 213 | 215 | |
| ... | ... | @@ -356,63 +358,63 @@ pub fn main() !void { |
| 356 | 358 | inline for (hashes) |H| { |
| 357 | 359 | if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) { |
| 358 | 360 | const throughput = try benchmarkHash(H.ty, mode(128 * MiB)); |
| 359 | try stdout.print("{:>17}: {:10} MiB/s\n", .{ H.name, throughput / (1 * MiB) }); | |
| 361 | try stdout.print("{s:>17}: {:10} MiB/s\n", .{ H.name, throughput / (1 * MiB) }); | |
| 360 | 362 | } |
| 361 | 363 | } |
| 362 | 364 | |
| 363 | 365 | inline for (macs) |M| { |
| 364 | 366 | if (filter == null or std.mem.indexOf(u8, M.name, filter.?) != null) { |
| 365 | 367 | const throughput = try benchmarkMac(M.ty, mode(128 * MiB)); |
| 366 | try stdout.print("{:>17}: {:10} MiB/s\n", .{ M.name, throughput / (1 * MiB) }); | |
| 368 | try stdout.print("{s:>17}: {:10} MiB/s\n", .{ M.name, throughput / (1 * MiB) }); | |
| 367 | 369 | } |
| 368 | 370 | } |
| 369 | 371 | |
| 370 | 372 | inline for (exchanges) |E| { |
| 371 | 373 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| 372 | 374 | const throughput = try benchmarkKeyExchange(E.ty, mode(1000)); |
| 373 | try stdout.print("{:>17}: {:10} exchanges/s\n", .{ E.name, throughput }); | |
| 375 | try stdout.print("{s:>17}: {:10} exchanges/s\n", .{ E.name, throughput }); | |
| 374 | 376 | } |
| 375 | 377 | } |
| 376 | 378 | |
| 377 | 379 | inline for (signatures) |E| { |
| 378 | 380 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| 379 | 381 | const throughput = try benchmarkSignature(E.ty, mode(1000)); |
| 380 | try stdout.print("{:>17}: {:10} signatures/s\n", .{ E.name, throughput }); | |
| 382 | try stdout.print("{s:>17}: {:10} signatures/s\n", .{ E.name, throughput }); | |
| 381 | 383 | } |
| 382 | 384 | } |
| 383 | 385 | |
| 384 | 386 | inline for (signature_verifications) |E| { |
| 385 | 387 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| 386 | 388 | const throughput = try benchmarkSignatureVerification(E.ty, mode(1000)); |
| 387 | try stdout.print("{:>17}: {:10} verifications/s\n", .{ E.name, throughput }); | |
| 389 | try stdout.print("{s:>17}: {:10} verifications/s\n", .{ E.name, throughput }); | |
| 388 | 390 | } |
| 389 | 391 | } |
| 390 | 392 | |
| 391 | 393 | inline for (batch_signature_verifications) |E| { |
| 392 | 394 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| 393 | 395 | const throughput = try benchmarkBatchSignatureVerification(E.ty, mode(1000)); |
| 394 | try stdout.print("{:>17}: {:10} verifications/s (batch)\n", .{ E.name, throughput }); | |
| 396 | try stdout.print("{s:>17}: {:10} verifications/s (batch)\n", .{ E.name, throughput }); | |
| 395 | 397 | } |
| 396 | 398 | } |
| 397 | 399 | |
| 398 | 400 | inline for (aeads) |E| { |
| 399 | 401 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| 400 | 402 | const throughput = try benchmarkAead(E.ty, mode(128 * MiB)); |
| 401 | try stdout.print("{:>17}: {:10} MiB/s\n", .{ E.name, throughput / (1 * MiB) }); | |
| 403 | try stdout.print("{s:>17}: {:10} MiB/s\n", .{ E.name, throughput / (1 * MiB) }); | |
| 402 | 404 | } |
| 403 | 405 | } |
| 404 | 406 | |
| 405 | 407 | inline for (aes) |E| { |
| 406 | 408 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| 407 | 409 | const throughput = try benchmarkAes(E.ty, mode(100000000)); |
| 408 | try stdout.print("{:>17}: {:10} ops/s\n", .{ E.name, throughput }); | |
| 410 | try stdout.print("{s:>17}: {:10} ops/s\n", .{ E.name, throughput }); | |
| 409 | 411 | } |
| 410 | 412 | } |
| 411 | 413 | |
| 412 | 414 | inline for (aes8) |E| { |
| 413 | 415 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| 414 | 416 | const throughput = try benchmarkAes8(E.ty, mode(10000000)); |
| 415 | try stdout.print("{:>17}: {:10} ops/s\n", .{ E.name, throughput }); | |
| 417 | try stdout.print("{s:>17}: {:10} ops/s\n", .{ E.name, throughput }); | |
| 416 | 418 | } |
| 417 | 419 | } |
| 418 | 420 | } |
lib/std/event/loop.zig+5-5| ... | ... | @@ -185,7 +185,7 @@ pub const Loop = struct { |
| 185 | 185 | errdefer self.deinitOsData(); |
| 186 | 186 | |
| 187 | 187 | if (!builtin.single_threaded) { |
| 188 | self.fs_thread = try Thread.spawn(self, posixFsRun); | |
| 188 | self.fs_thread = try Thread.spawn(posixFsRun, self); | |
| 189 | 189 | } |
| 190 | 190 | errdefer if (!builtin.single_threaded) { |
| 191 | 191 | self.posixFsRequest(&self.fs_end_request); |
| ... | ... | @@ -264,7 +264,7 @@ pub const Loop = struct { |
| 264 | 264 | } |
| 265 | 265 | } |
| 266 | 266 | while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) { |
| 267 | self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun); | |
| 267 | self.extra_threads[extra_thread_index] = try Thread.spawn(workerRun, self); | |
| 268 | 268 | } |
| 269 | 269 | }, |
| 270 | 270 | .macos, .freebsd, .netbsd, .dragonfly, .openbsd => { |
| ... | ... | @@ -329,7 +329,7 @@ pub const Loop = struct { |
| 329 | 329 | } |
| 330 | 330 | } |
| 331 | 331 | while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) { |
| 332 | self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun); | |
| 332 | self.extra_threads[extra_thread_index] = try Thread.spawn(workerRun, self); | |
| 333 | 333 | } |
| 334 | 334 | }, |
| 335 | 335 | .windows => { |
| ... | ... | @@ -378,7 +378,7 @@ pub const Loop = struct { |
| 378 | 378 | } |
| 379 | 379 | } |
| 380 | 380 | while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) { |
| 381 | self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun); | |
| 381 | self.extra_threads[extra_thread_index] = try Thread.spawn(workerRun, self); | |
| 382 | 382 | } |
| 383 | 383 | }, |
| 384 | 384 | else => {}, |
| ... | ... | @@ -798,7 +798,7 @@ pub const Loop = struct { |
| 798 | 798 | .event = std.Thread.AutoResetEvent{}, |
| 799 | 799 | .is_running = true, |
| 800 | 800 | // Must be last so that it can read the other state, such as `is_running`. |
| 801 | .thread = try std.Thread.spawn(self, DelayQueue.run), | |
| 801 | .thread = try std.Thread.spawn(DelayQueue.run, self), | |
| 802 | 802 | }; |
| 803 | 803 | } |
| 804 | 804 |
lib/std/fs/path.zig+54-38| ... | ... | @@ -39,8 +39,8 @@ pub fn isSep(byte: u8) bool { |
| 39 | 39 | |
| 40 | 40 | /// This is different from mem.join in that the separator will not be repeated if |
| 41 | 41 | /// it is found at the end or beginning of a pair of consecutive paths. |
| 42 | fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, paths: []const []const u8) ![]u8 { | |
| 43 | if (paths.len == 0) return &[0]u8{}; | |
| 42 | fn joinSepMaybeZ(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, paths: []const []const u8, zero: bool) ![]u8 { | |
| 43 | if (paths.len == 0) return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{}; | |
| 44 | 44 | |
| 45 | 45 | const total_len = blk: { |
| 46 | 46 | var sum: usize = paths[0].len; |
| ... | ... | @@ -53,6 +53,7 @@ fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, pat |
| 53 | 53 | sum += @boolToInt(!prev_sep and !this_sep); |
| 54 | 54 | sum += if (prev_sep and this_sep) this_path.len - 1 else this_path.len; |
| 55 | 55 | } |
| 56 | if (zero) sum += 1; | |
| 56 | 57 | break :blk sum; |
| 57 | 58 | }; |
| 58 | 59 | |
| ... | ... | @@ -76,6 +77,8 @@ fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, pat |
| 76 | 77 | buf_index += adjusted_path.len; |
| 77 | 78 | } |
| 78 | 79 | |
| 80 | if (zero) buf[buf.len - 1] = 0; | |
| 81 | ||
| 79 | 82 | // No need for shrink since buf is exactly the correct size. |
| 80 | 83 | return buf; |
| 81 | 84 | } |
| ... | ... | @@ -83,60 +86,73 @@ fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, pat |
| 83 | 86 | /// Naively combines a series of paths with the native path seperator. |
| 84 | 87 | /// Allocates memory for the result, which must be freed by the caller. |
| 85 | 88 | pub fn join(allocator: *Allocator, paths: []const []const u8) ![]u8 { |
| 86 | return joinSep(allocator, sep, isSep, paths); | |
| 89 | return joinSepMaybeZ(allocator, sep, isSep, paths, false); | |
| 90 | } | |
| 91 | ||
| 92 | /// Naively combines a series of paths with the native path seperator and null terminator. | |
| 93 | /// Allocates memory for the result, which must be freed by the caller. | |
| 94 | pub fn joinZ(allocator: *Allocator, paths: []const []const u8) ![:0]u8 { | |
| 95 | const out = joinSepMaybeZ(allocator, sep, isSep, paths, true); | |
| 96 | return out[0 .. out.len - 1 :0]; | |
| 87 | 97 | } |
| 88 | 98 | |
| 89 | fn testJoinWindows(paths: []const []const u8, expected: []const u8) void { | |
| 99 | fn testJoinMaybeZWindows(paths: []const []const u8, expected: []const u8, zero: bool) void { | |
| 90 | 100 | const windowsIsSep = struct { |
| 91 | 101 | fn isSep(byte: u8) bool { |
| 92 | 102 | return byte == '/' or byte == '\\'; |
| 93 | 103 | } |
| 94 | 104 | }.isSep; |
| 95 | const actual = joinSep(testing.allocator, sep_windows, windowsIsSep, paths) catch @panic("fail"); | |
| 105 | const actual = joinSepMaybeZ(testing.allocator, sep_windows, windowsIsSep, paths, zero) catch @panic("fail"); | |
| 96 | 106 | defer testing.allocator.free(actual); |
| 97 | testing.expectEqualSlices(u8, expected, actual); | |
| 107 | testing.expectEqualSlices(u8, expected, if (zero) actual[0 .. actual.len - 1 :0] else actual); | |
| 98 | 108 | } |
| 99 | 109 | |
| 100 | fn testJoinPosix(paths: []const []const u8, expected: []const u8) void { | |
| 110 | fn testJoinMaybeZPosix(paths: []const []const u8, expected: []const u8, zero: bool) void { | |
| 101 | 111 | const posixIsSep = struct { |
| 102 | 112 | fn isSep(byte: u8) bool { |
| 103 | 113 | return byte == '/'; |
| 104 | 114 | } |
| 105 | 115 | }.isSep; |
| 106 | const actual = joinSep(testing.allocator, sep_posix, posixIsSep, paths) catch @panic("fail"); | |
| 116 | const actual = joinSepMaybeZ(testing.allocator, sep_posix, posixIsSep, paths, zero) catch @panic("fail"); | |
| 107 | 117 | defer testing.allocator.free(actual); |
| 108 | testing.expectEqualSlices(u8, expected, actual); | |
| 118 | testing.expectEqualSlices(u8, expected, if (zero) actual[0 .. actual.len - 1 :0] else actual); | |
| 109 | 119 | } |
| 110 | 120 | |
| 111 | 121 | test "join" { |
| 112 | testJoinWindows(&[_][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c"); | |
| 113 | testJoinWindows(&[_][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c"); | |
| 114 | testJoinWindows(&[_][]const u8{ "c:\\a\\b\\", "c" }, "c:\\a\\b\\c"); | |
| 115 | ||
| 116 | testJoinWindows(&[_][]const u8{ "c:\\", "a", "b\\", "c" }, "c:\\a\\b\\c"); | |
| 117 | testJoinWindows(&[_][]const u8{ "c:\\a\\", "b\\", "c" }, "c:\\a\\b\\c"); | |
| 118 | ||
| 119 | testJoinWindows( | |
| 120 | &[_][]const u8{ "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std", "io.zig" }, | |
| 121 | "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig", | |
| 122 | ); | |
| 123 | ||
| 124 | testJoinWindows(&[_][]const u8{ "c:\\", "a", "b/", "c" }, "c:\\a\\b/c"); | |
| 125 | testJoinWindows(&[_][]const u8{ "c:\\a/", "b\\", "/c" }, "c:\\a/b\\c"); | |
| 126 | ||
| 127 | testJoinPosix(&[_][]const u8{ "/a/b", "c" }, "/a/b/c"); | |
| 128 | testJoinPosix(&[_][]const u8{ "/a/b/", "c" }, "/a/b/c"); | |
| 129 | ||
| 130 | testJoinPosix(&[_][]const u8{ "/", "a", "b/", "c" }, "/a/b/c"); | |
| 131 | testJoinPosix(&[_][]const u8{ "/a/", "b/", "c" }, "/a/b/c"); | |
| 132 | ||
| 133 | testJoinPosix( | |
| 134 | &[_][]const u8{ "/home/andy/dev/zig/build/lib/zig/std", "io.zig" }, | |
| 135 | "/home/andy/dev/zig/build/lib/zig/std/io.zig", | |
| 136 | ); | |
| 137 | ||
| 138 | testJoinPosix(&[_][]const u8{ "a", "/c" }, "a/c"); | |
| 139 | testJoinPosix(&[_][]const u8{ "a/", "/c" }, "a/c"); | |
| 122 | for (&[_]bool{ false, true }) |zero| { | |
| 123 | testJoinMaybeZWindows(&[_][]const u8{}, "", zero); | |
| 124 | testJoinMaybeZWindows(&[_][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c", zero); | |
| 125 | testJoinMaybeZWindows(&[_][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c", zero); | |
| 126 | testJoinMaybeZWindows(&[_][]const u8{ "c:\\a\\b\\", "c" }, "c:\\a\\b\\c", zero); | |
| 127 | ||
| 128 | testJoinMaybeZWindows(&[_][]const u8{ "c:\\", "a", "b\\", "c" }, "c:\\a\\b\\c", zero); | |
| 129 | testJoinMaybeZWindows(&[_][]const u8{ "c:\\a\\", "b\\", "c" }, "c:\\a\\b\\c", zero); | |
| 130 | ||
| 131 | testJoinMaybeZWindows( | |
| 132 | &[_][]const u8{ "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std", "io.zig" }, | |
| 133 | "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig", | |
| 134 | zero, | |
| 135 | ); | |
| 136 | ||
| 137 | testJoinMaybeZWindows(&[_][]const u8{ "c:\\", "a", "b/", "c" }, "c:\\a\\b/c", zero); | |
| 138 | testJoinMaybeZWindows(&[_][]const u8{ "c:\\a/", "b\\", "/c" }, "c:\\a/b\\c", zero); | |
| 139 | ||
| 140 | testJoinMaybeZPosix(&[_][]const u8{}, "", zero); | |
| 141 | testJoinMaybeZPosix(&[_][]const u8{ "/a/b", "c" }, "/a/b/c", zero); | |
| 142 | testJoinMaybeZPosix(&[_][]const u8{ "/a/b/", "c" }, "/a/b/c", zero); | |
| 143 | ||
| 144 | testJoinMaybeZPosix(&[_][]const u8{ "/", "a", "b/", "c" }, "/a/b/c", zero); | |
| 145 | testJoinMaybeZPosix(&[_][]const u8{ "/a/", "b/", "c" }, "/a/b/c", zero); | |
| 146 | ||
| 147 | testJoinMaybeZPosix( | |
| 148 | &[_][]const u8{ "/home/andy/dev/zig/build/lib/zig/std", "io.zig" }, | |
| 149 | "/home/andy/dev/zig/build/lib/zig/std/io.zig", | |
| 150 | zero, | |
| 151 | ); | |
| 152 | ||
| 153 | testJoinMaybeZPosix(&[_][]const u8{ "a", "/c" }, "a/c", zero); | |
| 154 | testJoinMaybeZPosix(&[_][]const u8{ "a/", "/c" }, "a/c", zero); | |
| 155 | } | |
| 140 | 156 | } |
| 141 | 157 | |
| 142 | 158 | pub const isAbsoluteC = @compileError("deprecated: renamed to isAbsoluteZ"); |
| ... | ... | @@ -1210,7 +1226,7 @@ fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []cons |
| 1210 | 1226 | /// pointer address range of `path`, even if it is length zero. |
| 1211 | 1227 | pub fn extension(path: []const u8) []const u8 { |
| 1212 | 1228 | const filename = basename(path); |
| 1213 | const index = mem.lastIndexOf(u8, filename, ".") orelse return path[path.len..]; | |
| 1229 | const index = mem.lastIndexOfScalar(u8, filename, '.') orelse return path[path.len..]; | |
| 1214 | 1230 | if (index == 0) return path[path.len..]; |
| 1215 | 1231 | return filename[index..]; |
| 1216 | 1232 | } |
lib/std/fs/test.zig+1-1| ... | ... | @@ -762,7 +762,7 @@ test "open file with exclusive lock twice, make sure it waits" { |
| 762 | 762 | try evt.init(); |
| 763 | 763 | defer evt.deinit(); |
| 764 | 764 | |
| 765 | const t = try std.Thread.spawn(S.C{ .dir = &tmp.dir, .evt = &evt }, S.checkFn); | |
| 765 | const t = try std.Thread.spawn(S.checkFn, S.C{ .dir = &tmp.dir, .evt = &evt }); | |
| 766 | 766 | defer t.wait(); |
| 767 | 767 | |
| 768 | 768 | const SLEEP_TIMEOUT_NS = 10 * std.time.ns_per_ms; |
lib/std/hash_map.zig+1-2| ... | ... | @@ -563,7 +563,6 @@ pub fn HashMapUnmanaged( |
| 563 | 563 | } |
| 564 | 564 | |
| 565 | 565 | /// Insert an entry if the associated key is not already present, otherwise update preexisting value. |
| 566 | /// Returns true if the key was already present. | |
| 567 | 566 | pub fn put(self: *Self, allocator: *Allocator, key: K, value: V) !void { |
| 568 | 567 | const result = try self.getOrPut(allocator, key); |
| 569 | 568 | result.entry.value = value; |
| ... | ... | @@ -1116,7 +1115,7 @@ test "std.hash_map put" { |
| 1116 | 1115 | |
| 1117 | 1116 | var i: u32 = 0; |
| 1118 | 1117 | while (i < 16) : (i += 1) { |
| 1119 | _ = try map.put(i, i); | |
| 1118 | try map.put(i, i); | |
| 1120 | 1119 | } |
| 1121 | 1120 | |
| 1122 | 1121 | i = 0; |
lib/std/json.zig+6-6| ... | ... | @@ -2077,27 +2077,27 @@ pub const Parser = struct { |
| 2077 | 2077 | p.state = .ArrayValue; |
| 2078 | 2078 | }, |
| 2079 | 2079 | .String => |s| { |
| 2080 | _ = try object.put(key, try p.parseString(allocator, s, input, i)); | |
| 2080 | try object.put(key, try p.parseString(allocator, s, input, i)); | |
| 2081 | 2081 | _ = p.stack.pop(); |
| 2082 | 2082 | p.state = .ObjectKey; |
| 2083 | 2083 | }, |
| 2084 | 2084 | .Number => |n| { |
| 2085 | _ = try object.put(key, try p.parseNumber(n, input, i)); | |
| 2085 | try object.put(key, try p.parseNumber(n, input, i)); | |
| 2086 | 2086 | _ = p.stack.pop(); |
| 2087 | 2087 | p.state = .ObjectKey; |
| 2088 | 2088 | }, |
| 2089 | 2089 | .True => { |
| 2090 | _ = try object.put(key, Value{ .Bool = true }); | |
| 2090 | try object.put(key, Value{ .Bool = true }); | |
| 2091 | 2091 | _ = p.stack.pop(); |
| 2092 | 2092 | p.state = .ObjectKey; |
| 2093 | 2093 | }, |
| 2094 | 2094 | .False => { |
| 2095 | _ = try object.put(key, Value{ .Bool = false }); | |
| 2095 | try object.put(key, Value{ .Bool = false }); | |
| 2096 | 2096 | _ = p.stack.pop(); |
| 2097 | 2097 | p.state = .ObjectKey; |
| 2098 | 2098 | }, |
| 2099 | 2099 | .Null => { |
| 2100 | _ = try object.put(key, Value.Null); | |
| 2100 | try object.put(key, Value.Null); | |
| 2101 | 2101 | _ = p.stack.pop(); |
| 2102 | 2102 | p.state = .ObjectKey; |
| 2103 | 2103 | }, |
| ... | ... | @@ -2184,7 +2184,7 @@ pub const Parser = struct { |
| 2184 | 2184 | _ = p.stack.pop(); |
| 2185 | 2185 | |
| 2186 | 2186 | var object = &p.stack.items[p.stack.items.len - 1].Object; |
| 2187 | _ = try object.put(key, value.*); | |
| 2187 | try object.put(key, value.*); | |
| 2188 | 2188 | p.state = .ObjectKey; |
| 2189 | 2189 | }, |
| 2190 | 2190 | // Array Parent -> [ ..., <array>, value ] |
lib/std/json/write_stream.zig+2-2| ... | ... | @@ -293,7 +293,7 @@ test "json write stream" { |
| 293 | 293 | |
| 294 | 294 | fn getJsonObject(allocator: *std.mem.Allocator) !std.json.Value { |
| 295 | 295 | var value = std.json.Value{ .Object = std.json.ObjectMap.init(allocator) }; |
| 296 | _ = try value.Object.put("one", std.json.Value{ .Integer = @intCast(i64, 1) }); | |
| 297 | _ = try value.Object.put("two", std.json.Value{ .Float = 2.0 }); | |
| 296 | try value.Object.put("one", std.json.Value{ .Integer = @intCast(i64, 1) }); | |
| 297 | try value.Object.put("two", std.json.Value{ .Float = 2.0 }); | |
| 298 | 298 | return value; |
| 299 | 299 | } |
lib/std/net/test.zig+2-2| ... | ... | @@ -161,7 +161,7 @@ test "listen on a port, send bytes, receive bytes" { |
| 161 | 161 | } |
| 162 | 162 | }; |
| 163 | 163 | |
| 164 | const t = try std.Thread.spawn(server.listen_address, S.clientFn); | |
| 164 | const t = try std.Thread.spawn(S.clientFn, server.listen_address); | |
| 165 | 165 | defer t.wait(); |
| 166 | 166 | |
| 167 | 167 | var client = try server.accept(); |
| ... | ... | @@ -285,7 +285,7 @@ test "listen on a unix socket, send bytes, receive bytes" { |
| 285 | 285 | } |
| 286 | 286 | }; |
| 287 | 287 | |
| 288 | const t = try std.Thread.spawn({}, S.clientFn); | |
| 288 | const t = try std.Thread.spawn(S.clientFn, {}); | |
| 289 | 289 | defer t.wait(); |
| 290 | 290 | |
| 291 | 291 | var client = try server.accept(); |
lib/std/once.zig+2-2| ... | ... | @@ -59,11 +59,11 @@ test "Once executes its function just once" { |
| 59 | 59 | defer for (threads) |handle| handle.wait(); |
| 60 | 60 | |
| 61 | 61 | for (threads) |*handle| { |
| 62 | handle.* = try std.Thread.spawn(@as(u8, 0), struct { | |
| 62 | handle.* = try std.Thread.spawn(struct { | |
| 63 | 63 | fn thread_fn(x: u8) void { |
| 64 | 64 | global_once.call(); |
| 65 | 65 | } |
| 66 | }.thread_fn); | |
| 66 | }.thread_fn, 0); | |
| 67 | 67 | } |
| 68 | 68 | } |
| 69 | 69 |
lib/std/os.zig+74-1| ... | ... | @@ -4840,7 +4840,7 @@ pub const SendError = error{ |
| 4840 | 4840 | NetworkSubsystemFailed, |
| 4841 | 4841 | } || UnexpectedError; |
| 4842 | 4842 | |
| 4843 | pub const SendToError = SendError || error{ | |
| 4843 | pub const SendMsgError = SendError || error{ | |
| 4844 | 4844 | /// The passed address didn't have the correct address family in its sa_family field. |
| 4845 | 4845 | AddressFamilyNotSupported, |
| 4846 | 4846 | |
| ... | ... | @@ -4859,6 +4859,79 @@ pub const SendToError = SendError || error{ |
| 4859 | 4859 | AddressNotAvailable, |
| 4860 | 4860 | }; |
| 4861 | 4861 | |
| 4862 | pub fn sendmsg( | |
| 4863 | /// The file descriptor of the sending socket. | |
| 4864 | sockfd: socket_t, | |
| 4865 | /// Message header and iovecs | |
| 4866 | msg: msghdr_const, | |
| 4867 | flags: u32, | |
| 4868 | ) SendMsgError!usize { | |
| 4869 | while (true) { | |
| 4870 | const rc = system.sendmsg(sockfd, &msg, flags); | |
| 4871 | if (builtin.os.tag == .windows) { | |
| 4872 | if (rc == windows.ws2_32.SOCKET_ERROR) { | |
| 4873 | switch (windows.ws2_32.WSAGetLastError()) { | |
| 4874 | .WSAEACCES => return error.AccessDenied, | |
| 4875 | .WSAEADDRNOTAVAIL => return error.AddressNotAvailable, | |
| 4876 | .WSAECONNRESET => return error.ConnectionResetByPeer, | |
| 4877 | .WSAEMSGSIZE => return error.MessageTooBig, | |
| 4878 | .WSAENOBUFS => return error.SystemResources, | |
| 4879 | .WSAENOTSOCK => return error.FileDescriptorNotASocket, | |
| 4880 | .WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported, | |
| 4881 | .WSAEDESTADDRREQ => unreachable, // A destination address is required. | |
| 4882 | .WSAEFAULT => unreachable, // The lpBuffers, lpTo, lpOverlapped, lpNumberOfBytesSent, or lpCompletionRoutine parameters are not part of the user address space, or the lpTo parameter is too small. | |
| 4883 | .WSAEHOSTUNREACH => return error.NetworkUnreachable, | |
| 4884 | // TODO: WSAEINPROGRESS, WSAEINTR | |
| 4885 | .WSAEINVAL => unreachable, | |
| 4886 | .WSAENETDOWN => return error.NetworkSubsystemFailed, | |
| 4887 | .WSAENETRESET => return error.ConnectionResetByPeer, | |
| 4888 | .WSAENETUNREACH => return error.NetworkUnreachable, | |
| 4889 | .WSAENOTCONN => return error.SocketNotConnected, | |
| 4890 | .WSAESHUTDOWN => unreachable, // The socket has been shut down; it is not possible to WSASendTo on a socket after shutdown has been invoked with how set to SD_SEND or SD_BOTH. | |
| 4891 | .WSAEWOULDBLOCK => return error.WouldBlock, | |
| 4892 | .WSANOTINITIALISED => unreachable, // A successful WSAStartup call must occur before using this function. | |
| 4893 | else => |err| return windows.unexpectedWSAError(err), | |
| 4894 | } | |
| 4895 | } else { | |
| 4896 | return @intCast(usize, rc); | |
| 4897 | } | |
| 4898 | } else { | |
| 4899 | switch (errno(rc)) { | |
| 4900 | 0 => return @intCast(usize, rc), | |
| 4901 | ||
| 4902 | EACCES => return error.AccessDenied, | |
| 4903 | EAGAIN => return error.WouldBlock, | |
| 4904 | EALREADY => return error.FastOpenAlreadyInProgress, | |
| 4905 | EBADF => unreachable, // always a race condition | |
| 4906 | ECONNRESET => return error.ConnectionResetByPeer, | |
| 4907 | EDESTADDRREQ => unreachable, // The socket is not connection-mode, and no peer address is set. | |
| 4908 | EFAULT => unreachable, // An invalid user space address was specified for an argument. | |
| 4909 | EINTR => continue, | |
| 4910 | EINVAL => unreachable, // Invalid argument passed. | |
| 4911 | EISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified | |
| 4912 | EMSGSIZE => return error.MessageTooBig, | |
| 4913 | ENOBUFS => return error.SystemResources, | |
| 4914 | ENOMEM => return error.SystemResources, | |
| 4915 | ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket. | |
| 4916 | EOPNOTSUPP => unreachable, // Some bit in the flags argument is inappropriate for the socket type. | |
| 4917 | EPIPE => return error.BrokenPipe, | |
| 4918 | EAFNOSUPPORT => return error.AddressFamilyNotSupported, | |
| 4919 | ELOOP => return error.SymLinkLoop, | |
| 4920 | ENAMETOOLONG => return error.NameTooLong, | |
| 4921 | ENOENT => return error.FileNotFound, | |
| 4922 | ENOTDIR => return error.NotDir, | |
| 4923 | EHOSTUNREACH => return error.NetworkUnreachable, | |
| 4924 | ENETUNREACH => return error.NetworkUnreachable, | |
| 4925 | ENOTCONN => return error.SocketNotConnected, | |
| 4926 | ENETDOWN => return error.NetworkSubsystemFailed, | |
| 4927 | else => |err| return unexpectedErrno(err), | |
| 4928 | } | |
| 4929 | } | |
| 4930 | } | |
| 4931 | } | |
| 4932 | ||
| 4933 | pub const SendToError = SendMsgError; | |
| 4934 | ||
| 4862 | 4935 | /// Transmit a message to another socket. |
| 4863 | 4936 | /// |
| 4864 | 4937 | /// The `sendto` call may be used only when the socket is in a connected state (so that the intended |
lib/std/os/bits/linux/arm64.zig+4-4| ... | ... | @@ -400,10 +400,10 @@ pub const msghdr = extern struct { |
| 400 | 400 | msg_namelen: socklen_t, |
| 401 | 401 | msg_iov: [*]iovec, |
| 402 | 402 | msg_iovlen: i32, |
| 403 | __pad1: i32, | |
| 403 | __pad1: i32 = 0, | |
| 404 | 404 | msg_control: ?*c_void, |
| 405 | 405 | msg_controllen: socklen_t, |
| 406 | __pad2: socklen_t, | |
| 406 | __pad2: socklen_t = 0, | |
| 407 | 407 | msg_flags: i32, |
| 408 | 408 | }; |
| 409 | 409 | |
| ... | ... | @@ -412,10 +412,10 @@ pub const msghdr_const = extern struct { |
| 412 | 412 | msg_namelen: socklen_t, |
| 413 | 413 | msg_iov: [*]iovec_const, |
| 414 | 414 | msg_iovlen: i32, |
| 415 | __pad1: i32, | |
| 415 | __pad1: i32 = 0, | |
| 416 | 416 | msg_control: ?*c_void, |
| 417 | 417 | msg_controllen: socklen_t, |
| 418 | __pad2: socklen_t, | |
| 418 | __pad2: socklen_t = 0, | |
| 419 | 419 | msg_flags: i32, |
| 420 | 420 | }; |
| 421 | 421 |
lib/std/os/bits/linux/x86_64.zig+4-4| ... | ... | @@ -495,10 +495,10 @@ pub const msghdr = extern struct { |
| 495 | 495 | msg_namelen: socklen_t, |
| 496 | 496 | msg_iov: [*]iovec, |
| 497 | 497 | msg_iovlen: i32, |
| 498 | __pad1: i32, | |
| 498 | __pad1: i32 = 0, | |
| 499 | 499 | msg_control: ?*c_void, |
| 500 | 500 | msg_controllen: socklen_t, |
| 501 | __pad2: socklen_t, | |
| 501 | __pad2: socklen_t = 0, | |
| 502 | 502 | msg_flags: i32, |
| 503 | 503 | }; |
| 504 | 504 | |
| ... | ... | @@ -507,10 +507,10 @@ pub const msghdr_const = extern struct { |
| 507 | 507 | msg_namelen: socklen_t, |
| 508 | 508 | msg_iov: [*]iovec_const, |
| 509 | 509 | msg_iovlen: i32, |
| 510 | __pad1: i32, | |
| 510 | __pad1: i32 = 0, | |
| 511 | 511 | msg_control: ?*c_void, |
| 512 | 512 | msg_controllen: socklen_t, |
| 513 | __pad2: socklen_t, | |
| 513 | __pad2: socklen_t = 0, | |
| 514 | 514 | msg_flags: i32, |
| 515 | 515 | }; |
| 516 | 516 |
lib/std/os/linux.zig+1-1| ... | ... | @@ -977,7 +977,7 @@ pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noal |
| 977 | 977 | return syscall5(.getsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen)); |
| 978 | 978 | } |
| 979 | 979 | |
| 980 | pub fn sendmsg(fd: i32, msg: *msghdr_const, flags: u32) usize { | |
| 980 | pub fn sendmsg(fd: i32, msg: *const msghdr_const, flags: u32) usize { | |
| 981 | 981 | if (builtin.arch == .i386) { |
| 982 | 982 | return socketcall(SC_sendmsg, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags }); |
| 983 | 983 | } |
lib/std/os/test.zig+7-7| ... | ... | @@ -317,7 +317,7 @@ test "std.Thread.getCurrentId" { |
| 317 | 317 | if (builtin.single_threaded) return error.SkipZigTest; |
| 318 | 318 | |
| 319 | 319 | var thread_current_id: Thread.Id = undefined; |
| 320 | const thread = try Thread.spawn(&thread_current_id, testThreadIdFn); | |
| 320 | const thread = try Thread.spawn(testThreadIdFn, &thread_current_id); | |
| 321 | 321 | const thread_id = thread.handle(); |
| 322 | 322 | thread.wait(); |
| 323 | 323 | if (Thread.use_pthreads) { |
| ... | ... | @@ -336,10 +336,10 @@ test "spawn threads" { |
| 336 | 336 | |
| 337 | 337 | var shared_ctx: i32 = 1; |
| 338 | 338 | |
| 339 | const thread1 = try Thread.spawn({}, start1); | |
| 340 | const thread2 = try Thread.spawn(&shared_ctx, start2); | |
| 341 | const thread3 = try Thread.spawn(&shared_ctx, start2); | |
| 342 | const thread4 = try Thread.spawn(&shared_ctx, start2); | |
| 339 | const thread1 = try Thread.spawn(start1, {}); | |
| 340 | const thread2 = try Thread.spawn(start2, &shared_ctx); | |
| 341 | const thread3 = try Thread.spawn(start2, &shared_ctx); | |
| 342 | const thread4 = try Thread.spawn(start2, &shared_ctx); | |
| 343 | 343 | |
| 344 | 344 | thread1.wait(); |
| 345 | 345 | thread2.wait(); |
| ... | ... | @@ -367,8 +367,8 @@ test "cpu count" { |
| 367 | 367 | |
| 368 | 368 | test "thread local storage" { |
| 369 | 369 | if (builtin.single_threaded) return error.SkipZigTest; |
| 370 | const thread1 = try Thread.spawn({}, testTls); | |
| 371 | const thread2 = try Thread.spawn({}, testTls); | |
| 370 | const thread1 = try Thread.spawn(testTls, {}); | |
| 371 | const thread2 = try Thread.spawn(testTls, {}); | |
| 372 | 372 | testTls({}); |
| 373 | 373 | thread1.wait(); |
| 374 | 374 | thread2.wait(); |
lib/std/os/windows.zig+13| ... | ... | @@ -1291,6 +1291,19 @@ pub fn getsockname(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.so |
| 1291 | 1291 | return ws2_32.getsockname(s, name, @ptrCast(*i32, namelen)); |
| 1292 | 1292 | } |
| 1293 | 1293 | |
| 1294 | pub fn sendmsg( | |
| 1295 | s: ws2_32.SOCKET, | |
| 1296 | msg: *const ws2_32.WSAMSG, | |
| 1297 | flags: u32, | |
| 1298 | ) i32 { | |
| 1299 | var bytes_send: DWORD = undefined; | |
| 1300 | if (ws2_32.WSASendMsg(s, msg, flags, &bytes_send, null, null) == ws2_32.SOCKET_ERROR) { | |
| 1301 | return ws2_32.SOCKET_ERROR; | |
| 1302 | } else { | |
| 1303 | return @as(i32, @intCast(u31, bytes_send)); | |
| 1304 | } | |
| 1305 | } | |
| 1306 | ||
| 1294 | 1307 | pub fn sendto(s: ws2_32.SOCKET, buf: [*]const u8, len: usize, flags: u32, to: ?*const ws2_32.sockaddr, to_len: ws2_32.socklen_t) i32 { |
| 1295 | 1308 | var buffer = ws2_32.WSABUF{ .len = @truncate(u31, len), .buf = @intToPtr([*]u8, @ptrToInt(buf)) }; |
| 1296 | 1309 | var bytes_send: DWORD = undefined; |
lib/std/priority_queue.zig+1-1| ... | ... | @@ -410,7 +410,7 @@ test "std.PriorityQueue: iterator" { |
| 410 | 410 | const items = [_]u32{ 54, 12, 7, 23, 25, 13 }; |
| 411 | 411 | for (items) |e| { |
| 412 | 412 | _ = try queue.add(e); |
| 413 | _ = try map.put(e, {}); | |
| 413 | try map.put(e, {}); | |
| 414 | 414 | } |
| 415 | 415 | |
| 416 | 416 | var it = queue.iterator(); |
src/Module.zig-1| ... | ... | @@ -4101,7 +4101,6 @@ pub fn namedFieldPtr( |
| 4101 | 4101 | scope.arena(), |
| 4102 | 4102 | try Value.Tag.@"error".create(scope.arena(), .{ |
| 4103 | 4103 | .name = entry.key, |
| 4104 | .value = entry.value, | |
| 4105 | 4104 | }), |
| 4106 | 4105 | ), |
| 4107 | 4106 | }); |
src/ThreadPool.zig+1-1| ... | ... | @@ -74,7 +74,7 @@ pub fn init(self: *ThreadPool, allocator: *std.mem.Allocator) !void { |
| 74 | 74 | try worker.idle_node.data.init(); |
| 75 | 75 | errdefer worker.idle_node.data.deinit(); |
| 76 | 76 | |
| 77 | worker.thread = try std.Thread.spawn(worker, Worker.run); | |
| 77 | worker.thread = try std.Thread.spawn(Worker.run, worker); | |
| 78 | 78 | } |
| 79 | 79 | } |
| 80 | 80 |
src/clang.zig+38| ... | ... | @@ -432,6 +432,9 @@ pub const FieldDecl = opaque { |
| 432 | 432 | |
| 433 | 433 | pub const getLocation = ZigClangFieldDecl_getLocation; |
| 434 | 434 | extern fn ZigClangFieldDecl_getLocation(*const FieldDecl) SourceLocation; |
| 435 | ||
| 436 | pub const getParent = ZigClangFieldDecl_getParent; | |
| 437 | extern fn ZigClangFieldDecl_getParent(*const FieldDecl) ?*const RecordDecl; | |
| 435 | 438 | }; |
| 436 | 439 | |
| 437 | 440 | pub const FileID = opaque {}; |
| ... | ... | @@ -593,6 +596,34 @@ pub const TypeOfExprType = opaque { |
| 593 | 596 | extern fn ZigClangTypeOfExprType_getUnderlyingExpr(*const TypeOfExprType) *const Expr; |
| 594 | 597 | }; |
| 595 | 598 | |
| 599 | pub const OffsetOfNode = opaque { | |
| 600 | pub const getKind = ZigClangOffsetOfNode_getKind; | |
| 601 | extern fn ZigClangOffsetOfNode_getKind(*const OffsetOfNode) OffsetOfNode_Kind; | |
| 602 | ||
| 603 | pub const getArrayExprIndex = ZigClangOffsetOfNode_getArrayExprIndex; | |
| 604 | extern fn ZigClangOffsetOfNode_getArrayExprIndex(*const OffsetOfNode) c_uint; | |
| 605 | ||
| 606 | pub const getField = ZigClangOffsetOfNode_getField; | |
| 607 | extern fn ZigClangOffsetOfNode_getField(*const OffsetOfNode) *FieldDecl; | |
| 608 | }; | |
| 609 | ||
| 610 | pub const OffsetOfExpr = opaque { | |
| 611 | pub const getNumComponents = ZigClangOffsetOfExpr_getNumComponents; | |
| 612 | extern fn ZigClangOffsetOfExpr_getNumComponents(*const OffsetOfExpr) c_uint; | |
| 613 | ||
| 614 | pub const getNumExpressions = ZigClangOffsetOfExpr_getNumExpressions; | |
| 615 | extern fn ZigClangOffsetOfExpr_getNumExpressions(*const OffsetOfExpr) c_uint; | |
| 616 | ||
| 617 | pub const getIndexExpr = ZigClangOffsetOfExpr_getIndexExpr; | |
| 618 | extern fn ZigClangOffsetOfExpr_getIndexExpr(*const OffsetOfExpr, idx: c_uint) *const Expr; | |
| 619 | ||
| 620 | pub const getComponent = ZigClangOffsetOfExpr_getComponent; | |
| 621 | extern fn ZigClangOffsetOfExpr_getComponent(*const OffsetOfExpr, idx: c_uint) *const OffsetOfNode; | |
| 622 | ||
| 623 | pub const getBeginLoc = ZigClangOffsetOfExpr_getBeginLoc; | |
| 624 | extern fn ZigClangOffsetOfExpr_getBeginLoc(*const OffsetOfExpr) SourceLocation; | |
| 625 | }; | |
| 626 | ||
| 596 | 627 | pub const MemberExpr = opaque { |
| 597 | 628 | pub const getBase = ZigClangMemberExpr_getBase; |
| 598 | 629 | extern fn ZigClangMemberExpr_getBase(*const MemberExpr) *const Expr; |
| ... | ... | @@ -1662,6 +1693,13 @@ pub const UnaryExprOrTypeTrait_Kind = extern enum { |
| 1662 | 1693 | PreferredAlignOf, |
| 1663 | 1694 | }; |
| 1664 | 1695 | |
| 1696 | pub const OffsetOfNode_Kind = extern enum { | |
| 1697 | Array, | |
| 1698 | Field, | |
| 1699 | Identifier, | |
| 1700 | Base, | |
| 1701 | }; | |
| 1702 | ||
| 1665 | 1703 | pub const Stage2ErrorMsg = extern struct { |
| 1666 | 1704 | filename_ptr: ?[*]const u8, |
| 1667 | 1705 | filename_len: usize, |
src/link/Elf.zig+3-3| ... | ... | @@ -2165,7 +2165,7 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void { |
| 2165 | 2165 | // is desired for both. |
| 2166 | 2166 | _ = self.dbg_line_fn_free_list.remove(&decl.fn_link.elf); |
| 2167 | 2167 | if (decl.fn_link.elf.prev) |prev| { |
| 2168 | _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {}; | |
| 2168 | self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {}; | |
| 2169 | 2169 | prev.next = decl.fn_link.elf.next; |
| 2170 | 2170 | if (decl.fn_link.elf.next) |next| { |
| 2171 | 2171 | next.prev = prev; |
| ... | ... | @@ -2423,7 +2423,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2423 | 2423 | if (src_fn.off + src_fn.len + min_nop_size > next.off) { |
| 2424 | 2424 | // It grew too big, so we move it to a new location. |
| 2425 | 2425 | if (src_fn.prev) |prev| { |
| 2426 | _ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {}; | |
| 2426 | self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {}; | |
| 2427 | 2427 | prev.next = src_fn.next; |
| 2428 | 2428 | } |
| 2429 | 2429 | assert(src_fn.prev != next); |
| ... | ... | @@ -2579,7 +2579,7 @@ fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) ! |
| 2579 | 2579 | if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) { |
| 2580 | 2580 | // It grew too big, so we move it to a new location. |
| 2581 | 2581 | if (text_block.dbg_info_prev) |prev| { |
| 2582 | _ = self.dbg_info_decl_free_list.put(self.base.allocator, prev, {}) catch {}; | |
| 2582 | self.dbg_info_decl_free_list.put(self.base.allocator, prev, {}) catch {}; | |
| 2583 | 2583 | prev.dbg_info_next = text_block.dbg_info_next; |
| 2584 | 2584 | } |
| 2585 | 2585 | next.dbg_info_prev = text_block.dbg_info_prev; |
src/link/MachO/DebugSymbols.zig+2-2| ... | ... | @@ -1096,7 +1096,7 @@ pub fn commitDeclDebugInfo( |
| 1096 | 1096 | if (src_fn.off + src_fn.len + min_nop_size > next.off) { |
| 1097 | 1097 | // It grew too big, so we move it to a new location. |
| 1098 | 1098 | if (src_fn.prev) |prev| { |
| 1099 | _ = self.dbg_line_fn_free_list.put(allocator, prev, {}) catch {}; | |
| 1099 | self.dbg_line_fn_free_list.put(allocator, prev, {}) catch {}; | |
| 1100 | 1100 | prev.next = src_fn.next; |
| 1101 | 1101 | } |
| 1102 | 1102 | next.prev = src_fn.prev; |
| ... | ... | @@ -1256,7 +1256,7 @@ fn updateDeclDebugInfoAllocation( |
| 1256 | 1256 | if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) { |
| 1257 | 1257 | // It grew too big, so we move it to a new location. |
| 1258 | 1258 | if (text_block.dbg_info_prev) |prev| { |
| 1259 | _ = self.dbg_info_decl_free_list.put(allocator, prev, {}) catch {}; | |
| 1259 | self.dbg_info_decl_free_list.put(allocator, prev, {}) catch {}; | |
| 1260 | 1260 | prev.dbg_info_next = text_block.dbg_info_next; |
| 1261 | 1261 | } |
| 1262 | 1262 | next.dbg_info_prev = text_block.dbg_info_prev; |
src/liveness.zig+2-2| ... | ... | @@ -119,7 +119,7 @@ fn analyzeInst( |
| 119 | 119 | if (!else_table.contains(then_death)) { |
| 120 | 120 | try else_entry_deaths.append(then_death); |
| 121 | 121 | } |
| 122 | _ = try table.put(then_death, {}); | |
| 122 | try table.put(then_death, {}); | |
| 123 | 123 | } |
| 124 | 124 | } |
| 125 | 125 | // Now we have to correctly populate new_set. |
| ... | ... | @@ -195,7 +195,7 @@ fn analyzeInst( |
| 195 | 195 | } |
| 196 | 196 | } |
| 197 | 197 | // undo resetting the table |
| 198 | _ = try table.put(case_death, {}); | |
| 198 | try table.put(case_death, {}); | |
| 199 | 199 | } |
| 200 | 200 | } |
| 201 | 201 |
src/translate_c.zig+62-10| ... | ... | @@ -377,7 +377,7 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void { |
| 377 | 377 | const macro = @ptrCast(*clang.MacroDefinitionRecord, entity); |
| 378 | 378 | const raw_name = macro.getName_getNameStart(); |
| 379 | 379 | const name = try c.str(raw_name); |
| 380 | _ = try c.global_names.put(c.gpa, name, {}); | |
| 380 | try c.global_names.put(c.gpa, name, {}); | |
| 381 | 381 | }, |
| 382 | 382 | else => {}, |
| 383 | 383 | } |
| ... | ... | @@ -399,7 +399,7 @@ fn declVisitorC(context: ?*c_void, decl: *const clang.Decl) callconv(.C) bool { |
| 399 | 399 | fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void { |
| 400 | 400 | if (decl.castToNamedDecl()) |named_decl| { |
| 401 | 401 | const decl_name = try c.str(named_decl.getName_bytes_begin()); |
| 402 | _ = try c.global_names.put(c.gpa, decl_name, {}); | |
| 402 | try c.global_names.put(c.gpa, decl_name, {}); | |
| 403 | 403 | } |
| 404 | 404 | } |
| 405 | 405 | |
| ... | ... | @@ -788,7 +788,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD |
| 788 | 788 | const is_pub = toplevel and !is_unnamed; |
| 789 | 789 | const init_node = blk: { |
| 790 | 790 | const record_def = record_decl.getDefinition() orelse { |
| 791 | _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {}); | |
| 791 | try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {}); | |
| 792 | 792 | break :blk Tag.opaque_literal.init(); |
| 793 | 793 | }; |
| 794 | 794 | |
| ... | ... | @@ -805,13 +805,13 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD |
| 805 | 805 | const field_qt = field_decl.getType(); |
| 806 | 806 | |
| 807 | 807 | if (field_decl.isBitField()) { |
| 808 | _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {}); | |
| 808 | try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {}); | |
| 809 | 809 | try warn(c, scope, field_loc, "{s} demoted to opaque type - has bitfield", .{container_kind_name}); |
| 810 | 810 | break :blk Tag.opaque_literal.init(); |
| 811 | 811 | } |
| 812 | 812 | |
| 813 | 813 | if (qualTypeCanon(field_qt).isIncompleteOrZeroLengthArrayType(c.clang_context)) { |
| 814 | _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {}); | |
| 814 | try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {}); | |
| 815 | 815 | try warn(c, scope, field_loc, "{s} demoted to opaque type - has variable length array", .{container_kind_name}); |
| 816 | 816 | break :blk Tag.opaque_literal.init(); |
| 817 | 817 | } |
| ... | ... | @@ -826,7 +826,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD |
| 826 | 826 | } |
| 827 | 827 | const field_type = transQualType(c, scope, field_qt, field_loc) catch |err| switch (err) { |
| 828 | 828 | error.UnsupportedType => { |
| 829 | _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {}); | |
| 829 | try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {}); | |
| 830 | 830 | try warn(c, scope, record_loc, "{s} demoted to opaque type - unable to translate type of field {s}", .{ container_kind_name, field_name }); |
| 831 | 831 | break :blk Tag.opaque_literal.init(); |
| 832 | 832 | }, |
| ... | ... | @@ -972,7 +972,7 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E |
| 972 | 972 | .fields = try c.arena.dupe(ast.Payload.Enum.Field, fields.items), |
| 973 | 973 | }); |
| 974 | 974 | } else blk: { |
| 975 | _ = try c.opaque_demotes.put(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), {}); | |
| 975 | try c.opaque_demotes.put(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), {}); | |
| 976 | 976 | break :blk Tag.opaque_literal.init(); |
| 977 | 977 | }; |
| 978 | 978 | |
| ... | ... | @@ -1069,12 +1069,64 @@ fn transStmt( |
| 1069 | 1069 | const expr = try transExpr(c, scope, source_expr, .used); |
| 1070 | 1070 | return maybeSuppressResult(c, scope, result_used, expr); |
| 1071 | 1071 | }, |
| 1072 | .OffsetOfExprClass => return transOffsetOfExpr(c, scope, @ptrCast(*const clang.OffsetOfExpr, stmt), result_used), | |
| 1072 | 1073 | else => { |
| 1073 | 1074 | return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)}); |
| 1074 | 1075 | }, |
| 1075 | 1076 | } |
| 1076 | 1077 | } |
| 1077 | 1078 | |
| 1079 | /// Translate a "simple" offsetof expression containing exactly one component, | |
| 1080 | /// when that component is of kind .Field - e.g. offsetof(mytype, myfield) | |
| 1081 | fn transSimpleOffsetOfExpr( | |
| 1082 | c: *Context, | |
| 1083 | scope: *Scope, | |
| 1084 | expr: *const clang.OffsetOfExpr, | |
| 1085 | ) TransError!Node { | |
| 1086 | assert(expr.getNumComponents() == 1); | |
| 1087 | const component = expr.getComponent(0); | |
| 1088 | if (component.getKind() == .Field) { | |
| 1089 | const field_decl = component.getField(); | |
| 1090 | if (field_decl.getParent()) |record_decl| { | |
| 1091 | if (c.decl_table.get(@ptrToInt(record_decl.getCanonicalDecl()))) |type_name| { | |
| 1092 | const type_node = try Tag.type.create(c.arena, type_name); | |
| 1093 | ||
| 1094 | var raw_field_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin()); | |
| 1095 | const quoted_field_name = try std.fmt.allocPrint(c.arena, "\"{s}\"", .{raw_field_name}); | |
| 1096 | const field_name_node = try Tag.string_literal.create(c.arena, quoted_field_name); | |
| 1097 | ||
| 1098 | return Tag.byte_offset_of.create(c.arena, .{ | |
| 1099 | .lhs = type_node, | |
| 1100 | .rhs = field_name_node, | |
| 1101 | }); | |
| 1102 | } | |
| 1103 | } | |
| 1104 | } | |
| 1105 | return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "Failed to translate simple OffsetOfExpr", .{}); | |
| 1106 | } | |
| 1107 | ||
| 1108 | fn transOffsetOfExpr( | |
| 1109 | c: *Context, | |
| 1110 | scope: *Scope, | |
| 1111 | expr: *const clang.OffsetOfExpr, | |
| 1112 | result_used: ResultUsed, | |
| 1113 | ) TransError!Node { | |
| 1114 | if (expr.getNumComponents() == 1) { | |
| 1115 | const offsetof_expr = try transSimpleOffsetOfExpr(c, scope, expr); | |
| 1116 | return maybeSuppressResult(c, scope, result_used, offsetof_expr); | |
| 1117 | } | |
| 1118 | ||
| 1119 | // TODO implement OffsetOfExpr with more than 1 component | |
| 1120 | // OffsetOfExpr API: | |
| 1121 | // call expr.getComponent(idx) while idx < expr.getNumComponents() | |
| 1122 | // component.getKind() will be either .Array or .Field (other kinds are C++-only) | |
| 1123 | // if .Field, use component.getField() to retrieve *clang.FieldDecl | |
| 1124 | // if .Array, use component.getArrayExprIndex() to get a c_uint which | |
| 1125 | // can be passed to expr.getIndexExpr(expr_index) to get the *clang.Expr for the array index | |
| 1126 | ||
| 1127 | return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO: implement complex OffsetOfExpr translation", .{}); | |
| 1128 | } | |
| 1129 | ||
| 1078 | 1130 | fn transBinaryOperator( |
| 1079 | 1131 | c: *Context, |
| 1080 | 1132 | scope: *Scope, |
| ... | ... | @@ -3199,7 +3251,7 @@ fn maybeSuppressResult( |
| 3199 | 3251 | } |
| 3200 | 3252 | |
| 3201 | 3253 | fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void { |
| 3202 | _ = try c.global_scope.sym_table.put(name, decl_node); | |
| 3254 | try c.global_scope.sym_table.put(name, decl_node); | |
| 3203 | 3255 | try c.global_scope.nodes.append(decl_node); |
| 3204 | 3256 | } |
| 3205 | 3257 | |
| ... | ... | @@ -4235,7 +4287,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 4235 | 4287 | return m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(last)}); |
| 4236 | 4288 | |
| 4237 | 4289 | const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node }); |
| 4238 | _ = try c.global_scope.macro_table.put(m.name, var_decl); | |
| 4290 | try c.global_scope.macro_table.put(m.name, var_decl); | |
| 4239 | 4291 | } |
| 4240 | 4292 | |
| 4241 | 4293 | fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| ... | ... | @@ -4294,7 +4346,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 4294 | 4346 | .return_type = return_type, |
| 4295 | 4347 | .body = try block_scope.complete(c), |
| 4296 | 4348 | }); |
| 4297 | _ = try c.global_scope.macro_table.put(m.name, fn_decl); | |
| 4349 | try c.global_scope.macro_table.put(m.name, fn_decl); | |
| 4298 | 4350 | } |
| 4299 | 4351 | |
| 4300 | 4352 | const ParseError = Error || error{ParseError}; |
src/translate_c/ast.zig+8| ... | ... | @@ -148,6 +148,8 @@ pub const Node = extern union { |
| 148 | 148 | ptr_cast, |
| 149 | 149 | /// @divExact(lhs, rhs) |
| 150 | 150 | div_exact, |
| 151 | /// @byteOffsetOf(lhs, rhs) | |
| 152 | byte_offset_of, | |
| 151 | 153 | |
| 152 | 154 | negate, |
| 153 | 155 | negate_wrap, |
| ... | ... | @@ -303,6 +305,7 @@ pub const Node = extern union { |
| 303 | 305 | .std_mem_zeroinit, |
| 304 | 306 | .ptr_cast, |
| 305 | 307 | .div_exact, |
| 308 | .byte_offset_of, | |
| 306 | 309 | => Payload.BinOp, |
| 307 | 310 | |
| 308 | 311 | .integer_literal, |
| ... | ... | @@ -1135,6 +1138,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 1135 | 1138 | const payload = node.castTag(.div_exact).?.data; |
| 1136 | 1139 | return renderBuiltinCall(c, "@divExact", &.{ payload.lhs, payload.rhs }); |
| 1137 | 1140 | }, |
| 1141 | .byte_offset_of => { | |
| 1142 | const payload = node.castTag(.byte_offset_of).?.data; | |
| 1143 | return renderBuiltinCall(c, "@byteOffsetOf", &.{ payload.lhs, payload.rhs }); | |
| 1144 | }, | |
| 1138 | 1145 | .sizeof => { |
| 1139 | 1146 | const payload = node.castTag(.sizeof).?.data; |
| 1140 | 1147 | return renderBuiltinCall(c, "@sizeOf", &.{payload}); |
| ... | ... | @@ -2001,6 +2008,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { |
| 2001 | 2008 | .array_type, |
| 2002 | 2009 | .bool_to_int, |
| 2003 | 2010 | .div_exact, |
| 2011 | .byte_offset_of, | |
| 2004 | 2012 | => { |
| 2005 | 2013 | // no grouping needed |
| 2006 | 2014 | return renderNode(c, node); |
src/value.zig-2| ... | ... | @@ -1561,7 +1561,6 @@ pub const Value = extern union { |
| 1561 | 1561 | .@"error" => { |
| 1562 | 1562 | const payload = self.castTag(.@"error").?.data; |
| 1563 | 1563 | hasher.update(payload.name); |
| 1564 | std.hash.autoHash(&hasher, payload.value); | |
| 1565 | 1564 | }, |
| 1566 | 1565 | .error_union => { |
| 1567 | 1566 | const payload = self.castTag(.error_union).?.data; |
| ... | ... | @@ -2157,7 +2156,6 @@ pub const Value = extern union { |
| 2157 | 2156 | /// duration of the compilation. |
| 2158 | 2157 | /// TODO revisit this when we have the concept of the error tag type |
| 2159 | 2158 | name: []const u8, |
| 2160 | value: u16, | |
| 2161 | 2159 | }, |
| 2162 | 2160 | }; |
| 2163 | 2161 |
src/zig_clang.cpp+45| ... | ... | @@ -2623,6 +2623,46 @@ const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct |
| 2623 | 2623 | return reinterpret_cast<const struct ZigClangExpr *>(casted->getUnderlyingExpr()); |
| 2624 | 2624 | } |
| 2625 | 2625 | |
| 2626 | enum ZigClangOffsetOfNode_Kind ZigClangOffsetOfNode_getKind(const struct ZigClangOffsetOfNode *self) { | |
| 2627 | auto casted = reinterpret_cast<const clang::OffsetOfNode *>(self); | |
| 2628 | return (ZigClangOffsetOfNode_Kind)casted->getKind(); | |
| 2629 | } | |
| 2630 | ||
| 2631 | unsigned ZigClangOffsetOfNode_getArrayExprIndex(const struct ZigClangOffsetOfNode *self) { | |
| 2632 | auto casted = reinterpret_cast<const clang::OffsetOfNode *>(self); | |
| 2633 | return casted->getArrayExprIndex(); | |
| 2634 | } | |
| 2635 | ||
| 2636 | struct ZigClangFieldDecl *ZigClangOffsetOfNode_getField(const struct ZigClangOffsetOfNode *self) { | |
| 2637 | auto casted = reinterpret_cast<const clang::OffsetOfNode *>(self); | |
| 2638 | return reinterpret_cast<ZigClangFieldDecl *>(casted->getField()); | |
| 2639 | } | |
| 2640 | ||
| 2641 | unsigned ZigClangOffsetOfExpr_getNumComponents(const struct ZigClangOffsetOfExpr *self) { | |
| 2642 | auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self); | |
| 2643 | return casted->getNumComponents(); | |
| 2644 | } | |
| 2645 | ||
| 2646 | unsigned ZigClangOffsetOfExpr_getNumExpressions(const struct ZigClangOffsetOfExpr *self) { | |
| 2647 | auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self); | |
| 2648 | return casted->getNumExpressions(); | |
| 2649 | } | |
| 2650 | ||
| 2651 | const struct ZigClangExpr *ZigClangOffsetOfExpr_getIndexExpr(const struct ZigClangOffsetOfExpr *self, unsigned idx) { | |
| 2652 | auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self); | |
| 2653 | return reinterpret_cast<const struct ZigClangExpr *>(casted->getIndexExpr(idx)); | |
| 2654 | } | |
| 2655 | ||
| 2656 | const struct ZigClangOffsetOfNode *ZigClangOffsetOfExpr_getComponent(const struct ZigClangOffsetOfExpr *self, unsigned idx) { | |
| 2657 | auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self); | |
| 2658 | return reinterpret_cast<const struct ZigClangOffsetOfNode *>(&casted->getComponent(idx)); | |
| 2659 | } | |
| 2660 | ||
| 2661 | ZigClangSourceLocation ZigClangOffsetOfExpr_getBeginLoc(const ZigClangOffsetOfExpr *self) { | |
| 2662 | auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self); | |
| 2663 | return bitcast(casted->getBeginLoc()); | |
| 2664 | } | |
| 2665 | ||
| 2626 | 2666 | struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *self) { |
| 2627 | 2667 | auto casted = reinterpret_cast<const clang::ElaboratedType *>(self); |
| 2628 | 2668 | return bitcast(casted->getNamedType()); |
| ... | ... | @@ -3022,6 +3062,11 @@ ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldD |
| 3022 | 3062 | return bitcast(casted->getLocation()); |
| 3023 | 3063 | } |
| 3024 | 3064 | |
| 3065 | const struct ZigClangRecordDecl *ZigClangFieldDecl_getParent(const struct ZigClangFieldDecl *self) { | |
| 3066 | auto casted = reinterpret_cast<const clang::FieldDecl *>(self); | |
| 3067 | return reinterpret_cast<const ZigClangRecordDecl *>(casted->getParent()); | |
| 3068 | } | |
| 3069 | ||
| 3025 | 3070 | ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *self) { |
| 3026 | 3071 | auto casted = reinterpret_cast<const clang::FieldDecl *>(self); |
| 3027 | 3072 | return bitcast(casted->getType()); |
src/zig_clang.h+18| ... | ... | @@ -935,6 +935,13 @@ enum ZigClangUnaryExprOrTypeTrait_Kind { |
| 935 | 935 | ZigClangUnaryExprOrTypeTrait_KindPreferredAlignOf, |
| 936 | 936 | }; |
| 937 | 937 | |
| 938 | enum ZigClangOffsetOfNode_Kind { | |
| 939 | ZigClangOffsetOfNode_KindArray, | |
| 940 | ZigClangOffsetOfNode_KindField, | |
| 941 | ZigClangOffsetOfNode_KindIdentifier, | |
| 942 | ZigClangOffsetOfNode_KindBase, | |
| 943 | }; | |
| 944 | ||
| 938 | 945 | ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const struct ZigClangSourceManager *, |
| 939 | 946 | struct ZigClangSourceLocation Loc); |
| 940 | 947 | ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const struct ZigClangSourceManager *, |
| ... | ... | @@ -1168,6 +1175,16 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangTypeOfType_getUnderlyingType(const |
| 1168 | 1175 | |
| 1169 | 1176 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct ZigClangTypeOfExprType *); |
| 1170 | 1177 | |
| 1178 | ZIG_EXTERN_C enum ZigClangOffsetOfNode_Kind ZigClangOffsetOfNode_getKind(const struct ZigClangOffsetOfNode *); | |
| 1179 | ZIG_EXTERN_C unsigned ZigClangOffsetOfNode_getArrayExprIndex(const struct ZigClangOffsetOfNode *); | |
| 1180 | ZIG_EXTERN_C struct ZigClangFieldDecl * ZigClangOffsetOfNode_getField(const struct ZigClangOffsetOfNode *); | |
| 1181 | ||
| 1182 | ZIG_EXTERN_C unsigned ZigClangOffsetOfExpr_getNumComponents(const struct ZigClangOffsetOfExpr *); | |
| 1183 | ZIG_EXTERN_C unsigned ZigClangOffsetOfExpr_getNumExpressions(const struct ZigClangOffsetOfExpr *); | |
| 1184 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangOffsetOfExpr_getIndexExpr(const struct ZigClangOffsetOfExpr *, unsigned idx); | |
| 1185 | ZIG_EXTERN_C const struct ZigClangOffsetOfNode *ZigClangOffsetOfExpr_getComponent(const struct ZigClangOffsetOfExpr *, unsigned idx); | |
| 1186 | ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangOffsetOfExpr_getBeginLoc(const struct ZigClangOffsetOfExpr *); | |
| 1187 | ||
| 1171 | 1188 | ZIG_EXTERN_C struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *); |
| 1172 | 1189 | ZIG_EXTERN_C enum ZigClangElaboratedTypeKeyword ZigClangElaboratedType_getKeyword(const struct ZigClangElaboratedType *); |
| 1173 | 1190 | |
| ... | ... | @@ -1268,6 +1285,7 @@ ZIG_EXTERN_C bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *) |
| 1268 | 1285 | ZIG_EXTERN_C bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *); |
| 1269 | 1286 | ZIG_EXTERN_C struct ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *); |
| 1270 | 1287 | ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldDecl *); |
| 1288 | ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangFieldDecl_getParent(const struct ZigClangFieldDecl *); | |
| 1271 | 1289 | |
| 1272 | 1290 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangEnumConstantDecl_getInitExpr(const struct ZigClangEnumConstantDecl *); |
| 1273 | 1291 | ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangEnumConstantDecl_getInitVal(const struct ZigClangEnumConstantDecl *); |
src/zir_sema.zig+2-2| ... | ... | @@ -1178,7 +1178,6 @@ fn zirErrorValue(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorValue) InnerE |
| 1178 | 1178 | .ty = result_type, |
| 1179 | 1179 | .val = try Value.Tag.@"error".create(scope.arena(), .{ |
| 1180 | 1180 | .name = entry.key, |
| 1181 | .value = entry.value, | |
| 1182 | 1181 | }), |
| 1183 | 1182 | }); |
| 1184 | 1183 | } |
| ... | ... | @@ -2215,7 +2214,8 @@ fn zirCmp( |
| 2215 | 2214 | } |
| 2216 | 2215 | if (rhs.value()) |rval| { |
| 2217 | 2216 | if (lhs.value()) |lval| { |
| 2218 | return mod.constBool(scope, inst.base.src, (lval.castTag(.@"error").?.data.value == rval.castTag(.@"error").?.data.value) == (op == .eq)); | |
| 2217 | // TODO optimisation oppurtunity: evaluate if std.mem.eql is faster with the names, or calling to Module.getErrorValue to get the values and then compare them is faster | |
| 2218 | return mod.constBool(scope, inst.base.src, std.mem.eql(u8, lval.castTag(.@"error").?.data.name, rval.castTag(.@"error").?.data.name) == (op == .eq)); | |
| 2219 | 2219 | } |
| 2220 | 2220 | } |
| 2221 | 2221 | return mod.fail(scope, inst.base.src, "TODO implement equality comparison between runtime errors", .{}); |
test/run_translated_c.zig+56| ... | ... | @@ -1073,4 +1073,60 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { |
| 1073 | 1073 | \\ return 0; |
| 1074 | 1074 | \\} |
| 1075 | 1075 | , ""); |
| 1076 | ||
| 1077 | cases.add("offsetof", | |
| 1078 | \\#include <stddef.h> | |
| 1079 | \\#include <stdlib.h> | |
| 1080 | \\#define container_of(ptr, type, member) ({ \ | |
| 1081 | \\ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ | |
| 1082 | \\ (type *)( (char *)__mptr - offsetof(type,member) );}) | |
| 1083 | \\typedef struct { | |
| 1084 | \\ int i; | |
| 1085 | \\ struct { int x; char y; int z; } s; | |
| 1086 | \\ float f; | |
| 1087 | \\} container; | |
| 1088 | \\int main(void) { | |
| 1089 | \\ if (offsetof(container, i) != 0) abort(); | |
| 1090 | \\ if (offsetof(container, s) <= offsetof(container, i)) abort(); | |
| 1091 | \\ if (offsetof(container, f) <= offsetof(container, s)) abort(); | |
| 1092 | \\ | |
| 1093 | \\ container my_container; | |
| 1094 | \\ typeof(my_container.s) *inner_member_pointer = &my_container.s; | |
| 1095 | \\ float *float_member_pointer = &my_container.f; | |
| 1096 | \\ int *anon_member_pointer = &my_container.s.z; | |
| 1097 | \\ container *my_container_p; | |
| 1098 | \\ | |
| 1099 | \\ my_container_p = container_of(inner_member_pointer, container, s); | |
| 1100 | \\ if (my_container_p != &my_container) abort(); | |
| 1101 | \\ | |
| 1102 | \\ my_container_p = container_of(float_member_pointer, container, f); | |
| 1103 | \\ if (my_container_p != &my_container) abort(); | |
| 1104 | \\ | |
| 1105 | \\ if (container_of(anon_member_pointer, typeof(my_container.s), z) != inner_member_pointer) abort(); | |
| 1106 | \\ return 0; | |
| 1107 | \\} | |
| 1108 | , ""); | |
| 1109 | ||
| 1110 | cases.add("handle assert.h", | |
| 1111 | \\#include <assert.h> | |
| 1112 | \\int main() { | |
| 1113 | \\ int x = 1; | |
| 1114 | \\ int *xp = &x; | |
| 1115 | \\ assert(1); | |
| 1116 | \\ assert(x != 0); | |
| 1117 | \\ assert(xp); | |
| 1118 | \\ assert(*xp); | |
| 1119 | \\ return 0; | |
| 1120 | \\} | |
| 1121 | , ""); | |
| 1122 | ||
| 1123 | cases.add("NDEBUG disables assert", | |
| 1124 | \\#define NDEBUG | |
| 1125 | \\#include <assert.h> | |
| 1126 | \\int main() { | |
| 1127 | \\ assert(0); | |
| 1128 | \\ assert(NULL); | |
| 1129 | \\ return 0; | |
| 1130 | \\} | |
| 1131 | , ""); | |
| 1076 | 1132 | } |
tools/update_glibc.zig+2-2| ... | ... | @@ -200,7 +200,7 @@ pub fn main() !void { |
| 200 | 200 | continue; |
| 201 | 201 | } |
| 202 | 202 | if (std.mem.startsWith(u8, ver, "GCC_")) continue; |
| 203 | _ = try global_ver_set.put(ver, undefined); | |
| 203 | try global_ver_set.put(ver, undefined); | |
| 204 | 204 | const gop = try global_fn_set.getOrPut(name); |
| 205 | 205 | if (gop.found_existing) { |
| 206 | 206 | if (!std.mem.eql(u8, gop.entry.value.lib, "c")) { |
| ... | ... | @@ -242,7 +242,7 @@ pub fn main() !void { |
| 242 | 242 | var buffered = std.io.bufferedWriter(vers_txt_file.writer()); |
| 243 | 243 | const vers_txt = buffered.writer(); |
| 244 | 244 | for (global_ver_list) |name, i| { |
| 245 | _ = global_ver_set.put(name, i) catch unreachable; | |
| 245 | global_ver_set.put(name, i) catch unreachable; | |
| 246 | 246 | try vers_txt.print("{s}\n", .{name}); |
| 247 | 247 | } |
| 248 | 248 | try buffered.flush(); |