mirror of
https://github.com/ziglang/zig.git
synced 2026-02-20 08:14:48 +00:00
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:
commit
8b7539bd95
@ -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,
|
||||
|
||||
@ -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 <- ContainerDeclType LBRACE ContainerMembers RBRACE
|
||||
|
||||
ContainerDeclType
|
||||
<- (KEYWORD_struct / KEYWORD_enum) (LPAREN Expr RPAREN)?
|
||||
<- (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 <- 'inline' end_of_word
|
||||
KEYWORD_noalias <- 'noalias' end_of_word
|
||||
KEYWORD_nosuspend <- 'nosuspend' end_of_word
|
||||
KEYWORD_null <- 'null' end_of_word
|
||||
KEYWORD_opaque <- 'opaque' end_of_word
|
||||
KEYWORD_or <- 'or' end_of_word
|
||||
KEYWORD_orelse <- 'orelse' end_of_word
|
||||
KEYWORD_packed <- 'packed' end_of_word
|
||||
@ -11368,7 +11370,7 @@ keyword <- 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
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
490
lib/std/crypto/aes/armcrypto.zig
Normal file
490
lib/std/crypto/aes/armcrypto.zig
Normal 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);
|
||||
}
|
||||
};
|
||||
@ -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
|
||||
|
||||
@ -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");
|
||||
}
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
120
lib/std/event/wait_group.zig
Normal file
120
lib/std/event/wait_group.zig
Normal 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);
|
||||
}
|
||||
@ -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}));
|
||||
}
|
||||
|
||||
|
||||
@ -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)));
|
||||
}
|
||||
|
||||
|
||||
@ -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 {};
|
||||
|
||||
@ -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 {};
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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 '{}'");
|
||||
|
||||
@ -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, .{
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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",
|
||||
|
||||
1448
src/clang.zig
1448
src/clang.zig
File diff suppressed because it is too large
Load Diff
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
24
src/main.zig
24
src/main.zig
@ -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);
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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`
|
||||
|
||||
@ -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, "");
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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";
|
||||
|
||||
@ -81,6 +81,7 @@ enum TokenId {
|
||||
TokenIdKeywordNoAlias,
|
||||
TokenIdKeywordNoSuspend,
|
||||
TokenIdKeywordNull,
|
||||
TokenIdKeywordOpaque,
|
||||
TokenIdKeywordOr,
|
||||
TokenIdKeywordOrElse,
|
||||
TokenIdKeywordPacked,
|
||||
|
||||
1352
src/translate_c.zig
1352
src/translate_c.zig
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
||||
@ -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;
|
||||
\\}
|
||||
|
||||
@ -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{
|
||||
|
||||
@ -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" });
|
||||
|
||||
@ -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" {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
,
|
||||
|
||||
@ -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) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user