| 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,8 +933,8 @@ const assert = std.debug.assert; |
| 933 | threadlocal var x: i32 = 1234; | 933 | threadlocal var x: i32 = 1234; |
| 934 | 934 | ||
| 935 | test "thread local storage" { | 935 | test "thread local storage" { |
| 936 | const thread1 = try std.Thread.spawn({}, testTls); | 936 | const thread1 = try std.Thread.spawn(testTls, {}); |
| 937 | const thread2 = try std.Thread.spawn({}, testTls); | 937 | const thread2 = try std.Thread.spawn(testTls, {}); |
| 938 | testTls({}); | 938 | testTls({}); |
| 939 | thread1.wait(); | 939 | thread1.wait(); |
| 940 | thread2.wait(); | 940 | thread2.wait(); |
lib/std/Thread.zig+20-6| ... | @@ -165,18 +165,32 @@ pub const SpawnError = error{ | ... | @@ -165,18 +165,32 @@ pub const SpawnError = error{ |
| 165 | Unexpected, | 165 | Unexpected, |
| 166 | }; | 166 | }; |
| 167 | 167 | ||
| 168 | /// caller must call wait on the returned thread | 168 | // Given `T`, the type of the thread startFn, extract the expected type for the |
| 169 | /// fn startFn(@TypeOf(context)) T | 169 | // context parameter. |
| 170 | /// where T is u8, noreturn, void, or !void | 170 | fn SpawnContextType(comptime T: type) type { |
| 171 | /// caller must call wait on the returned thread | 171 | const TI = @typeInfo(T); |
| 172 | pub fn spawn(context: anytype, comptime startFn: anytype) SpawnError!*Thread { | 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 | if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode"); | 188 | if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode"); |
| 174 | // TODO compile-time call graph analysis to determine stack upper bound | 189 | // TODO compile-time call graph analysis to determine stack upper bound |
| 175 | // https://github.com/ziglang/zig/issues/157 | 190 | // https://github.com/ziglang/zig/issues/157 |
| 176 | const default_stack_size = 16 * 1024 * 1024; | 191 | const default_stack_size = 16 * 1024 * 1024; |
| 177 | 192 | ||
| 178 | const Context = @TypeOf(context); | 193 | const Context = @TypeOf(context); |
| 179 | comptime assert(@typeInfo(@TypeOf(startFn)).Fn.args[0].arg_type.? == Context); | ||
| 180 | 194 | ||
| 181 | if (std.Target.current.os.tag == .windows) { | 195 | if (std.Target.current.os.tag == .windows) { |
| 182 | const WinThread = struct { | 196 | const WinThread = struct { |
lib/std/Thread/AutoResetEvent.zig+2-2| ... | @@ -220,8 +220,8 @@ test "basic usage" { | ... | @@ -220,8 +220,8 @@ test "basic usage" { |
| 220 | }; | 220 | }; |
| 221 | 221 | ||
| 222 | var context = Context{}; | 222 | var context = Context{}; |
| 223 | const send_thread = try std.Thread.spawn(&context, Context.sender); | 223 | const send_thread = try std.Thread.spawn(Context.sender, &context); |
| 224 | const recv_thread = try std.Thread.spawn(&context, Context.receiver); | 224 | const recv_thread = try std.Thread.spawn(Context.receiver, &context); |
| 225 | 225 | ||
| 226 | send_thread.wait(); | 226 | send_thread.wait(); |
| 227 | recv_thread.wait(); | 227 | recv_thread.wait(); |
lib/std/Thread/Mutex.zig+1-1| ... | @@ -299,7 +299,7 @@ test "basic usage" { | ... | @@ -299,7 +299,7 @@ test "basic usage" { |
| 299 | const thread_count = 10; | 299 | const thread_count = 10; |
| 300 | var threads: [thread_count]*std.Thread = undefined; | 300 | var threads: [thread_count]*std.Thread = undefined; |
| 301 | for (threads) |*t| { | 301 | for (threads) |*t| { |
| 302 | t.* = try std.Thread.spawn(&context, worker); | 302 | t.* = try std.Thread.spawn(worker, &context); |
| 303 | } | 303 | } |
| 304 | for (threads) |t| | 304 | for (threads) |t| |
| 305 | t.wait(); | 305 | t.wait(); |
lib/std/Thread/ResetEvent.zig+2-2| ... | @@ -281,7 +281,7 @@ test "basic usage" { | ... | @@ -281,7 +281,7 @@ test "basic usage" { |
| 281 | var context: Context = undefined; | 281 | var context: Context = undefined; |
| 282 | try context.init(); | 282 | try context.init(); |
| 283 | defer context.deinit(); | 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 | defer receiver.wait(); | 285 | defer receiver.wait(); |
| 286 | context.sender(); | 286 | context.sender(); |
| 287 | 287 | ||
| ... | @@ -290,7 +290,7 @@ test "basic usage" { | ... | @@ -290,7 +290,7 @@ test "basic usage" { |
| 290 | // https://github.com/ziglang/zig/issues/7009 | 290 | // https://github.com/ziglang/zig/issues/7009 |
| 291 | var timed = Context.init(); | 291 | var timed = Context.init(); |
| 292 | defer timed.deinit(); | 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 | defer sleeper.wait(); | 294 | defer sleeper.wait(); |
| 295 | try timed.timedWaiter(); | 295 | try timed.timedWaiter(); |
| 296 | } | 296 | } |
lib/std/Thread/StaticResetEvent.zig+2-2| ... | @@ -379,7 +379,7 @@ test "basic usage" { | ... | @@ -379,7 +379,7 @@ test "basic usage" { |
| 379 | }; | 379 | }; |
| 380 | 380 | ||
| 381 | var context = Context{}; | 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 | defer receiver.wait(); | 383 | defer receiver.wait(); |
| 384 | context.sender(); | 384 | context.sender(); |
| 385 | 385 | ||
| ... | @@ -388,7 +388,7 @@ test "basic usage" { | ... | @@ -388,7 +388,7 @@ test "basic usage" { |
| 388 | // https://github.com/ziglang/zig/issues/7009 | 388 | // https://github.com/ziglang/zig/issues/7009 |
| 389 | var timed = Context.init(); | 389 | var timed = Context.init(); |
| 390 | defer timed.deinit(); | 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 | defer sleeper.wait(); | 392 | defer sleeper.wait(); |
| 393 | try timed.timedWaiter(); | 393 | try timed.timedWaiter(); |
| 394 | } | 394 | } |
lib/std/atomic/queue.zig+2-2| ... | @@ -216,11 +216,11 @@ test "std.atomic.Queue" { | ... | @@ -216,11 +216,11 @@ test "std.atomic.Queue" { |
| 216 | 216 | ||
| 217 | var putters: [put_thread_count]*std.Thread = undefined; | 217 | var putters: [put_thread_count]*std.Thread = undefined; |
| 218 | for (putters) |*t| { | 218 | for (putters) |*t| { |
| 219 | t.* = try std.Thread.spawn(&context, startPuts); | 219 | t.* = try std.Thread.spawn(startPuts, &context); |
| 220 | } | 220 | } |
| 221 | var getters: [put_thread_count]*std.Thread = undefined; | 221 | var getters: [put_thread_count]*std.Thread = undefined; |
| 222 | for (getters) |*t| { | 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 | for (putters) |t| | 226 | for (putters) |t| |
lib/std/atomic/stack.zig+2-2| ... | @@ -123,11 +123,11 @@ test "std.atomic.stack" { | ... | @@ -123,11 +123,11 @@ test "std.atomic.stack" { |
| 123 | } else { | 123 | } else { |
| 124 | var putters: [put_thread_count]*std.Thread = undefined; | 124 | var putters: [put_thread_count]*std.Thread = undefined; |
| 125 | for (putters) |*t| { | 125 | for (putters) |*t| { |
| 126 | t.* = try std.Thread.spawn(&context, startPuts); | 126 | t.* = try std.Thread.spawn(startPuts, &context); |
| 127 | } | 127 | } |
| 128 | var getters: [put_thread_count]*std.Thread = undefined; | 128 | var getters: [put_thread_count]*std.Thread = undefined; |
| 129 | for (getters) |*t| { | 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 | for (putters) |t| | 133 | for (putters) |t| |
lib/std/buf_set.zig+1-1| ... | @@ -32,7 +32,7 @@ pub const BufSet = struct { | ... | @@ -32,7 +32,7 @@ pub const BufSet = struct { |
| 32 | if (self.hash_map.get(key) == null) { | 32 | if (self.hash_map.get(key) == null) { |
| 33 | const key_copy = try self.copy(key); | 33 | const key_copy = try self.copy(key); |
| 34 | errdefer self.free(key_copy); | 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,7 +790,7 @@ pub const Builder = struct { |
| 790 | var list = ArrayList([]const u8).init(self.allocator); | 790 | var list = ArrayList([]const u8).init(self.allocator); |
| 791 | list.append(s) catch unreachable; | 791 | list.append(s) catch unreachable; |
| 792 | list.append(value) catch unreachable; | 792 | list.append(value) catch unreachable; |
| 793 | _ = self.user_input_options.put(name, UserInputOption{ | 793 | self.user_input_options.put(name, UserInputOption{ |
| 794 | .name = name, | 794 | .name = name, |
| 795 | .value = UserValue{ .List = list }, | 795 | .value = UserValue{ .List = list }, |
| 796 | .used = false, | 796 | .used = false, |
| ... | @@ -799,7 +799,7 @@ pub const Builder = struct { | ... | @@ -799,7 +799,7 @@ pub const Builder = struct { |
| 799 | UserValue.List => |*list| { | 799 | UserValue.List => |*list| { |
| 800 | // append to the list | 800 | // append to the list |
| 801 | list.append(value) catch unreachable; | 801 | list.append(value) catch unreachable; |
| 802 | _ = self.user_input_options.put(name, UserInputOption{ | 802 | self.user_input_options.put(name, UserInputOption{ |
| 803 | .name = name, | 803 | .name = name, |
| 804 | .value = UserValue{ .List = list.* }, | 804 | .value = UserValue{ .List = list.* }, |
| 805 | .used = false, | 805 | .used = false, |
lib/std/c/builtins.zig+6| ... | @@ -182,3 +182,9 @@ pub fn __builtin_memcpy( | ... | @@ -182,3 +182,9 @@ pub fn __builtin_memcpy( |
| 182 | @memcpy(dst_cast, src_cast, len); | 182 | @memcpy(dst_cast, src_cast, len); |
| 183 | return dst; | 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,6 +16,11 @@ pub const aead = struct { |
| 16 | pub const Aes256Gcm = @import("crypto/aes_gcm.zig").Aes256Gcm; | 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 | pub const Gimli = @import("crypto/gimli.zig").Aead; | 24 | pub const Gimli = @import("crypto/gimli.zig").Aead; |
| 20 | 25 | ||
| 21 | pub const chacha_poly = struct { | 26 | pub const chacha_poly = struct { |
| ... | @@ -157,30 +162,11 @@ test "crypto" { | ... | @@ -157,30 +162,11 @@ test "crypto" { |
| 157 | } | 162 | } |
| 158 | } | 163 | } |
| 159 | 164 | ||
| 160 | _ = @import("crypto/aes.zig"); | 165 | _ = @import("crypto/aegis.zig"); |
| 161 | _ = @import("crypto/bcrypt.zig"); | 166 | _ = @import("crypto/aes_gcm.zig"); |
| 167 | _ = @import("crypto/aes_ocb.zig"); | ||
| 162 | _ = @import("crypto/blake2.zig"); | 168 | _ = @import("crypto/blake2.zig"); |
| 163 | _ = @import("crypto/blake3.zig"); | ||
| 164 | _ = @import("crypto/chacha20.zig"); | 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 | test "CSPRNG" { | 172 | test "CSPRNG" { |
lib/std/crypto/aes/aesni.zig+2-8| ... | @@ -313,10 +313,7 @@ pub fn AesEncryptCtx(comptime Aes: type) type { | ... | @@ -313,10 +313,7 @@ pub fn AesEncryptCtx(comptime Aes: type) type { |
| 313 | inline while (i < rounds) : (i += 1) { | 313 | inline while (i < rounds) : (i += 1) { |
| 314 | ts = Block.parallel.encryptWide(count, ts, round_keys[i]); | 314 | ts = Block.parallel.encryptWide(count, ts, round_keys[i]); |
| 315 | } | 315 | } |
| 316 | i = 1; | 316 | ts = Block.parallel.encryptLastWide(count, ts, round_keys[i]); |
| 317 | inline while (i < count) : (i += 1) { | ||
| 318 | ts = Block.parallel.encryptLastWide(count, ts, round_keys[i]); | ||
| 319 | } | ||
| 320 | j = 0; | 317 | j = 0; |
| 321 | inline while (j < count) : (j += 1) { | 318 | inline while (j < count) : (j += 1) { |
| 322 | dst[16 * j .. 16 * j + 16].* = ts[j].toBytes(); | 319 | dst[16 * j .. 16 * j + 16].* = ts[j].toBytes(); |
| ... | @@ -392,10 +389,7 @@ pub fn AesDecryptCtx(comptime Aes: type) type { | ... | @@ -392,10 +389,7 @@ pub fn AesDecryptCtx(comptime Aes: type) type { |
| 392 | inline while (i < rounds) : (i += 1) { | 389 | inline while (i < rounds) : (i += 1) { |
| 393 | ts = Block.parallel.decryptWide(count, ts, inv_round_keys[i]); | 390 | ts = Block.parallel.decryptWide(count, ts, inv_round_keys[i]); |
| 394 | } | 391 | } |
| 395 | i = 1; | 392 | ts = Block.parallel.decryptLastWide(count, ts, inv_round_keys[i]); |
| 396 | inline while (i < count) : (i += 1) { | ||
| 397 | ts = Block.parallel.decryptLastWide(count, ts, inv_round_keys[i]); | ||
| 398 | } | ||
| 399 | j = 0; | 393 | j = 0; |
| 400 | inline while (j < count) : (j += 1) { | 394 | inline while (j < count) : (j += 1) { |
| 401 | dst[16 * j .. 16 * j + 16].* = ts[j].toBytes(); | 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,10 +364,7 @@ pub fn AesEncryptCtx(comptime Aes: type) type { |
| 364 | inline while (i < rounds) : (i += 1) { | 364 | inline while (i < rounds) : (i += 1) { |
| 365 | ts = Block.parallel.encryptWide(count, ts, round_keys[i]); | 365 | ts = Block.parallel.encryptWide(count, ts, round_keys[i]); |
| 366 | } | 366 | } |
| 367 | i = 1; | 367 | ts = Block.parallel.encryptLastWide(count, ts, round_keys[i]); |
| 368 | inline while (i < count) : (i += 1) { | ||
| 369 | ts = Block.parallel.encryptLastWide(count, ts, round_keys[i]); | ||
| 370 | } | ||
| 371 | j = 0; | 368 | j = 0; |
| 372 | inline while (j < count) : (j += 1) { | 369 | inline while (j < count) : (j += 1) { |
| 373 | dst[16 * j .. 16 * j + 16].* = ts[j].toBytes(); | 370 | dst[16 * j .. 16 * j + 16].* = ts[j].toBytes(); |
| ... | @@ -443,10 +440,7 @@ pub fn AesDecryptCtx(comptime Aes: type) type { | ... | @@ -443,10 +440,7 @@ pub fn AesDecryptCtx(comptime Aes: type) type { |
| 443 | inline while (i < rounds) : (i += 1) { | 440 | inline while (i < rounds) : (i += 1) { |
| 444 | ts = Block.parallel.decryptWide(count, ts, inv_round_keys[i]); | 441 | ts = Block.parallel.decryptWide(count, ts, inv_round_keys[i]); |
| 445 | } | 442 | } |
| 446 | i = 1; | 443 | ts = Block.parallel.decryptLastWide(count, ts, inv_round_keys[i]); |
| 447 | inline while (i < count) : (i += 1) { | ||
| 448 | ts = Block.parallel.decryptLastWide(count, ts, inv_round_keys[i]); | ||
| 449 | } | ||
| 450 | j = 0; | 444 | j = 0; |
| 451 | inline while (j < count) : (j += 1) { | 445 | inline while (j < count) : (j += 1) { |
| 452 | dst[16 * j .. 16 * j + 16].* = ts[j].toBytes(); | 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,6 +208,8 @@ const aeads = [_]Crypto{ |
| 208 | Crypto{ .ty = crypto.aead.aegis.Aegis256, .name = "aegis-256" }, | 208 | Crypto{ .ty = crypto.aead.aegis.Aegis256, .name = "aegis-256" }, |
| 209 | Crypto{ .ty = crypto.aead.aes_gcm.Aes128Gcm, .name = "aes128-gcm" }, | 209 | Crypto{ .ty = crypto.aead.aes_gcm.Aes128Gcm, .name = "aes128-gcm" }, |
| 210 | Crypto{ .ty = crypto.aead.aes_gcm.Aes256Gcm, .name = "aes256-gcm" }, | 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 | Crypto{ .ty = crypto.aead.isap.IsapA128A, .name = "isapa128a" }, | 213 | Crypto{ .ty = crypto.aead.isap.IsapA128A, .name = "isapa128a" }, |
| 212 | }; | 214 | }; |
| 213 | 215 | ||
| ... | @@ -356,63 +358,63 @@ pub fn main() !void { | ... | @@ -356,63 +358,63 @@ pub fn main() !void { |
| 356 | inline for (hashes) |H| { | 358 | inline for (hashes) |H| { |
| 357 | if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) { | 359 | if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) { |
| 358 | const throughput = try benchmarkHash(H.ty, mode(128 * MiB)); | 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 | inline for (macs) |M| { | 365 | inline for (macs) |M| { |
| 364 | if (filter == null or std.mem.indexOf(u8, M.name, filter.?) != null) { | 366 | if (filter == null or std.mem.indexOf(u8, M.name, filter.?) != null) { |
| 365 | const throughput = try benchmarkMac(M.ty, mode(128 * MiB)); | 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 | inline for (exchanges) |E| { | 372 | inline for (exchanges) |E| { |
| 371 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { | 373 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| 372 | const throughput = try benchmarkKeyExchange(E.ty, mode(1000)); | 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 | inline for (signatures) |E| { | 379 | inline for (signatures) |E| { |
| 378 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { | 380 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| 379 | const throughput = try benchmarkSignature(E.ty, mode(1000)); | 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 | inline for (signature_verifications) |E| { | 386 | inline for (signature_verifications) |E| { |
| 385 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { | 387 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| 386 | const throughput = try benchmarkSignatureVerification(E.ty, mode(1000)); | 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 | inline for (batch_signature_verifications) |E| { | 393 | inline for (batch_signature_verifications) |E| { |
| 392 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { | 394 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| 393 | const throughput = try benchmarkBatchSignatureVerification(E.ty, mode(1000)); | 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 | inline for (aeads) |E| { | 400 | inline for (aeads) |E| { |
| 399 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { | 401 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| 400 | const throughput = try benchmarkAead(E.ty, mode(128 * MiB)); | 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 | inline for (aes) |E| { | 407 | inline for (aes) |E| { |
| 406 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { | 408 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| 407 | const throughput = try benchmarkAes(E.ty, mode(100000000)); | 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 | inline for (aes8) |E| { | 414 | inline for (aes8) |E| { |
| 413 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { | 415 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { |
| 414 | const throughput = try benchmarkAes8(E.ty, mode(10000000)); | 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,7 +185,7 @@ pub const Loop = struct { |
| 185 | errdefer self.deinitOsData(); | 185 | errdefer self.deinitOsData(); |
| 186 | 186 | ||
| 187 | if (!builtin.single_threaded) { | 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 | errdefer if (!builtin.single_threaded) { | 190 | errdefer if (!builtin.single_threaded) { |
| 191 | self.posixFsRequest(&self.fs_end_request); | 191 | self.posixFsRequest(&self.fs_end_request); |
| ... | @@ -264,7 +264,7 @@ pub const Loop = struct { | ... | @@ -264,7 +264,7 @@ pub const Loop = struct { |
| 264 | } | 264 | } |
| 265 | } | 265 | } |
| 266 | while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) { | 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 | .macos, .freebsd, .netbsd, .dragonfly, .openbsd => { | 270 | .macos, .freebsd, .netbsd, .dragonfly, .openbsd => { |
| ... | @@ -329,7 +329,7 @@ pub const Loop = struct { | ... | @@ -329,7 +329,7 @@ pub const Loop = struct { |
| 329 | } | 329 | } |
| 330 | } | 330 | } |
| 331 | while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) { | 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 | .windows => { | 335 | .windows => { |
| ... | @@ -378,7 +378,7 @@ pub const Loop = struct { | ... | @@ -378,7 +378,7 @@ pub const Loop = struct { |
| 378 | } | 378 | } |
| 379 | } | 379 | } |
| 380 | while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) { | 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 | else => {}, | 384 | else => {}, |
| ... | @@ -798,7 +798,7 @@ pub const Loop = struct { | ... | @@ -798,7 +798,7 @@ pub const Loop = struct { |
| 798 | .event = std.Thread.AutoResetEvent{}, | 798 | .event = std.Thread.AutoResetEvent{}, |
| 799 | .is_running = true, | 799 | .is_running = true, |
| 800 | // Must be last so that it can read the other state, such as `is_running`. | 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,8 +39,8 @@ pub fn isSep(byte: u8) bool { |
| 39 | 39 | ||
| 40 | /// This is different from mem.join in that the separator will not be repeated if | 40 | /// This is different from mem.join in that the separator will not be repeated if |
| 41 | /// it is found at the end or beginning of a pair of consecutive paths. | 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 { | 42 | fn joinSepMaybeZ(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, paths: []const []const u8, zero: bool) ![]u8 { |
| 43 | if (paths.len == 0) return &[0]u8{}; | 43 | if (paths.len == 0) return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{}; |
| 44 | 44 | ||
| 45 | const total_len = blk: { | 45 | const total_len = blk: { |
| 46 | var sum: usize = paths[0].len; | 46 | var sum: usize = paths[0].len; |
| ... | @@ -53,6 +53,7 @@ fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, pat | ... | @@ -53,6 +53,7 @@ fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, pat |
| 53 | sum += @boolToInt(!prev_sep and !this_sep); | 53 | sum += @boolToInt(!prev_sep and !this_sep); |
| 54 | sum += if (prev_sep and this_sep) this_path.len - 1 else this_path.len; | 54 | sum += if (prev_sep and this_sep) this_path.len - 1 else this_path.len; |
| 55 | } | 55 | } |
| 56 | if (zero) sum += 1; | ||
| 56 | break :blk sum; | 57 | break :blk sum; |
| 57 | }; | 58 | }; |
| 58 | 59 | ||
| ... | @@ -76,6 +77,8 @@ fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, pat | ... | @@ -76,6 +77,8 @@ fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, pat |
| 76 | buf_index += adjusted_path.len; | 77 | buf_index += adjusted_path.len; |
| 77 | } | 78 | } |
| 78 | 79 | ||
| 80 | if (zero) buf[buf.len - 1] = 0; | ||
| 81 | |||
| 79 | // No need for shrink since buf is exactly the correct size. | 82 | // No need for shrink since buf is exactly the correct size. |
| 80 | return buf; | 83 | return buf; |
| 81 | } | 84 | } |
| ... | @@ -83,60 +86,73 @@ fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, pat | ... | @@ -83,60 +86,73 @@ fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, pat |
| 83 | /// Naively combines a series of paths with the native path seperator. | 86 | /// Naively combines a series of paths with the native path seperator. |
| 84 | /// Allocates memory for the result, which must be freed by the caller. | 87 | /// Allocates memory for the result, which must be freed by the caller. |
| 85 | pub fn join(allocator: *Allocator, paths: []const []const u8) ![]u8 { | 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 | const windowsIsSep = struct { | 100 | const windowsIsSep = struct { |
| 91 | fn isSep(byte: u8) bool { | 101 | fn isSep(byte: u8) bool { |
| 92 | return byte == '/' or byte == '\\'; | 102 | return byte == '/' or byte == '\\'; |
| 93 | } | 103 | } |
| 94 | }.isSep; | 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 | defer testing.allocator.free(actual); | 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 | const posixIsSep = struct { | 111 | const posixIsSep = struct { |
| 102 | fn isSep(byte: u8) bool { | 112 | fn isSep(byte: u8) bool { |
| 103 | return byte == '/'; | 113 | return byte == '/'; |
| 104 | } | 114 | } |
| 105 | }.isSep; | 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 | defer testing.allocator.free(actual); | 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 | test "join" { | 121 | test "join" { |
| 112 | testJoinWindows(&[_][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c"); | 122 | for (&[_]bool{ false, true }) |zero| { |
| 113 | testJoinWindows(&[_][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c"); | 123 | testJoinMaybeZWindows(&[_][]const u8{}, "", zero); |
| 114 | testJoinWindows(&[_][]const u8{ "c:\\a\\b\\", "c" }, "c:\\a\\b\\c"); | 124 | testJoinMaybeZWindows(&[_][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c", zero); |
| 115 | 125 | testJoinMaybeZWindows(&[_][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c", zero); | |
| 116 | testJoinWindows(&[_][]const u8{ "c:\\", "a", "b\\", "c" }, "c:\\a\\b\\c"); | 126 | testJoinMaybeZWindows(&[_][]const u8{ "c:\\a\\b\\", "c" }, "c:\\a\\b\\c", zero); |
| 117 | testJoinWindows(&[_][]const u8{ "c:\\a\\", "b\\", "c" }, "c:\\a\\b\\c"); | 127 | |
| 118 | 128 | testJoinMaybeZWindows(&[_][]const u8{ "c:\\", "a", "b\\", "c" }, "c:\\a\\b\\c", zero); | |
| 119 | testJoinWindows( | 129 | testJoinMaybeZWindows(&[_][]const u8{ "c:\\a\\", "b\\", "c" }, "c:\\a\\b\\c", zero); |
| 120 | &[_][]const u8{ "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std", "io.zig" }, | 130 | |
| 121 | "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig", | 131 | testJoinMaybeZWindows( |
| 122 | ); | 132 | &[_][]const u8{ "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std", "io.zig" }, |
| 123 | 133 | "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig", | |
| 124 | testJoinWindows(&[_][]const u8{ "c:\\", "a", "b/", "c" }, "c:\\a\\b/c"); | 134 | zero, |
| 125 | testJoinWindows(&[_][]const u8{ "c:\\a/", "b\\", "/c" }, "c:\\a/b\\c"); | 135 | ); |
| 126 | 136 | ||
| 127 | testJoinPosix(&[_][]const u8{ "/a/b", "c" }, "/a/b/c"); | 137 | testJoinMaybeZWindows(&[_][]const u8{ "c:\\", "a", "b/", "c" }, "c:\\a\\b/c", zero); |
| 128 | testJoinPosix(&[_][]const u8{ "/a/b/", "c" }, "/a/b/c"); | 138 | testJoinMaybeZWindows(&[_][]const u8{ "c:\\a/", "b\\", "/c" }, "c:\\a/b\\c", zero); |
| 129 | 139 | ||
| 130 | testJoinPosix(&[_][]const u8{ "/", "a", "b/", "c" }, "/a/b/c"); | 140 | testJoinMaybeZPosix(&[_][]const u8{}, "", zero); |
| 131 | testJoinPosix(&[_][]const u8{ "/a/", "b/", "c" }, "/a/b/c"); | 141 | testJoinMaybeZPosix(&[_][]const u8{ "/a/b", "c" }, "/a/b/c", zero); |
| 132 | 142 | testJoinMaybeZPosix(&[_][]const u8{ "/a/b/", "c" }, "/a/b/c", zero); | |
| 133 | testJoinPosix( | 143 | |
| 134 | &[_][]const u8{ "/home/andy/dev/zig/build/lib/zig/std", "io.zig" }, | 144 | testJoinMaybeZPosix(&[_][]const u8{ "/", "a", "b/", "c" }, "/a/b/c", zero); |
| 135 | "/home/andy/dev/zig/build/lib/zig/std/io.zig", | 145 | testJoinMaybeZPosix(&[_][]const u8{ "/a/", "b/", "c" }, "/a/b/c", zero); |
| 136 | ); | 146 | |
| 137 | 147 | testJoinMaybeZPosix( | |
| 138 | testJoinPosix(&[_][]const u8{ "a", "/c" }, "a/c"); | 148 | &[_][]const u8{ "/home/andy/dev/zig/build/lib/zig/std", "io.zig" }, |
| 139 | testJoinPosix(&[_][]const u8{ "a/", "/c" }, "a/c"); | 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 | pub const isAbsoluteC = @compileError("deprecated: renamed to isAbsoluteZ"); | 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,7 +1226,7 @@ fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []cons |
| 1210 | /// pointer address range of `path`, even if it is length zero. | 1226 | /// pointer address range of `path`, even if it is length zero. |
| 1211 | pub fn extension(path: []const u8) []const u8 { | 1227 | pub fn extension(path: []const u8) []const u8 { |
| 1212 | const filename = basename(path); | 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 | if (index == 0) return path[path.len..]; | 1230 | if (index == 0) return path[path.len..]; |
| 1215 | return filename[index..]; | 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,7 +762,7 @@ test "open file with exclusive lock twice, make sure it waits" { |
| 762 | try evt.init(); | 762 | try evt.init(); |
| 763 | defer evt.deinit(); | 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 | defer t.wait(); | 766 | defer t.wait(); |
| 767 | 767 | ||
| 768 | const SLEEP_TIMEOUT_NS = 10 * std.time.ns_per_ms; | 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,7 +563,6 @@ pub fn HashMapUnmanaged( |
| 563 | } | 563 | } |
| 564 | 564 | ||
| 565 | /// Insert an entry if the associated key is not already present, otherwise update preexisting value. | 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 | pub fn put(self: *Self, allocator: *Allocator, key: K, value: V) !void { | 566 | pub fn put(self: *Self, allocator: *Allocator, key: K, value: V) !void { |
| 568 | const result = try self.getOrPut(allocator, key); | 567 | const result = try self.getOrPut(allocator, key); |
| 569 | result.entry.value = value; | 568 | result.entry.value = value; |
| ... | @@ -1116,7 +1115,7 @@ test "std.hash_map put" { | ... | @@ -1116,7 +1115,7 @@ test "std.hash_map put" { |
| 1116 | 1115 | ||
| 1117 | var i: u32 = 0; | 1116 | var i: u32 = 0; |
| 1118 | while (i < 16) : (i += 1) { | 1117 | while (i < 16) : (i += 1) { |
| 1119 | _ = try map.put(i, i); | 1118 | try map.put(i, i); |
| 1120 | } | 1119 | } |
| 1121 | 1120 | ||
| 1122 | i = 0; | 1121 | i = 0; |
lib/std/json.zig+6-6| ... | @@ -2077,27 +2077,27 @@ pub const Parser = struct { | ... | @@ -2077,27 +2077,27 @@ pub const Parser = struct { |
| 2077 | p.state = .ArrayValue; | 2077 | p.state = .ArrayValue; |
| 2078 | }, | 2078 | }, |
| 2079 | .String => |s| { | 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 | _ = p.stack.pop(); | 2081 | _ = p.stack.pop(); |
| 2082 | p.state = .ObjectKey; | 2082 | p.state = .ObjectKey; |
| 2083 | }, | 2083 | }, |
| 2084 | .Number => |n| { | 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 | _ = p.stack.pop(); | 2086 | _ = p.stack.pop(); |
| 2087 | p.state = .ObjectKey; | 2087 | p.state = .ObjectKey; |
| 2088 | }, | 2088 | }, |
| 2089 | .True => { | 2089 | .True => { |
| 2090 | _ = try object.put(key, Value{ .Bool = true }); | 2090 | try object.put(key, Value{ .Bool = true }); |
| 2091 | _ = p.stack.pop(); | 2091 | _ = p.stack.pop(); |
| 2092 | p.state = .ObjectKey; | 2092 | p.state = .ObjectKey; |
| 2093 | }, | 2093 | }, |
| 2094 | .False => { | 2094 | .False => { |
| 2095 | _ = try object.put(key, Value{ .Bool = false }); | 2095 | try object.put(key, Value{ .Bool = false }); |
| 2096 | _ = p.stack.pop(); | 2096 | _ = p.stack.pop(); |
| 2097 | p.state = .ObjectKey; | 2097 | p.state = .ObjectKey; |
| 2098 | }, | 2098 | }, |
| 2099 | .Null => { | 2099 | .Null => { |
| 2100 | _ = try object.put(key, Value.Null); | 2100 | try object.put(key, Value.Null); |
| 2101 | _ = p.stack.pop(); | 2101 | _ = p.stack.pop(); |
| 2102 | p.state = .ObjectKey; | 2102 | p.state = .ObjectKey; |
| 2103 | }, | 2103 | }, |
| ... | @@ -2184,7 +2184,7 @@ pub const Parser = struct { | ... | @@ -2184,7 +2184,7 @@ pub const Parser = struct { |
| 2184 | _ = p.stack.pop(); | 2184 | _ = p.stack.pop(); |
| 2185 | 2185 | ||
| 2186 | var object = &p.stack.items[p.stack.items.len - 1].Object; | 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 | p.state = .ObjectKey; | 2188 | p.state = .ObjectKey; |
| 2189 | }, | 2189 | }, |
| 2190 | // Array Parent -> [ ..., <array>, value ] | 2190 | // Array Parent -> [ ..., <array>, value ] |
lib/std/json/write_stream.zig+2-2| ... | @@ -293,7 +293,7 @@ test "json write stream" { | ... | @@ -293,7 +293,7 @@ test "json write stream" { |
| 293 | 293 | ||
| 294 | fn getJsonObject(allocator: *std.mem.Allocator) !std.json.Value { | 294 | fn getJsonObject(allocator: *std.mem.Allocator) !std.json.Value { |
| 295 | var value = std.json.Value{ .Object = std.json.ObjectMap.init(allocator) }; | 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) }); | 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 }); | 297 | try value.Object.put("two", std.json.Value{ .Float = 2.0 }); |
| 298 | return value; | 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,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 | defer t.wait(); | 165 | defer t.wait(); |
| 166 | 166 | ||
| 167 | var client = try server.accept(); | 167 | var client = try server.accept(); |
| ... | @@ -285,7 +285,7 @@ test "listen on a unix socket, send bytes, receive bytes" { | ... | @@ -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 | defer t.wait(); | 289 | defer t.wait(); |
| 290 | 290 | ||
| 291 | var client = try server.accept(); | 291 | var client = try server.accept(); |
lib/std/once.zig+2-2| ... | @@ -59,11 +59,11 @@ test "Once executes its function just once" { | ... | @@ -59,11 +59,11 @@ test "Once executes its function just once" { |
| 59 | defer for (threads) |handle| handle.wait(); | 59 | defer for (threads) |handle| handle.wait(); |
| 60 | 60 | ||
| 61 | for (threads) |*handle| { | 61 | for (threads) |*handle| { |
| 62 | handle.* = try std.Thread.spawn(@as(u8, 0), struct { | 62 | handle.* = try std.Thread.spawn(struct { |
| 63 | fn thread_fn(x: u8) void { | 63 | fn thread_fn(x: u8) void { |
| 64 | global_once.call(); | 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,7 +4840,7 @@ pub const SendError = error{ |
| 4840 | NetworkSubsystemFailed, | 4840 | NetworkSubsystemFailed, |
| 4841 | } || UnexpectedError; | 4841 | } || UnexpectedError; |
| 4842 | 4842 | ||
| 4843 | pub const SendToError = SendError || error{ | 4843 | pub const SendMsgError = SendError || error{ |
| 4844 | /// The passed address didn't have the correct address family in its sa_family field. | 4844 | /// The passed address didn't have the correct address family in its sa_family field. |
| 4845 | AddressFamilyNotSupported, | 4845 | AddressFamilyNotSupported, |
| 4846 | 4846 | ||
| ... | @@ -4859,6 +4859,79 @@ pub const SendToError = SendError || error{ | ... | @@ -4859,6 +4859,79 @@ pub const SendToError = SendError || error{ |
| 4859 | AddressNotAvailable, | 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 | /// Transmit a message to another socket. | 4935 | /// Transmit a message to another socket. |
| 4863 | /// | 4936 | /// |
| 4864 | /// The `sendto` call may be used only when the socket is in a connected state (so that the intended | 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,10 +400,10 @@ pub const msghdr = extern struct { |
| 400 | msg_namelen: socklen_t, | 400 | msg_namelen: socklen_t, |
| 401 | msg_iov: [*]iovec, | 401 | msg_iov: [*]iovec, |
| 402 | msg_iovlen: i32, | 402 | msg_iovlen: i32, |
| 403 | __pad1: i32, | 403 | __pad1: i32 = 0, |
| 404 | msg_control: ?*c_void, | 404 | msg_control: ?*c_void, |
| 405 | msg_controllen: socklen_t, | 405 | msg_controllen: socklen_t, |
| 406 | __pad2: socklen_t, | 406 | __pad2: socklen_t = 0, |
| 407 | msg_flags: i32, | 407 | msg_flags: i32, |
| 408 | }; | 408 | }; |
| 409 | 409 | ||
| ... | @@ -412,10 +412,10 @@ pub const msghdr_const = extern struct { | ... | @@ -412,10 +412,10 @@ pub const msghdr_const = extern struct { |
| 412 | msg_namelen: socklen_t, | 412 | msg_namelen: socklen_t, |
| 413 | msg_iov: [*]iovec_const, | 413 | msg_iov: [*]iovec_const, |
| 414 | msg_iovlen: i32, | 414 | msg_iovlen: i32, |
| 415 | __pad1: i32, | 415 | __pad1: i32 = 0, |
| 416 | msg_control: ?*c_void, | 416 | msg_control: ?*c_void, |
| 417 | msg_controllen: socklen_t, | 417 | msg_controllen: socklen_t, |
| 418 | __pad2: socklen_t, | 418 | __pad2: socklen_t = 0, |
| 419 | msg_flags: i32, | 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,10 +495,10 @@ pub const msghdr = extern struct { |
| 495 | msg_namelen: socklen_t, | 495 | msg_namelen: socklen_t, |
| 496 | msg_iov: [*]iovec, | 496 | msg_iov: [*]iovec, |
| 497 | msg_iovlen: i32, | 497 | msg_iovlen: i32, |
| 498 | __pad1: i32, | 498 | __pad1: i32 = 0, |
| 499 | msg_control: ?*c_void, | 499 | msg_control: ?*c_void, |
| 500 | msg_controllen: socklen_t, | 500 | msg_controllen: socklen_t, |
| 501 | __pad2: socklen_t, | 501 | __pad2: socklen_t = 0, |
| 502 | msg_flags: i32, | 502 | msg_flags: i32, |
| 503 | }; | 503 | }; |
| 504 | 504 | ||
| ... | @@ -507,10 +507,10 @@ pub const msghdr_const = extern struct { | ... | @@ -507,10 +507,10 @@ pub const msghdr_const = extern struct { |
| 507 | msg_namelen: socklen_t, | 507 | msg_namelen: socklen_t, |
| 508 | msg_iov: [*]iovec_const, | 508 | msg_iov: [*]iovec_const, |
| 509 | msg_iovlen: i32, | 509 | msg_iovlen: i32, |
| 510 | __pad1: i32, | 510 | __pad1: i32 = 0, |
| 511 | msg_control: ?*c_void, | 511 | msg_control: ?*c_void, |
| 512 | msg_controllen: socklen_t, | 512 | msg_controllen: socklen_t, |
| 513 | __pad2: socklen_t, | 513 | __pad2: socklen_t = 0, |
| 514 | msg_flags: i32, | 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,7 +977,7 @@ pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noal |
| 977 | return syscall5(.getsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen)); | 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 | if (builtin.arch == .i386) { | 981 | if (builtin.arch == .i386) { |
| 982 | return socketcall(SC_sendmsg, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags }); | 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,7 +317,7 @@ test "std.Thread.getCurrentId" { |
| 317 | if (builtin.single_threaded) return error.SkipZigTest; | 317 | if (builtin.single_threaded) return error.SkipZigTest; |
| 318 | 318 | ||
| 319 | var thread_current_id: Thread.Id = undefined; | 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 | const thread_id = thread.handle(); | 321 | const thread_id = thread.handle(); |
| 322 | thread.wait(); | 322 | thread.wait(); |
| 323 | if (Thread.use_pthreads) { | 323 | if (Thread.use_pthreads) { |
| ... | @@ -336,10 +336,10 @@ test "spawn threads" { | ... | @@ -336,10 +336,10 @@ test "spawn threads" { |
| 336 | 336 | ||
| 337 | var shared_ctx: i32 = 1; | 337 | var shared_ctx: i32 = 1; |
| 338 | 338 | ||
| 339 | const thread1 = try Thread.spawn({}, start1); | 339 | const thread1 = try Thread.spawn(start1, {}); |
| 340 | const thread2 = try Thread.spawn(&shared_ctx, start2); | 340 | const thread2 = try Thread.spawn(start2, &shared_ctx); |
| 341 | const thread3 = try Thread.spawn(&shared_ctx, start2); | 341 | const thread3 = try Thread.spawn(start2, &shared_ctx); |
| 342 | const thread4 = try Thread.spawn(&shared_ctx, start2); | 342 | const thread4 = try Thread.spawn(start2, &shared_ctx); |
| 343 | 343 | ||
| 344 | thread1.wait(); | 344 | thread1.wait(); |
| 345 | thread2.wait(); | 345 | thread2.wait(); |
| ... | @@ -367,8 +367,8 @@ test "cpu count" { | ... | @@ -367,8 +367,8 @@ test "cpu count" { |
| 367 | 367 | ||
| 368 | test "thread local storage" { | 368 | test "thread local storage" { |
| 369 | if (builtin.single_threaded) return error.SkipZigTest; | 369 | if (builtin.single_threaded) return error.SkipZigTest; |
| 370 | const thread1 = try Thread.spawn({}, testTls); | 370 | const thread1 = try Thread.spawn(testTls, {}); |
| 371 | const thread2 = try Thread.spawn({}, testTls); | 371 | const thread2 = try Thread.spawn(testTls, {}); |
| 372 | testTls({}); | 372 | testTls({}); |
| 373 | thread1.wait(); | 373 | thread1.wait(); |
| 374 | thread2.wait(); | 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,6 +1291,19 @@ pub fn getsockname(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.so |
| 1291 | return ws2_32.getsockname(s, name, @ptrCast(*i32, namelen)); | 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 | 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 { | 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 | var buffer = ws2_32.WSABUF{ .len = @truncate(u31, len), .buf = @intToPtr([*]u8, @ptrToInt(buf)) }; | 1308 | var buffer = ws2_32.WSABUF{ .len = @truncate(u31, len), .buf = @intToPtr([*]u8, @ptrToInt(buf)) }; |
| 1296 | var bytes_send: DWORD = undefined; | 1309 | var bytes_send: DWORD = undefined; |
lib/std/priority_queue.zig+1-1| ... | @@ -410,7 +410,7 @@ test "std.PriorityQueue: iterator" { | ... | @@ -410,7 +410,7 @@ test "std.PriorityQueue: iterator" { |
| 410 | const items = [_]u32{ 54, 12, 7, 23, 25, 13 }; | 410 | const items = [_]u32{ 54, 12, 7, 23, 25, 13 }; |
| 411 | for (items) |e| { | 411 | for (items) |e| { |
| 412 | _ = try queue.add(e); | 412 | _ = try queue.add(e); |
| 413 | _ = try map.put(e, {}); | 413 | try map.put(e, {}); |
| 414 | } | 414 | } |
| 415 | 415 | ||
| 416 | var it = queue.iterator(); | 416 | var it = queue.iterator(); |
src/Module.zig-1| ... | @@ -4101,7 +4101,6 @@ pub fn namedFieldPtr( | ... | @@ -4101,7 +4101,6 @@ pub fn namedFieldPtr( |
| 4101 | scope.arena(), | 4101 | scope.arena(), |
| 4102 | try Value.Tag.@"error".create(scope.arena(), .{ | 4102 | try Value.Tag.@"error".create(scope.arena(), .{ |
| 4103 | .name = entry.key, | 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,7 +74,7 @@ pub fn init(self: *ThreadPool, allocator: *std.mem.Allocator) !void { |
| 74 | try worker.idle_node.data.init(); | 74 | try worker.idle_node.data.init(); |
| 75 | errdefer worker.idle_node.data.deinit(); | 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,6 +432,9 @@ pub const FieldDecl = opaque { |
| 432 | 432 | ||
| 433 | pub const getLocation = ZigClangFieldDecl_getLocation; | 433 | pub const getLocation = ZigClangFieldDecl_getLocation; |
| 434 | extern fn ZigClangFieldDecl_getLocation(*const FieldDecl) SourceLocation; | 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 | pub const FileID = opaque {}; | 440 | pub const FileID = opaque {}; |
| ... | @@ -593,6 +596,34 @@ pub const TypeOfExprType = opaque { | ... | @@ -593,6 +596,34 @@ pub const TypeOfExprType = opaque { |
| 593 | extern fn ZigClangTypeOfExprType_getUnderlyingExpr(*const TypeOfExprType) *const Expr; | 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 | pub const MemberExpr = opaque { | 627 | pub const MemberExpr = opaque { |
| 597 | pub const getBase = ZigClangMemberExpr_getBase; | 628 | pub const getBase = ZigClangMemberExpr_getBase; |
| 598 | extern fn ZigClangMemberExpr_getBase(*const MemberExpr) *const Expr; | 629 | extern fn ZigClangMemberExpr_getBase(*const MemberExpr) *const Expr; |
| ... | @@ -1662,6 +1693,13 @@ pub const UnaryExprOrTypeTrait_Kind = extern enum { | ... | @@ -1662,6 +1693,13 @@ pub const UnaryExprOrTypeTrait_Kind = extern enum { |
| 1662 | PreferredAlignOf, | 1693 | PreferredAlignOf, |
| 1663 | }; | 1694 | }; |
| 1664 | 1695 | ||
| 1696 | pub const OffsetOfNode_Kind = extern enum { | ||
| 1697 | Array, | ||
| 1698 | Field, | ||
| 1699 | Identifier, | ||
| 1700 | Base, | ||
| 1701 | }; | ||
| 1702 | |||
| 1665 | pub const Stage2ErrorMsg = extern struct { | 1703 | pub const Stage2ErrorMsg = extern struct { |
| 1666 | filename_ptr: ?[*]const u8, | 1704 | filename_ptr: ?[*]const u8, |
| 1667 | filename_len: usize, | 1705 | filename_len: usize, |
src/link/Elf.zig+3-3| ... | @@ -2165,7 +2165,7 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void { | ... | @@ -2165,7 +2165,7 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void { |
| 2165 | // is desired for both. | 2165 | // is desired for both. |
| 2166 | _ = self.dbg_line_fn_free_list.remove(&decl.fn_link.elf); | 2166 | _ = self.dbg_line_fn_free_list.remove(&decl.fn_link.elf); |
| 2167 | if (decl.fn_link.elf.prev) |prev| { | 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 | prev.next = decl.fn_link.elf.next; | 2169 | prev.next = decl.fn_link.elf.next; |
| 2170 | if (decl.fn_link.elf.next) |next| { | 2170 | if (decl.fn_link.elf.next) |next| { |
| 2171 | next.prev = prev; | 2171 | next.prev = prev; |
| ... | @@ -2423,7 +2423,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { | ... | @@ -2423,7 +2423,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { |
| 2423 | if (src_fn.off + src_fn.len + min_nop_size > next.off) { | 2423 | if (src_fn.off + src_fn.len + min_nop_size > next.off) { |
| 2424 | // It grew too big, so we move it to a new location. | 2424 | // It grew too big, so we move it to a new location. |
| 2425 | if (src_fn.prev) |prev| { | 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 | prev.next = src_fn.next; | 2427 | prev.next = src_fn.next; |
| 2428 | } | 2428 | } |
| 2429 | assert(src_fn.prev != next); | 2429 | assert(src_fn.prev != next); |
| ... | @@ -2579,7 +2579,7 @@ fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) ! | ... | @@ -2579,7 +2579,7 @@ fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) ! |
| 2579 | if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) { | 2579 | if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) { |
| 2580 | // It grew too big, so we move it to a new location. | 2580 | // It grew too big, so we move it to a new location. |
| 2581 | if (text_block.dbg_info_prev) |prev| { | 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 | prev.dbg_info_next = text_block.dbg_info_next; | 2583 | prev.dbg_info_next = text_block.dbg_info_next; |
| 2584 | } | 2584 | } |
| 2585 | next.dbg_info_prev = text_block.dbg_info_prev; | 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,7 +1096,7 @@ pub fn commitDeclDebugInfo( |
| 1096 | if (src_fn.off + src_fn.len + min_nop_size > next.off) { | 1096 | if (src_fn.off + src_fn.len + min_nop_size > next.off) { |
| 1097 | // It grew too big, so we move it to a new location. | 1097 | // It grew too big, so we move it to a new location. |
| 1098 | if (src_fn.prev) |prev| { | 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 | prev.next = src_fn.next; | 1100 | prev.next = src_fn.next; |
| 1101 | } | 1101 | } |
| 1102 | next.prev = src_fn.prev; | 1102 | next.prev = src_fn.prev; |
| ... | @@ -1256,7 +1256,7 @@ fn updateDeclDebugInfoAllocation( | ... | @@ -1256,7 +1256,7 @@ fn updateDeclDebugInfoAllocation( |
| 1256 | if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) { | 1256 | if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) { |
| 1257 | // It grew too big, so we move it to a new location. | 1257 | // It grew too big, so we move it to a new location. |
| 1258 | if (text_block.dbg_info_prev) |prev| { | 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 | prev.dbg_info_next = text_block.dbg_info_next; | 1260 | prev.dbg_info_next = text_block.dbg_info_next; |
| 1261 | } | 1261 | } |
| 1262 | next.dbg_info_prev = text_block.dbg_info_prev; | 1262 | next.dbg_info_prev = text_block.dbg_info_prev; |
src/liveness.zig+2-2| ... | @@ -119,7 +119,7 @@ fn analyzeInst( | ... | @@ -119,7 +119,7 @@ fn analyzeInst( |
| 119 | if (!else_table.contains(then_death)) { | 119 | if (!else_table.contains(then_death)) { |
| 120 | try else_entry_deaths.append(then_death); | 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 | // Now we have to correctly populate new_set. | 125 | // Now we have to correctly populate new_set. |
| ... | @@ -195,7 +195,7 @@ fn analyzeInst( | ... | @@ -195,7 +195,7 @@ fn analyzeInst( |
| 195 | } | 195 | } |
| 196 | } | 196 | } |
| 197 | // undo resetting the table | 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,7 +377,7 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void { |
| 377 | const macro = @ptrCast(*clang.MacroDefinitionRecord, entity); | 377 | const macro = @ptrCast(*clang.MacroDefinitionRecord, entity); |
| 378 | const raw_name = macro.getName_getNameStart(); | 378 | const raw_name = macro.getName_getNameStart(); |
| 379 | const name = try c.str(raw_name); | 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 | else => {}, | 382 | else => {}, |
| 383 | } | 383 | } |
| ... | @@ -399,7 +399,7 @@ fn declVisitorC(context: ?*c_void, decl: *const clang.Decl) callconv(.C) bool { | ... | @@ -399,7 +399,7 @@ fn declVisitorC(context: ?*c_void, decl: *const clang.Decl) callconv(.C) bool { |
| 399 | fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void { | 399 | fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void { |
| 400 | if (decl.castToNamedDecl()) |named_decl| { | 400 | if (decl.castToNamedDecl()) |named_decl| { |
| 401 | const decl_name = try c.str(named_decl.getName_bytes_begin()); | 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,7 +788,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD |
| 788 | const is_pub = toplevel and !is_unnamed; | 788 | const is_pub = toplevel and !is_unnamed; |
| 789 | const init_node = blk: { | 789 | const init_node = blk: { |
| 790 | const record_def = record_decl.getDefinition() orelse { | 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 | break :blk Tag.opaque_literal.init(); | 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,13 +805,13 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD |
| 805 | const field_qt = field_decl.getType(); | 805 | const field_qt = field_decl.getType(); |
| 806 | 806 | ||
| 807 | if (field_decl.isBitField()) { | 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 | try warn(c, scope, field_loc, "{s} demoted to opaque type - has bitfield", .{container_kind_name}); | 809 | try warn(c, scope, field_loc, "{s} demoted to opaque type - has bitfield", .{container_kind_name}); |
| 810 | break :blk Tag.opaque_literal.init(); | 810 | break :blk Tag.opaque_literal.init(); |
| 811 | } | 811 | } |
| 812 | 812 | ||
| 813 | if (qualTypeCanon(field_qt).isIncompleteOrZeroLengthArrayType(c.clang_context)) { | 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 | try warn(c, scope, field_loc, "{s} demoted to opaque type - has variable length array", .{container_kind_name}); | 815 | try warn(c, scope, field_loc, "{s} demoted to opaque type - has variable length array", .{container_kind_name}); |
| 816 | break :blk Tag.opaque_literal.init(); | 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,7 +826,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD |
| 826 | } | 826 | } |
| 827 | const field_type = transQualType(c, scope, field_qt, field_loc) catch |err| switch (err) { | 827 | const field_type = transQualType(c, scope, field_qt, field_loc) catch |err| switch (err) { |
| 828 | error.UnsupportedType => { | 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 | try warn(c, scope, record_loc, "{s} demoted to opaque type - unable to translate type of field {s}", .{ container_kind_name, field_name }); | 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 | break :blk Tag.opaque_literal.init(); | 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,7 +972,7 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E |
| 972 | .fields = try c.arena.dupe(ast.Payload.Enum.Field, fields.items), | 972 | .fields = try c.arena.dupe(ast.Payload.Enum.Field, fields.items), |
| 973 | }); | 973 | }); |
| 974 | } else blk: { | 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 | break :blk Tag.opaque_literal.init(); | 976 | break :blk Tag.opaque_literal.init(); |
| 977 | }; | 977 | }; |
| 978 | 978 | ||
| ... | @@ -1069,12 +1069,64 @@ fn transStmt( | ... | @@ -1069,12 +1069,64 @@ fn transStmt( |
| 1069 | const expr = try transExpr(c, scope, source_expr, .used); | 1069 | const expr = try transExpr(c, scope, source_expr, .used); |
| 1070 | return maybeSuppressResult(c, scope, result_used, expr); | 1070 | return maybeSuppressResult(c, scope, result_used, expr); |
| 1071 | }, | 1071 | }, |
| 1072 | .OffsetOfExprClass => return transOffsetOfExpr(c, scope, @ptrCast(*const clang.OffsetOfExpr, stmt), result_used), | ||
| 1072 | else => { | 1073 | else => { |
| 1073 | return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)}); | 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 | fn transBinaryOperator( | 1130 | fn transBinaryOperator( |
| 1079 | c: *Context, | 1131 | c: *Context, |
| 1080 | scope: *Scope, | 1132 | scope: *Scope, |
| ... | @@ -3199,7 +3251,7 @@ fn maybeSuppressResult( | ... | @@ -3199,7 +3251,7 @@ fn maybeSuppressResult( |
| 3199 | } | 3251 | } |
| 3200 | 3252 | ||
| 3201 | fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void { | 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 | try c.global_scope.nodes.append(decl_node); | 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,7 +4287,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 4235 | return m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(last)}); | 4287 | return m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(last)}); |
| 4236 | 4288 | ||
| 4237 | const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node }); | 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 | fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { | 4293 | fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| ... | @@ -4294,7 +4346,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { | ... | @@ -4294,7 +4346,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void { |
| 4294 | .return_type = return_type, | 4346 | .return_type = return_type, |
| 4295 | .body = try block_scope.complete(c), | 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 | const ParseError = Error || error{ParseError}; | 4352 | const ParseError = Error || error{ParseError}; |
src/translate_c/ast.zig+8| ... | @@ -148,6 +148,8 @@ pub const Node = extern union { | ... | @@ -148,6 +148,8 @@ pub const Node = extern union { |
| 148 | ptr_cast, | 148 | ptr_cast, |
| 149 | /// @divExact(lhs, rhs) | 149 | /// @divExact(lhs, rhs) |
| 150 | div_exact, | 150 | div_exact, |
| 151 | /// @byteOffsetOf(lhs, rhs) | ||
| 152 | byte_offset_of, | ||
| 151 | 153 | ||
| 152 | negate, | 154 | negate, |
| 153 | negate_wrap, | 155 | negate_wrap, |
| ... | @@ -303,6 +305,7 @@ pub const Node = extern union { | ... | @@ -303,6 +305,7 @@ pub const Node = extern union { |
| 303 | .std_mem_zeroinit, | 305 | .std_mem_zeroinit, |
| 304 | .ptr_cast, | 306 | .ptr_cast, |
| 305 | .div_exact, | 307 | .div_exact, |
| 308 | .byte_offset_of, | ||
| 306 | => Payload.BinOp, | 309 | => Payload.BinOp, |
| 307 | 310 | ||
| 308 | .integer_literal, | 311 | .integer_literal, |
| ... | @@ -1135,6 +1138,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { | ... | @@ -1135,6 +1138,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 1135 | const payload = node.castTag(.div_exact).?.data; | 1138 | const payload = node.castTag(.div_exact).?.data; |
| 1136 | return renderBuiltinCall(c, "@divExact", &.{ payload.lhs, payload.rhs }); | 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 | .sizeof => { | 1145 | .sizeof => { |
| 1139 | const payload = node.castTag(.sizeof).?.data; | 1146 | const payload = node.castTag(.sizeof).?.data; |
| 1140 | return renderBuiltinCall(c, "@sizeOf", &.{payload}); | 1147 | return renderBuiltinCall(c, "@sizeOf", &.{payload}); |
| ... | @@ -2001,6 +2008,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { | ... | @@ -2001,6 +2008,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { |
| 2001 | .array_type, | 2008 | .array_type, |
| 2002 | .bool_to_int, | 2009 | .bool_to_int, |
| 2003 | .div_exact, | 2010 | .div_exact, |
| 2011 | .byte_offset_of, | ||
| 2004 | => { | 2012 | => { |
| 2005 | // no grouping needed | 2013 | // no grouping needed |
| 2006 | return renderNode(c, node); | 2014 | return renderNode(c, node); |
src/value.zig-2| ... | @@ -1561,7 +1561,6 @@ pub const Value = extern union { | ... | @@ -1561,7 +1561,6 @@ pub const Value = extern union { |
| 1561 | .@"error" => { | 1561 | .@"error" => { |
| 1562 | const payload = self.castTag(.@"error").?.data; | 1562 | const payload = self.castTag(.@"error").?.data; |
| 1563 | hasher.update(payload.name); | 1563 | hasher.update(payload.name); |
| 1564 | std.hash.autoHash(&hasher, payload.value); | ||
| 1565 | }, | 1564 | }, |
| 1566 | .error_union => { | 1565 | .error_union => { |
| 1567 | const payload = self.castTag(.error_union).?.data; | 1566 | const payload = self.castTag(.error_union).?.data; |
| ... | @@ -2157,7 +2156,6 @@ pub const Value = extern union { | ... | @@ -2157,7 +2156,6 @@ pub const Value = extern union { |
| 2157 | /// duration of the compilation. | 2156 | /// duration of the compilation. |
| 2158 | /// TODO revisit this when we have the concept of the error tag type | 2157 | /// TODO revisit this when we have the concept of the error tag type |
| 2159 | name: []const u8, | 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,6 +2623,46 @@ const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct |
| 2623 | return reinterpret_cast<const struct ZigClangExpr *>(casted->getUnderlyingExpr()); | 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 | struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *self) { | 2666 | struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *self) { |
| 2627 | auto casted = reinterpret_cast<const clang::ElaboratedType *>(self); | 2667 | auto casted = reinterpret_cast<const clang::ElaboratedType *>(self); |
| 2628 | return bitcast(casted->getNamedType()); | 2668 | return bitcast(casted->getNamedType()); |
| ... | @@ -3022,6 +3062,11 @@ ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldD | ... | @@ -3022,6 +3062,11 @@ ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldD |
| 3022 | return bitcast(casted->getLocation()); | 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 | ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *self) { | 3070 | ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *self) { |
| 3026 | auto casted = reinterpret_cast<const clang::FieldDecl *>(self); | 3071 | auto casted = reinterpret_cast<const clang::FieldDecl *>(self); |
| 3027 | return bitcast(casted->getType()); | 3072 | return bitcast(casted->getType()); |
src/zig_clang.h+18| ... | @@ -935,6 +935,13 @@ enum ZigClangUnaryExprOrTypeTrait_Kind { | ... | @@ -935,6 +935,13 @@ enum ZigClangUnaryExprOrTypeTrait_Kind { |
| 935 | ZigClangUnaryExprOrTypeTrait_KindPreferredAlignOf, | 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 | ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const struct ZigClangSourceManager *, | 945 | ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const struct ZigClangSourceManager *, |
| 939 | struct ZigClangSourceLocation Loc); | 946 | struct ZigClangSourceLocation Loc); |
| 940 | ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const struct ZigClangSourceManager *, | 947 | ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const struct ZigClangSourceManager *, |
| ... | @@ -1168,6 +1175,16 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangTypeOfType_getUnderlyingType(const | ... | @@ -1168,6 +1175,16 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangTypeOfType_getUnderlyingType(const |
| 1168 | 1175 | ||
| 1169 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct ZigClangTypeOfExprType *); | 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 | ZIG_EXTERN_C struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *); | 1188 | ZIG_EXTERN_C struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *); |
| 1172 | ZIG_EXTERN_C enum ZigClangElaboratedTypeKeyword ZigClangElaboratedType_getKeyword(const struct ZigClangElaboratedType *); | 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,6 +1285,7 @@ ZIG_EXTERN_C bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *) |
| 1268 | ZIG_EXTERN_C bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *); | 1285 | ZIG_EXTERN_C bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *); |
| 1269 | ZIG_EXTERN_C struct ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *); | 1286 | ZIG_EXTERN_C struct ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *); |
| 1270 | ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldDecl *); | 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 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangEnumConstantDecl_getInitExpr(const struct ZigClangEnumConstantDecl *); | 1290 | ZIG_EXTERN_C const struct ZigClangExpr *ZigClangEnumConstantDecl_getInitExpr(const struct ZigClangEnumConstantDecl *); |
| 1273 | ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangEnumConstantDecl_getInitVal(const struct ZigClangEnumConstantDecl *); | 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,7 +1178,6 @@ fn zirErrorValue(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorValue) InnerE |
| 1178 | .ty = result_type, | 1178 | .ty = result_type, |
| 1179 | .val = try Value.Tag.@"error".create(scope.arena(), .{ | 1179 | .val = try Value.Tag.@"error".create(scope.arena(), .{ |
| 1180 | .name = entry.key, | 1180 | .name = entry.key, |
| 1181 | .value = entry.value, | ||
| 1182 | }), | 1181 | }), |
| 1183 | }); | 1182 | }); |
| 1184 | } | 1183 | } |
| ... | @@ -2215,7 +2214,8 @@ fn zirCmp( | ... | @@ -2215,7 +2214,8 @@ fn zirCmp( |
| 2215 | } | 2214 | } |
| 2216 | if (rhs.value()) |rval| { | 2215 | if (rhs.value()) |rval| { |
| 2217 | if (lhs.value()) |lval| { | 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 | return mod.fail(scope, inst.base.src, "TODO implement equality comparison between runtime errors", .{}); | 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,4 +1073,60 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { |
| 1073 | \\ return 0; | 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,7 +200,7 @@ pub fn main() !void { |
| 200 | continue; | 200 | continue; |
| 201 | } | 201 | } |
| 202 | if (std.mem.startsWith(u8, ver, "GCC_")) continue; | 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 | const gop = try global_fn_set.getOrPut(name); | 204 | const gop = try global_fn_set.getOrPut(name); |
| 205 | if (gop.found_existing) { | 205 | if (gop.found_existing) { |
| 206 | if (!std.mem.eql(u8, gop.entry.value.lib, "c")) { | 206 | if (!std.mem.eql(u8, gop.entry.value.lib, "c")) { |
| ... | @@ -242,7 +242,7 @@ pub fn main() !void { | ... | @@ -242,7 +242,7 @@ pub fn main() !void { |
| 242 | var buffered = std.io.bufferedWriter(vers_txt_file.writer()); | 242 | var buffered = std.io.bufferedWriter(vers_txt_file.writer()); |
| 243 | const vers_txt = buffered.writer(); | 243 | const vers_txt = buffered.writer(); |
| 244 | for (global_ver_list) |name, i| { | 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 | try vers_txt.print("{s}\n", .{name}); | 246 | try vers_txt.print("{s}\n", .{name}); |
| 247 | } | 247 | } |
| 248 | try buffered.flush(); | 248 | try buffered.flush(); |