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

Conflicts:
  src/clang.zig

Master branch renamed an enum; this branch gave it an explicit tag type
and explicitly initialized values. This commit combines the changes
together.
This commit is contained in:
Andrew Kelley 2020-10-08 15:47:45 -07:00
commit 8b7539bd95
45 changed files with 2682 additions and 1438 deletions

View File

@ -808,6 +808,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: anytype, source_token:
.Keyword_noalias,
.Keyword_noinline,
.Keyword_nosuspend,
.Keyword_opaque,
.Keyword_or,
.Keyword_orelse,
.Keyword_packed,

View File

@ -1988,7 +1988,7 @@ test "null terminated array" {
<li>Supports slice syntax: {#syntax#}ptr[start..end]{#endsyntax#}</li>
<li>Supports pointer arithmetic: {#syntax#}ptr + x{#endsyntax#}, {#syntax#}ptr - x{#endsyntax#}</li>
<li>{#syntax#}T{#endsyntax#} must have a known size, which means that it cannot be
{#syntax#}c_void{#endsyntax#} or any other {#link|opaque type|Opaque Types#}.</li>
{#syntax#}c_void{#endsyntax#} or any other {#link|opaque type|opaque#}.</li>
</ul>
</li>
</ul>
@ -5545,7 +5545,7 @@ test "turn HashMap into a set with void" {
</p>
<p>
{#syntax#}void{#endsyntax#} is distinct from {#syntax#}c_void{#endsyntax#}, which is defined like this:
{#syntax#}pub const c_void = @Type(.Opaque);{#endsyntax#}.
{#syntax#}pub const c_void = opaque {};{#endsyntax#}.
{#syntax#}void{#endsyntax#} has a known size of 0 bytes, and {#syntax#}c_void{#endsyntax#} has an unknown, but non-zero, size.
</p>
<p>
@ -8471,7 +8471,7 @@ test "integer truncation" {
<li>{#link|Error Set Type#}</li>
<li>{#link|Error Union Type#}</li>
<li>{#link|Vectors#}</li>
<li>{#link|Opaque Types#}</li>
<li>{#link|opaque#}</li>
<li>{#link|@Frame#}</li>
<li>{#syntax#}anyframe{#endsyntax#}</li>
<li>{#link|struct#}</li>
@ -8547,17 +8547,18 @@ fn foo(comptime T: type, ptr: *T) T {
{#header_close#}
{#header_close#}
{#header_open|Opaque Types#}
{#header_open|opaque#}
<p>
{#syntax#}@Type(.Opaque){#endsyntax#} creates a new type with an unknown (but non-zero) size and alignment.
{#syntax#}opaque {}{#endsyntax#} declares a new type with an unknown (but non-zero) size and alignment.
It can have declarations like structs, unions, or enums.
</p>
<p>
This is typically used for type safety when interacting with C code that does not expose struct details.
Example:
</p>
{#code_begin|test_err|expected type '*Derp', found '*Wat'#}
const Derp = @Type(.Opaque);
const Wat = @Type(.Opaque);
const Derp = opaque {};
const Wat = opaque {};
extern fn bar(d: *Derp) void;
fn foo(w: *Wat) callconv(.C) void {
@ -11193,7 +11194,7 @@ PtrTypeStart
ContainerDeclAuto &lt;- ContainerDeclType LBRACE ContainerMembers RBRACE
ContainerDeclType
&lt;- (KEYWORD_struct / KEYWORD_enum) (LPAREN Expr RPAREN)?
&lt;- (KEYWORD_struct / KEYWORD_enum / KEYWORD_opaque) (LPAREN Expr RPAREN)?
/ KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
# Alignment
@ -11340,6 +11341,7 @@ KEYWORD_inline &lt;- 'inline' end_of_word
KEYWORD_noalias &lt;- 'noalias' end_of_word
KEYWORD_nosuspend &lt;- 'nosuspend' end_of_word
KEYWORD_null &lt;- 'null' end_of_word
KEYWORD_opaque &lt;- 'opaque' end_of_word
KEYWORD_or &lt;- 'or' end_of_word
KEYWORD_orelse &lt;- 'orelse' end_of_word
KEYWORD_packed &lt;- 'packed' end_of_word
@ -11368,7 +11370,7 @@ keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_anyframe / KEYWORD_anytype
/ KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer
/ KEYWORD_error / KEYWORD_export / KEYWORD_extern / KEYWORD_false
/ KEYWORD_fn / KEYWORD_for / KEYWORD_if / KEYWORD_inline
/ KEYWORD_noalias / KEYWORD_null / KEYWORD_or
/ KEYWORD_noalias / KEYWORD_null / KEYWORD_opaque / KEYWORD_or
/ KEYWORD_orelse / KEYWORD_packed / KEYWORD_pub
/ KEYWORD_resume / KEYWORD_return / KEYWORD_linksection
/ KEYWORD_struct / KEYWORD_suspend

View File

@ -151,7 +151,6 @@ pub const Mode = enum {
pub const CallingConvention = enum {
Unspecified,
C,
Cold,
Naked,
Async,
Interrupt,
@ -199,7 +198,7 @@ pub const TypeInfo = union(enum) {
Union: Union,
Fn: Fn,
BoundFn: Fn,
Opaque: void,
Opaque: Opaque,
Frame: Frame,
AnyFrame: AnyFrame,
Vector: Vector,
@ -360,6 +359,12 @@ pub const TypeInfo = union(enum) {
args: []const FnArg,
};
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
pub const Opaque = struct {
decls: []const Declaration,
};
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
pub const Frame = struct {

View File

@ -329,8 +329,8 @@ pub extern "c" fn pthread_cond_signal(cond: *pthread_cond_t) c_int;
pub extern "c" fn pthread_cond_broadcast(cond: *pthread_cond_t) c_int;
pub extern "c" fn pthread_cond_destroy(cond: *pthread_cond_t) c_int;
pub const pthread_t = *@Type(.Opaque);
pub const FILE = @Type(.Opaque);
pub const pthread_t = *opaque {};
pub const FILE = opaque {};
pub extern "c" fn dlopen(path: [*:0]const u8, mode: c_int) ?*c_void;
pub extern "c" fn dlclose(handle: *c_void) c_int;

View File

@ -10,7 +10,15 @@ const builtin = std.builtin;
const has_aesni = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .aes);
const has_avx = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .avx);
const impl = if (std.Target.current.cpu.arch == .x86_64 and has_aesni and has_avx) @import("aes/aesni.zig") else @import("aes/soft.zig");
const has_armaes = comptime std.Target.aarch64.featureSetHas(std.Target.current.cpu.features, .aes);
const impl = if (std.Target.current.cpu.arch == .x86_64 and has_aesni and has_avx) impl: {
break :impl @import("aes/aesni.zig");
} else if (std.Target.current.cpu.arch == .aarch64 and has_armaes)
impl: {
break :impl @import("aes/armcrypto.zig");
} else impl: {
break :impl @import("aes/soft.zig");
};
pub const Block = impl.Block;
pub const AESEncryptCtx = impl.AESEncryptCtx;

View File

@ -3,7 +3,6 @@
// 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.
// Based on Go stdlib implementation
const std = @import("../../std.zig");
const mem = std.mem;

View File

@ -0,0 +1,490 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2015-2020 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.zig");
const mem = std.mem;
const debug = std.debug;
const Vector = std.meta.Vector;
const BlockVec = Vector(2, u64);
/// A single AES block.
pub const Block = struct {
pub const block_size: usize = 16;
/// Internal representation of a block.
repr: BlockVec,
/// Convert a byte sequence into an internal representation.
pub inline fn fromBytes(bytes: *const [16]u8) Block {
const repr = mem.bytesToValue(BlockVec, bytes);
return Block{ .repr = repr };
}
/// Convert the internal representation of a block into a byte sequence.
pub inline fn toBytes(block: Block) [16]u8 {
return mem.toBytes(block.repr);
}
/// XOR the block with a byte sequence.
pub inline fn xorBytes(block: Block, bytes: *const [16]u8) [16]u8 {
const x = block.repr ^ fromBytes(bytes).repr;
return mem.toBytes(x);
}
const zero = Vector(2, u64){ 0, 0 };
/// Encrypt a block with a round key.
pub inline fn encrypt(block: Block, round_key: Block) Block {
return Block{
.repr = asm (
\\ mov %[out].16b, %[in].16b
\\ aese %[out].16b, %[zero].16b
\\ aesmc %[out].16b, %[out].16b
\\ eor %[out].16b, %[out].16b, %[rk].16b
: [out] "=&x" (-> BlockVec)
: [in] "x" (block.repr),
[rk] "x" (round_key.repr),
[zero] "x" (zero)
),
};
}
/// Encrypt a block with the last round key.
pub inline fn encryptLast(block: Block, round_key: Block) Block {
return Block{
.repr = asm (
\\ mov %[out].16b, %[in].16b
\\ aese %[out].16b, %[zero].16b
\\ eor %[out].16b, %[out].16b, %[rk].16b
: [out] "=&x" (-> BlockVec)
: [in] "x" (block.repr),
[rk] "x" (round_key.repr),
[zero] "x" (zero)
),
};
}
/// Decrypt a block with a round key.
pub inline fn decrypt(block: Block, inv_round_key: Block) Block {
return Block{
.repr = asm (
\\ mov %[out].16b, %[in].16b
\\ aesd %[out].16b, %[zero].16b
\\ aesimc %[out].16b, %[out].16b
\\ eor %[out].16b, %[out].16b, %[rk].16b
: [out] "=&x" (-> BlockVec)
: [in] "x" (block.repr),
[rk] "x" (inv_round_key.repr),
[zero] "x" (zero)
),
};
}
/// Decrypt a block with the last round key.
pub inline fn decryptLast(block: Block, inv_round_key: Block) Block {
return Block{
.repr = asm (
\\ mov %[out].16b, %[in].16b
\\ aesd %[out].16b, %[zero].16b
\\ eor %[out].16b, %[out].16b, %[rk].16b
: [out] "=&x" (-> BlockVec)
: [in] "x" (block.repr),
[rk] "x" (inv_round_key.repr),
[zero] "x" (zero)
),
};
}
/// Apply the bitwise XOR operation to the content of two blocks.
pub inline fn xorBlocks(block1: Block, block2: Block) Block {
return Block{ .repr = block1.repr ^ block2.repr };
}
/// Apply the bitwise AND operation to the content of two blocks.
pub inline fn andBlocks(block1: Block, block2: Block) Block {
return Block{ .repr = block1.repr & block2.repr };
}
/// Apply the bitwise OR operation to the content of two blocks.
pub inline fn orBlocks(block1: Block, block2: Block) Block {
return Block{ .repr = block1.repr | block2.repr };
}
/// Perform operations on multiple blocks in parallel.
pub const parallel = struct {
/// The recommended number of AES encryption/decryption to perform in parallel for the chosen implementation.
pub const optimal_parallel_blocks = 8;
/// Encrypt multiple blocks in parallel, each their own round key.
pub inline fn encryptParallel(comptime count: usize, blocks: [count]Block, round_keys: [count]Block) [count]Block {
comptime var i = 0;
var out: [count]Block = undefined;
inline while (i < count) : (i += 1) {
out[i] = blocks[i].encrypt(round_keys[i]);
}
return out;
}
/// Decrypt multiple blocks in parallel, each their own round key.
pub inline fn decryptParallel(comptime count: usize, blocks: [count]Block, round_keys: [count]Block) [count]Block {
comptime var i = 0;
var out: [count]Block = undefined;
inline while (i < count) : (i += 1) {
out[i] = blocks[i].decrypt(round_keys[i]);
}
return out;
}
/// Encrypt multple blocks in parallel with the same round key.
pub inline fn encryptWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
comptime var i = 0;
var out: [count]Block = undefined;
inline while (i < count) : (i += 1) {
out[i] = blocks[i].encrypt(round_key);
}
return out;
}
/// Decrypt multple blocks in parallel with the same round key.
pub inline fn decryptWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
comptime var i = 0;
var out: [count]Block = undefined;
inline while (i < count) : (i += 1) {
out[i] = blocks[i].decrypt(round_key);
}
return out;
}
/// Encrypt multple blocks in parallel with the same last round key.
pub inline fn encryptLastWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
comptime var i = 0;
var out: [count]Block = undefined;
inline while (i < count) : (i += 1) {
out[i] = blocks[i].encryptLast(round_key);
}
return out;
}
/// Decrypt multple blocks in parallel with the same last round key.
pub inline fn decryptLastWide(comptime count: usize, blocks: [count]Block, round_key: Block) [count]Block {
comptime var i = 0;
var out: [count]Block = undefined;
inline while (i < count) : (i += 1) {
out[i] = blocks[i].decryptLast(round_key);
}
return out;
}
};
};
fn KeySchedule(comptime AES: type) type {
std.debug.assert(AES.rounds == 10 or AES.rounds == 14);
const rounds = AES.rounds;
return struct {
const Self = @This();
const zero = Vector(2, u64){ 0, 0 };
const mask1 = @Vector(16, u8){ 13, 14, 15, 12, 13, 14, 15, 12, 13, 14, 15, 12, 13, 14, 15, 12 };
const mask2 = @Vector(16, u8){ 12, 13, 14, 15, 12, 13, 14, 15, 12, 13, 14, 15, 12, 13, 14, 15 };
round_keys: [rounds + 1]Block,
fn drc128(comptime rc: u8, t: BlockVec) BlockVec {
var v1: BlockVec = undefined;
var v2: BlockVec = undefined;
var v3: BlockVec = undefined;
var v4: BlockVec = undefined;
return asm (
\\ movi %[v2].4s, %[rc]
\\ tbl %[v4].16b, {%[t].16b}, %[mask].16b
\\ ext %[r].16b, %[zero].16b, %[t].16b, #12
\\ aese %[v4].16b, %[zero].16b
\\ eor %[v2].16b, %[r].16b, %[v2].16b
\\ ext %[r].16b, %[zero].16b, %[r].16b, #12
\\ eor %[v1].16b, %[v2].16b, %[t].16b
\\ ext %[v3].16b, %[zero].16b, %[r].16b, #12
\\ eor %[v1].16b, %[v1].16b, %[r].16b
\\ eor %[r].16b, %[v1].16b, %[v3].16b
\\ eor %[r].16b, %[r].16b, %[v4].16b
: [r] "=&x" (-> BlockVec),
[v1] "=&x" (v1),
[v2] "=&x" (v2),
[v3] "=&x" (v3),
[v4] "=&x" (v4)
: [rc] "N" (rc),
[t] "x" (t),
[zero] "x" (zero),
[mask] "x" (mask1)
);
}
fn drc256(comptime second: bool, comptime rc: u8, t: BlockVec, tx: BlockVec) BlockVec {
var v1: BlockVec = undefined;
var v2: BlockVec = undefined;
var v3: BlockVec = undefined;
var v4: BlockVec = undefined;
return asm (
\\ movi %[v2].4s, %[rc]
\\ tbl %[v4].16b, {%[t].16b}, %[mask].16b
\\ ext %[r].16b, %[zero].16b, %[tx].16b, #12
\\ aese %[v4].16b, %[zero].16b
\\ eor %[v1].16b, %[tx].16b, %[r].16b
\\ ext %[r].16b, %[zero].16b, %[r].16b, #12
\\ eor %[v1].16b, %[v1].16b, %[r].16b
\\ ext %[v3].16b, %[zero].16b, %[r].16b, #12
\\ eor %[v1].16b, %[v1].16b, %[v2].16b
\\ eor %[v1].16b, %[v1].16b, %[v3].16b
\\ eor %[r].16b, %[v1].16b, %[v4].16b
: [r] "=&x" (-> BlockVec),
[v1] "=&x" (v1),
[v2] "=&x" (v2),
[v3] "=&x" (v3),
[v4] "=&x" (v4)
: [rc] "N" (if (second) @as(u8, 0) else rc),
[t] "x" (t),
[tx] "x" (tx),
[zero] "x" (zero),
[mask] "x" (if (second) mask2 else mask1)
);
}
fn expand128(t1: *Block) Self {
var round_keys: [11]Block = undefined;
const rcs = [_]u8{ 1, 2, 4, 8, 16, 32, 64, 128, 27, 54 };
inline for (rcs) |rc, round| {
round_keys[round] = t1.*;
t1.repr = drc128(rc, t1.repr);
}
round_keys[rcs.len] = t1.*;
return Self{ .round_keys = round_keys };
}
fn expand256(t1: *Block, t2: *Block) Self {
var round_keys: [15]Block = undefined;
const rcs = [_]u8{ 1, 2, 4, 8, 16, 32 };
round_keys[0] = t1.*;
inline for (rcs) |rc, round| {
round_keys[round * 2 + 1] = t2.*;
t1.repr = drc256(false, rc, t2.repr, t1.repr);
round_keys[round * 2 + 2] = t1.*;
t2.repr = drc256(true, rc, t1.repr, t2.repr);
}
round_keys[rcs.len * 2 + 1] = t2.*;
t1.repr = drc256(false, 64, t2.repr, t1.repr);
round_keys[rcs.len * 2 + 2] = t1.*;
return Self{ .round_keys = round_keys };
}
/// Invert the key schedule.
pub fn invert(key_schedule: Self) Self {
const round_keys = &key_schedule.round_keys;
var inv_round_keys: [rounds + 1]Block = undefined;
inv_round_keys[0] = round_keys[rounds];
comptime var i = 1;
inline while (i < rounds) : (i += 1) {
inv_round_keys[i] = Block{
.repr = asm (
\\ aesimc %[inv_rk].16b, %[rk].16b
: [inv_rk] "=x" (-> BlockVec)
: [rk] "x" (round_keys[rounds - i].repr)
),
};
}
inv_round_keys[rounds] = round_keys[0];
return Self{ .round_keys = inv_round_keys };
}
};
}
/// A context to perform encryption using the standard AES key schedule.
pub fn AESEncryptCtx(comptime AES: type) type {
std.debug.assert(AES.key_bits == 128 or AES.key_bits == 256);
const rounds = AES.rounds;
return struct {
const Self = @This();
pub const block = AES.block;
pub const block_size = block.block_size;
key_schedule: KeySchedule(AES),
/// Create a new encryption context with the given key.
pub fn init(key: [AES.key_bits / 8]u8) Self {
var t1 = Block.fromBytes(key[0..16]);
const key_schedule = if (AES.key_bits == 128) ks: {
break :ks KeySchedule(AES).expand128(&t1);
} else ks: {
var t2 = Block.fromBytes(key[16..32]);
break :ks KeySchedule(AES).expand256(&t1, &t2);
};
return Self{
.key_schedule = key_schedule,
};
}
/// Encrypt a single block.
pub fn encrypt(ctx: Self, dst: *[16]u8, src: *const [16]u8) void {
const round_keys = ctx.key_schedule.round_keys;
var t = Block.fromBytes(src).xorBlocks(round_keys[0]);
comptime var i = 1;
inline while (i < rounds) : (i += 1) {
t = t.encrypt(round_keys[i]);
}
t = t.encryptLast(round_keys[rounds]);
dst.* = t.toBytes();
}
/// Encrypt+XOR a single block.
pub fn xor(ctx: Self, dst: *[16]u8, src: *const [16]u8, counter: [16]u8) void {
const round_keys = ctx.key_schedule.round_keys;
var t = Block.fromBytes(&counter).xorBlocks(round_keys[0]);
comptime var i = 1;
inline while (i < rounds) : (i += 1) {
t = t.encrypt(round_keys[i]);
}
t = t.encryptLast(round_keys[rounds]);
dst.* = t.xorBytes(src);
}
/// Encrypt multiple blocks, possibly leveraging parallelization.
pub fn encryptWide(ctx: Self, comptime count: usize, dst: *[16 * count]u8, src: *const [16 * count]u8) void {
const round_keys = ctx.key_schedule.round_keys;
var ts: [count]Block = undefined;
comptime var j = 0;
inline while (j < count) : (j += 1) {
ts[j] = Block.fromBytes(src[j * 16 .. j * 16 + 16][0..16]).xorBlocks(round_keys[0]);
}
comptime var i = 1;
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]);
}
j = 0;
inline while (j < count) : (j += 1) {
dst[16 * j .. 16 * j + 16].* = ts[j].toBytes();
}
}
/// Encrypt+XOR multiple blocks, possibly leveraging parallelization.
pub fn xorWide(ctx: Self, comptime count: usize, dst: *[16 * count]u8, src: *const [16 * count]u8, counters: [16 * count]u8) void {
const round_keys = ctx.key_schedule.round_keys;
var ts: [count]Block = undefined;
comptime var j = 0;
inline while (j < count) : (j += 1) {
ts[j] = Block.fromBytes(counters[j * 16 .. j * 16 + 16][0..16]).xorBlocks(round_keys[0]);
}
comptime var i = 1;
inline while (i < rounds) : (i += 1) {
ts = Block.parallel.encryptWide(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].xorBytes(src[16 * j .. 16 * j + 16]);
}
}
};
}
/// A context to perform decryption using the standard AES key schedule.
pub fn AESDecryptCtx(comptime AES: type) type {
std.debug.assert(AES.key_bits == 128 or AES.key_bits == 256);
const rounds = AES.rounds;
return struct {
const Self = @This();
pub const block = AES.block;
pub const block_size = block.block_size;
key_schedule: KeySchedule(AES),
/// Create a decryption context from an existing encryption context.
pub fn initFromEnc(ctx: AESEncryptCtx(AES)) Self {
return Self{
.key_schedule = ctx.key_schedule.invert(),
};
}
/// Create a new decryption context with the given key.
pub fn init(key: [AES.key_bits / 8]u8) Self {
const enc_ctx = AESEncryptCtx(AES).init(key);
return initFromEnc(enc_ctx);
}
/// Decrypt a single block.
pub fn decrypt(ctx: Self, dst: *[16]u8, src: *const [16]u8) void {
const inv_round_keys = ctx.key_schedule.round_keys;
var t = Block.fromBytes(src).xorBlocks(inv_round_keys[0]);
comptime var i = 1;
inline while (i < rounds) : (i += 1) {
t = t.decrypt(inv_round_keys[i]);
}
t = t.decryptLast(inv_round_keys[rounds]);
dst.* = t.toBytes();
}
/// Decrypt multiple blocks, possibly leveraging parallelization.
pub fn decryptWide(ctx: Self, comptime count: usize, dst: *[16 * count]u8, src: *const [16 * count]u8) void {
const inv_round_keys = ctx.key_schedule.round_keys;
var ts: [count]Block = undefined;
comptime var j = 0;
inline while (j < count) : (j += 1) {
ts[j] = Block.fromBytes(src[j * 16 .. j * 16 + 16][0..16]).xorBlocks(inv_round_keys[0]);
}
comptime var i = 1;
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]);
}
j = 0;
inline while (j < count) : (j += 1) {
dst[16 * j .. 16 * j + 16].* = ts[j].toBytes();
}
}
};
}
/// AES-128 with the standard key schedule.
pub const AES128 = struct {
pub const key_bits: usize = 128;
pub const rounds = ((key_bits - 64) / 32 + 8);
pub const block = Block;
/// Create a new context for encryption.
pub fn initEnc(key: [key_bits / 8]u8) AESEncryptCtx(AES128) {
return AESEncryptCtx(AES128).init(key);
}
/// Create a new context for decryption.
pub fn initDec(key: [key_bits / 8]u8) AESDecryptCtx(AES128) {
return AESDecryptCtx(AES128).init(key);
}
};
/// AES-256 with the standard key schedule.
pub const AES256 = struct {
pub const key_bits: usize = 256;
pub const rounds = ((key_bits - 64) / 32 + 8);
pub const block = Block;
/// Create a new context for encryption.
pub fn initEnc(key: [key_bits / 8]u8) AESEncryptCtx(AES256) {
return AESEncryptCtx(AES256).init(key);
}
/// Create a new context for decryption.
pub fn initDec(key: [key_bits / 8]u8) AESDecryptCtx(AES256) {
return AESDecryptCtx(AES256).init(key);
}
};

View File

@ -105,6 +105,17 @@ pub const Ghash = struct {
return product[0];
}
inline fn clmul_pmull(x: u64, y: u64) u64 {
const Vector = std.meta.Vector;
const product = asm (
\\ pmull %[out].1q, %[x].1d, %[y].1d
: [out] "=w" (-> Vector(2, u64))
: [x] "w" (@bitCast(Vector(2, u64), @as(u128, x))),
[y] "w" (@bitCast(Vector(2, u64), @as(u128, y)))
);
return product[0];
}
fn clmul_soft(x: u64, y: u64) u64 {
const x0 = x & 0x1111111111111111;
const x1 = x & 0x2222222222222222;
@ -127,7 +138,14 @@ pub const Ghash = struct {
const has_pclmul = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .pclmul);
const has_avx = comptime std.Target.x86.featureSetHas(std.Target.current.cpu.features, .avx);
const clmul = if (std.Target.current.cpu.arch == .x86_64 and has_pclmul and has_avx) clmul_pclmul else clmul_soft;
const has_armaes = comptime std.Target.aarch64.featureSetHas(std.Target.current.cpu.features, .aes);
const clmul = if (std.Target.current.cpu.arch == .x86_64 and has_pclmul and has_avx) impl: {
break :impl clmul_pclmul;
} else if (std.Target.current.cpu.arch == .aarch64 and has_armaes) impl: {
break :impl clmul_pmull;
} else impl: {
break :impl clmul_soft;
};
fn blocks(st: *Ghash, msg: []const u8) void {
assert(msg.len % 16 == 0); // GHASH blocks() expects full blocks

View File

@ -12,6 +12,7 @@ pub const Locked = @import("event/locked.zig").Locked;
pub const RwLock = @import("event/rwlock.zig").RwLock;
pub const RwLocked = @import("event/rwlocked.zig").RwLocked;
pub const Loop = @import("event/loop.zig").Loop;
pub const WaitGroup = @import("event/WaitGroup.zig").WaitGroup;
test "import event tests" {
_ = @import("event/channel.zig");
@ -23,4 +24,5 @@ test "import event tests" {
_ = @import("event/rwlock.zig");
_ = @import("event/rwlocked.zig");
_ = @import("event/loop.zig");
_ = @import("event/wait_group.zig");
}

View File

@ -660,9 +660,11 @@ pub const Loop = struct {
const Wrapper = struct {
const Args = @TypeOf(args);
fn run(func_args: Args, loop: *Loop, allocator: *mem.Allocator) void {
loop.beginOneEvent();
loop.yield();
const result = @call(.{}, func, func_args);
suspend {
loop.finishOneEvent();
allocator.destroy(@frame());
}
}

View File

@ -0,0 +1,120 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2015-2020 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.zig");
const builtin = @import("builtin");
const Loop = std.event.Loop;
/// A WaitGroup keeps track and waits for a group of async tasks to finish.
/// Call `begin` when creating new tasks, and have tasks call `finish` when done.
/// You can provide a count for both operations to perform them in bulk.
/// Call `wait` to suspend until all tasks are completed.
/// Multiple waiters are supported.
///
/// WaitGroup is an instance of WaitGroupGeneric, which takes in a bitsize
/// for the internal counter. WaitGroup defaults to a `usize` counter.
/// It's also possible to define a max value for the counter so that
/// `begin` will return error.Overflow when the limit is reached, even
/// if the integer type has not has not overflowed.
/// By default `max_value` is set to std.math.maxInt(CounterType).
pub const WaitGroup = WaitGroupGeneric(std.meta.bitCount(usize));
pub fn WaitGroupGeneric(comptime counter_size: u16) type {
const CounterType = std.meta.Int(false, counter_size);
const global_event_loop = Loop.instance orelse
@compileError("std.event.WaitGroup currently only works with event-based I/O");
return struct {
counter: CounterType = 0,
max_counter: CounterType = std.math.maxInt(CounterType),
mutex: std.Mutex = .{},
waiters: ?*Waiter = null,
const Waiter = struct {
next: ?*Waiter,
tail: *Waiter,
node: Loop.NextTickNode,
};
const Self = @This();
pub fn begin(self: *Self, count: CounterType) error{Overflow}!void {
const held = self.mutex.acquire();
defer held.release();
const new_counter = try std.math.add(CounterType, self.counter, count);
if (new_counter > self.max_counter) return error.Overflow;
self.counter = new_counter;
}
pub fn finish(self: *Self, count: CounterType) void {
var waiters = blk: {
const held = self.mutex.acquire();
defer held.release();
self.counter = std.math.sub(CounterType, self.counter, count) catch unreachable;
if (self.counter == 0) {
const temp = self.waiters;
self.waiters = null;
break :blk temp;
}
break :blk null;
};
// We don't need to hold the lock to reschedule any potential waiter.
while (waiters) |w| {
const temp_w = w;
waiters = w.next;
global_event_loop.onNextTick(&temp_w.node);
}
}
pub fn wait(self: *Self) void {
const held = self.mutex.acquire();
if (self.counter == 0) {
held.release();
return;
}
var self_waiter: Waiter = undefined;
self_waiter.node.data = @frame();
if (self.waiters) |head| {
head.tail.next = &self_waiter;
head.tail = &self_waiter;
} else {
self.waiters = &self_waiter;
self_waiter.tail = &self_waiter;
self_waiter.next = null;
}
suspend {
held.release();
}
}
};
}
test "basic WaitGroup usage" {
if (!std.io.is_async) return error.SkipZigTest;
// TODO https://github.com/ziglang/zig/issues/1908
if (builtin.single_threaded) return error.SkipZigTest;
// TODO https://github.com/ziglang/zig/issues/3251
if (builtin.os.tag == .freebsd) return error.SkipZigTest;
var initial_wg = WaitGroup{};
var final_wg = WaitGroup{};
try initial_wg.begin(1);
try final_wg.begin(1);
var task_frame = async task(&initial_wg, &final_wg);
initial_wg.finish(1);
final_wg.wait();
await task_frame;
}
fn task(wg_i: *WaitGroup, wg_f: *WaitGroup) void {
wg_i.wait();
wg_f.finish(1);
}

View File

@ -1181,13 +1181,16 @@ fn bufPrintIntToSlice(buf: []u8, value: anytype, base: u8, uppercase: bool, opti
return buf[0..formatIntBuf(buf, value, base, uppercase, options)];
}
pub fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [count(fmt, args)]u8 {
comptime var buf: [count(fmt, args)]u8 = undefined;
pub fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [count(fmt, args):0]u8 {
comptime var buf: [count(fmt, args):0]u8 = undefined;
_ = bufPrint(&buf, fmt, args) catch unreachable;
buf[buf.len] = 0;
return &buf;
}
test "comptimePrint" {
@setEvalBranchQuota(2000);
std.testing.expectEqual(*const [3:0]u8, @TypeOf(comptime comptimePrint("{}", .{100})));
std.testing.expectEqualSlices(u8, "100", comptime comptimePrint("{}", .{100}));
}

View File

@ -110,7 +110,12 @@ pub fn approxEq(comptime T: type, x: T, y: T, epsilon: T) bool {
}
pub fn doNotOptimizeAway(value: anytype) void {
mem.doNotOptimizeAway(value);
// TODO: use @declareSideEffect() when it is available.
// https://github.com/ziglang/zig/issues/6168
const T = @TypeOf(value);
var x: T = undefined;
const p = @ptrCast(*volatile T, &x);
p.* = x;
}
pub fn raiseInvalid() void {
@ -1131,3 +1136,9 @@ test "compare between signed and unsigned" {
testing.expect(!compare(@as(u8, 255), .eq, @as(i8, -1)));
testing.expect(compare(@as(u8, 1), .eq, @as(u8, 1)));
}
test "math.comptime" {
comptime const v = sin(@as(f32, 1)) + ln(@as(f32, 5));
testing.expect(v == sin(@as(f32, 1)) + ln(@as(f32, 5)));
}

View File

@ -12,28 +12,28 @@ const in_bpf_program = switch (std.builtin.arch) {
pub const helpers = if (in_bpf_program) @import("helpers.zig") else struct {};
pub const BpfSock = @Type(.Opaque);
pub const BpfSockAddr = @Type(.Opaque);
pub const FibLookup = @Type(.Opaque);
pub const MapDef = @Type(.Opaque);
pub const PerfEventData = @Type(.Opaque);
pub const PerfEventValue = @Type(.Opaque);
pub const PidNsInfo = @Type(.Opaque);
pub const SeqFile = @Type(.Opaque);
pub const SkBuff = @Type(.Opaque);
pub const SkMsgMd = @Type(.Opaque);
pub const SkReusePortMd = @Type(.Opaque);
pub const Sock = @Type(.Opaque);
pub const SockAddr = @Type(.Opaque);
pub const SockOps = @Type(.Opaque);
pub const SockTuple = @Type(.Opaque);
pub const SpinLock = @Type(.Opaque);
pub const SysCtl = @Type(.Opaque);
pub const Tcp6Sock = @Type(.Opaque);
pub const TcpRequestSock = @Type(.Opaque);
pub const TcpSock = @Type(.Opaque);
pub const TcpTimewaitSock = @Type(.Opaque);
pub const TunnelKey = @Type(.Opaque);
pub const Udp6Sock = @Type(.Opaque);
pub const XdpMd = @Type(.Opaque);
pub const XfrmState = @Type(.Opaque);
pub const BpfSock = opaque {};
pub const BpfSockAddr = opaque {};
pub const FibLookup = opaque {};
pub const MapDef = opaque {};
pub const PerfEventData = opaque {};
pub const PerfEventValue = opaque {};
pub const PidNsInfo = opaque {};
pub const SeqFile = opaque {};
pub const SkBuff = opaque {};
pub const SkMsgMd = opaque {};
pub const SkReusePortMd = opaque {};
pub const Sock = opaque {};
pub const SockAddr = opaque {};
pub const SockOps = opaque {};
pub const SockTuple = opaque {};
pub const SpinLock = opaque {};
pub const SysCtl = opaque {};
pub const Tcp6Sock = opaque {};
pub const TcpRequestSock = opaque {};
pub const TcpSock = opaque {};
pub const TcpTimewaitSock = opaque {};
pub const TunnelKey = opaque {};
pub const Udp6Sock = opaque {};
pub const XdpMd = opaque {};
pub const XfrmState = opaque {};

View File

@ -17,7 +17,7 @@ pub var handle: Handle = undefined;
pub var system_table: *tables.SystemTable = undefined;
/// A handle to an event structure.
pub const Event = *@Type(.Opaque);
pub const Event = *opaque {};
/// GUIDs must be align(8)
pub const Guid = extern struct {
@ -51,7 +51,7 @@ pub const Guid = extern struct {
};
/// An EFI Handle represents a collection of related interfaces.
pub const Handle = *@Type(.Opaque);
pub const Handle = *opaque {};
/// This structure represents time information.
pub const Time = extern struct {
@ -108,4 +108,4 @@ pub const TimeCapabilities = extern struct {
};
/// File Handle as specified in the EFI Shell Spec
pub const FileHandle = *@Type(.Opaque);
pub const FileHandle = *opaque {};

View File

@ -6,7 +6,7 @@
const uefi = @import("std").os.uefi;
const Guid = uefi.Guid;
pub const HIIHandle = *@Type(.Opaque);
pub const HIIHandle = *opaque {};
/// The header found at the start of each package.
pub const HIIPackageHeader = packed struct {

View File

@ -32,16 +32,16 @@ pub const UCHAR = u8;
pub const FLOAT = f32;
pub const HANDLE = *c_void;
pub const HCRYPTPROV = ULONG_PTR;
pub const HBRUSH = *@Type(.Opaque);
pub const HCURSOR = *@Type(.Opaque);
pub const HICON = *@Type(.Opaque);
pub const HINSTANCE = *@Type(.Opaque);
pub const HMENU = *@Type(.Opaque);
pub const HMODULE = *@Type(.Opaque);
pub const HWND = *@Type(.Opaque);
pub const HDC = *@Type(.Opaque);
pub const HGLRC = *@Type(.Opaque);
pub const FARPROC = *@Type(.Opaque);
pub const HBRUSH = *opaque {};
pub const HCURSOR = *opaque {};
pub const HICON = *opaque {};
pub const HINSTANCE = *opaque {};
pub const HMENU = *opaque {};
pub const HMODULE = *opaque {};
pub const HWND = *opaque {};
pub const HDC = *opaque {};
pub const HGLRC = *opaque {};
pub const FARPROC = *opaque {};
pub const INT = c_int;
pub const LPBYTE = *BYTE;
pub const LPCH = *CHAR;
@ -81,7 +81,7 @@ pub const WPARAM = usize;
pub const LPARAM = ?*c_void;
pub const LRESULT = ?*c_void;
pub const va_list = *@Type(.Opaque);
pub const va_list = *opaque {};
pub const TRUE = 1;
pub const FALSE = 0;
@ -1175,10 +1175,10 @@ pub const UNICODE_STRING = extern struct {
Buffer: [*]WCHAR,
};
const ACTIVATION_CONTEXT_DATA = @Type(.Opaque);
const ASSEMBLY_STORAGE_MAP = @Type(.Opaque);
const FLS_CALLBACK_INFO = @Type(.Opaque);
const RTL_BITMAP = @Type(.Opaque);
const ACTIVATION_CONTEXT_DATA = opaque {};
const ASSEMBLY_STORAGE_MAP = opaque {};
const FLS_CALLBACK_INFO = opaque {};
const RTL_BITMAP = opaque {};
pub const PRTL_BITMAP = *RTL_BITMAP;
const KAFFINITY = usize;

View File

@ -5,7 +5,7 @@
// and substantial portions of the software.
usingnamespace @import("bits.zig");
pub const SOCKET = *@Type(.Opaque);
pub const SOCKET = *opaque {};
pub const INVALID_SOCKET = @intToPtr(SOCKET, ~@as(usize, 0));
pub const SOCKET_ERROR = -1;

View File

@ -288,7 +288,7 @@ pub const Error = union(enum) {
pub const ExpectedVarDecl = SingleTokenError("Expected variable declaration, found '{}'");
pub const ExpectedFn = SingleTokenError("Expected function, found '{}'");
pub const ExpectedReturnType = SingleTokenError("Expected 'var' or return type expression, found '{}'");
pub const ExpectedAggregateKw = SingleTokenError("Expected '" ++ Token.Id.Keyword_struct.symbol() ++ "', '" ++ Token.Id.Keyword_union.symbol() ++ "', or '" ++ Token.Id.Keyword_enum.symbol() ++ "', found '{}'");
pub const ExpectedAggregateKw = SingleTokenError("Expected '" ++ Token.Id.Keyword_struct.symbol() ++ "', '" ++ Token.Id.Keyword_union.symbol() ++ "', '" ++ Token.Id.Keyword_enum.symbol() ++ "', or '" ++ Token.Id.Keyword_opaque.symbol() ++ "', found '{}'");
pub const ExpectedEqOrSemi = SingleTokenError("Expected '=' or ';', found '{}'");
pub const ExpectedSemiOrLBrace = SingleTokenError("Expected ';' or '{{', found '{}'");
pub const ExpectedSemiOrElse = SingleTokenError("Expected ';' or 'else', found '{}'");

View File

@ -2896,11 +2896,12 @@ const Parser = struct {
/// <- KEYWORD_struct
/// / KEYWORD_enum (LPAREN Expr RPAREN)?
/// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
/// / KEYWORD_opaque
fn parseContainerDeclType(p: *Parser) !?ContainerDeclType {
const kind_token = p.nextToken();
const init_arg_expr = switch (p.token_ids[kind_token]) {
.Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} },
.Keyword_struct, .Keyword_opaque => Node.ContainerDecl.InitArg{ .None = {} },
.Keyword_enum => blk: {
if (p.eatToken(.LParen) != null) {
const expr = try p.expectNode(parseExpr, .{

View File

@ -1492,7 +1492,19 @@ fn renderExpression(
// TODO remove after 0.7.0 release
if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@OpaqueType"))
return ais.writer().writeAll("@Type(.Opaque)");
return ais.writer().writeAll("opaque {}");
// TODO remove after 0.7.0 release
{
const params = builtin_call.paramsConst();
if (mem.eql(u8, tree.tokenSlice(builtin_call.builtin_token), "@Type") and
params.len == 1)
{
if (params[0].castTag(.EnumLiteral)) |enum_literal|
if (mem.eql(u8, tree.tokenSlice(enum_literal.name), "Opaque"))
return ais.writer().writeAll("opaque {}");
}
}
try renderToken(tree, ais, builtin_call.builtin_token, Space.None); // @name

View File

@ -47,6 +47,7 @@ pub const Token = struct {
.{ "noinline", .Keyword_noinline },
.{ "nosuspend", .Keyword_nosuspend },
.{ "null", .Keyword_null },
.{ "opaque", .Keyword_opaque },
.{ "or", .Keyword_or },
.{ "orelse", .Keyword_orelse },
.{ "packed", .Keyword_packed },
@ -173,6 +174,7 @@ pub const Token = struct {
Keyword_noinline,
Keyword_nosuspend,
Keyword_null,
Keyword_opaque,
Keyword_or,
Keyword_orelse,
Keyword_packed,
@ -296,6 +298,7 @@ pub const Token = struct {
.Keyword_noinline => "noinline",
.Keyword_nosuspend => "nosuspend",
.Keyword_null => "null",
.Keyword_opaque => "opaque",
.Keyword_or => "or",
.Keyword_orelse => "orelse",
.Keyword_packed => "packed",

File diff suppressed because it is too large Load Diff

View File

@ -76,8 +76,22 @@ flagpd1("M"),
.psl = false,
},
flagpd1("Mach"),
flagpd1("O0"),
flagpd1("O4"),
.{
.name = "O0",
.syntax = .flag,
.zig_equivalent = .optimize,
.pd1 = true,
.pd2 = false,
.psl = false,
},
.{
.name = "O4",
.syntax = .flag,
.zig_equivalent = .optimize,
.pd1 = true,
.pd2 = false,
.psl = false,
},
.{
.name = "O",
.syntax = .flag,
@ -2186,7 +2200,7 @@ flagpd1("fcuda-rdc"),
.{
.name = "Os",
.syntax = .flag,
.zig_equivalent = .other,
.zig_equivalent = .optimize,
.pd1 = true,
.pd2 = false,
.psl = true,
@ -3377,7 +3391,14 @@ flagpd1("fxray-link-deps"),
flagpd1("fzero-initialized-in-bss"),
flagpd1("fzvector"),
flagpd1("g0"),
flagpd1("g1"),
.{
.name = "g1",
.syntax = .flag,
.zig_equivalent = .debug,
.pd1 = true,
.pd2 = false,
.psl = false,
},
flagpd1("g2"),
flagpd1("g3"),
.{
@ -3410,7 +3431,14 @@ flagpd1("ggdb3"),
flagpd1("ggnu-pubnames"),
flagpd1("ginline-line-tables"),
flagpd1("gline-directives-only"),
flagpd1("gline-tables-only"),
.{
.name = "gline-tables-only",
.syntax = .flag,
.zig_equivalent = .debug,
.pd1 = true,
.pd2 = false,
.psl = false,
},
flagpd1("glldb"),
flagpd1("gmlt"),
flagpd1("gmodules"),
@ -5535,7 +5563,7 @@ jspd1("iquote"),
joinpd1("weak-l"),
.{
.name = "Ofast",
.syntax = .joined,
.syntax = .flag,
.zig_equivalent = .optimize,
.pd1 = true,
.pd2 = false,

View File

@ -287,9 +287,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
}
const cmd = &self.load_commands.items[self.dylinker_cmd_index.?].Dylinker;
off += cmd.name;
const padding = cmd.cmdsize - @sizeOf(macho.dylinker_command);
log.debug("writing LC_LOAD_DYLINKER padding of size {} at 0x{x}\n", .{ padding, off });
try self.addPadding(padding, off);
log.debug("writing LC_LOAD_DYLINKER path to dyld at 0x{x}\n", .{off});
try self.base.file.?.pwriteAll(mem.spanZ(DEFAULT_DYLD_PATH), off);
}
@ -302,9 +299,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
}
const cmd = &self.load_commands.items[self.libsystem_cmd_index.?].Dylib;
off += cmd.dylib.name;
const padding = cmd.cmdsize - @sizeOf(macho.dylib_command);
log.debug("writing LC_LOAD_DYLIB padding of size {} at 0x{x}\n", .{ padding, off });
try self.addPadding(padding, off);
log.debug("writing LC_LOAD_DYLIB path to libSystem at 0x{x}\n", .{off});
try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), off);
}
@ -1264,21 +1258,6 @@ fn updateString(self: *MachO, old_str_off: u32, new_name: []const u8) !u32 {
return self.makeString(new_name);
}
/// TODO This should not heap allocate, instead it should utilize a fixed size, statically allocated
/// global const array. You could even use pwritev to write the same buffer multiple times with only
/// 1 syscall if you needed to, for example, write 8192 bytes using a buffer of only 4096 bytes.
/// This size parameter should probably be a usize not u64.
fn addPadding(self: *MachO, size: u64, file_offset: u64) !void {
if (size == 0) return;
const buf = try self.base.allocator.alloc(u8, @intCast(usize, size));
defer self.base.allocator.free(buf);
mem.set(u8, buf[0..], 0);
try self.base.file.?.pwriteAll(buf, file_offset);
}
fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 {
const hdr_size: u64 = @sizeOf(macho.mach_header_64);
if (start < hdr_size) return hdr_size;

View File

@ -992,15 +992,20 @@ fn buildOutputType(
},
.optimize => {
// Alright, what release mode do they want?
if (mem.eql(u8, it.only_arg, "Os")) {
const level = if (it.only_arg.len >= 1 and it.only_arg[0] == 'O') it.only_arg[1..] else it.only_arg;
if (mem.eql(u8, level, "s") or
mem.eql(u8, level, "z"))
{
optimize_mode = .ReleaseSmall;
} else if (mem.eql(u8, it.only_arg, "O2") or
mem.eql(u8, it.only_arg, "O3") or
mem.eql(u8, it.only_arg, "O4"))
} else if (mem.eql(u8, level, "1") or
mem.eql(u8, level, "2") or
mem.eql(u8, level, "3") or
mem.eql(u8, level, "4") or
mem.eql(u8, level, "fast"))
{
optimize_mode = .ReleaseFast;
} else if (mem.eql(u8, it.only_arg, "Og") or
mem.eql(u8, it.only_arg, "O0"))
} else if (mem.eql(u8, level, "g") or
mem.eql(u8, level, "0"))
{
optimize_mode = .Debug;
} else {
@ -1009,8 +1014,13 @@ fn buildOutputType(
},
.debug => {
strip = false;
if (mem.eql(u8, it.only_arg, "-g")) {
if (mem.eql(u8, it.only_arg, "g")) {
// We handled with strip = false above.
} else if (mem.eql(u8, it.only_arg, "g1") or
mem.eql(u8, it.only_arg, "gline-tables-only"))
{
// We handled with strip = false above. but we also want reduced debug info.
try clang_argv.append("-gline-tables-only");
} else {
try clang_argv.appendSlice(it.other_args);
}

View File

@ -72,7 +72,6 @@ enum PtrLen {
enum CallingConvention {
CallingConventionUnspecified,
CallingConventionC,
CallingConventionCold,
CallingConventionNaked,
CallingConventionAsync,
CallingConventionInterrupt,
@ -1054,6 +1053,7 @@ enum ContainerKind {
ContainerKindStruct,
ContainerKindEnum,
ContainerKindUnion,
ContainerKindOpaque,
};
enum ContainerLayout {
@ -1571,7 +1571,10 @@ enum OnePossibleValue {
};
struct ZigTypeOpaque {
AstNode *decl_node;
Buf *bare_name;
ScopeDecls *decls_scope;
};
struct ZigTypeFnFrame {

View File

@ -86,14 +86,18 @@ ZigType *new_type_table_entry(ZigTypeId id) {
}
static ScopeDecls **get_container_scope_ptr(ZigType *type_entry) {
if (type_entry->id == ZigTypeIdStruct) {
return &type_entry->data.structure.decls_scope;
} else if (type_entry->id == ZigTypeIdEnum) {
return &type_entry->data.enumeration.decls_scope;
} else if (type_entry->id == ZigTypeIdUnion) {
return &type_entry->data.unionation.decls_scope;
switch (type_entry->id) {
case ZigTypeIdStruct:
return &type_entry->data.structure.decls_scope;
case ZigTypeIdEnum:
return &type_entry->data.enumeration.decls_scope;
case ZigTypeIdUnion:
return &type_entry->data.unionation.decls_scope;
case ZigTypeIdOpaque:
return &type_entry->data.opaque.decls_scope;
default:
zig_unreachable();
}
zig_unreachable();
}
static ScopeExpr *find_expr_scope(Scope *scope) {
@ -912,13 +916,17 @@ ZigType *get_opaque_type(CodeGen *g, Scope *scope, AstNode *source_node, const c
ZigType *import = scope ? get_scope_import(scope) : nullptr;
unsigned line = source_node ? (unsigned)(source_node->line + 1) : 0;
// Note: duplicated in get_partial_container_type
entry->llvm_type = LLVMInt8Type();
entry->llvm_di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder,
ZigLLVMTag_DW_structure_type(), full_name,
import ? ZigLLVMFileToScope(import->data.structure.root_struct->di_file) : nullptr,
import ? import->data.structure.root_struct->di_file : nullptr,
line);
entry->data.opaque.decl_node = source_node;
entry->data.opaque.bare_name = bare_name;
entry->data.opaque.decls_scope = create_decls_scope(
g, source_node, scope, entry, import, &entry->name);
// The actual size is unknown, but the value must not be 0 because that
// is how type_has_bits is determined.
@ -949,7 +957,6 @@ const char *calling_convention_name(CallingConvention cc) {
switch (cc) {
case CallingConventionUnspecified: return "Unspecified";
case CallingConventionC: return "C";
case CallingConventionCold: return "Cold";
case CallingConventionNaked: return "Naked";
case CallingConventionAsync: return "Async";
case CallingConventionInterrupt: return "Interrupt";
@ -971,7 +978,6 @@ bool calling_convention_allows_zig_types(CallingConvention cc) {
case CallingConventionAsync:
return true;
case CallingConventionC:
case CallingConventionCold:
case CallingConventionNaked:
case CallingConventionInterrupt:
case CallingConventionSignal:
@ -1080,6 +1086,8 @@ static ZigTypeId container_to_type(ContainerKind kind) {
return ZigTypeIdEnum;
case ContainerKindUnion:
return ZigTypeIdUnion;
case ContainerKindOpaque:
return ZigTypeIdOpaque;
}
zig_unreachable();
}
@ -1121,6 +1129,22 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind
entry->data.unionation.decl_node = decl_node;
entry->data.unionation.layout = layout;
break;
case ContainerKindOpaque: {
ZigType *import = scope ? get_scope_import(scope) : nullptr;
unsigned line = decl_node ? (unsigned)(decl_node->line + 1) : 0;
// Note: duplicated in get_opaque_type
entry->llvm_type = LLVMInt8Type();
entry->llvm_di_type = ZigLLVMCreateDebugForwardDeclType(g->dbuilder,
ZigLLVMTag_DW_structure_type(), full_name,
import ? ZigLLVMFileToScope(import->data.structure.root_struct->di_file) : nullptr,
import ? import->data.structure.root_struct->di_file : nullptr,
line);
entry->data.opaque.decl_node = decl_node;
entry->abi_size = SIZE_MAX;
entry->size_in_bits = SIZE_MAX;
entry->abi_align = 1;
break;
}
}
buf_init_from_str(&entry->name, full_name);
@ -1730,7 +1754,7 @@ static Error emit_error_unless_type_allowed_in_packed_union(CodeGen *g, ZigType
return emit_error_unless_type_allowed_in_packed_container(g, type_entry, source_node, "union");
}
Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result) {
Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, ExternPosition position, bool *result) {
Error err;
switch (type_entry->id) {
case ZigTypeIdInvalid:
@ -1749,8 +1773,10 @@ Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result) {
case ZigTypeIdAnyFrame:
*result = false;
return ErrorNone;
case ZigTypeIdOpaque:
case ZigTypeIdUnreachable:
*result = position == ExternPositionFunctionReturn;
return ErrorNone;
case ZigTypeIdOpaque:
case ZigTypeIdBool:
*result = true;
return ErrorNone;
@ -1768,23 +1794,27 @@ Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result) {
return ErrorNone;
}
case ZigTypeIdVector:
return type_allowed_in_extern(g, type_entry->data.vector.elem_type, result);
return type_allowed_in_extern(g, type_entry->data.vector.elem_type, ExternPositionOther, result);
case ZigTypeIdFloat:
*result = true;
return ErrorNone;
case ZigTypeIdArray:
return type_allowed_in_extern(g, type_entry->data.array.child_type, result);
if ((err = type_allowed_in_extern(g, type_entry->data.array.child_type, ExternPositionOther, result)))
return err;
*result = *result &&
position != ExternPositionFunctionParameter &&
position != ExternPositionFunctionReturn;
return ErrorNone;
case ZigTypeIdFn:
*result = !calling_convention_allows_zig_types(type_entry->data.fn.fn_type_id.cc);
return ErrorNone;
case ZigTypeIdPointer:
if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
return err;
if (!type_has_bits(g, type_entry)) {
*result = false;
return ErrorNone;
}
*result = true;
bool has_bits;
if ((err = type_has_bits2(g, type_entry, &has_bits)))
return err;
*result = has_bits;
return ErrorNone;
case ZigTypeIdStruct:
*result = type_entry->data.structure.layout == ContainerLayoutExtern ||
@ -1796,23 +1826,24 @@ Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result) {
*result = false;
return ErrorNone;
}
if (!type_is_nonnull_ptr(g, child_type)) {
bool is_nonnull_ptr;
if ((err = type_is_nonnull_ptr2(g, child_type, &is_nonnull_ptr)))
return err;
if (!is_nonnull_ptr) {
*result = false;
return ErrorNone;
}
return type_allowed_in_extern(g, child_type, result);
return type_allowed_in_extern(g, child_type, ExternPositionOther, result);
}
case ZigTypeIdEnum: {
if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
return err;
ZigType *tag_int_type = type_entry->data.enumeration.tag_int_type;
if (type_entry->data.enumeration.has_explicit_tag_type) {
return type_allowed_in_extern(g, tag_int_type, result);
} else {
*result = type_entry->data.enumeration.layout == ContainerLayoutExtern ||
type_entry->data.enumeration.layout == ContainerLayoutPacked;
return ErrorNone;
}
if (type_entry->data.enumeration.has_explicit_tag_type)
return type_allowed_in_extern(g, tag_int_type, position, result);
*result = type_entry->data.enumeration.layout == ContainerLayoutExtern ||
type_entry->data.enumeration.layout == ContainerLayoutPacked;
return ErrorNone;
}
case ZigTypeIdUnion:
*result = type_entry->data.unionation.layout == ContainerLayoutExtern ||
@ -1909,7 +1940,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
bool ok_type;
if ((err = type_allowed_in_extern(g, type_entry, &ok_type)))
if ((err = type_allowed_in_extern(g, type_entry, ExternPositionFunctionParameter, &ok_type)))
return g->builtin_types.entry_invalid;
if (!ok_type) {
add_node_error(g, param_node->data.param_decl.type,
@ -2014,7 +2045,7 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
if ((err = type_resolve(g, fn_type_id.return_type, ResolveStatusSizeKnown)))
return g->builtin_types.entry_invalid;
bool ok_type;
if ((err = type_allowed_in_extern(g, fn_type_id.return_type, &ok_type)))
if ((err = type_allowed_in_extern(g, fn_type_id.return_type, ExternPositionFunctionReturn, &ok_type)))
return g->builtin_types.entry_invalid;
if (!ok_type) {
add_node_error(g, fn_proto->return_type,
@ -2333,7 +2364,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
if (struct_type->data.structure.layout == ContainerLayoutExtern) {
bool ok_type;
if ((err = type_allowed_in_extern(g, field_type, &ok_type))) {
if ((err = type_allowed_in_extern(g, field_type, ExternPositionOther, &ok_type))) {
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
return ErrorSemanticAnalyzeFail;
}
@ -2588,7 +2619,7 @@ static Error type_is_valid_extern_enum_tag(CodeGen *g, ZigType *ty, bool *result
// signed char, a signed integer or an unsigned one. But GCC/Clang allow
// other integral types as a compiler extension so let's accomodate them
// aswell.
return type_allowed_in_extern(g, ty, result);
return type_allowed_in_extern(g, ty, ExternPositionOther, result);
}
static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
@ -3430,6 +3461,21 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
return ErrorNone;
}
static Error resolve_opaque_type(CodeGen *g, ZigType *opaque_type) {
Error err = ErrorNone;
AstNode *container_node = opaque_type->data.opaque.decl_node;
if (container_node != nullptr) {
assert(container_node->type == NodeTypeContainerDecl);
AstNodeContainerDecl *container_decl = &container_node->data.container_decl;
for (size_t i = 0; i < container_decl->fields.length; i++) {
AstNode *field_node = container_decl->fields.items[i];
add_node_error(g, field_node, buf_create_from_str("opaque types cannot have fields"));
err = ErrorSemanticAnalyzeFail;
}
}
return err;
}
void append_namespace_qualification(CodeGen *g, Buf *buf, ZigType *container_type) {
if (g->root_import == container_type || buf_len(&container_type->name) == 0) return;
buf_append_buf(buf, &container_type->name);
@ -3603,7 +3649,6 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
tld_fn->base.resolution = TldResolutionInvalid;
return;
case CallingConventionC:
case CallingConventionCold:
case CallingConventionNaked:
case CallingConventionInterrupt:
case CallingConventionSignal:
@ -3896,6 +3941,8 @@ static Error resolve_decl_container(CodeGen *g, TldContainer *tld_container) {
return resolve_enum_zero_bits(g, tld_container->type_entry);
case ZigTypeIdUnion:
return resolve_union_type(g, tld_container->type_entry);
case ZigTypeIdOpaque:
return resolve_opaque_type(g, tld_container->type_entry);
default:
zig_unreachable();
}
@ -4462,6 +4509,7 @@ bool is_container(ZigType *type_entry) {
return type_entry->data.structure.special != StructSpecialSlice;
case ZigTypeIdEnum:
case ZigTypeIdUnion:
case ZigTypeIdOpaque:
return true;
case ZigTypeIdPointer:
case ZigTypeIdMetaType:
@ -4481,7 +4529,6 @@ bool is_container(ZigType *type_entry) {
case ZigTypeIdErrorSet:
case ZigTypeIdFn:
case ZigTypeIdBoundFn:
case ZigTypeIdOpaque:
case ZigTypeIdVector:
case ZigTypeIdFnFrame:
case ZigTypeIdAnyFrame:
@ -8168,6 +8215,7 @@ const char *container_string(ContainerKind kind) {
case ContainerKindEnum: return "enum";
case ContainerKindStruct: return "struct";
case ContainerKindUnion: return "union";
case ContainerKindOpaque: return "opaque";
}
zig_unreachable();
}
@ -8186,8 +8234,6 @@ Buf *type_bare_name(ZigType *type_entry) {
return &type_entry->name;
} else if (is_container(type_entry)) {
return get_container_scope(type_entry)->bare_name;
} else if (type_entry->id == ZigTypeIdOpaque) {
return type_entry->data.opaque.bare_name;
} else {
return &type_entry->name;
}

View File

@ -50,7 +50,13 @@ bool handle_is_ptr(CodeGen *g, ZigType *type_entry);
bool type_has_bits(CodeGen *g, ZigType *type_entry);
Error type_has_bits2(CodeGen *g, ZigType *type_entry, bool *result);
Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result);
enum ExternPosition {
ExternPositionFunctionParameter,
ExternPositionFunctionReturn,
ExternPositionOther, // array element, struct field, optional element, etc
};
Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, ExternPosition position, bool *result);
bool ptr_allows_addr_zero(ZigType *ptr_type);
// Deprecated, use `type_is_nonnull_ptr2`

View File

@ -161,12 +161,6 @@ static ZigLLVM_CallingConv get_llvm_cc(CodeGen *g, CallingConvention cc) {
return ZigLLVM_Fast;
case CallingConventionC:
return ZigLLVM_C;
case CallingConventionCold:
if ((g->zig_target->arch == ZigLLVM_x86 ||
g->zig_target->arch == ZigLLVM_x86_64) &&
g->zig_target->os != OsWindows)
return ZigLLVM_Cold;
return ZigLLVM_C;
case CallingConventionNaked:
zig_unreachable();
case CallingConventionStdcall:
@ -340,7 +334,6 @@ static bool cc_want_sret_attr(CallingConvention cc) {
case CallingConventionNaked:
zig_unreachable();
case CallingConventionC:
case CallingConventionCold:
case CallingConventionInterrupt:
case CallingConventionSignal:
case CallingConventionStdcall:
@ -449,7 +442,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
ZigLLVMFunctionSetCallingConv(llvm_fn, get_llvm_cc(g, cc));
}
bool want_cold = fn->is_cold || cc == CallingConventionCold;
bool want_cold = fn->is_cold;
if (want_cold) {
ZigLLVMAddFunctionAttrCold(llvm_fn);
}
@ -8819,18 +8812,17 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
static_assert(CallingConventionUnspecified == 0, "");
static_assert(CallingConventionC == 1, "");
static_assert(CallingConventionCold == 2, "");
static_assert(CallingConventionNaked == 3, "");
static_assert(CallingConventionAsync == 4, "");
static_assert(CallingConventionInterrupt == 5, "");
static_assert(CallingConventionSignal == 6, "");
static_assert(CallingConventionStdcall == 7, "");
static_assert(CallingConventionFastcall == 8, "");
static_assert(CallingConventionVectorcall == 9, "");
static_assert(CallingConventionThiscall == 10, "");
static_assert(CallingConventionAPCS == 11, "");
static_assert(CallingConventionAAPCS == 12, "");
static_assert(CallingConventionAAPCSVFP == 13, "");
static_assert(CallingConventionNaked == 2, "");
static_assert(CallingConventionAsync == 3, "");
static_assert(CallingConventionInterrupt == 4, "");
static_assert(CallingConventionSignal == 5, "");
static_assert(CallingConventionStdcall == 6, "");
static_assert(CallingConventionFastcall == 7, "");
static_assert(CallingConventionVectorcall == 8, "");
static_assert(CallingConventionThiscall == 9, "");
static_assert(CallingConventionAPCS == 10, "");
static_assert(CallingConventionAAPCS == 11, "");
static_assert(CallingConventionAAPCSVFP == 12, "");
static_assert(FnInlineAuto == 0, "");
static_assert(FnInlineAlways == 1, "");

View File

@ -18917,7 +18917,6 @@ static IrInstGen *ir_analyze_instruction_export(IrAnalyze *ira, IrInstSrcExport
add_error_note(ira->codegen, msg, fn_entry->proto_node, buf_sprintf("declared here"));
} break;
case CallingConventionC:
case CallingConventionCold:
case CallingConventionNaked:
case CallingConventionInterrupt:
case CallingConventionSignal:
@ -18965,7 +18964,7 @@ static IrInstGen *ir_analyze_instruction_export(IrAnalyze *ira, IrInstSrcExport
break;
case ZigTypeIdArray: {
bool ok_type;
if ((err = type_allowed_in_extern(ira->codegen, target->value->type->data.array.child_type, &ok_type)))
if ((err = type_allowed_in_extern(ira->codegen, target->value->type->data.array.child_type, ExternPositionOther, &ok_type)))
return ira->codegen->invalid_inst_gen;
if (!ok_type) {
@ -20103,7 +20102,7 @@ static IrInstGen *ir_analyze_store_ptr(IrAnalyze *ira, IrInst* source_instr,
if (uncasted_value->value->type->id == ZigTypeIdErrorUnion ||
uncasted_value->value->type->id == ZigTypeIdErrorSet)
{
ir_add_error(ira, source_instr, buf_sprintf("error is discarded"));
ir_add_error(ira, source_instr, buf_sprintf("error is discarded. consider using `try`, `catch`, or `if`"));
return ira->codegen->invalid_inst_gen;
}
return ir_const_void(ira, source_instr);
@ -22388,6 +22387,8 @@ static IrInstGen *ir_analyze_container_member_access_inner(IrAnalyze *ira,
prefix_name = "enum ";
} else if (bare_struct_type->id == ZigTypeIdUnion) {
prefix_name = "union ";
} else if (bare_struct_type->id == ZigTypeIdOpaque) {
prefix_name = "opaque type ";
} else {
prefix_name = "";
}
@ -22588,7 +22589,7 @@ static IrInstGen *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name
}
}
if (bare_type->id == ZigTypeIdEnum) {
if (bare_type->id == ZigTypeIdEnum || bare_type->id == ZigTypeIdOpaque) {
return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
source_instr, container_ptr, container_ptr_src, container_type);
}
@ -25184,7 +25185,6 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
case ZigTypeIdEnumLiteral:
case ZigTypeIdUndefined:
case ZigTypeIdNull:
case ZigTypeIdOpaque:
result = ira->codegen->intern.for_void();
break;
case ZigTypeIdInt:
@ -25738,6 +25738,25 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy
if ((err = ir_make_type_info_value(ira, source_instr, fn_type, &result)))
return err;
break;
}
case ZigTypeIdOpaque:
{
result = ira->codegen->pass1_arena->create<ZigValue>();
result->special = ConstValSpecialStatic;
result->type = ir_type_info_get_type(ira, "Opaque", nullptr);
ZigValue **fields = alloc_const_vals_ptrs(ira->codegen, 1);
result->data.x_struct.fields = fields;
// decls: []TypeInfo.Declaration
ensure_field_index(result->type, "decls", 0);
if ((err = ir_make_type_info_decls(ira, source_instr, fields[0],
type_entry->data.opaque.decls_scope, false)))
{
return err;
}
break;
}
case ZigTypeIdFnFrame:
@ -26045,6 +26064,21 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI
return get_error_union_type(ira->codegen, err_set_type, payload_type);
}
case ZigTypeIdOpaque: {
assert(payload->special == ConstValSpecialStatic);
assert(payload->type == ir_type_info_get_type(ira, "Opaque", nullptr));
ZigValue *decls_value = get_const_field(ira, source_instr->source_node, payload, "decls", 0);
if (decls_value == nullptr)
return ira->codegen->invalid_inst_gen->value->type;
assert(decls_value->special == ConstValSpecialStatic);
assert(is_slice(decls_value->type));
ZigValue *decls_len_value = decls_value->data.x_struct.fields[slice_len_index];
size_t decls_len = bigint_as_usize(&decls_len_value->data.x_bigint);
if (decls_len != 0) {
ir_add_error(ira, source_instr, buf_create_from_str("TypeInfo.Struct.decls must be empty for @Type"));
return ira->codegen->invalid_inst_gen->value->type;
}
Buf *bare_name = buf_alloc();
Buf *full_name = get_anon_type_name(ira->codegen,
ira->old_irb.exec, "opaque", source_instr->scope, source_instr->source_node, bare_name);
@ -29493,7 +29527,11 @@ static IrInstGen *ir_analyze_instruction_check_statement_is_void(IrAnalyze *ira,
return ira->codegen->invalid_inst_gen;
if (statement_type->id != ZigTypeIdVoid && statement_type->id != ZigTypeIdUnreachable) {
ir_add_error(ira, &instruction->base.base, buf_sprintf("expression value is ignored"));
if(statement_type->id == ZigTypeIdErrorUnion || statement_type->id == ZigTypeIdErrorSet) {
ir_add_error(ira, &instruction->base.base, buf_sprintf("error is ignored. consider using `try`, `catch`, or `if`"));
}else{
ir_add_error(ira, &instruction->base.base, buf_sprintf("expression value is ignored"));
}
}
return ir_const_void(ira, &instruction->base.base);
@ -32708,7 +32746,7 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
return ErrorSemanticAnalyzeFail;
} else if (lazy_ptr_type->ptr_len == PtrLenC) {
bool ok_type;
if ((err = type_allowed_in_extern(ira->codegen, elem_type, &ok_type)))
if ((err = type_allowed_in_extern(ira->codegen, elem_type, ExternPositionOther, &ok_type)))
return err;
if (!ok_type) {
ir_add_error(ira, &lazy_ptr_type->elem_type->base,

View File

@ -2920,6 +2920,7 @@ static AstNode *ast_parse_container_decl_auto(ParseContext *pc) {
// <- KEYWORD_struct
// / KEYWORD_enum (LPAREN Expr RPAREN)?
// / KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? / Expr) RPAREN)?
// / KEYWORD_opaque
static AstNode *ast_parse_container_decl_type(ParseContext *pc) {
Token *first = eat_token_if(pc, TokenIdKeywordStruct);
if (first != nullptr) {
@ -2929,6 +2930,14 @@ static AstNode *ast_parse_container_decl_type(ParseContext *pc) {
return res;
}
first = eat_token_if(pc, TokenIdKeywordOpaque);
if (first != nullptr) {
AstNode *res = ast_create_node(pc, NodeTypeContainerDecl, first);
res->data.container_decl.init_arg_expr = nullptr;
res->data.container_decl.kind = ContainerKindOpaque;
return res;
}
first = eat_token_if(pc, TokenIdKeywordEnum);
if (first != nullptr) {
AstNode *init_arg_expr = nullptr;

View File

@ -133,6 +133,7 @@ static const struct ZigKeyword zig_keywords[] = {
{"noinline", TokenIdKeywordNoInline},
{"nosuspend", TokenIdKeywordNoSuspend},
{"null", TokenIdKeywordNull},
{"opaque", TokenIdKeywordOpaque},
{"or", TokenIdKeywordOr},
{"orelse", TokenIdKeywordOrElse},
{"packed", TokenIdKeywordPacked},
@ -1595,6 +1596,7 @@ const char * token_name(TokenId id) {
case TokenIdKeywordNoInline: return "noinline";
case TokenIdKeywordNoSuspend: return "nosuspend";
case TokenIdKeywordNull: return "null";
case TokenIdKeywordOpaque: return "opaque";
case TokenIdKeywordOr: return "or";
case TokenIdKeywordOrElse: return "orelse";
case TokenIdKeywordPacked: return "packed";

View File

@ -81,6 +81,7 @@ enum TokenId {
TokenIdKeywordNoAlias,
TokenIdKeywordNoSuspend,
TokenIdKeywordNull,
TokenIdKeywordOpaque,
TokenIdKeywordOr,
TokenIdKeywordOrElse,
TokenIdKeywordPacked,

File diff suppressed because it is too large Load Diff

View File

@ -68,16 +68,17 @@ struct ZigClangExprEvalResult {
ZigClangAPValue Val;
};
struct ZigClangAbstractConditionalOperator;
struct ZigClangAPFloat;
struct ZigClangAPInt;
struct ZigClangAPSInt;
struct ZigClangAPValue;
struct ZigClangASTContext;
struct ZigClangASTUnit;
struct ZigClangArraySubscriptExpr;
struct ZigClangArrayType;
struct ZigClangAttributedType;
struct ZigClangBinaryOperator;
struct ZigClangBinaryConditionalOperator;
struct ZigClangBreakStmt;
struct ZigClangBuiltinType;
struct ZigClangCStyleCastExpr;

View File

@ -2,6 +2,19 @@ const tests = @import("tests.zig");
const std = @import("std");
pub fn addCases(cases: *tests.CompileErrorContext) void {
cases.add("array in c exported function",
\\export fn zig_array(x: [10]u8) void {
\\ expect(std.mem.eql(u8, &x, "1234567890"));
\\}
\\
\\export fn zig_return_array() [10]u8 {
\\ return "1234567890".*;
\\}
, &[_][]const u8{
"tmp.zig:1:24: error: parameter of type '[10]u8' not allowed in function with calling convention 'C'",
"tmp.zig:5:30: error: return type '[10]u8' not allowed in function with calling convention 'C'",
});
cases.add("@Type for exhaustive enum with undefined tag type",
\\const TypeInfo = @import("builtin").TypeInfo;
\\const Tag = @Type(.{
@ -125,6 +138,31 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:15:23: error: enum field missing: 'arst'",
"tmp.zig:27:24: note: referenced here",
});
cases.add("field access of opaque type",
\\const MyType = opaque {};
\\
\\export fn entry() bool {
\\ var x: i32 = 1;
\\ return bar(@ptrCast(*MyType, &x));
\\}
\\
\\fn bar(x: *MyType) bool {
\\ return x.blah;
\\}
, &[_][]const u8{
"tmp.zig:9:13: error: no member named 'blah' in opaque type 'MyType'",
});
cases.add("opaque type with field",
\\const Opaque = opaque { foo: i32 };
\\export fn entry() void {
\\ const foo: ?*Opaque = null;
\\}
, &[_][]const u8{
"tmp.zig:1:25: error: opaque types cannot have fields",
});
cases.add("@Type(.Fn) with is_generic = true",
\\const Foo = @Type(.{
\\ .Fn = .{
@ -180,7 +218,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ .layout = .Auto,
\\ .tag_type = null,
\\ .fields = &[_]TypeInfo.UnionField{
\\ .{ .name = "foo", .field_type = @Type(.Opaque), .alignment = 1 },
\\ .{ .name = "foo", .field_type = opaque {}, .alignment = 1 },
\\ },
\\ .decls = &[_]TypeInfo.Declaration{},
\\ },
@ -2287,7 +2325,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return error.OutOfMemory;
\\}
, &[_][]const u8{
"tmp.zig:2:12: error: error is discarded",
"tmp.zig:2:12: error: error is discarded. consider using `try`, `catch`, or `if`",
});
cases.add("volatile on global assembly",
@ -2338,9 +2376,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ return error.Bad;
\\}
, &[_][]const u8{
"tmp.zig:2:24: error: expression value is ignored",
"tmp.zig:6:25: error: expression value is ignored",
"tmp.zig:10:25: error: expression value is ignored",
"tmp.zig:2:24: error: error is ignored. consider using `try`, `catch`, or `if`",
"tmp.zig:6:25: error: error is ignored. consider using `try`, `catch`, or `if`",
"tmp.zig:10:25: error: error is ignored. consider using `try`, `catch`, or `if`",
});
cases.add("empty while loop body",
@ -2613,7 +2651,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
});
cases.add("directly embedding opaque type in struct and union",
\\const O = @Type(.Opaque);
\\const O = opaque {};
\\const Foo = struct {
\\ o: O,
\\};
@ -2628,7 +2666,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\ var bar: Bar = undefined;
\\}
\\export fn c() void {
\\ var baz: *@Type(.Opaque) = undefined;
\\ var baz: *opaque {} = undefined;
\\ const qux = .{baz.*};
\\}
, &[_][]const u8{
@ -3592,7 +3630,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
});
cases.add("unknown length pointer to opaque",
\\export const T = [*]@Type(.Opaque);
\\export const T = [*]opaque {};
, &[_][]const u8{
"tmp.zig:1:21: error: unknown-length pointer to opaque",
});
@ -6236,7 +6274,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\}
\\fn bar() anyerror!i32 { return 0; }
, &[_][]const u8{
"tmp.zig:2:14: error: expression value is ignored",
"tmp.zig:2:14: error: error is ignored. consider using `try`, `catch`, or `if`",
});
cases.add("dereference an array",
@ -6827,8 +6865,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:2:31: error: index 2 outside array of size 2",
});
cases.add("wrong pointer coerced to pointer to @Type(.Opaque)",
\\const Derp = @Type(.Opaque);
cases.add("wrong pointer coerced to pointer to opaque {}",
\\const Derp = opaque {};
\\extern fn bar(d: *Derp) void;
\\export fn foo() void {
\\ var x = @as(u8, 1);
@ -6854,8 +6892,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn entry5() void {
\\ var d = null;
\\}
\\export fn entry6(opaque: *Opaque) void {
\\ var e = opaque.*;
\\export fn entry6(opaque_: *Opaque) void {
\\ var e = opaque_.*;
\\}
\\export fn entry7() void {
\\ var f = i32;
@ -6866,7 +6904,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\export fn entry9() void {
\\ var z: noreturn = return;
\\}
\\const Opaque = @Type(.Opaque);
\\const Opaque = opaque {};
\\const Foo = struct {
\\ fn bar(self: *const Foo) void {}
\\};
@ -7019,21 +7057,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
"tmp.zig:37:29: error: cannot store runtime value in compile time variable",
});
cases.add("field access of opaque type",
\\const MyType = @Type(.Opaque);
\\
\\export fn entry() bool {
\\ var x: i32 = 1;
\\ return bar(@ptrCast(*MyType, &x));
\\}
\\
\\fn bar(x: *MyType) bool {
\\ return x.blah;
\\}
, &[_][]const u8{
"tmp.zig:9:13: error: type '*MyType' does not support field access",
});
cases.add("invalid legacy unicode escape",
\\export fn entry() void {
\\ const a = '\U1234';
@ -7623,7 +7646,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
});
cases.add("function returning opaque type",
\\const FooType = @Type(.Opaque);
\\const FooType = opaque {};
\\export fn bar() !FooType {
\\ return error.InvalidValue;
\\}
@ -7641,7 +7664,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
});
cases.add("generic function returning opaque type",
\\const FooType = @Type(.Opaque);
\\const FooType = opaque {};
\\fn generic(comptime T: type) !T {
\\ return undefined;
\\}
@ -7665,7 +7688,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
});
cases.add("function parameter is opaque",
\\const FooType = @Type(.Opaque);
\\const FooType = opaque {};
\\export fn entry1() void {
\\ const someFuncPtr: fn (FooType) void = undefined;
\\}

View File

@ -74,7 +74,7 @@ pub fn addCases(cases: *tests.GenHContext) void {
});
cases.add("declare opaque type",
\\const Foo = @Type(.Opaque);
\\const Foo = opaque {};
\\
\\export fn entry(foo: ?*Foo) void { }
, &[_][]const u8{

View File

@ -438,8 +438,8 @@ export fn writeToVRam() void {
vram[0] = 'X';
}
const OpaqueA = @Type(.Opaque);
const OpaqueB = @Type(.Opaque);
const OpaqueA = opaque {};
const OpaqueB = opaque {};
test "opaque types" {
expect(*OpaqueA != *OpaqueB);
expect(mem.eql(u8, @typeName(OpaqueA), "OpaqueA"));
@ -704,7 +704,7 @@ test "auto created variables have correct alignment" {
comptime expect(S.foo("\x7a\x7a\x7a\x7a") == 0x7a7a7a7a);
}
extern var opaque_extern_var: @Type(.Opaque);
extern var opaque_extern_var: opaque {};
var var_to_export: u32 = 42;
test "extern variable with non-pointer opaque type" {
@export(var_to_export, .{ .name = "opaque_extern_var" });

View File

@ -190,8 +190,17 @@ test "Type.ErrorUnion" {
}
test "Type.Opaque" {
testing.expect(@Type(.Opaque) != @Type(.Opaque));
testing.expect(@typeInfo(@Type(.Opaque)) == .Opaque);
const Opaque = @Type(.{
.Opaque = .{
.decls = &[_]TypeInfo.Declaration{},
},
});
testing.expect(Opaque != opaque {});
testing.expectEqualSlices(
TypeInfo.Declaration,
&[_]TypeInfo.Declaration{},
@typeInfo(Opaque).Opaque.decls,
);
}
test "Type.Vector" {

View File

@ -199,7 +199,7 @@ fn testUnion() void {
expect(typeinfo_info.Union.tag_type.? == TypeId);
expect(typeinfo_info.Union.fields.len == 25);
expect(typeinfo_info.Union.fields[4].field_type == @TypeOf(@typeInfo(u8).Int));
expect(typeinfo_info.Union.decls.len == 21);
expect(typeinfo_info.Union.decls.len == 22);
const TestNoTagUnion = union {
Foo: void,
@ -265,6 +265,21 @@ const TestStruct = packed struct {
const Self = @This();
};
test "type info: opaque info" {
testOpaque();
comptime testOpaque();
}
fn testOpaque() void {
const Foo = opaque {
const A = 1;
fn b() void {}
};
const foo_info = @typeInfo(Foo);
expect(foo_info.Opaque.decls.len == 2);
}
test "type info: function type info" {
// wasm doesn't support align attributes on functions
if (builtin.arch == .wasm32 or builtin.arch == .wasm64) return error.SkipZigTest;

View File

@ -28,8 +28,6 @@ void zig_ptr(void *);
void zig_bool(bool);
void zig_array(uint8_t[10]);
struct BigStruct {
uint64_t a;
uint64_t b;
@ -97,9 +95,6 @@ void run_c_tests(void) {
zig_bool(true);
uint8_t array[10] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
zig_array(array);
{
struct BigStruct s = {1, 2, 3, 4, 5};
zig_big_struct(s);
@ -190,19 +185,6 @@ void c_five_floats(float a, float b, float c, float d, float e) {
assert_or_panic(e == 5.0);
}
void c_array(uint8_t x[10]) {
assert_or_panic(x[0] == '1');
assert_or_panic(x[1] == '2');
assert_or_panic(x[2] == '3');
assert_or_panic(x[3] == '4');
assert_or_panic(x[4] == '5');
assert_or_panic(x[5] == '6');
assert_or_panic(x[6] == '7');
assert_or_panic(x[7] == '8');
assert_or_panic(x[8] == '9');
assert_or_panic(x[9] == '0');
}
void c_big_struct(struct BigStruct x) {
assert_or_panic(x.a == 1);
assert_or_panic(x.b == 2);

View File

@ -116,17 +116,6 @@ export fn zig_bool(x: bool) void {
expect(x);
}
extern fn c_array([10]u8) void;
test "C ABI array" {
var array: [10]u8 = "1234567890".*;
c_array(array);
}
export fn zig_array(x: [10]u8) void {
expect(std.mem.eql(u8, &x, "1234567890"));
}
const BigStruct = extern struct {
a: u64,
b: u64,

View File

@ -137,9 +137,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\struct foo { int x; int y[]; };
\\struct bar { int x; int y[0]; };
, &[_][]const u8{
\\pub const struct_foo = @Type(.Opaque);
\\pub const struct_foo = opaque {};
,
\\pub const struct_bar = @Type(.Opaque);
\\pub const struct_bar = opaque {};
});
cases.add("nested loops without blocks",
@ -207,7 +207,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const struct_arcan_shmif_page = //
,
\\warning: unsupported type: 'Atomic'
\\ @Type(.Opaque); //
\\ opaque {}; //
,
\\ warning: struct demoted to opaque type - unable to translate type of field abufused
, // TODO should be `addr: *struct_arcan_shmif_page`
@ -386,8 +386,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ struct opaque_2 *cast = (struct opaque_2 *)opaque;
\\}
, &[_][]const u8{
\\pub const struct_opaque = @Type(.Opaque);
\\pub const struct_opaque_2 = @Type(.Opaque);
\\pub const struct_opaque = opaque {};
\\pub const struct_opaque_2 = opaque {};
\\pub export fn function(arg_opaque_1: ?*struct_opaque) void {
\\ var opaque_1 = arg_opaque_1;
\\ var cast: ?*struct_opaque_2 = @ptrCast(?*struct_opaque_2, opaque_1);
@ -628,7 +628,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ struct Foo *foo;
\\};
, &[_][]const u8{
\\pub const struct_Foo = @Type(.Opaque);
\\pub const struct_Foo = opaque {};
,
\\pub const struct_Bar = extern struct {
\\ foo: ?*struct_Foo,
@ -705,7 +705,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\struct Foo;
\\struct Foo *some_func(struct Foo *foo, int x);
, &[_][]const u8{
\\pub const struct_Foo = @Type(.Opaque);
\\pub const struct_Foo = opaque {};
,
\\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo;
,

View File

@ -130,6 +130,10 @@ const known_options = [_]KnownOpt{
.name = "assemble",
.ident = "asm_only",
},
.{
.name = "O0",
.ident = "optimize",
},
.{
.name = "O1",
.ident = "optimize",
@ -138,10 +142,20 @@ const known_options = [_]KnownOpt{
.name = "O2",
.ident = "optimize",
},
// O3 is only detected from the joined "-O" option
.{
.name = "O4",
.ident = "optimize",
},
.{
.name = "Og",
.ident = "optimize",
},
.{
.name = "Os",
.ident = "optimize",
},
// Oz is only detected from the joined "-O" option
.{
.name = "O",
.ident = "optimize",
@ -154,6 +168,14 @@ const known_options = [_]KnownOpt{
.name = "optimize",
.ident = "optimize",
},
.{
.name = "g1",
.ident = "debug",
},
.{
.name = "gline-tables-only",
.ident = "debug",
},
.{
.name = "g",
.ident = "debug",
@ -390,6 +412,10 @@ pub fn main() anyerror!void {
// the only way.
try stdout.print("flagpsl(\"{}\"),\n", .{name});
} else if (knownOption(name)) |ident| {
// Workaround the fact that in 'Options.td' -Ofast is listed as 'joined'
const final_syntax = if (std.mem.eql(u8, name, "Ofast")) .flag else syntax;
try stdout.print(
\\.{{
\\ .name = "{}",
@ -400,7 +426,7 @@ pub fn main() anyerror!void {
\\ .psl = {},
\\}},
\\
, .{ name, syntax, ident, pd1, pd2, pslash });
, .{ name, final_syntax, ident, pd1, pd2, pslash });
} else if (pd1 and !pd2 and !pslash and syntax == .flag) {
try stdout.print("flagpd1(\"{}\"),\n", .{name});
} else if (!pd1 and !pd2 and pslash and syntax == .flag) {