authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-01 12:09:26-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-01 12:09:26-07:00
log584cb2e4fb67eb95a8c9d790f807235c8088bd76
tree26e1a211055647edf04734ce0d10ff5f762df31c
parent24215df8c56ba64e624487f914513212e3e747e9
parentbee7db77fe65802a41f2812caac4faa7dcb8acd3

Merge remote-tracking branch 'origin/master' into llvm12


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;
933threadlocal var x: i32 = 1234;933threadlocal var x: i32 = 1234;
934934
935test "thread local storage" {935test "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};
167167
168/// caller must call wait on the returned thread168// Given `T`, the type of the thread startFn, extract the expected type for the
169/// fn startFn(@TypeOf(context)) T169// context parameter.
170/// where T is u8, noreturn, void, or !void170fn SpawnContextType(comptime T: type) type {
171/// caller must call wait on the returned thread171 const TI = @typeInfo(T);
172pub 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.
187pub 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 bound189 // TODO compile-time call graph analysis to determine stack upper bound
175 // https://github.com/ziglang/zig/issues/157190 // https://github.com/ziglang/zig/issues/157
176 const default_stack_size = 16 * 1024 * 1024;191 const default_stack_size = 16 * 1024 * 1024;
177192
178 const Context = @TypeOf(context);193 const Context = @TypeOf(context);
179 comptime assert(@typeInfo(@TypeOf(startFn)).Fn.args[0].arg_type.? == Context);
180194
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 };
221221
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);
225225
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();
287287
...@@ -290,7 +290,7 @@ test "basic usage" {...@@ -290,7 +290,7 @@ test "basic usage" {
290 // https://github.com/ziglang/zig/issues/7009290 // 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 };
380380
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();
385385
...@@ -388,7 +388,7 @@ test "basic usage" {...@@ -388,7 +388,7 @@ test "basic usage" {
388 // https://github.com/ziglang/zig/issues/7009388 // 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" {
216216
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 }
225225
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 }
132132
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 }
3838
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 list800 // 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.
188pub 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 };
1818
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;
2025
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 }
159164
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}
185171
186test "CSPRNG" {172test "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
7const std = @import("std");
8const crypto = std.crypto;
9const aes = crypto.core.aes;
10const assert = std.debug.assert;
11const math = std.math;
12const mem = std.mem;
13
14pub const Aes128Ocb = AesOcb(aes.Aes128);
15pub const Aes256Ocb = AesOcb(aes.Aes256);
16
17const Block = [16]u8;
18
19/// AES-OCB (RFC 7253 - https://competitions.cr.yp.to/round3/ocbv11.pdf)
20fn 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
247fn 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
255fn xorWith(x: *Block, y: Block) callconv(.Inline) void {
256 for (x) |*v, i| {
257 v.* ^= y[i];
258 }
259}
260
261const hexToBytes = std.fmt.hexToBytes;
262
263test "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
281test "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
300test "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
322test "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};
213215
...@@ -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 }
362364
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 }
369371
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 }
376378
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 }
383385
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 }
390392
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 }
397399
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 }
404406
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 }
411413
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();
186186
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 }
804804
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 {
3939
40/// This is different from mem.join in that the separator will not be repeated if40/// 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.
42fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, paths: []const []const u8) ![]u8 {42fn 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{};
4444
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 };
5859
...@@ -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 }
7879
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.
85pub fn join(allocator: *Allocator, paths: []const []const u8) ![]u8 {88pub 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.
94pub 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}
8898
89fn testJoinWindows(paths: []const []const u8, expected: []const u8) void {99fn 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}
99109
100fn testJoinPosix(paths: []const []const u8, expected: []const u8) void {110fn 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}
110120
111test "join" {121test "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);
115125 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
118128 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" },
123133 "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 );
126136
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);
129139
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);
132142 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
137147 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}
141157
142pub const isAbsoluteC = @compileError("deprecated: renamed to isAbsoluteZ");158pub 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.
1211pub fn extension(path: []const u8) []const u8 {1227pub 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();
764764
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();
767767
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 }
564564
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" {
11161115
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 }
11211120
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();
21852185
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" {
293293
294fn getJsonObject(allocator: *std.mem.Allocator) !std.json.Value {294fn 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 };
163163
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();
166166
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 };
287287
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();
290290
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();
6060
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 }
6969
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;
48424842
4843pub const SendToError = SendError || error{4843pub 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,
48464846
...@@ -4859,6 +4859,79 @@ pub const SendToError = SendError || error{...@@ -4859,6 +4859,79 @@ pub const SendToError = SendError || error{
4859 AddressNotAvailable,4859 AddressNotAvailable,
4860};4860};
48614861
4862pub 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
4933pub 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 intended4937/// 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};
409409
...@@ -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};
421421
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};
504504
...@@ -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};
516516
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}
979979
980pub fn sendmsg(fd: i32, msg: *msghdr_const, flags: u32) usize {980pub 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;
318318
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" {
336336
337 var shared_ctx: i32 = 1;337 var shared_ctx: i32 = 1;
338338
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);
343343
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" {
367367
368test "thread local storage" {368test "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}
12931293
1294pub 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
1294pub 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 {1307pub 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 }
415415
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();
7676
77 worker.thread = try std.Thread.spawn(worker, Worker.run);77 worker.thread = try std.Thread.spawn(Worker.run, worker);
78 }78 }
79}79}
8080
src/clang.zig+38
...@@ -432,6 +432,9 @@ pub const FieldDecl = opaque {...@@ -432,6 +432,9 @@ pub const FieldDecl = opaque {
432432
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};
436439
437pub const FileID = opaque {};440pub 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};
595598
599pub 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
610pub 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
596pub const MemberExpr = opaque {627pub 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};
16641695
1696pub const OffsetOfNode_Kind = extern enum {
1697 Array,
1698 Field,
1699 Identifier,
1700 Base,
1701};
1702
1665pub const Stage2ErrorMsg = extern struct {1703pub 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 table197 // undo resetting the table
198 _ = try table.put(case_death, {});198 try table.put(case_death, {});
199 }199 }
200 }200 }
201201
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 {
399fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void {399fn 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}
405405
...@@ -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 };
794794
...@@ -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();
806806
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 }
812812
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 };
978978
...@@ -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}
10771078
1079/// Translate a "simple" offsetof expression containing exactly one component,
1080/// when that component is of kind .Field - e.g. offsetof(mytype, myfield)
1081fn 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
1108fn 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
1078fn transBinaryOperator(1130fn 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}
32003252
3201fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void {3253fn 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}
32053257
...@@ -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)});
42364288
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}
42404292
4241fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {4293fn 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}
42994351
4300const ParseError = Error || error{ParseError};4352const 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,
151153
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,
307310
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 needed2013 // 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 type2157 /// 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 };
21632161
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}
26252625
2626enum 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
2631unsigned ZigClangOffsetOfNode_getArrayExprIndex(const struct ZigClangOffsetOfNode *self) {
2632 auto casted = reinterpret_cast<const clang::OffsetOfNode *>(self);
2633 return casted->getArrayExprIndex();
2634}
2635
2636struct 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
2641unsigned ZigClangOffsetOfExpr_getNumComponents(const struct ZigClangOffsetOfExpr *self) {
2642 auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self);
2643 return casted->getNumComponents();
2644}
2645
2646unsigned ZigClangOffsetOfExpr_getNumExpressions(const struct ZigClangOffsetOfExpr *self) {
2647 auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self);
2648 return casted->getNumExpressions();
2649}
2650
2651const 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
2656const 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
2661ZigClangSourceLocation ZigClangOffsetOfExpr_getBeginLoc(const ZigClangOffsetOfExpr *self) {
2662 auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self);
2663 return bitcast(casted->getBeginLoc());
2664}
2665
2626struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *self) {2666struct 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}
30243064
3065const 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
3025ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *self) {3070ZigClangQualType 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};
937937
938enum ZigClangOffsetOfNode_Kind {
939 ZigClangOffsetOfNode_KindArray,
940 ZigClangOffsetOfNode_KindField,
941 ZigClangOffsetOfNode_KindIdentifier,
942 ZigClangOffsetOfNode_KindBase,
943};
944
938ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const struct ZigClangSourceManager *,945ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const struct ZigClangSourceManager *,
939 struct ZigClangSourceLocation Loc);946 struct ZigClangSourceLocation Loc);
940ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const struct ZigClangSourceManager *,947ZIG_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
11681175
1169ZIG_EXTERN_C const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct ZigClangTypeOfExprType *);1176ZIG_EXTERN_C const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct ZigClangTypeOfExprType *);
11701177
1178ZIG_EXTERN_C enum ZigClangOffsetOfNode_Kind ZigClangOffsetOfNode_getKind(const struct ZigClangOffsetOfNode *);
1179ZIG_EXTERN_C unsigned ZigClangOffsetOfNode_getArrayExprIndex(const struct ZigClangOffsetOfNode *);
1180ZIG_EXTERN_C struct ZigClangFieldDecl * ZigClangOffsetOfNode_getField(const struct ZigClangOffsetOfNode *);
1181
1182ZIG_EXTERN_C unsigned ZigClangOffsetOfExpr_getNumComponents(const struct ZigClangOffsetOfExpr *);
1183ZIG_EXTERN_C unsigned ZigClangOffsetOfExpr_getNumExpressions(const struct ZigClangOffsetOfExpr *);
1184ZIG_EXTERN_C const struct ZigClangExpr *ZigClangOffsetOfExpr_getIndexExpr(const struct ZigClangOffsetOfExpr *, unsigned idx);
1185ZIG_EXTERN_C const struct ZigClangOffsetOfNode *ZigClangOffsetOfExpr_getComponent(const struct ZigClangOffsetOfExpr *, unsigned idx);
1186ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangOffsetOfExpr_getBeginLoc(const struct ZigClangOffsetOfExpr *);
1187
1171ZIG_EXTERN_C struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *);1188ZIG_EXTERN_C struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *);
1172ZIG_EXTERN_C enum ZigClangElaboratedTypeKeyword ZigClangElaboratedType_getKeyword(const struct ZigClangElaboratedType *);1189ZIG_EXTERN_C enum ZigClangElaboratedTypeKeyword ZigClangElaboratedType_getKeyword(const struct ZigClangElaboratedType *);
11731190
...@@ -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 *)
1268ZIG_EXTERN_C bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *);1285ZIG_EXTERN_C bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *);
1269ZIG_EXTERN_C struct ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *);1286ZIG_EXTERN_C struct ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *);
1270ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldDecl *);1287ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldDecl *);
1288ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangFieldDecl_getParent(const struct ZigClangFieldDecl *);
12711289
1272ZIG_EXTERN_C const struct ZigClangExpr *ZigClangEnumConstantDecl_getInitExpr(const struct ZigClangEnumConstantDecl *);1290ZIG_EXTERN_C const struct ZigClangExpr *ZigClangEnumConstantDecl_getInitExpr(const struct ZigClangEnumConstantDecl *);
1273ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangEnumConstantDecl_getInitVal(const struct ZigClangEnumConstantDecl *);1291ZIG_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();