mirror of
https://github.com/ziglang/zig.git
synced 2024-11-26 23:22:44 +00:00
Merge remote-tracking branch 'origin/master' into llvm12
This commit is contained in:
commit
584cb2e4fb
@ -933,8 +933,8 @@ const assert = std.debug.assert;
|
||||
threadlocal var x: i32 = 1234;
|
||||
|
||||
test "thread local storage" {
|
||||
const thread1 = try std.Thread.spawn({}, testTls);
|
||||
const thread2 = try std.Thread.spawn({}, testTls);
|
||||
const thread1 = try std.Thread.spawn(testTls, {});
|
||||
const thread2 = try std.Thread.spawn(testTls, {});
|
||||
testTls({});
|
||||
thread1.wait();
|
||||
thread2.wait();
|
||||
|
@ -165,18 +165,32 @@ pub const SpawnError = error{
|
||||
Unexpected,
|
||||
};
|
||||
|
||||
/// caller must call wait on the returned thread
|
||||
/// fn startFn(@TypeOf(context)) T
|
||||
/// where T is u8, noreturn, void, or !void
|
||||
/// caller must call wait on the returned thread
|
||||
pub fn spawn(context: anytype, comptime startFn: anytype) SpawnError!*Thread {
|
||||
// Given `T`, the type of the thread startFn, extract the expected type for the
|
||||
// context parameter.
|
||||
fn SpawnContextType(comptime T: type) type {
|
||||
const TI = @typeInfo(T);
|
||||
if (TI != .Fn)
|
||||
@compileError("expected function type, found " ++ @typeName(T));
|
||||
|
||||
if (TI.Fn.args.len != 1)
|
||||
@compileError("expected function with single argument, found " ++ @typeName(T));
|
||||
|
||||
return TI.Fn.args[0].arg_type orelse
|
||||
@compileError("cannot use a generic function as thread startFn");
|
||||
}
|
||||
|
||||
/// Spawns a new thread executing startFn, returning an handle for it.
|
||||
/// Caller must call wait on the returned thread.
|
||||
/// The `startFn` function must take a single argument of type T and return a
|
||||
/// value of type u8, noreturn, void or !void.
|
||||
/// The `context` parameter is of type T and is passed to the spawned thread.
|
||||
pub fn spawn(comptime startFn: anytype, context: SpawnContextType(@TypeOf(startFn))) SpawnError!*Thread {
|
||||
if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode");
|
||||
// TODO compile-time call graph analysis to determine stack upper bound
|
||||
// https://github.com/ziglang/zig/issues/157
|
||||
const default_stack_size = 16 * 1024 * 1024;
|
||||
|
||||
const Context = @TypeOf(context);
|
||||
comptime assert(@typeInfo(@TypeOf(startFn)).Fn.args[0].arg_type.? == Context);
|
||||
|
||||
if (std.Target.current.os.tag == .windows) {
|
||||
const WinThread = struct {
|
||||
|
@ -220,8 +220,8 @@ test "basic usage" {
|
||||
};
|
||||
|
||||
var context = Context{};
|
||||
const send_thread = try std.Thread.spawn(&context, Context.sender);
|
||||
const recv_thread = try std.Thread.spawn(&context, Context.receiver);
|
||||
const send_thread = try std.Thread.spawn(Context.sender, &context);
|
||||
const recv_thread = try std.Thread.spawn(Context.receiver, &context);
|
||||
|
||||
send_thread.wait();
|
||||
recv_thread.wait();
|
||||
|
@ -299,7 +299,7 @@ test "basic usage" {
|
||||
const thread_count = 10;
|
||||
var threads: [thread_count]*std.Thread = undefined;
|
||||
for (threads) |*t| {
|
||||
t.* = try std.Thread.spawn(&context, worker);
|
||||
t.* = try std.Thread.spawn(worker, &context);
|
||||
}
|
||||
for (threads) |t|
|
||||
t.wait();
|
||||
|
@ -281,7 +281,7 @@ test "basic usage" {
|
||||
var context: Context = undefined;
|
||||
try context.init();
|
||||
defer context.deinit();
|
||||
const receiver = try std.Thread.spawn(&context, Context.receiver);
|
||||
const receiver = try std.Thread.spawn(Context.receiver, &context);
|
||||
defer receiver.wait();
|
||||
context.sender();
|
||||
|
||||
@ -290,7 +290,7 @@ test "basic usage" {
|
||||
// https://github.com/ziglang/zig/issues/7009
|
||||
var timed = Context.init();
|
||||
defer timed.deinit();
|
||||
const sleeper = try std.Thread.spawn(&timed, Context.sleeper);
|
||||
const sleeper = try std.Thread.spawn(Context.sleeper, &timed);
|
||||
defer sleeper.wait();
|
||||
try timed.timedWaiter();
|
||||
}
|
||||
|
@ -379,7 +379,7 @@ test "basic usage" {
|
||||
};
|
||||
|
||||
var context = Context{};
|
||||
const receiver = try std.Thread.spawn(&context, Context.receiver);
|
||||
const receiver = try std.Thread.spawn(Context.receiver, &context);
|
||||
defer receiver.wait();
|
||||
context.sender();
|
||||
|
||||
@ -388,7 +388,7 @@ test "basic usage" {
|
||||
// https://github.com/ziglang/zig/issues/7009
|
||||
var timed = Context.init();
|
||||
defer timed.deinit();
|
||||
const sleeper = try std.Thread.spawn(&timed, Context.sleeper);
|
||||
const sleeper = try std.Thread.spawn(Context.sleeper, &timed);
|
||||
defer sleeper.wait();
|
||||
try timed.timedWaiter();
|
||||
}
|
||||
|
@ -216,11 +216,11 @@ test "std.atomic.Queue" {
|
||||
|
||||
var putters: [put_thread_count]*std.Thread = undefined;
|
||||
for (putters) |*t| {
|
||||
t.* = try std.Thread.spawn(&context, startPuts);
|
||||
t.* = try std.Thread.spawn(startPuts, &context);
|
||||
}
|
||||
var getters: [put_thread_count]*std.Thread = undefined;
|
||||
for (getters) |*t| {
|
||||
t.* = try std.Thread.spawn(&context, startGets);
|
||||
t.* = try std.Thread.spawn(startGets, &context);
|
||||
}
|
||||
|
||||
for (putters) |t|
|
||||
|
@ -123,11 +123,11 @@ test "std.atomic.stack" {
|
||||
} else {
|
||||
var putters: [put_thread_count]*std.Thread = undefined;
|
||||
for (putters) |*t| {
|
||||
t.* = try std.Thread.spawn(&context, startPuts);
|
||||
t.* = try std.Thread.spawn(startPuts, &context);
|
||||
}
|
||||
var getters: [put_thread_count]*std.Thread = undefined;
|
||||
for (getters) |*t| {
|
||||
t.* = try std.Thread.spawn(&context, startGets);
|
||||
t.* = try std.Thread.spawn(startGets, &context);
|
||||
}
|
||||
|
||||
for (putters) |t|
|
||||
|
@ -32,7 +32,7 @@ pub const BufSet = struct {
|
||||
if (self.hash_map.get(key) == null) {
|
||||
const key_copy = try self.copy(key);
|
||||
errdefer self.free(key_copy);
|
||||
_ = try self.hash_map.put(key_copy, {});
|
||||
try self.hash_map.put(key_copy, {});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -790,7 +790,7 @@ pub const Builder = struct {
|
||||
var list = ArrayList([]const u8).init(self.allocator);
|
||||
list.append(s) catch unreachable;
|
||||
list.append(value) catch unreachable;
|
||||
_ = self.user_input_options.put(name, UserInputOption{
|
||||
self.user_input_options.put(name, UserInputOption{
|
||||
.name = name,
|
||||
.value = UserValue{ .List = list },
|
||||
.used = false,
|
||||
@ -799,7 +799,7 @@ pub const Builder = struct {
|
||||
UserValue.List => |*list| {
|
||||
// append to the list
|
||||
list.append(value) catch unreachable;
|
||||
_ = self.user_input_options.put(name, UserInputOption{
|
||||
self.user_input_options.put(name, UserInputOption{
|
||||
.name = name,
|
||||
.value = UserValue{ .List = list.* },
|
||||
.used = false,
|
||||
|
@ -182,3 +182,9 @@ pub fn __builtin_memcpy(
|
||||
@memcpy(dst_cast, src_cast, len);
|
||||
return dst;
|
||||
}
|
||||
|
||||
/// The return value of __builtin_expect is `expr`. `c` is the expected value
|
||||
/// of `expr` and is used as a hint to the compiler in C. Here it is unused.
|
||||
pub fn __builtin_expect(expr: c_long, c: c_long) callconv(.Inline) c_long {
|
||||
return expr;
|
||||
}
|
||||
|
@ -16,6 +16,11 @@ pub const aead = struct {
|
||||
pub const Aes256Gcm = @import("crypto/aes_gcm.zig").Aes256Gcm;
|
||||
};
|
||||
|
||||
pub const aes_ocb = struct {
|
||||
pub const Aes128Ocb = @import("crypto/aes_ocb.zig").Aes128Ocb;
|
||||
pub const Aes256Ocb = @import("crypto/aes_ocb.zig").Aes256Ocb;
|
||||
};
|
||||
|
||||
pub const Gimli = @import("crypto/gimli.zig").Aead;
|
||||
|
||||
pub const chacha_poly = struct {
|
||||
@ -157,30 +162,11 @@ test "crypto" {
|
||||
}
|
||||
}
|
||||
|
||||
_ = @import("crypto/aes.zig");
|
||||
_ = @import("crypto/bcrypt.zig");
|
||||
_ = @import("crypto/aegis.zig");
|
||||
_ = @import("crypto/aes_gcm.zig");
|
||||
_ = @import("crypto/aes_ocb.zig");
|
||||
_ = @import("crypto/blake2.zig");
|
||||
_ = @import("crypto/blake3.zig");
|
||||
_ = @import("crypto/chacha20.zig");
|
||||
_ = @import("crypto/gimli.zig");
|
||||
_ = @import("crypto/hmac.zig");
|
||||
_ = @import("crypto/isap.zig");
|
||||
_ = @import("crypto/md5.zig");
|
||||
_ = @import("crypto/modes.zig");
|
||||
_ = @import("crypto/pbkdf2.zig");
|
||||
_ = @import("crypto/poly1305.zig");
|
||||
_ = @import("crypto/sha1.zig");
|
||||
_ = @import("crypto/sha2.zig");
|
||||
_ = @import("crypto/sha3.zig");
|
||||
_ = @import("crypto/salsa20.zig");
|
||||
_ = @import("crypto/siphash.zig");
|
||||
_ = @import("crypto/25519/curve25519.zig");
|
||||
_ = @import("crypto/25519/ed25519.zig");
|
||||
_ = @import("crypto/25519/edwards25519.zig");
|
||||
_ = @import("crypto/25519/field.zig");
|
||||
_ = @import("crypto/25519/scalar.zig");
|
||||
_ = @import("crypto/25519/x25519.zig");
|
||||
_ = @import("crypto/25519/ristretto255.zig");
|
||||
}
|
||||
|
||||
test "CSPRNG" {
|
||||
|
@ -313,10 +313,7 @@ pub fn AesEncryptCtx(comptime Aes: type) type {
|
||||
inline while (i < rounds) : (i += 1) {
|
||||
ts = Block.parallel.encryptWide(count, ts, round_keys[i]);
|
||||
}
|
||||
i = 1;
|
||||
inline while (i < count) : (i += 1) {
|
||||
ts = Block.parallel.encryptLastWide(count, ts, round_keys[i]);
|
||||
}
|
||||
ts = Block.parallel.encryptLastWide(count, ts, round_keys[i]);
|
||||
j = 0;
|
||||
inline while (j < count) : (j += 1) {
|
||||
dst[16 * j .. 16 * j + 16].* = ts[j].toBytes();
|
||||
@ -392,10 +389,7 @@ pub fn AesDecryptCtx(comptime Aes: type) type {
|
||||
inline while (i < rounds) : (i += 1) {
|
||||
ts = Block.parallel.decryptWide(count, ts, inv_round_keys[i]);
|
||||
}
|
||||
i = 1;
|
||||
inline while (i < count) : (i += 1) {
|
||||
ts = Block.parallel.decryptLastWide(count, ts, inv_round_keys[i]);
|
||||
}
|
||||
ts = Block.parallel.decryptLastWide(count, ts, inv_round_keys[i]);
|
||||
j = 0;
|
||||
inline while (j < count) : (j += 1) {
|
||||
dst[16 * j .. 16 * j + 16].* = ts[j].toBytes();
|
||||
|
@ -364,10 +364,7 @@ pub fn AesEncryptCtx(comptime Aes: type) type {
|
||||
inline while (i < rounds) : (i += 1) {
|
||||
ts = Block.parallel.encryptWide(count, ts, round_keys[i]);
|
||||
}
|
||||
i = 1;
|
||||
inline while (i < count) : (i += 1) {
|
||||
ts = Block.parallel.encryptLastWide(count, ts, round_keys[i]);
|
||||
}
|
||||
ts = Block.parallel.encryptLastWide(count, ts, round_keys[i]);
|
||||
j = 0;
|
||||
inline while (j < count) : (j += 1) {
|
||||
dst[16 * j .. 16 * j + 16].* = ts[j].toBytes();
|
||||
@ -443,10 +440,7 @@ pub fn AesDecryptCtx(comptime Aes: type) type {
|
||||
inline while (i < rounds) : (i += 1) {
|
||||
ts = Block.parallel.decryptWide(count, ts, inv_round_keys[i]);
|
||||
}
|
||||
i = 1;
|
||||
inline while (i < count) : (i += 1) {
|
||||
ts = Block.parallel.decryptLastWide(count, ts, inv_round_keys[i]);
|
||||
}
|
||||
ts = Block.parallel.decryptLastWide(count, ts, inv_round_keys[i]);
|
||||
j = 0;
|
||||
inline while (j < count) : (j += 1) {
|
||||
dst[16 * j .. 16 * j + 16].* = ts[j].toBytes();
|
||||
|
343
lib/std/crypto/aes_ocb.zig
Normal file
343
lib/std/crypto/aes_ocb.zig
Normal file
@ -0,0 +1,343 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2015-2021 Zig Contributors
|
||||
// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
|
||||
// The MIT license requires this copyright notice to be included in all copies
|
||||
// and substantial portions of the software.
|
||||
|
||||
const std = @import("std");
|
||||
const crypto = std.crypto;
|
||||
const aes = crypto.core.aes;
|
||||
const assert = std.debug.assert;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
|
||||
pub const Aes128Ocb = AesOcb(aes.Aes128);
|
||||
pub const Aes256Ocb = AesOcb(aes.Aes256);
|
||||
|
||||
const Block = [16]u8;
|
||||
|
||||
/// AES-OCB (RFC 7253 - https://competitions.cr.yp.to/round3/ocbv11.pdf)
|
||||
fn AesOcb(comptime Aes: anytype) type {
|
||||
const EncryptCtx = aes.AesEncryptCtx(Aes);
|
||||
const DecryptCtx = aes.AesDecryptCtx(Aes);
|
||||
|
||||
return struct {
|
||||
pub const key_length = Aes.key_bits / 8;
|
||||
pub const nonce_length: usize = 12;
|
||||
pub const tag_length: usize = 16;
|
||||
|
||||
const Lx = struct {
|
||||
star: Block align(16),
|
||||
dol: Block align(16),
|
||||
table: [56]Block align(16) = undefined,
|
||||
upto: usize,
|
||||
|
||||
fn double(l: Block) callconv(.Inline) Block {
|
||||
const l_ = mem.readIntBig(u128, &l);
|
||||
const l_2 = (l_ << 1) ^ (0x87 & -%(l_ >> 127));
|
||||
var l2: Block = undefined;
|
||||
mem.writeIntBig(u128, &l2, l_2);
|
||||
return l2;
|
||||
}
|
||||
|
||||
fn precomp(lx: *Lx, upto: usize) []const Block {
|
||||
const table = &lx.table;
|
||||
assert(upto < table.len);
|
||||
var i = lx.upto;
|
||||
while (i + 1 <= upto) : (i += 1) {
|
||||
table[i + 1] = double(table[i]);
|
||||
}
|
||||
lx.upto = upto;
|
||||
return lx.table[0 .. upto + 1];
|
||||
}
|
||||
|
||||
fn init(aes_enc_ctx: EncryptCtx) Lx {
|
||||
const zeros = [_]u8{0} ** 16;
|
||||
var star: Block = undefined;
|
||||
aes_enc_ctx.encrypt(&star, &zeros);
|
||||
const dol = double(star);
|
||||
var lx = Lx{ .star = star, .dol = dol, .upto = 0 };
|
||||
lx.table[0] = double(dol);
|
||||
return lx;
|
||||
}
|
||||
};
|
||||
|
||||
fn hash(aes_enc_ctx: EncryptCtx, lx: *Lx, a: []const u8) Block {
|
||||
const full_blocks: usize = a.len / 16;
|
||||
const x_max = if (full_blocks > 0) math.log2_int(usize, full_blocks) else 0;
|
||||
const lt = lx.precomp(x_max);
|
||||
var sum = [_]u8{0} ** 16;
|
||||
var offset = [_]u8{0} ** 16;
|
||||
var i: usize = 0;
|
||||
while (i < full_blocks) : (i += 1) {
|
||||
xorWith(&offset, lt[@ctz(usize, i + 1)]);
|
||||
var e = xorBlocks(offset, a[i * 16 ..][0..16].*);
|
||||
aes_enc_ctx.encrypt(&e, &e);
|
||||
xorWith(&sum, e);
|
||||
}
|
||||
const leftover = a.len % 16;
|
||||
if (leftover > 0) {
|
||||
xorWith(&offset, lx.star);
|
||||
var padded = [_]u8{0} ** 16;
|
||||
mem.copy(u8, padded[0..leftover], a[i * 16 ..][0..leftover]);
|
||||
padded[leftover] = 1;
|
||||
var e = xorBlocks(offset, padded);
|
||||
aes_enc_ctx.encrypt(&e, &e);
|
||||
xorWith(&sum, e);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
fn getOffset(aes_enc_ctx: EncryptCtx, npub: [nonce_length]u8) Block {
|
||||
var nx = [_]u8{0} ** 16;
|
||||
nx[0] = @intCast(u8, @truncate(u7, tag_length * 8) << 1);
|
||||
nx[16 - nonce_length - 1] = 1;
|
||||
mem.copy(u8, nx[16 - nonce_length ..], &npub);
|
||||
|
||||
const bottom = @truncate(u6, nx[15]);
|
||||
nx[15] &= 0xc0;
|
||||
var ktop_: Block = undefined;
|
||||
aes_enc_ctx.encrypt(&ktop_, &nx);
|
||||
const ktop = mem.readIntBig(u128, &ktop_);
|
||||
var stretch = (@as(u192, ktop) << 64) | @as(u192, @truncate(u64, ktop >> 64) ^ @truncate(u64, ktop >> 56));
|
||||
var offset: Block = undefined;
|
||||
mem.writeIntBig(u128, &offset, @truncate(u128, stretch >> (64 - @as(u7, bottom))));
|
||||
return offset;
|
||||
}
|
||||
|
||||
const has_aesni = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .aes);
|
||||
const has_armaes = comptime std.Target.aarch64.featureSetHas(std.Target.current.cpu.features, .aes);
|
||||
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;
|
||||
|
||||
/// c: ciphertext: output buffer should be of size m.len
|
||||
/// tag: authentication tag: output MAC
|
||||
/// m: message
|
||||
/// ad: Associated Data
|
||||
/// npub: public nonce
|
||||
/// k: secret key
|
||||
pub fn encrypt(c: []u8, tag: *[tag_length]u8, m: []const u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) void {
|
||||
assert(c.len == m.len);
|
||||
|
||||
const aes_enc_ctx = Aes.initEnc(key);
|
||||
const full_blocks: usize = m.len / 16;
|
||||
const x_max = if (full_blocks > 0) math.log2_int(usize, full_blocks) else 0;
|
||||
var lx = Lx.init(aes_enc_ctx);
|
||||
const lt = lx.precomp(x_max);
|
||||
|
||||
var offset = getOffset(aes_enc_ctx, npub);
|
||||
var sum = [_]u8{0} ** 16;
|
||||
var i: usize = 0;
|
||||
|
||||
while (wb > 0 and i + wb <= full_blocks) : (i += wb) {
|
||||
var offsets: [wb]Block align(16) = undefined;
|
||||
var es: [16 * wb]u8 align(16) = undefined;
|
||||
var j: usize = 0;
|
||||
while (j < wb) : (j += 1) {
|
||||
xorWith(&offset, lt[@ctz(usize, i + 1 + j)]);
|
||||
offsets[j] = offset;
|
||||
const p = m[(i + j) * 16 ..][0..16].*;
|
||||
mem.copy(u8, es[j * 16 ..][0..16], &xorBlocks(p, offsets[j]));
|
||||
xorWith(&sum, p);
|
||||
}
|
||||
aes_enc_ctx.encryptWide(wb, &es, &es);
|
||||
j = 0;
|
||||
while (j < wb) : (j += 1) {
|
||||
const e = es[j * 16 ..][0..16].*;
|
||||
mem.copy(u8, c[(i + j) * 16 ..][0..16], &xorBlocks(e, offsets[j]));
|
||||
}
|
||||
}
|
||||
while (i < full_blocks) : (i += 1) {
|
||||
xorWith(&offset, lt[@ctz(usize, i + 1)]);
|
||||
const p = m[i * 16 ..][0..16].*;
|
||||
var e = xorBlocks(p, offset);
|
||||
aes_enc_ctx.encrypt(&e, &e);
|
||||
mem.copy(u8, c[i * 16 ..][0..16], &xorBlocks(e, offset));
|
||||
xorWith(&sum, p);
|
||||
}
|
||||
const leftover = m.len % 16;
|
||||
if (leftover > 0) {
|
||||
xorWith(&offset, lx.star);
|
||||
var pad = offset;
|
||||
aes_enc_ctx.encrypt(&pad, &pad);
|
||||
for (m[i * 16 ..]) |x, j| {
|
||||
c[i * 16 + j] = pad[j] ^ x;
|
||||
}
|
||||
var e = [_]u8{0} ** 16;
|
||||
mem.copy(u8, e[0..leftover], m[i * 16 ..][0..leftover]);
|
||||
e[leftover] = 0x80;
|
||||
xorWith(&sum, e);
|
||||
}
|
||||
var e = xorBlocks(xorBlocks(sum, offset), lx.dol);
|
||||
aes_enc_ctx.encrypt(&e, &e);
|
||||
tag.* = xorBlocks(e, hash(aes_enc_ctx, &lx, ad));
|
||||
}
|
||||
|
||||
/// m: message: output buffer should be of size c.len
|
||||
/// c: ciphertext
|
||||
/// tag: authentication tag
|
||||
/// ad: Associated Data
|
||||
/// npub: public nonce
|
||||
/// k: secret key
|
||||
pub fn decrypt(m: []u8, c: []const u8, tag: [tag_length]u8, ad: []const u8, npub: [nonce_length]u8, key: [key_length]u8) !void {
|
||||
assert(c.len == m.len);
|
||||
|
||||
const aes_enc_ctx = Aes.initEnc(key);
|
||||
const aes_dec_ctx = DecryptCtx.initFromEnc(aes_enc_ctx);
|
||||
const full_blocks: usize = m.len / 16;
|
||||
const x_max = if (full_blocks > 0) math.log2_int(usize, full_blocks) else 0;
|
||||
var lx = Lx.init(aes_enc_ctx);
|
||||
const lt = lx.precomp(x_max);
|
||||
|
||||
var offset = getOffset(aes_enc_ctx, npub);
|
||||
var sum = [_]u8{0} ** 16;
|
||||
var i: usize = 0;
|
||||
|
||||
while (wb > 0 and i + wb <= full_blocks) : (i += wb) {
|
||||
var offsets: [wb]Block align(16) = undefined;
|
||||
var es: [16 * wb]u8 align(16) = undefined;
|
||||
var j: usize = 0;
|
||||
while (j < wb) : (j += 1) {
|
||||
xorWith(&offset, lt[@ctz(usize, i + 1 + j)]);
|
||||
offsets[j] = offset;
|
||||
const q = c[(i + j) * 16 ..][0..16].*;
|
||||
mem.copy(u8, es[j * 16 ..][0..16], &xorBlocks(q, offsets[j]));
|
||||
}
|
||||
aes_dec_ctx.decryptWide(wb, &es, &es);
|
||||
j = 0;
|
||||
while (j < wb) : (j += 1) {
|
||||
const p = xorBlocks(es[j * 16 ..][0..16].*, offsets[j]);
|
||||
mem.copy(u8, m[(i + j) * 16 ..][0..16], &p);
|
||||
xorWith(&sum, p);
|
||||
}
|
||||
}
|
||||
while (i < full_blocks) : (i += 1) {
|
||||
xorWith(&offset, lt[@ctz(usize, i + 1)]);
|
||||
const q = c[i * 16 ..][0..16].*;
|
||||
var e = xorBlocks(q, offset);
|
||||
aes_dec_ctx.decrypt(&e, &e);
|
||||
const p = xorBlocks(e, offset);
|
||||
mem.copy(u8, m[i * 16 ..][0..16], &p);
|
||||
xorWith(&sum, p);
|
||||
}
|
||||
const leftover = m.len % 16;
|
||||
if (leftover > 0) {
|
||||
xorWith(&offset, lx.star);
|
||||
var pad = offset;
|
||||
aes_enc_ctx.encrypt(&pad, &pad);
|
||||
for (c[i * 16 ..]) |x, j| {
|
||||
m[i * 16 + j] = pad[j] ^ x;
|
||||
}
|
||||
var e = [_]u8{0} ** 16;
|
||||
mem.copy(u8, e[0..leftover], m[i * 16 ..][0..leftover]);
|
||||
e[leftover] = 0x80;
|
||||
xorWith(&sum, e);
|
||||
}
|
||||
var e = xorBlocks(xorBlocks(sum, offset), lx.dol);
|
||||
aes_enc_ctx.encrypt(&e, &e);
|
||||
var computed_tag = xorBlocks(e, hash(aes_enc_ctx, &lx, ad));
|
||||
const verify = crypto.utils.timingSafeEql([tag_length]u8, computed_tag, tag);
|
||||
crypto.utils.secureZero(u8, &computed_tag);
|
||||
if (!verify) {
|
||||
return error.AuthenticationFailed;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn xorBlocks(x: Block, y: Block) callconv(.Inline) Block {
|
||||
var z: Block = x;
|
||||
for (z) |*v, i| {
|
||||
v.* = x[i] ^ y[i];
|
||||
}
|
||||
return z;
|
||||
}
|
||||
|
||||
fn xorWith(x: *Block, y: Block) callconv(.Inline) void {
|
||||
for (x) |*v, i| {
|
||||
v.* ^= y[i];
|
||||
}
|
||||
}
|
||||
|
||||
const hexToBytes = std.fmt.hexToBytes;
|
||||
|
||||
test "AesOcb test vector 1" {
|
||||
var k: [Aes128Ocb.key_length]u8 = undefined;
|
||||
var nonce: [Aes128Ocb.nonce_length]u8 = undefined;
|
||||
var tag: [Aes128Ocb.tag_length]u8 = undefined;
|
||||
_ = try hexToBytes(&k, "000102030405060708090A0B0C0D0E0F");
|
||||
_ = try hexToBytes(&nonce, "BBAA99887766554433221100");
|
||||
|
||||
var c: [0]u8 = undefined;
|
||||
Aes128Ocb.encrypt(&c, &tag, "", "", nonce, k);
|
||||
|
||||
var expected_c: [c.len]u8 = undefined;
|
||||
var expected_tag: [tag.len]u8 = undefined;
|
||||
_ = try hexToBytes(&expected_tag, "785407BFFFC8AD9EDCC5520AC9111EE6");
|
||||
|
||||
var m: [0]u8 = undefined;
|
||||
try Aes128Ocb.decrypt(&m, "", tag, "", nonce, k);
|
||||
}
|
||||
|
||||
test "AesOcb test vector 2" {
|
||||
var k: [Aes128Ocb.key_length]u8 = undefined;
|
||||
var nonce: [Aes128Ocb.nonce_length]u8 = undefined;
|
||||
var tag: [Aes128Ocb.tag_length]u8 = undefined;
|
||||
var ad: [40]u8 = undefined;
|
||||
_ = try hexToBytes(&k, "000102030405060708090A0B0C0D0E0F");
|
||||
_ = try hexToBytes(&ad, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627");
|
||||
_ = try hexToBytes(&nonce, "BBAA9988776655443322110E");
|
||||
|
||||
var c: [0]u8 = undefined;
|
||||
Aes128Ocb.encrypt(&c, &tag, "", &ad, nonce, k);
|
||||
|
||||
var expected_tag: [tag.len]u8 = undefined;
|
||||
_ = try hexToBytes(&expected_tag, "C5CD9D1850C141E358649994EE701B68");
|
||||
|
||||
var m: [0]u8 = undefined;
|
||||
try Aes128Ocb.decrypt(&m, &c, tag, &ad, nonce, k);
|
||||
}
|
||||
|
||||
test "AesOcb test vector 3" {
|
||||
var k: [Aes128Ocb.key_length]u8 = undefined;
|
||||
var nonce: [Aes128Ocb.nonce_length]u8 = undefined;
|
||||
var tag: [Aes128Ocb.tag_length]u8 = undefined;
|
||||
var m: [40]u8 = undefined;
|
||||
var c: [m.len]u8 = undefined;
|
||||
_ = try hexToBytes(&k, "000102030405060708090A0B0C0D0E0F");
|
||||
_ = try hexToBytes(&m, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627");
|
||||
_ = try hexToBytes(&nonce, "BBAA9988776655443322110F");
|
||||
|
||||
Aes128Ocb.encrypt(&c, &tag, &m, "", nonce, k);
|
||||
|
||||
var expected_c: [c.len]u8 = undefined;
|
||||
var expected_tag: [tag.len]u8 = undefined;
|
||||
_ = try hexToBytes(&expected_tag, "479AD363AC366B95A98CA5F3000B1479");
|
||||
_ = try hexToBytes(&expected_c, "4412923493C57D5DE0D700F753CCE0D1D2D95060122E9F15A5DDBFC5787E50B5CC55EE507BCB084E");
|
||||
|
||||
var m2: [m.len]u8 = undefined;
|
||||
try Aes128Ocb.decrypt(&m2, &c, tag, "", nonce, k);
|
||||
assert(mem.eql(u8, &m, &m2));
|
||||
}
|
||||
|
||||
test "AesOcb test vector 4" {
|
||||
var k: [Aes128Ocb.key_length]u8 = undefined;
|
||||
var nonce: [Aes128Ocb.nonce_length]u8 = undefined;
|
||||
var tag: [Aes128Ocb.tag_length]u8 = undefined;
|
||||
var m: [40]u8 = undefined;
|
||||
var ad = m;
|
||||
var c: [m.len]u8 = undefined;
|
||||
_ = try hexToBytes(&k, "000102030405060708090A0B0C0D0E0F");
|
||||
_ = try hexToBytes(&m, "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627");
|
||||
_ = try hexToBytes(&nonce, "BBAA99887766554433221104");
|
||||
|
||||
Aes128Ocb.encrypt(&c, &tag, &m, &ad, nonce, k);
|
||||
|
||||
var expected_c: [c.len]u8 = undefined;
|
||||
var expected_tag: [tag.len]u8 = undefined;
|
||||
_ = try hexToBytes(&expected_tag, "3AD7A4FF3835B8C5701C1CCEC8FC3358");
|
||||
_ = try hexToBytes(&expected_c, "571D535B60B277188BE5147170A9A22C");
|
||||
|
||||
var m2: [m.len]u8 = undefined;
|
||||
try Aes128Ocb.decrypt(&m2, &c, tag, &ad, nonce, k);
|
||||
assert(mem.eql(u8, &m, &m2));
|
||||
}
|
@ -208,6 +208,8 @@ const aeads = [_]Crypto{
|
||||
Crypto{ .ty = crypto.aead.aegis.Aegis256, .name = "aegis-256" },
|
||||
Crypto{ .ty = crypto.aead.aes_gcm.Aes128Gcm, .name = "aes128-gcm" },
|
||||
Crypto{ .ty = crypto.aead.aes_gcm.Aes256Gcm, .name = "aes256-gcm" },
|
||||
Crypto{ .ty = crypto.aead.aes_ocb.Aes128Ocb, .name = "aes128-ocb" },
|
||||
Crypto{ .ty = crypto.aead.aes_ocb.Aes256Ocb, .name = "aes256-ocb" },
|
||||
Crypto{ .ty = crypto.aead.isap.IsapA128A, .name = "isapa128a" },
|
||||
};
|
||||
|
||||
@ -356,63 +358,63 @@ pub fn main() !void {
|
||||
inline for (hashes) |H| {
|
||||
if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) {
|
||||
const throughput = try benchmarkHash(H.ty, mode(128 * MiB));
|
||||
try stdout.print("{:>17}: {:10} MiB/s\n", .{ H.name, throughput / (1 * MiB) });
|
||||
try stdout.print("{s:>17}: {:10} MiB/s\n", .{ H.name, throughput / (1 * MiB) });
|
||||
}
|
||||
}
|
||||
|
||||
inline for (macs) |M| {
|
||||
if (filter == null or std.mem.indexOf(u8, M.name, filter.?) != null) {
|
||||
const throughput = try benchmarkMac(M.ty, mode(128 * MiB));
|
||||
try stdout.print("{:>17}: {:10} MiB/s\n", .{ M.name, throughput / (1 * MiB) });
|
||||
try stdout.print("{s:>17}: {:10} MiB/s\n", .{ M.name, throughput / (1 * MiB) });
|
||||
}
|
||||
}
|
||||
|
||||
inline for (exchanges) |E| {
|
||||
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
|
||||
const throughput = try benchmarkKeyExchange(E.ty, mode(1000));
|
||||
try stdout.print("{:>17}: {:10} exchanges/s\n", .{ E.name, throughput });
|
||||
try stdout.print("{s:>17}: {:10} exchanges/s\n", .{ E.name, throughput });
|
||||
}
|
||||
}
|
||||
|
||||
inline for (signatures) |E| {
|
||||
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
|
||||
const throughput = try benchmarkSignature(E.ty, mode(1000));
|
||||
try stdout.print("{:>17}: {:10} signatures/s\n", .{ E.name, throughput });
|
||||
try stdout.print("{s:>17}: {:10} signatures/s\n", .{ E.name, throughput });
|
||||
}
|
||||
}
|
||||
|
||||
inline for (signature_verifications) |E| {
|
||||
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
|
||||
const throughput = try benchmarkSignatureVerification(E.ty, mode(1000));
|
||||
try stdout.print("{:>17}: {:10} verifications/s\n", .{ E.name, throughput });
|
||||
try stdout.print("{s:>17}: {:10} verifications/s\n", .{ E.name, throughput });
|
||||
}
|
||||
}
|
||||
|
||||
inline for (batch_signature_verifications) |E| {
|
||||
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
|
||||
const throughput = try benchmarkBatchSignatureVerification(E.ty, mode(1000));
|
||||
try stdout.print("{:>17}: {:10} verifications/s (batch)\n", .{ E.name, throughput });
|
||||
try stdout.print("{s:>17}: {:10} verifications/s (batch)\n", .{ E.name, throughput });
|
||||
}
|
||||
}
|
||||
|
||||
inline for (aeads) |E| {
|
||||
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
|
||||
const throughput = try benchmarkAead(E.ty, mode(128 * MiB));
|
||||
try stdout.print("{:>17}: {:10} MiB/s\n", .{ E.name, throughput / (1 * MiB) });
|
||||
try stdout.print("{s:>17}: {:10} MiB/s\n", .{ E.name, throughput / (1 * MiB) });
|
||||
}
|
||||
}
|
||||
|
||||
inline for (aes) |E| {
|
||||
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
|
||||
const throughput = try benchmarkAes(E.ty, mode(100000000));
|
||||
try stdout.print("{:>17}: {:10} ops/s\n", .{ E.name, throughput });
|
||||
try stdout.print("{s:>17}: {:10} ops/s\n", .{ E.name, throughput });
|
||||
}
|
||||
}
|
||||
|
||||
inline for (aes8) |E| {
|
||||
if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) {
|
||||
const throughput = try benchmarkAes8(E.ty, mode(10000000));
|
||||
try stdout.print("{:>17}: {:10} ops/s\n", .{ E.name, throughput });
|
||||
try stdout.print("{s:>17}: {:10} ops/s\n", .{ E.name, throughput });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ pub const Loop = struct {
|
||||
errdefer self.deinitOsData();
|
||||
|
||||
if (!builtin.single_threaded) {
|
||||
self.fs_thread = try Thread.spawn(self, posixFsRun);
|
||||
self.fs_thread = try Thread.spawn(posixFsRun, self);
|
||||
}
|
||||
errdefer if (!builtin.single_threaded) {
|
||||
self.posixFsRequest(&self.fs_end_request);
|
||||
@ -264,7 +264,7 @@ pub const Loop = struct {
|
||||
}
|
||||
}
|
||||
while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
|
||||
self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);
|
||||
self.extra_threads[extra_thread_index] = try Thread.spawn(workerRun, self);
|
||||
}
|
||||
},
|
||||
.macos, .freebsd, .netbsd, .dragonfly, .openbsd => {
|
||||
@ -329,7 +329,7 @@ pub const Loop = struct {
|
||||
}
|
||||
}
|
||||
while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
|
||||
self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);
|
||||
self.extra_threads[extra_thread_index] = try Thread.spawn(workerRun, self);
|
||||
}
|
||||
},
|
||||
.windows => {
|
||||
@ -378,7 +378,7 @@ pub const Loop = struct {
|
||||
}
|
||||
}
|
||||
while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
|
||||
self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);
|
||||
self.extra_threads[extra_thread_index] = try Thread.spawn(workerRun, self);
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
@ -798,7 +798,7 @@ pub const Loop = struct {
|
||||
.event = std.Thread.AutoResetEvent{},
|
||||
.is_running = true,
|
||||
// Must be last so that it can read the other state, such as `is_running`.
|
||||
.thread = try std.Thread.spawn(self, DelayQueue.run),
|
||||
.thread = try std.Thread.spawn(DelayQueue.run, self),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -39,8 +39,8 @@ pub fn isSep(byte: u8) bool {
|
||||
|
||||
/// This is different from mem.join in that the separator will not be repeated if
|
||||
/// it is found at the end or beginning of a pair of consecutive paths.
|
||||
fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, paths: []const []const u8) ![]u8 {
|
||||
if (paths.len == 0) return &[0]u8{};
|
||||
fn joinSepMaybeZ(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, paths: []const []const u8, zero: bool) ![]u8 {
|
||||
if (paths.len == 0) return if (zero) try allocator.dupe(u8, &[1]u8{0}) else &[0]u8{};
|
||||
|
||||
const total_len = blk: {
|
||||
var sum: usize = paths[0].len;
|
||||
@ -53,6 +53,7 @@ fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, pat
|
||||
sum += @boolToInt(!prev_sep and !this_sep);
|
||||
sum += if (prev_sep and this_sep) this_path.len - 1 else this_path.len;
|
||||
}
|
||||
if (zero) sum += 1;
|
||||
break :blk sum;
|
||||
};
|
||||
|
||||
@ -76,6 +77,8 @@ fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, pat
|
||||
buf_index += adjusted_path.len;
|
||||
}
|
||||
|
||||
if (zero) buf[buf.len - 1] = 0;
|
||||
|
||||
// No need for shrink since buf is exactly the correct size.
|
||||
return buf;
|
||||
}
|
||||
@ -83,60 +86,73 @@ fn joinSep(allocator: *Allocator, separator: u8, sepPredicate: fn (u8) bool, pat
|
||||
/// Naively combines a series of paths with the native path seperator.
|
||||
/// Allocates memory for the result, which must be freed by the caller.
|
||||
pub fn join(allocator: *Allocator, paths: []const []const u8) ![]u8 {
|
||||
return joinSep(allocator, sep, isSep, paths);
|
||||
return joinSepMaybeZ(allocator, sep, isSep, paths, false);
|
||||
}
|
||||
|
||||
fn testJoinWindows(paths: []const []const u8, expected: []const u8) void {
|
||||
/// Naively combines a series of paths with the native path seperator and null terminator.
|
||||
/// Allocates memory for the result, which must be freed by the caller.
|
||||
pub fn joinZ(allocator: *Allocator, paths: []const []const u8) ![:0]u8 {
|
||||
const out = joinSepMaybeZ(allocator, sep, isSep, paths, true);
|
||||
return out[0 .. out.len - 1 :0];
|
||||
}
|
||||
|
||||
fn testJoinMaybeZWindows(paths: []const []const u8, expected: []const u8, zero: bool) void {
|
||||
const windowsIsSep = struct {
|
||||
fn isSep(byte: u8) bool {
|
||||
return byte == '/' or byte == '\\';
|
||||
}
|
||||
}.isSep;
|
||||
const actual = joinSep(testing.allocator, sep_windows, windowsIsSep, paths) catch @panic("fail");
|
||||
const actual = joinSepMaybeZ(testing.allocator, sep_windows, windowsIsSep, paths, zero) catch @panic("fail");
|
||||
defer testing.allocator.free(actual);
|
||||
testing.expectEqualSlices(u8, expected, actual);
|
||||
testing.expectEqualSlices(u8, expected, if (zero) actual[0 .. actual.len - 1 :0] else actual);
|
||||
}
|
||||
|
||||
fn testJoinPosix(paths: []const []const u8, expected: []const u8) void {
|
||||
fn testJoinMaybeZPosix(paths: []const []const u8, expected: []const u8, zero: bool) void {
|
||||
const posixIsSep = struct {
|
||||
fn isSep(byte: u8) bool {
|
||||
return byte == '/';
|
||||
}
|
||||
}.isSep;
|
||||
const actual = joinSep(testing.allocator, sep_posix, posixIsSep, paths) catch @panic("fail");
|
||||
const actual = joinSepMaybeZ(testing.allocator, sep_posix, posixIsSep, paths, zero) catch @panic("fail");
|
||||
defer testing.allocator.free(actual);
|
||||
testing.expectEqualSlices(u8, expected, actual);
|
||||
testing.expectEqualSlices(u8, expected, if (zero) actual[0 .. actual.len - 1 :0] else actual);
|
||||
}
|
||||
|
||||
test "join" {
|
||||
testJoinWindows(&[_][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c");
|
||||
testJoinWindows(&[_][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c");
|
||||
testJoinWindows(&[_][]const u8{ "c:\\a\\b\\", "c" }, "c:\\a\\b\\c");
|
||||
for (&[_]bool{ false, true }) |zero| {
|
||||
testJoinMaybeZWindows(&[_][]const u8{}, "", zero);
|
||||
testJoinMaybeZWindows(&[_][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c", zero);
|
||||
testJoinMaybeZWindows(&[_][]const u8{ "c:\\a\\b", "c" }, "c:\\a\\b\\c", zero);
|
||||
testJoinMaybeZWindows(&[_][]const u8{ "c:\\a\\b\\", "c" }, "c:\\a\\b\\c", zero);
|
||||
|
||||
testJoinWindows(&[_][]const u8{ "c:\\", "a", "b\\", "c" }, "c:\\a\\b\\c");
|
||||
testJoinWindows(&[_][]const u8{ "c:\\a\\", "b\\", "c" }, "c:\\a\\b\\c");
|
||||
testJoinMaybeZWindows(&[_][]const u8{ "c:\\", "a", "b\\", "c" }, "c:\\a\\b\\c", zero);
|
||||
testJoinMaybeZWindows(&[_][]const u8{ "c:\\a\\", "b\\", "c" }, "c:\\a\\b\\c", zero);
|
||||
|
||||
testJoinWindows(
|
||||
&[_][]const u8{ "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std", "io.zig" },
|
||||
"c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig",
|
||||
);
|
||||
testJoinMaybeZWindows(
|
||||
&[_][]const u8{ "c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std", "io.zig" },
|
||||
"c:\\home\\andy\\dev\\zig\\build\\lib\\zig\\std\\io.zig",
|
||||
zero,
|
||||
);
|
||||
|
||||
testJoinWindows(&[_][]const u8{ "c:\\", "a", "b/", "c" }, "c:\\a\\b/c");
|
||||
testJoinWindows(&[_][]const u8{ "c:\\a/", "b\\", "/c" }, "c:\\a/b\\c");
|
||||
testJoinMaybeZWindows(&[_][]const u8{ "c:\\", "a", "b/", "c" }, "c:\\a\\b/c", zero);
|
||||
testJoinMaybeZWindows(&[_][]const u8{ "c:\\a/", "b\\", "/c" }, "c:\\a/b\\c", zero);
|
||||
|
||||
testJoinPosix(&[_][]const u8{ "/a/b", "c" }, "/a/b/c");
|
||||
testJoinPosix(&[_][]const u8{ "/a/b/", "c" }, "/a/b/c");
|
||||
testJoinMaybeZPosix(&[_][]const u8{}, "", zero);
|
||||
testJoinMaybeZPosix(&[_][]const u8{ "/a/b", "c" }, "/a/b/c", zero);
|
||||
testJoinMaybeZPosix(&[_][]const u8{ "/a/b/", "c" }, "/a/b/c", zero);
|
||||
|
||||
testJoinPosix(&[_][]const u8{ "/", "a", "b/", "c" }, "/a/b/c");
|
||||
testJoinPosix(&[_][]const u8{ "/a/", "b/", "c" }, "/a/b/c");
|
||||
testJoinMaybeZPosix(&[_][]const u8{ "/", "a", "b/", "c" }, "/a/b/c", zero);
|
||||
testJoinMaybeZPosix(&[_][]const u8{ "/a/", "b/", "c" }, "/a/b/c", zero);
|
||||
|
||||
testJoinPosix(
|
||||
&[_][]const u8{ "/home/andy/dev/zig/build/lib/zig/std", "io.zig" },
|
||||
"/home/andy/dev/zig/build/lib/zig/std/io.zig",
|
||||
);
|
||||
testJoinMaybeZPosix(
|
||||
&[_][]const u8{ "/home/andy/dev/zig/build/lib/zig/std", "io.zig" },
|
||||
"/home/andy/dev/zig/build/lib/zig/std/io.zig",
|
||||
zero,
|
||||
);
|
||||
|
||||
testJoinPosix(&[_][]const u8{ "a", "/c" }, "a/c");
|
||||
testJoinPosix(&[_][]const u8{ "a/", "/c" }, "a/c");
|
||||
testJoinMaybeZPosix(&[_][]const u8{ "a", "/c" }, "a/c", zero);
|
||||
testJoinMaybeZPosix(&[_][]const u8{ "a/", "/c" }, "a/c", zero);
|
||||
}
|
||||
}
|
||||
|
||||
pub const isAbsoluteC = @compileError("deprecated: renamed to isAbsoluteZ");
|
||||
@ -1210,7 +1226,7 @@ fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []cons
|
||||
/// pointer address range of `path`, even if it is length zero.
|
||||
pub fn extension(path: []const u8) []const u8 {
|
||||
const filename = basename(path);
|
||||
const index = mem.lastIndexOf(u8, filename, ".") orelse return path[path.len..];
|
||||
const index = mem.lastIndexOfScalar(u8, filename, '.') orelse return path[path.len..];
|
||||
if (index == 0) return path[path.len..];
|
||||
return filename[index..];
|
||||
}
|
||||
|
@ -762,7 +762,7 @@ test "open file with exclusive lock twice, make sure it waits" {
|
||||
try evt.init();
|
||||
defer evt.deinit();
|
||||
|
||||
const t = try std.Thread.spawn(S.C{ .dir = &tmp.dir, .evt = &evt }, S.checkFn);
|
||||
const t = try std.Thread.spawn(S.checkFn, S.C{ .dir = &tmp.dir, .evt = &evt });
|
||||
defer t.wait();
|
||||
|
||||
const SLEEP_TIMEOUT_NS = 10 * std.time.ns_per_ms;
|
||||
|
@ -563,7 +563,6 @@ pub fn HashMapUnmanaged(
|
||||
}
|
||||
|
||||
/// Insert an entry if the associated key is not already present, otherwise update preexisting value.
|
||||
/// Returns true if the key was already present.
|
||||
pub fn put(self: *Self, allocator: *Allocator, key: K, value: V) !void {
|
||||
const result = try self.getOrPut(allocator, key);
|
||||
result.entry.value = value;
|
||||
@ -1116,7 +1115,7 @@ test "std.hash_map put" {
|
||||
|
||||
var i: u32 = 0;
|
||||
while (i < 16) : (i += 1) {
|
||||
_ = try map.put(i, i);
|
||||
try map.put(i, i);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
|
@ -2077,27 +2077,27 @@ pub const Parser = struct {
|
||||
p.state = .ArrayValue;
|
||||
},
|
||||
.String => |s| {
|
||||
_ = try object.put(key, try p.parseString(allocator, s, input, i));
|
||||
try object.put(key, try p.parseString(allocator, s, input, i));
|
||||
_ = p.stack.pop();
|
||||
p.state = .ObjectKey;
|
||||
},
|
||||
.Number => |n| {
|
||||
_ = try object.put(key, try p.parseNumber(n, input, i));
|
||||
try object.put(key, try p.parseNumber(n, input, i));
|
||||
_ = p.stack.pop();
|
||||
p.state = .ObjectKey;
|
||||
},
|
||||
.True => {
|
||||
_ = try object.put(key, Value{ .Bool = true });
|
||||
try object.put(key, Value{ .Bool = true });
|
||||
_ = p.stack.pop();
|
||||
p.state = .ObjectKey;
|
||||
},
|
||||
.False => {
|
||||
_ = try object.put(key, Value{ .Bool = false });
|
||||
try object.put(key, Value{ .Bool = false });
|
||||
_ = p.stack.pop();
|
||||
p.state = .ObjectKey;
|
||||
},
|
||||
.Null => {
|
||||
_ = try object.put(key, Value.Null);
|
||||
try object.put(key, Value.Null);
|
||||
_ = p.stack.pop();
|
||||
p.state = .ObjectKey;
|
||||
},
|
||||
@ -2184,7 +2184,7 @@ pub const Parser = struct {
|
||||
_ = p.stack.pop();
|
||||
|
||||
var object = &p.stack.items[p.stack.items.len - 1].Object;
|
||||
_ = try object.put(key, value.*);
|
||||
try object.put(key, value.*);
|
||||
p.state = .ObjectKey;
|
||||
},
|
||||
// Array Parent -> [ ..., <array>, value ]
|
||||
|
@ -293,7 +293,7 @@ test "json write stream" {
|
||||
|
||||
fn getJsonObject(allocator: *std.mem.Allocator) !std.json.Value {
|
||||
var value = std.json.Value{ .Object = std.json.ObjectMap.init(allocator) };
|
||||
_ = try value.Object.put("one", std.json.Value{ .Integer = @intCast(i64, 1) });
|
||||
_ = try value.Object.put("two", std.json.Value{ .Float = 2.0 });
|
||||
try value.Object.put("one", std.json.Value{ .Integer = @intCast(i64, 1) });
|
||||
try value.Object.put("two", std.json.Value{ .Float = 2.0 });
|
||||
return value;
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ test "listen on a port, send bytes, receive bytes" {
|
||||
}
|
||||
};
|
||||
|
||||
const t = try std.Thread.spawn(server.listen_address, S.clientFn);
|
||||
const t = try std.Thread.spawn(S.clientFn, server.listen_address);
|
||||
defer t.wait();
|
||||
|
||||
var client = try server.accept();
|
||||
@ -285,7 +285,7 @@ test "listen on a unix socket, send bytes, receive bytes" {
|
||||
}
|
||||
};
|
||||
|
||||
const t = try std.Thread.spawn({}, S.clientFn);
|
||||
const t = try std.Thread.spawn(S.clientFn, {});
|
||||
defer t.wait();
|
||||
|
||||
var client = try server.accept();
|
||||
|
@ -59,11 +59,11 @@ test "Once executes its function just once" {
|
||||
defer for (threads) |handle| handle.wait();
|
||||
|
||||
for (threads) |*handle| {
|
||||
handle.* = try std.Thread.spawn(@as(u8, 0), struct {
|
||||
handle.* = try std.Thread.spawn(struct {
|
||||
fn thread_fn(x: u8) void {
|
||||
global_once.call();
|
||||
}
|
||||
}.thread_fn);
|
||||
}.thread_fn, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4840,7 +4840,7 @@ pub const SendError = error{
|
||||
NetworkSubsystemFailed,
|
||||
} || UnexpectedError;
|
||||
|
||||
pub const SendToError = SendError || error{
|
||||
pub const SendMsgError = SendError || error{
|
||||
/// The passed address didn't have the correct address family in its sa_family field.
|
||||
AddressFamilyNotSupported,
|
||||
|
||||
@ -4859,6 +4859,79 @@ pub const SendToError = SendError || error{
|
||||
AddressNotAvailable,
|
||||
};
|
||||
|
||||
pub fn sendmsg(
|
||||
/// The file descriptor of the sending socket.
|
||||
sockfd: socket_t,
|
||||
/// Message header and iovecs
|
||||
msg: msghdr_const,
|
||||
flags: u32,
|
||||
) SendMsgError!usize {
|
||||
while (true) {
|
||||
const rc = system.sendmsg(sockfd, &msg, flags);
|
||||
if (builtin.os.tag == .windows) {
|
||||
if (rc == windows.ws2_32.SOCKET_ERROR) {
|
||||
switch (windows.ws2_32.WSAGetLastError()) {
|
||||
.WSAEACCES => return error.AccessDenied,
|
||||
.WSAEADDRNOTAVAIL => return error.AddressNotAvailable,
|
||||
.WSAECONNRESET => return error.ConnectionResetByPeer,
|
||||
.WSAEMSGSIZE => return error.MessageTooBig,
|
||||
.WSAENOBUFS => return error.SystemResources,
|
||||
.WSAENOTSOCK => return error.FileDescriptorNotASocket,
|
||||
.WSAEAFNOSUPPORT => return error.AddressFamilyNotSupported,
|
||||
.WSAEDESTADDRREQ => unreachable, // A destination address is required.
|
||||
.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.
|
||||
.WSAEHOSTUNREACH => return error.NetworkUnreachable,
|
||||
// TODO: WSAEINPROGRESS, WSAEINTR
|
||||
.WSAEINVAL => unreachable,
|
||||
.WSAENETDOWN => return error.NetworkSubsystemFailed,
|
||||
.WSAENETRESET => return error.ConnectionResetByPeer,
|
||||
.WSAENETUNREACH => return error.NetworkUnreachable,
|
||||
.WSAENOTCONN => return error.SocketNotConnected,
|
||||
.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.
|
||||
.WSAEWOULDBLOCK => return error.WouldBlock,
|
||||
.WSANOTINITIALISED => unreachable, // A successful WSAStartup call must occur before using this function.
|
||||
else => |err| return windows.unexpectedWSAError(err),
|
||||
}
|
||||
} else {
|
||||
return @intCast(usize, rc);
|
||||
}
|
||||
} else {
|
||||
switch (errno(rc)) {
|
||||
0 => return @intCast(usize, rc),
|
||||
|
||||
EACCES => return error.AccessDenied,
|
||||
EAGAIN => return error.WouldBlock,
|
||||
EALREADY => return error.FastOpenAlreadyInProgress,
|
||||
EBADF => unreachable, // always a race condition
|
||||
ECONNRESET => return error.ConnectionResetByPeer,
|
||||
EDESTADDRREQ => unreachable, // The socket is not connection-mode, and no peer address is set.
|
||||
EFAULT => unreachable, // An invalid user space address was specified for an argument.
|
||||
EINTR => continue,
|
||||
EINVAL => unreachable, // Invalid argument passed.
|
||||
EISCONN => unreachable, // connection-mode socket was connected already but a recipient was specified
|
||||
EMSGSIZE => return error.MessageTooBig,
|
||||
ENOBUFS => return error.SystemResources,
|
||||
ENOMEM => return error.SystemResources,
|
||||
ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
|
||||
EOPNOTSUPP => unreachable, // Some bit in the flags argument is inappropriate for the socket type.
|
||||
EPIPE => return error.BrokenPipe,
|
||||
EAFNOSUPPORT => return error.AddressFamilyNotSupported,
|
||||
ELOOP => return error.SymLinkLoop,
|
||||
ENAMETOOLONG => return error.NameTooLong,
|
||||
ENOENT => return error.FileNotFound,
|
||||
ENOTDIR => return error.NotDir,
|
||||
EHOSTUNREACH => return error.NetworkUnreachable,
|
||||
ENETUNREACH => return error.NetworkUnreachable,
|
||||
ENOTCONN => return error.SocketNotConnected,
|
||||
ENETDOWN => return error.NetworkSubsystemFailed,
|
||||
else => |err| return unexpectedErrno(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const SendToError = SendMsgError;
|
||||
|
||||
/// Transmit a message to another socket.
|
||||
///
|
||||
/// The `sendto` call may be used only when the socket is in a connected state (so that the intended
|
||||
|
@ -400,10 +400,10 @@ pub const msghdr = extern struct {
|
||||
msg_namelen: socklen_t,
|
||||
msg_iov: [*]iovec,
|
||||
msg_iovlen: i32,
|
||||
__pad1: i32,
|
||||
__pad1: i32 = 0,
|
||||
msg_control: ?*c_void,
|
||||
msg_controllen: socklen_t,
|
||||
__pad2: socklen_t,
|
||||
__pad2: socklen_t = 0,
|
||||
msg_flags: i32,
|
||||
};
|
||||
|
||||
@ -412,10 +412,10 @@ pub const msghdr_const = extern struct {
|
||||
msg_namelen: socklen_t,
|
||||
msg_iov: [*]iovec_const,
|
||||
msg_iovlen: i32,
|
||||
__pad1: i32,
|
||||
__pad1: i32 = 0,
|
||||
msg_control: ?*c_void,
|
||||
msg_controllen: socklen_t,
|
||||
__pad2: socklen_t,
|
||||
__pad2: socklen_t = 0,
|
||||
msg_flags: i32,
|
||||
};
|
||||
|
||||
|
@ -495,10 +495,10 @@ pub const msghdr = extern struct {
|
||||
msg_namelen: socklen_t,
|
||||
msg_iov: [*]iovec,
|
||||
msg_iovlen: i32,
|
||||
__pad1: i32,
|
||||
__pad1: i32 = 0,
|
||||
msg_control: ?*c_void,
|
||||
msg_controllen: socklen_t,
|
||||
__pad2: socklen_t,
|
||||
__pad2: socklen_t = 0,
|
||||
msg_flags: i32,
|
||||
};
|
||||
|
||||
@ -507,10 +507,10 @@ pub const msghdr_const = extern struct {
|
||||
msg_namelen: socklen_t,
|
||||
msg_iov: [*]iovec_const,
|
||||
msg_iovlen: i32,
|
||||
__pad1: i32,
|
||||
__pad1: i32 = 0,
|
||||
msg_control: ?*c_void,
|
||||
msg_controllen: socklen_t,
|
||||
__pad2: socklen_t,
|
||||
__pad2: socklen_t = 0,
|
||||
msg_flags: i32,
|
||||
};
|
||||
|
||||
|
@ -977,7 +977,7 @@ pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noal
|
||||
return syscall5(.getsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
|
||||
}
|
||||
|
||||
pub fn sendmsg(fd: i32, msg: *msghdr_const, flags: u32) usize {
|
||||
pub fn sendmsg(fd: i32, msg: *const msghdr_const, flags: u32) usize {
|
||||
if (builtin.arch == .i386) {
|
||||
return socketcall(SC_sendmsg, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags });
|
||||
}
|
||||
|
@ -317,7 +317,7 @@ test "std.Thread.getCurrentId" {
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
|
||||
var thread_current_id: Thread.Id = undefined;
|
||||
const thread = try Thread.spawn(&thread_current_id, testThreadIdFn);
|
||||
const thread = try Thread.spawn(testThreadIdFn, &thread_current_id);
|
||||
const thread_id = thread.handle();
|
||||
thread.wait();
|
||||
if (Thread.use_pthreads) {
|
||||
@ -336,10 +336,10 @@ test "spawn threads" {
|
||||
|
||||
var shared_ctx: i32 = 1;
|
||||
|
||||
const thread1 = try Thread.spawn({}, start1);
|
||||
const thread2 = try Thread.spawn(&shared_ctx, start2);
|
||||
const thread3 = try Thread.spawn(&shared_ctx, start2);
|
||||
const thread4 = try Thread.spawn(&shared_ctx, start2);
|
||||
const thread1 = try Thread.spawn(start1, {});
|
||||
const thread2 = try Thread.spawn(start2, &shared_ctx);
|
||||
const thread3 = try Thread.spawn(start2, &shared_ctx);
|
||||
const thread4 = try Thread.spawn(start2, &shared_ctx);
|
||||
|
||||
thread1.wait();
|
||||
thread2.wait();
|
||||
@ -367,8 +367,8 @@ test "cpu count" {
|
||||
|
||||
test "thread local storage" {
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
const thread1 = try Thread.spawn({}, testTls);
|
||||
const thread2 = try Thread.spawn({}, testTls);
|
||||
const thread1 = try Thread.spawn(testTls, {});
|
||||
const thread2 = try Thread.spawn(testTls, {});
|
||||
testTls({});
|
||||
thread1.wait();
|
||||
thread2.wait();
|
||||
|
@ -1291,6 +1291,19 @@ pub fn getsockname(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.so
|
||||
return ws2_32.getsockname(s, name, @ptrCast(*i32, namelen));
|
||||
}
|
||||
|
||||
pub fn sendmsg(
|
||||
s: ws2_32.SOCKET,
|
||||
msg: *const ws2_32.WSAMSG,
|
||||
flags: u32,
|
||||
) i32 {
|
||||
var bytes_send: DWORD = undefined;
|
||||
if (ws2_32.WSASendMsg(s, msg, flags, &bytes_send, null, null) == ws2_32.SOCKET_ERROR) {
|
||||
return ws2_32.SOCKET_ERROR;
|
||||
} else {
|
||||
return @as(i32, @intCast(u31, bytes_send));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sendto(s: ws2_32.SOCKET, buf: [*]const u8, len: usize, flags: u32, to: ?*const ws2_32.sockaddr, to_len: ws2_32.socklen_t) i32 {
|
||||
var buffer = ws2_32.WSABUF{ .len = @truncate(u31, len), .buf = @intToPtr([*]u8, @ptrToInt(buf)) };
|
||||
var bytes_send: DWORD = undefined;
|
||||
|
@ -410,7 +410,7 @@ test "std.PriorityQueue: iterator" {
|
||||
const items = [_]u32{ 54, 12, 7, 23, 25, 13 };
|
||||
for (items) |e| {
|
||||
_ = try queue.add(e);
|
||||
_ = try map.put(e, {});
|
||||
try map.put(e, {});
|
||||
}
|
||||
|
||||
var it = queue.iterator();
|
||||
|
@ -4101,7 +4101,6 @@ pub fn namedFieldPtr(
|
||||
scope.arena(),
|
||||
try Value.Tag.@"error".create(scope.arena(), .{
|
||||
.name = entry.key,
|
||||
.value = entry.value,
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
@ -74,7 +74,7 @@ pub fn init(self: *ThreadPool, allocator: *std.mem.Allocator) !void {
|
||||
try worker.idle_node.data.init();
|
||||
errdefer worker.idle_node.data.deinit();
|
||||
|
||||
worker.thread = try std.Thread.spawn(worker, Worker.run);
|
||||
worker.thread = try std.Thread.spawn(Worker.run, worker);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -432,6 +432,9 @@ pub const FieldDecl = opaque {
|
||||
|
||||
pub const getLocation = ZigClangFieldDecl_getLocation;
|
||||
extern fn ZigClangFieldDecl_getLocation(*const FieldDecl) SourceLocation;
|
||||
|
||||
pub const getParent = ZigClangFieldDecl_getParent;
|
||||
extern fn ZigClangFieldDecl_getParent(*const FieldDecl) ?*const RecordDecl;
|
||||
};
|
||||
|
||||
pub const FileID = opaque {};
|
||||
@ -593,6 +596,34 @@ pub const TypeOfExprType = opaque {
|
||||
extern fn ZigClangTypeOfExprType_getUnderlyingExpr(*const TypeOfExprType) *const Expr;
|
||||
};
|
||||
|
||||
pub const OffsetOfNode = opaque {
|
||||
pub const getKind = ZigClangOffsetOfNode_getKind;
|
||||
extern fn ZigClangOffsetOfNode_getKind(*const OffsetOfNode) OffsetOfNode_Kind;
|
||||
|
||||
pub const getArrayExprIndex = ZigClangOffsetOfNode_getArrayExprIndex;
|
||||
extern fn ZigClangOffsetOfNode_getArrayExprIndex(*const OffsetOfNode) c_uint;
|
||||
|
||||
pub const getField = ZigClangOffsetOfNode_getField;
|
||||
extern fn ZigClangOffsetOfNode_getField(*const OffsetOfNode) *FieldDecl;
|
||||
};
|
||||
|
||||
pub const OffsetOfExpr = opaque {
|
||||
pub const getNumComponents = ZigClangOffsetOfExpr_getNumComponents;
|
||||
extern fn ZigClangOffsetOfExpr_getNumComponents(*const OffsetOfExpr) c_uint;
|
||||
|
||||
pub const getNumExpressions = ZigClangOffsetOfExpr_getNumExpressions;
|
||||
extern fn ZigClangOffsetOfExpr_getNumExpressions(*const OffsetOfExpr) c_uint;
|
||||
|
||||
pub const getIndexExpr = ZigClangOffsetOfExpr_getIndexExpr;
|
||||
extern fn ZigClangOffsetOfExpr_getIndexExpr(*const OffsetOfExpr, idx: c_uint) *const Expr;
|
||||
|
||||
pub const getComponent = ZigClangOffsetOfExpr_getComponent;
|
||||
extern fn ZigClangOffsetOfExpr_getComponent(*const OffsetOfExpr, idx: c_uint) *const OffsetOfNode;
|
||||
|
||||
pub const getBeginLoc = ZigClangOffsetOfExpr_getBeginLoc;
|
||||
extern fn ZigClangOffsetOfExpr_getBeginLoc(*const OffsetOfExpr) SourceLocation;
|
||||
};
|
||||
|
||||
pub const MemberExpr = opaque {
|
||||
pub const getBase = ZigClangMemberExpr_getBase;
|
||||
extern fn ZigClangMemberExpr_getBase(*const MemberExpr) *const Expr;
|
||||
@ -1662,6 +1693,13 @@ pub const UnaryExprOrTypeTrait_Kind = extern enum {
|
||||
PreferredAlignOf,
|
||||
};
|
||||
|
||||
pub const OffsetOfNode_Kind = extern enum {
|
||||
Array,
|
||||
Field,
|
||||
Identifier,
|
||||
Base,
|
||||
};
|
||||
|
||||
pub const Stage2ErrorMsg = extern struct {
|
||||
filename_ptr: ?[*]const u8,
|
||||
filename_len: usize,
|
||||
|
@ -2165,7 +2165,7 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
|
||||
// is desired for both.
|
||||
_ = self.dbg_line_fn_free_list.remove(&decl.fn_link.elf);
|
||||
if (decl.fn_link.elf.prev) |prev| {
|
||||
_ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
|
||||
self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
|
||||
prev.next = decl.fn_link.elf.next;
|
||||
if (decl.fn_link.elf.next) |next| {
|
||||
next.prev = prev;
|
||||
@ -2423,7 +2423,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
|
||||
if (src_fn.off + src_fn.len + min_nop_size > next.off) {
|
||||
// It grew too big, so we move it to a new location.
|
||||
if (src_fn.prev) |prev| {
|
||||
_ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
|
||||
self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
|
||||
prev.next = src_fn.next;
|
||||
}
|
||||
assert(src_fn.prev != next);
|
||||
@ -2579,7 +2579,7 @@ fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) !
|
||||
if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) {
|
||||
// It grew too big, so we move it to a new location.
|
||||
if (text_block.dbg_info_prev) |prev| {
|
||||
_ = self.dbg_info_decl_free_list.put(self.base.allocator, prev, {}) catch {};
|
||||
self.dbg_info_decl_free_list.put(self.base.allocator, prev, {}) catch {};
|
||||
prev.dbg_info_next = text_block.dbg_info_next;
|
||||
}
|
||||
next.dbg_info_prev = text_block.dbg_info_prev;
|
||||
|
@ -1096,7 +1096,7 @@ pub fn commitDeclDebugInfo(
|
||||
if (src_fn.off + src_fn.len + min_nop_size > next.off) {
|
||||
// It grew too big, so we move it to a new location.
|
||||
if (src_fn.prev) |prev| {
|
||||
_ = self.dbg_line_fn_free_list.put(allocator, prev, {}) catch {};
|
||||
self.dbg_line_fn_free_list.put(allocator, prev, {}) catch {};
|
||||
prev.next = src_fn.next;
|
||||
}
|
||||
next.prev = src_fn.prev;
|
||||
@ -1256,7 +1256,7 @@ fn updateDeclDebugInfoAllocation(
|
||||
if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) {
|
||||
// It grew too big, so we move it to a new location.
|
||||
if (text_block.dbg_info_prev) |prev| {
|
||||
_ = self.dbg_info_decl_free_list.put(allocator, prev, {}) catch {};
|
||||
self.dbg_info_decl_free_list.put(allocator, prev, {}) catch {};
|
||||
prev.dbg_info_next = text_block.dbg_info_next;
|
||||
}
|
||||
next.dbg_info_prev = text_block.dbg_info_prev;
|
||||
|
@ -119,7 +119,7 @@ fn analyzeInst(
|
||||
if (!else_table.contains(then_death)) {
|
||||
try else_entry_deaths.append(then_death);
|
||||
}
|
||||
_ = try table.put(then_death, {});
|
||||
try table.put(then_death, {});
|
||||
}
|
||||
}
|
||||
// Now we have to correctly populate new_set.
|
||||
@ -195,7 +195,7 @@ fn analyzeInst(
|
||||
}
|
||||
}
|
||||
// undo resetting the table
|
||||
_ = try table.put(case_death, {});
|
||||
try table.put(case_death, {});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -377,7 +377,7 @@ fn prepopulateGlobalNameTable(ast_unit: *clang.ASTUnit, c: *Context) !void {
|
||||
const macro = @ptrCast(*clang.MacroDefinitionRecord, entity);
|
||||
const raw_name = macro.getName_getNameStart();
|
||||
const name = try c.str(raw_name);
|
||||
_ = try c.global_names.put(c.gpa, name, {});
|
||||
try c.global_names.put(c.gpa, name, {});
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
@ -399,7 +399,7 @@ fn declVisitorC(context: ?*c_void, decl: *const clang.Decl) callconv(.C) bool {
|
||||
fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void {
|
||||
if (decl.castToNamedDecl()) |named_decl| {
|
||||
const decl_name = try c.str(named_decl.getName_bytes_begin());
|
||||
_ = try c.global_names.put(c.gpa, decl_name, {});
|
||||
try c.global_names.put(c.gpa, decl_name, {});
|
||||
}
|
||||
}
|
||||
|
||||
@ -788,7 +788,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
|
||||
const is_pub = toplevel and !is_unnamed;
|
||||
const init_node = blk: {
|
||||
const record_def = record_decl.getDefinition() orelse {
|
||||
_ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
|
||||
try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
|
||||
break :blk Tag.opaque_literal.init();
|
||||
};
|
||||
|
||||
@ -805,13 +805,13 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
|
||||
const field_qt = field_decl.getType();
|
||||
|
||||
if (field_decl.isBitField()) {
|
||||
_ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
|
||||
try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
|
||||
try warn(c, scope, field_loc, "{s} demoted to opaque type - has bitfield", .{container_kind_name});
|
||||
break :blk Tag.opaque_literal.init();
|
||||
}
|
||||
|
||||
if (qualTypeCanon(field_qt).isIncompleteOrZeroLengthArrayType(c.clang_context)) {
|
||||
_ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
|
||||
try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
|
||||
try warn(c, scope, field_loc, "{s} demoted to opaque type - has variable length array", .{container_kind_name});
|
||||
break :blk Tag.opaque_literal.init();
|
||||
}
|
||||
@ -826,7 +826,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
|
||||
}
|
||||
const field_type = transQualType(c, scope, field_qt, field_loc) catch |err| switch (err) {
|
||||
error.UnsupportedType => {
|
||||
_ = try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
|
||||
try c.opaque_demotes.put(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), {});
|
||||
try warn(c, scope, record_loc, "{s} demoted to opaque type - unable to translate type of field {s}", .{ container_kind_name, field_name });
|
||||
break :blk Tag.opaque_literal.init();
|
||||
},
|
||||
@ -972,7 +972,7 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E
|
||||
.fields = try c.arena.dupe(ast.Payload.Enum.Field, fields.items),
|
||||
});
|
||||
} else blk: {
|
||||
_ = try c.opaque_demotes.put(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), {});
|
||||
try c.opaque_demotes.put(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), {});
|
||||
break :blk Tag.opaque_literal.init();
|
||||
};
|
||||
|
||||
@ -1069,12 +1069,64 @@ fn transStmt(
|
||||
const expr = try transExpr(c, scope, source_expr, .used);
|
||||
return maybeSuppressResult(c, scope, result_used, expr);
|
||||
},
|
||||
.OffsetOfExprClass => return transOffsetOfExpr(c, scope, @ptrCast(*const clang.OffsetOfExpr, stmt), result_used),
|
||||
else => {
|
||||
return fail(c, error.UnsupportedTranslation, stmt.getBeginLoc(), "TODO implement translation of stmt class {s}", .{@tagName(sc)});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Translate a "simple" offsetof expression containing exactly one component,
|
||||
/// when that component is of kind .Field - e.g. offsetof(mytype, myfield)
|
||||
fn transSimpleOffsetOfExpr(
|
||||
c: *Context,
|
||||
scope: *Scope,
|
||||
expr: *const clang.OffsetOfExpr,
|
||||
) TransError!Node {
|
||||
assert(expr.getNumComponents() == 1);
|
||||
const component = expr.getComponent(0);
|
||||
if (component.getKind() == .Field) {
|
||||
const field_decl = component.getField();
|
||||
if (field_decl.getParent()) |record_decl| {
|
||||
if (c.decl_table.get(@ptrToInt(record_decl.getCanonicalDecl()))) |type_name| {
|
||||
const type_node = try Tag.type.create(c.arena, type_name);
|
||||
|
||||
var raw_field_name = try c.str(@ptrCast(*const clang.NamedDecl, field_decl).getName_bytes_begin());
|
||||
const quoted_field_name = try std.fmt.allocPrint(c.arena, "\"{s}\"", .{raw_field_name});
|
||||
const field_name_node = try Tag.string_literal.create(c.arena, quoted_field_name);
|
||||
|
||||
return Tag.byte_offset_of.create(c.arena, .{
|
||||
.lhs = type_node,
|
||||
.rhs = field_name_node,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "Failed to translate simple OffsetOfExpr", .{});
|
||||
}
|
||||
|
||||
fn transOffsetOfExpr(
|
||||
c: *Context,
|
||||
scope: *Scope,
|
||||
expr: *const clang.OffsetOfExpr,
|
||||
result_used: ResultUsed,
|
||||
) TransError!Node {
|
||||
if (expr.getNumComponents() == 1) {
|
||||
const offsetof_expr = try transSimpleOffsetOfExpr(c, scope, expr);
|
||||
return maybeSuppressResult(c, scope, result_used, offsetof_expr);
|
||||
}
|
||||
|
||||
// TODO implement OffsetOfExpr with more than 1 component
|
||||
// OffsetOfExpr API:
|
||||
// call expr.getComponent(idx) while idx < expr.getNumComponents()
|
||||
// component.getKind() will be either .Array or .Field (other kinds are C++-only)
|
||||
// if .Field, use component.getField() to retrieve *clang.FieldDecl
|
||||
// if .Array, use component.getArrayExprIndex() to get a c_uint which
|
||||
// can be passed to expr.getIndexExpr(expr_index) to get the *clang.Expr for the array index
|
||||
|
||||
return fail(c, error.UnsupportedTranslation, expr.getBeginLoc(), "TODO: implement complex OffsetOfExpr translation", .{});
|
||||
}
|
||||
|
||||
fn transBinaryOperator(
|
||||
c: *Context,
|
||||
scope: *Scope,
|
||||
@ -3199,7 +3251,7 @@ fn maybeSuppressResult(
|
||||
}
|
||||
|
||||
fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void {
|
||||
_ = try c.global_scope.sym_table.put(name, decl_node);
|
||||
try c.global_scope.sym_table.put(name, decl_node);
|
||||
try c.global_scope.nodes.append(decl_node);
|
||||
}
|
||||
|
||||
@ -4235,7 +4287,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
|
||||
return m.fail(c, "unable to translate C expr: unexpected token .{s}", .{@tagName(last)});
|
||||
|
||||
const var_decl = try Tag.pub_var_simple.create(c.arena, .{ .name = m.name, .init = init_node });
|
||||
_ = try c.global_scope.macro_table.put(m.name, var_decl);
|
||||
try c.global_scope.macro_table.put(m.name, var_decl);
|
||||
}
|
||||
|
||||
fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
|
||||
@ -4294,7 +4346,7 @@ fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
|
||||
.return_type = return_type,
|
||||
.body = try block_scope.complete(c),
|
||||
});
|
||||
_ = try c.global_scope.macro_table.put(m.name, fn_decl);
|
||||
try c.global_scope.macro_table.put(m.name, fn_decl);
|
||||
}
|
||||
|
||||
const ParseError = Error || error{ParseError};
|
||||
|
@ -148,6 +148,8 @@ pub const Node = extern union {
|
||||
ptr_cast,
|
||||
/// @divExact(lhs, rhs)
|
||||
div_exact,
|
||||
/// @byteOffsetOf(lhs, rhs)
|
||||
byte_offset_of,
|
||||
|
||||
negate,
|
||||
negate_wrap,
|
||||
@ -303,6 +305,7 @@ pub const Node = extern union {
|
||||
.std_mem_zeroinit,
|
||||
.ptr_cast,
|
||||
.div_exact,
|
||||
.byte_offset_of,
|
||||
=> Payload.BinOp,
|
||||
|
||||
.integer_literal,
|
||||
@ -1135,6 +1138,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
|
||||
const payload = node.castTag(.div_exact).?.data;
|
||||
return renderBuiltinCall(c, "@divExact", &.{ payload.lhs, payload.rhs });
|
||||
},
|
||||
.byte_offset_of => {
|
||||
const payload = node.castTag(.byte_offset_of).?.data;
|
||||
return renderBuiltinCall(c, "@byteOffsetOf", &.{ payload.lhs, payload.rhs });
|
||||
},
|
||||
.sizeof => {
|
||||
const payload = node.castTag(.sizeof).?.data;
|
||||
return renderBuiltinCall(c, "@sizeOf", &.{payload});
|
||||
@ -2001,6 +2008,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
|
||||
.array_type,
|
||||
.bool_to_int,
|
||||
.div_exact,
|
||||
.byte_offset_of,
|
||||
=> {
|
||||
// no grouping needed
|
||||
return renderNode(c, node);
|
||||
|
@ -1561,7 +1561,6 @@ pub const Value = extern union {
|
||||
.@"error" => {
|
||||
const payload = self.castTag(.@"error").?.data;
|
||||
hasher.update(payload.name);
|
||||
std.hash.autoHash(&hasher, payload.value);
|
||||
},
|
||||
.error_union => {
|
||||
const payload = self.castTag(.error_union).?.data;
|
||||
@ -2157,7 +2156,6 @@ pub const Value = extern union {
|
||||
/// duration of the compilation.
|
||||
/// TODO revisit this when we have the concept of the error tag type
|
||||
name: []const u8,
|
||||
value: u16,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -2623,6 +2623,46 @@ const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct
|
||||
return reinterpret_cast<const struct ZigClangExpr *>(casted->getUnderlyingExpr());
|
||||
}
|
||||
|
||||
enum ZigClangOffsetOfNode_Kind ZigClangOffsetOfNode_getKind(const struct ZigClangOffsetOfNode *self) {
|
||||
auto casted = reinterpret_cast<const clang::OffsetOfNode *>(self);
|
||||
return (ZigClangOffsetOfNode_Kind)casted->getKind();
|
||||
}
|
||||
|
||||
unsigned ZigClangOffsetOfNode_getArrayExprIndex(const struct ZigClangOffsetOfNode *self) {
|
||||
auto casted = reinterpret_cast<const clang::OffsetOfNode *>(self);
|
||||
return casted->getArrayExprIndex();
|
||||
}
|
||||
|
||||
struct ZigClangFieldDecl *ZigClangOffsetOfNode_getField(const struct ZigClangOffsetOfNode *self) {
|
||||
auto casted = reinterpret_cast<const clang::OffsetOfNode *>(self);
|
||||
return reinterpret_cast<ZigClangFieldDecl *>(casted->getField());
|
||||
}
|
||||
|
||||
unsigned ZigClangOffsetOfExpr_getNumComponents(const struct ZigClangOffsetOfExpr *self) {
|
||||
auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self);
|
||||
return casted->getNumComponents();
|
||||
}
|
||||
|
||||
unsigned ZigClangOffsetOfExpr_getNumExpressions(const struct ZigClangOffsetOfExpr *self) {
|
||||
auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self);
|
||||
return casted->getNumExpressions();
|
||||
}
|
||||
|
||||
const struct ZigClangExpr *ZigClangOffsetOfExpr_getIndexExpr(const struct ZigClangOffsetOfExpr *self, unsigned idx) {
|
||||
auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self);
|
||||
return reinterpret_cast<const struct ZigClangExpr *>(casted->getIndexExpr(idx));
|
||||
}
|
||||
|
||||
const struct ZigClangOffsetOfNode *ZigClangOffsetOfExpr_getComponent(const struct ZigClangOffsetOfExpr *self, unsigned idx) {
|
||||
auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self);
|
||||
return reinterpret_cast<const struct ZigClangOffsetOfNode *>(&casted->getComponent(idx));
|
||||
}
|
||||
|
||||
ZigClangSourceLocation ZigClangOffsetOfExpr_getBeginLoc(const ZigClangOffsetOfExpr *self) {
|
||||
auto casted = reinterpret_cast<const clang::OffsetOfExpr *>(self);
|
||||
return bitcast(casted->getBeginLoc());
|
||||
}
|
||||
|
||||
struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *self) {
|
||||
auto casted = reinterpret_cast<const clang::ElaboratedType *>(self);
|
||||
return bitcast(casted->getNamedType());
|
||||
@ -3022,6 +3062,11 @@ ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldD
|
||||
return bitcast(casted->getLocation());
|
||||
}
|
||||
|
||||
const struct ZigClangRecordDecl *ZigClangFieldDecl_getParent(const struct ZigClangFieldDecl *self) {
|
||||
auto casted = reinterpret_cast<const clang::FieldDecl *>(self);
|
||||
return reinterpret_cast<const ZigClangRecordDecl *>(casted->getParent());
|
||||
}
|
||||
|
||||
ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *self) {
|
||||
auto casted = reinterpret_cast<const clang::FieldDecl *>(self);
|
||||
return bitcast(casted->getType());
|
||||
|
@ -935,6 +935,13 @@ enum ZigClangUnaryExprOrTypeTrait_Kind {
|
||||
ZigClangUnaryExprOrTypeTrait_KindPreferredAlignOf,
|
||||
};
|
||||
|
||||
enum ZigClangOffsetOfNode_Kind {
|
||||
ZigClangOffsetOfNode_KindArray,
|
||||
ZigClangOffsetOfNode_KindField,
|
||||
ZigClangOffsetOfNode_KindIdentifier,
|
||||
ZigClangOffsetOfNode_KindBase,
|
||||
};
|
||||
|
||||
ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const struct ZigClangSourceManager *,
|
||||
struct ZigClangSourceLocation Loc);
|
||||
ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const struct ZigClangSourceManager *,
|
||||
@ -1168,6 +1175,16 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangTypeOfType_getUnderlyingType(const
|
||||
|
||||
ZIG_EXTERN_C const struct ZigClangExpr *ZigClangTypeOfExprType_getUnderlyingExpr(const struct ZigClangTypeOfExprType *);
|
||||
|
||||
ZIG_EXTERN_C enum ZigClangOffsetOfNode_Kind ZigClangOffsetOfNode_getKind(const struct ZigClangOffsetOfNode *);
|
||||
ZIG_EXTERN_C unsigned ZigClangOffsetOfNode_getArrayExprIndex(const struct ZigClangOffsetOfNode *);
|
||||
ZIG_EXTERN_C struct ZigClangFieldDecl * ZigClangOffsetOfNode_getField(const struct ZigClangOffsetOfNode *);
|
||||
|
||||
ZIG_EXTERN_C unsigned ZigClangOffsetOfExpr_getNumComponents(const struct ZigClangOffsetOfExpr *);
|
||||
ZIG_EXTERN_C unsigned ZigClangOffsetOfExpr_getNumExpressions(const struct ZigClangOffsetOfExpr *);
|
||||
ZIG_EXTERN_C const struct ZigClangExpr *ZigClangOffsetOfExpr_getIndexExpr(const struct ZigClangOffsetOfExpr *, unsigned idx);
|
||||
ZIG_EXTERN_C const struct ZigClangOffsetOfNode *ZigClangOffsetOfExpr_getComponent(const struct ZigClangOffsetOfExpr *, unsigned idx);
|
||||
ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangOffsetOfExpr_getBeginLoc(const struct ZigClangOffsetOfExpr *);
|
||||
|
||||
ZIG_EXTERN_C struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *);
|
||||
ZIG_EXTERN_C enum ZigClangElaboratedTypeKeyword ZigClangElaboratedType_getKeyword(const struct ZigClangElaboratedType *);
|
||||
|
||||
@ -1268,6 +1285,7 @@ ZIG_EXTERN_C bool ZigClangFieldDecl_isBitField(const struct ZigClangFieldDecl *)
|
||||
ZIG_EXTERN_C bool ZigClangFieldDecl_isAnonymousStructOrUnion(const ZigClangFieldDecl *);
|
||||
ZIG_EXTERN_C struct ZigClangQualType ZigClangFieldDecl_getType(const struct ZigClangFieldDecl *);
|
||||
ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangFieldDecl_getLocation(const struct ZigClangFieldDecl *);
|
||||
ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangFieldDecl_getParent(const struct ZigClangFieldDecl *);
|
||||
|
||||
ZIG_EXTERN_C const struct ZigClangExpr *ZigClangEnumConstantDecl_getInitExpr(const struct ZigClangEnumConstantDecl *);
|
||||
ZIG_EXTERN_C const struct ZigClangAPSInt *ZigClangEnumConstantDecl_getInitVal(const struct ZigClangEnumConstantDecl *);
|
||||
|
@ -1178,7 +1178,6 @@ fn zirErrorValue(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorValue) InnerE
|
||||
.ty = result_type,
|
||||
.val = try Value.Tag.@"error".create(scope.arena(), .{
|
||||
.name = entry.key,
|
||||
.value = entry.value,
|
||||
}),
|
||||
});
|
||||
}
|
||||
@ -2215,7 +2214,8 @@ fn zirCmp(
|
||||
}
|
||||
if (rhs.value()) |rval| {
|
||||
if (lhs.value()) |lval| {
|
||||
return mod.constBool(scope, inst.base.src, (lval.castTag(.@"error").?.data.value == rval.castTag(.@"error").?.data.value) == (op == .eq));
|
||||
// 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
|
||||
return mod.constBool(scope, inst.base.src, std.mem.eql(u8, lval.castTag(.@"error").?.data.name, rval.castTag(.@"error").?.data.name) == (op == .eq));
|
||||
}
|
||||
}
|
||||
return mod.fail(scope, inst.base.src, "TODO implement equality comparison between runtime errors", .{});
|
||||
|
@ -1073,4 +1073,60 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
|
||||
cases.add("offsetof",
|
||||
\\#include <stddef.h>
|
||||
\\#include <stdlib.h>
|
||||
\\#define container_of(ptr, type, member) ({ \
|
||||
\\ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
||||
\\ (type *)( (char *)__mptr - offsetof(type,member) );})
|
||||
\\typedef struct {
|
||||
\\ int i;
|
||||
\\ struct { int x; char y; int z; } s;
|
||||
\\ float f;
|
||||
\\} container;
|
||||
\\int main(void) {
|
||||
\\ if (offsetof(container, i) != 0) abort();
|
||||
\\ if (offsetof(container, s) <= offsetof(container, i)) abort();
|
||||
\\ if (offsetof(container, f) <= offsetof(container, s)) abort();
|
||||
\\
|
||||
\\ container my_container;
|
||||
\\ typeof(my_container.s) *inner_member_pointer = &my_container.s;
|
||||
\\ float *float_member_pointer = &my_container.f;
|
||||
\\ int *anon_member_pointer = &my_container.s.z;
|
||||
\\ container *my_container_p;
|
||||
\\
|
||||
\\ my_container_p = container_of(inner_member_pointer, container, s);
|
||||
\\ if (my_container_p != &my_container) abort();
|
||||
\\
|
||||
\\ my_container_p = container_of(float_member_pointer, container, f);
|
||||
\\ if (my_container_p != &my_container) abort();
|
||||
\\
|
||||
\\ if (container_of(anon_member_pointer, typeof(my_container.s), z) != inner_member_pointer) abort();
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
|
||||
cases.add("handle assert.h",
|
||||
\\#include <assert.h>
|
||||
\\int main() {
|
||||
\\ int x = 1;
|
||||
\\ int *xp = &x;
|
||||
\\ assert(1);
|
||||
\\ assert(x != 0);
|
||||
\\ assert(xp);
|
||||
\\ assert(*xp);
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
|
||||
cases.add("NDEBUG disables assert",
|
||||
\\#define NDEBUG
|
||||
\\#include <assert.h>
|
||||
\\int main() {
|
||||
\\ assert(0);
|
||||
\\ assert(NULL);
|
||||
\\ return 0;
|
||||
\\}
|
||||
, "");
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ pub fn main() !void {
|
||||
continue;
|
||||
}
|
||||
if (std.mem.startsWith(u8, ver, "GCC_")) continue;
|
||||
_ = try global_ver_set.put(ver, undefined);
|
||||
try global_ver_set.put(ver, undefined);
|
||||
const gop = try global_fn_set.getOrPut(name);
|
||||
if (gop.found_existing) {
|
||||
if (!std.mem.eql(u8, gop.entry.value.lib, "c")) {
|
||||
@ -242,7 +242,7 @@ pub fn main() !void {
|
||||
var buffered = std.io.bufferedWriter(vers_txt_file.writer());
|
||||
const vers_txt = buffered.writer();
|
||||
for (global_ver_list) |name, i| {
|
||||
_ = global_ver_set.put(name, i) catch unreachable;
|
||||
global_ver_set.put(name, i) catch unreachable;
|
||||
try vers_txt.print("{s}\n", .{name});
|
||||
}
|
||||
try buffered.flush();
|
||||
|
Loading…
Reference in New Issue
Block a user