mirror of
https://github.com/ziglang/zig.git
synced 2026-02-17 23:10:09 +00:00
Merge pull request #1965 from ziglang/c-pointer-type
implement C pointers
This commit is contained in:
commit
567c9b688e
@ -916,6 +916,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
|
||||
std.zig.Token.Id.AngleBracketAngleBracketRightEqual,
|
||||
std.zig.Token.Id.Tilde,
|
||||
std.zig.Token.Id.BracketStarBracket,
|
||||
std.zig.Token.Id.BracketStarCBracket,
|
||||
=> try writeEscaped(out, src[token.start..token.end]),
|
||||
|
||||
std.zig.Token.Id.Invalid => return parseError(
|
||||
|
||||
@ -1694,7 +1694,7 @@ test "comptime @intToPtr" {
|
||||
}
|
||||
}
|
||||
{#code_end#}
|
||||
{#see_also|Optional Pointers#}
|
||||
{#see_also|Optional Pointers|@intToPtr|@ptrToInt#}
|
||||
{#header_open|volatile#}
|
||||
<p>Loads and stores are assumed to not have side effects. If a given load or store
|
||||
should have side effects, such as Memory Mapped Input/Output (MMIO), use {#syntax#}volatile{#endsyntax#}.
|
||||
@ -1823,7 +1823,9 @@ fn foo(bytes: []u8) u32 {
|
||||
}
|
||||
{#code_end#}
|
||||
{#header_close#}
|
||||
{#see_also|C Pointers#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Slices#}
|
||||
{#code_begin|test_safety|index out of bounds#}
|
||||
const assert = @import("std").debug.assert;
|
||||
@ -3981,7 +3983,7 @@ test "implicit cast - invoke a type as a function" {
|
||||
{#code_end#}
|
||||
<p>
|
||||
Implicit casts are only allowed when it is completely unambiguous how to get from one type to another,
|
||||
and the transformation is guaranteed to be safe.
|
||||
and the transformation is guaranteed to be safe. There is one exception, which is {#link|C Pointers#}.
|
||||
</p>
|
||||
{#header_open|Implicit Cast: Stricter Qualification#}
|
||||
<p>
|
||||
@ -6104,6 +6106,10 @@ test "call foo" {
|
||||
<p>
|
||||
Converts a pointer of one type to a pointer of another type.
|
||||
</p>
|
||||
<p>
|
||||
{#link|Optional Pointers#} are allowed. Casting an optional pointer which is {#link|null#}
|
||||
to a non-optional pointer invokes safety-checked {#link|Undefined Behavior#}.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@ptrToInt#}
|
||||
@ -7345,10 +7351,27 @@ fn bar(f: *Foo) void {
|
||||
{#code_end#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Out of Bounds Float To Integer Cast#}
|
||||
{#header_open|Out of Bounds Float to Integer Cast#}
|
||||
<p>TODO</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Pointer Cast Invalid Null#}
|
||||
<p>At compile-time:</p>
|
||||
{#code_begin|test_err|null pointer casted to type#}
|
||||
comptime {
|
||||
const opt_ptr: ?*i32 = null;
|
||||
const ptr = @ptrCast(*i32, opt_ptr);
|
||||
}
|
||||
{#code_end#}
|
||||
<p>At runtime:</p>
|
||||
{#code_begin|exe_err#}
|
||||
pub fn main() void {
|
||||
var opt_ptr: ?*i32 = null;
|
||||
var ptr = @ptrCast(*i32, opt_ptr);
|
||||
}
|
||||
{#code_end#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_close#}
|
||||
{#header_open|Memory#}
|
||||
<p>TODO: explain no default allocator in zig</p>
|
||||
@ -7439,6 +7462,7 @@ pub fn main() void {
|
||||
{#code_end#}
|
||||
{#see_also|String Literals#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Import from C Header File#}
|
||||
<p>
|
||||
The {#syntax#}@cImport{#endsyntax#} builtin function can be used
|
||||
@ -7477,6 +7501,36 @@ const c = @cImport({
|
||||
{#code_end#}
|
||||
{#see_also|@cImport|@cInclude|@cDefine|@cUndef|@import#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|C Pointers#}
|
||||
<p>
|
||||
This type is to be avoided whenever possible. The only valid reason for using a C pointer is in
|
||||
auto-generated code from translating C code.
|
||||
</p>
|
||||
<p>
|
||||
When importing C header files, it is ambiguous whether pointers should be translated as
|
||||
single-item pointers ({#syntax#}*T{#endsyntax#}) or unknown-length pointers ({#syntax#}[*]T{#endsyntax#}).
|
||||
C pointers are a compromise so that Zig code can utilize translated header files directly.
|
||||
</p>
|
||||
<p>{#syntax#}[*c]T{#endsyntax#} - C pointer.</p>
|
||||
<ul>
|
||||
<li>Supports all the syntax of the other two pointer types.</li>
|
||||
<li>Implicitly casts to other pointer types, as well as {#link|Optional Pointers#}.
|
||||
When a C pointer is implicitly casted to a non-optional pointer, safety-checked
|
||||
{#link|Undefined Behavior#} occurs if the address is 0.
|
||||
</li>
|
||||
<li>Allows address 0. On non-freestanding targets, dereferencing address 0 is safety-checked
|
||||
{#link|Undefined Behavior#}. Optional C pointers introduce another bit to keep track of
|
||||
null, just like {#syntax#}?usize{#endsyntax#}. Note that creating an optional C pointer
|
||||
is unnecessary as one can use normal {#link|Optional Pointers#}.
|
||||
</li>
|
||||
<li>Supports {#link|implicit casting|Implicit Casts#} to and from integers.</li>
|
||||
<li>Supports comparison with integers.</li>
|
||||
<li>Does not support Zig-only pointer attributes such as alignment. Use normal {#link|Pointers#}
|
||||
please!</li>
|
||||
</ul>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Exporting a C Library#}
|
||||
<p>
|
||||
One of the primary use cases for Zig is exporting a library with the C ABI for other programming languages
|
||||
@ -8164,7 +8218,8 @@ ArrayTypeStart <- LBRACKET Expr? RBRACKET
|
||||
PtrTypeStart
|
||||
<- ASTERISK
|
||||
/ ASTERISK2
|
||||
/ LBRACKET ASTERISK RBRACKET
|
||||
/ PTRUNKNOWN
|
||||
/ PTRC
|
||||
|
||||
# ContainerDecl specific
|
||||
ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE
|
||||
@ -8262,7 +8317,7 @@ LARROW2 <- '<<' ![=] skip
|
||||
LARROW2EQUAL <- '<<=' skip
|
||||
LARROWEQUAL <- '<=' skip
|
||||
LBRACE <- '{' skip
|
||||
LBRACKET <- '[' skip
|
||||
LBRACKET <- '[' ![*] skip
|
||||
LPAREN <- '(' skip
|
||||
MINUS <- '-' ![%=>] skip
|
||||
MINUSEQUAL <- '-=' skip
|
||||
@ -8279,6 +8334,8 @@ PLUS2 <- '++' skip
|
||||
PLUSEQUAL <- '+=' skip
|
||||
PLUSPERCENT <- '+%' ![=] skip
|
||||
PLUSPERCENTEQUAL <- '+%=' skip
|
||||
PTRC <- '[*c]' skip
|
||||
PTRUNKNOWN <- '[*]' skip
|
||||
QUESTIONMARK <- '?' skip
|
||||
RARROW <- '>' ![>=] skip
|
||||
RARROW2 <- '>>' ![=] skip
|
||||
|
||||
@ -137,10 +137,10 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
|
||||
|
||||
pub const ObjectFile = struct {
|
||||
comp: *Compilation,
|
||||
module: llvm.ModuleRef,
|
||||
builder: llvm.BuilderRef,
|
||||
module: *llvm.Module,
|
||||
builder: *llvm.Builder,
|
||||
dibuilder: *llvm.DIBuilder,
|
||||
context: llvm.ContextRef,
|
||||
context: *llvm.Context,
|
||||
lock: event.Lock,
|
||||
arena: *std.mem.Allocator,
|
||||
|
||||
@ -323,7 +323,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)
|
||||
|
||||
fn addLLVMAttr(
|
||||
ofile: *ObjectFile,
|
||||
val: llvm.ValueRef,
|
||||
val: *llvm.Value,
|
||||
attr_index: llvm.AttributeIndex,
|
||||
attr_name: []const u8,
|
||||
) !void {
|
||||
@ -335,7 +335,7 @@ fn addLLVMAttr(
|
||||
|
||||
fn addLLVMAttrStr(
|
||||
ofile: *ObjectFile,
|
||||
val: llvm.ValueRef,
|
||||
val: *llvm.Value,
|
||||
attr_index: llvm.AttributeIndex,
|
||||
attr_name: []const u8,
|
||||
attr_val: []const u8,
|
||||
@ -351,7 +351,7 @@ fn addLLVMAttrStr(
|
||||
}
|
||||
|
||||
fn addLLVMAttrInt(
|
||||
val: llvm.ValueRef,
|
||||
val: *llvm.Value,
|
||||
attr_index: llvm.AttributeIndex,
|
||||
attr_name: []const u8,
|
||||
attr_val: u64,
|
||||
@ -362,25 +362,25 @@ fn addLLVMAttrInt(
|
||||
llvm.AddAttributeAtIndex(val, attr_index, llvm_attr);
|
||||
}
|
||||
|
||||
fn addLLVMFnAttr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8) !void {
|
||||
fn addLLVMFnAttr(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8) !void {
|
||||
return addLLVMAttr(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name);
|
||||
}
|
||||
|
||||
fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: []const u8) !void {
|
||||
fn addLLVMFnAttrStr(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8, attr_val: []const u8) !void {
|
||||
return addLLVMAttrStr(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name, attr_val);
|
||||
}
|
||||
|
||||
fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: llvm.ValueRef, attr_name: []const u8, attr_val: u64) !void {
|
||||
fn addLLVMFnAttrInt(ofile: *ObjectFile, fn_val: *llvm.Value, attr_name: []const u8, attr_val: u64) !void {
|
||||
return addLLVMAttrInt(ofile, fn_val, maxInt(llvm.AttributeIndex), attr_name, attr_val);
|
||||
}
|
||||
|
||||
fn renderLoadUntyped(
|
||||
ofile: *ObjectFile,
|
||||
ptr: llvm.ValueRef,
|
||||
ptr: *llvm.Value,
|
||||
alignment: Type.Pointer.Align,
|
||||
vol: Type.Pointer.Vol,
|
||||
name: [*]const u8,
|
||||
) !llvm.ValueRef {
|
||||
) !*llvm.Value {
|
||||
const result = llvm.BuildLoad(ofile.builder, ptr, name) orelse return error.OutOfMemory;
|
||||
switch (vol) {
|
||||
Type.Pointer.Vol.Non => {},
|
||||
@ -390,11 +390,11 @@ fn renderLoadUntyped(
|
||||
return result;
|
||||
}
|
||||
|
||||
fn renderLoad(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer, name: [*]const u8) !llvm.ValueRef {
|
||||
fn renderLoad(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer, name: [*]const u8) !*llvm.Value {
|
||||
return renderLoadUntyped(ofile, ptr, ptr_type.key.alignment, ptr_type.key.vol, name);
|
||||
}
|
||||
|
||||
pub fn getHandleValue(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Pointer) !?llvm.ValueRef {
|
||||
pub fn getHandleValue(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer) !?*llvm.Value {
|
||||
const child_type = ptr_type.key.child_type;
|
||||
if (!child_type.hasBits()) {
|
||||
return null;
|
||||
@ -407,11 +407,11 @@ pub fn getHandleValue(ofile: *ObjectFile, ptr: llvm.ValueRef, ptr_type: *Type.Po
|
||||
|
||||
pub fn renderStoreUntyped(
|
||||
ofile: *ObjectFile,
|
||||
value: llvm.ValueRef,
|
||||
ptr: llvm.ValueRef,
|
||||
value: *llvm.Value,
|
||||
ptr: *llvm.Value,
|
||||
alignment: Type.Pointer.Align,
|
||||
vol: Type.Pointer.Vol,
|
||||
) !llvm.ValueRef {
|
||||
) !*llvm.Value {
|
||||
const result = llvm.BuildStore(ofile.builder, value, ptr) orelse return error.OutOfMemory;
|
||||
switch (vol) {
|
||||
Type.Pointer.Vol.Non => {},
|
||||
@ -423,10 +423,10 @@ pub fn renderStoreUntyped(
|
||||
|
||||
pub fn renderStore(
|
||||
ofile: *ObjectFile,
|
||||
value: llvm.ValueRef,
|
||||
ptr: llvm.ValueRef,
|
||||
value: *llvm.Value,
|
||||
ptr: *llvm.Value,
|
||||
ptr_type: *Type.Pointer,
|
||||
) !llvm.ValueRef {
|
||||
) !*llvm.Value {
|
||||
return renderStoreUntyped(ofile, value, ptr, ptr_type.key.alignment, ptr_type.key.vol);
|
||||
}
|
||||
|
||||
@ -435,7 +435,7 @@ pub fn renderAlloca(
|
||||
var_type: *Type,
|
||||
name: []const u8,
|
||||
alignment: Type.Pointer.Align,
|
||||
) !llvm.ValueRef {
|
||||
) !*llvm.Value {
|
||||
const llvm_var_type = try var_type.getLlvmType(ofile.arena, ofile.context);
|
||||
const name_with_null = try std.cstr.addNullByte(ofile.arena, name);
|
||||
const result = llvm.BuildAlloca(ofile.builder, llvm_var_type, name_with_null.ptr) orelse return error.OutOfMemory;
|
||||
@ -443,7 +443,7 @@ pub fn renderAlloca(
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn resolveAlign(ofile: *ObjectFile, alignment: Type.Pointer.Align, llvm_type: llvm.TypeRef) u32 {
|
||||
pub fn resolveAlign(ofile: *ObjectFile, alignment: Type.Pointer.Align, llvm_type: *llvm.Type) u32 {
|
||||
return switch (alignment) {
|
||||
Type.Pointer.Align.Abi => return llvm.ABIAlignmentOfType(ofile.comp.target_data_ref, llvm_type),
|
||||
Type.Pointer.Align.Override => |a| a,
|
||||
|
||||
@ -37,7 +37,7 @@ const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB
|
||||
/// Data that is local to the event loop.
|
||||
pub const ZigCompiler = struct {
|
||||
loop: *event.Loop,
|
||||
llvm_handle_pool: std.atomic.Stack(llvm.ContextRef),
|
||||
llvm_handle_pool: std.atomic.Stack(*llvm.Context),
|
||||
lld_lock: event.Lock,
|
||||
|
||||
/// TODO pool these so that it doesn't have to lock
|
||||
@ -60,7 +60,7 @@ pub const ZigCompiler = struct {
|
||||
return ZigCompiler{
|
||||
.loop = loop,
|
||||
.lld_lock = event.Lock.init(loop),
|
||||
.llvm_handle_pool = std.atomic.Stack(llvm.ContextRef).init(),
|
||||
.llvm_handle_pool = std.atomic.Stack(*llvm.Context).init(),
|
||||
.prng = event.Locked(std.rand.DefaultPrng).init(loop, std.rand.DefaultPrng.init(seed)),
|
||||
.native_libc = event.Future(LibCInstallation).init(loop),
|
||||
};
|
||||
@ -70,7 +70,7 @@ pub const ZigCompiler = struct {
|
||||
fn deinit(self: *ZigCompiler) void {
|
||||
self.lld_lock.deinit();
|
||||
while (self.llvm_handle_pool.pop()) |node| {
|
||||
c.LLVMContextDispose(node.data);
|
||||
llvm.ContextDispose(node.data);
|
||||
self.loop.allocator.destroy(node);
|
||||
}
|
||||
}
|
||||
@ -80,11 +80,11 @@ pub const ZigCompiler = struct {
|
||||
pub fn getAnyLlvmContext(self: *ZigCompiler) !LlvmHandle {
|
||||
if (self.llvm_handle_pool.pop()) |node| return LlvmHandle{ .node = node };
|
||||
|
||||
const context_ref = c.LLVMContextCreate() orelse return error.OutOfMemory;
|
||||
errdefer c.LLVMContextDispose(context_ref);
|
||||
const context_ref = llvm.ContextCreate() orelse return error.OutOfMemory;
|
||||
errdefer llvm.ContextDispose(context_ref);
|
||||
|
||||
const node = try self.loop.allocator.create(std.atomic.Stack(llvm.ContextRef).Node);
|
||||
node.* = std.atomic.Stack(llvm.ContextRef).Node{
|
||||
const node = try self.loop.allocator.create(std.atomic.Stack(*llvm.Context).Node);
|
||||
node.* = std.atomic.Stack(*llvm.Context).Node{
|
||||
.next = undefined,
|
||||
.data = context_ref,
|
||||
};
|
||||
@ -114,7 +114,7 @@ pub const ZigCompiler = struct {
|
||||
};
|
||||
|
||||
pub const LlvmHandle = struct {
|
||||
node: *std.atomic.Stack(llvm.ContextRef).Node,
|
||||
node: *std.atomic.Stack(*llvm.Context).Node,
|
||||
|
||||
pub fn release(self: LlvmHandle, zig_compiler: *ZigCompiler) void {
|
||||
zig_compiler.llvm_handle_pool.push(self.node);
|
||||
@ -128,7 +128,7 @@ pub const Compilation = struct {
|
||||
llvm_triple: Buffer,
|
||||
root_src_path: ?[]const u8,
|
||||
target: Target,
|
||||
llvm_target: llvm.TargetRef,
|
||||
llvm_target: *llvm.Target,
|
||||
build_mode: builtin.Mode,
|
||||
zig_lib_dir: []const u8,
|
||||
zig_std_dir: []const u8,
|
||||
@ -212,8 +212,8 @@ pub const Compilation = struct {
|
||||
false_value: *Value.Bool,
|
||||
noreturn_value: *Value.NoReturn,
|
||||
|
||||
target_machine: llvm.TargetMachineRef,
|
||||
target_data_ref: llvm.TargetDataRef,
|
||||
target_machine: *llvm.TargetMachine,
|
||||
target_data_ref: *llvm.TargetData,
|
||||
target_layout_str: [*]u8,
|
||||
target_ptr_bits: u32,
|
||||
|
||||
|
||||
@ -67,7 +67,7 @@ pub const Inst = struct {
|
||||
parent: ?*Inst,
|
||||
|
||||
/// populated durign codegen
|
||||
llvm_value: ?llvm.ValueRef,
|
||||
llvm_value: ?*llvm.Value,
|
||||
|
||||
pub fn cast(base: *Inst, comptime T: type) ?*T {
|
||||
if (base.id == comptime typeToId(T)) {
|
||||
@ -129,7 +129,7 @@ pub const Inst = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) {
|
||||
pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?*llvm.Value) {
|
||||
switch (base.id) {
|
||||
Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val),
|
||||
Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val),
|
||||
@ -313,10 +313,10 @@ pub const Inst = struct {
|
||||
return new_inst;
|
||||
}
|
||||
|
||||
pub fn render(self: *Call, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
|
||||
pub fn render(self: *Call, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
|
||||
const fn_ref = self.params.fn_ref.llvm_value.?;
|
||||
|
||||
const args = try ofile.arena.alloc(llvm.ValueRef, self.params.args.len);
|
||||
const args = try ofile.arena.alloc(*llvm.Value, self.params.args.len);
|
||||
for (self.params.args) |arg, i| {
|
||||
args[i] = arg.llvm_value.?;
|
||||
}
|
||||
@ -360,7 +360,7 @@ pub const Inst = struct {
|
||||
return new_inst;
|
||||
}
|
||||
|
||||
pub fn render(self: *Const, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
|
||||
pub fn render(self: *Const, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
|
||||
return self.base.val.KnownValue.getLlvmConst(ofile);
|
||||
}
|
||||
};
|
||||
@ -392,7 +392,7 @@ pub const Inst = struct {
|
||||
return ira.irb.build(Return, self.base.scope, self.base.span, Params{ .return_value = casted_value });
|
||||
}
|
||||
|
||||
pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
|
||||
pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
|
||||
const value = self.params.return_value.llvm_value;
|
||||
const return_type = self.params.return_value.getKnownType();
|
||||
|
||||
@ -540,7 +540,7 @@ pub const Inst = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(self: *VarPtr, ofile: *ObjectFile, fn_val: *Value.Fn) llvm.ValueRef {
|
||||
pub fn render(self: *VarPtr, ofile: *ObjectFile, fn_val: *Value.Fn) *llvm.Value {
|
||||
switch (self.params.var_scope.data) {
|
||||
Scope.Var.Data.Const => unreachable, // turned into Inst.Const in analyze pass
|
||||
Scope.Var.Data.Param => |param| return param.llvm_value,
|
||||
@ -596,7 +596,7 @@ pub const Inst = struct {
|
||||
return new_inst;
|
||||
}
|
||||
|
||||
pub fn render(self: *LoadPtr, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
|
||||
pub fn render(self: *LoadPtr, ofile: *ObjectFile, fn_val: *Value.Fn) !?*llvm.Value {
|
||||
const child_type = self.base.getKnownType();
|
||||
if (!child_type.hasBits()) {
|
||||
return null;
|
||||
@ -935,8 +935,8 @@ pub const BasicBlock = struct {
|
||||
ref_instruction: ?*Inst,
|
||||
|
||||
/// for codegen
|
||||
llvm_block: llvm.BasicBlockRef,
|
||||
llvm_exit_block: llvm.BasicBlockRef,
|
||||
llvm_block: *llvm.BasicBlock,
|
||||
llvm_exit_block: *llvm.BasicBlock,
|
||||
|
||||
/// the basic block that is derived from this one in analysis
|
||||
child: ?*BasicBlock,
|
||||
|
||||
@ -154,8 +154,8 @@ pub const LibCInstallation = struct {
|
||||
c.ZigFindWindowsSdkError.None => {
|
||||
windows_sdk = sdk;
|
||||
|
||||
if (sdk.msvc_lib_dir_ptr) |ptr| {
|
||||
self.msvc_lib_dir = try std.mem.dupe(loop.allocator, u8, ptr[0..sdk.msvc_lib_dir_len]);
|
||||
if (sdk.msvc_lib_dir_ptr != 0) {
|
||||
self.msvc_lib_dir = try std.mem.dupe(loop.allocator, u8, sdk.msvc_lib_dir_ptr[0..sdk.msvc_lib_dir_len]);
|
||||
}
|
||||
try group.call(findNativeKernel32LibDir, self, loop, sdk);
|
||||
try group.call(findNativeIncludeDirWindows, self, loop, sdk);
|
||||
@ -437,20 +437,20 @@ const Search = struct {
|
||||
|
||||
fn fillSearch(search_buf: *[2]Search, sdk: *c.ZigWindowsSDK) []Search {
|
||||
var search_end: usize = 0;
|
||||
if (sdk.path10_ptr) |path10_ptr| {
|
||||
if (sdk.version10_ptr) |ver10_ptr| {
|
||||
if (sdk.path10_ptr != 0) {
|
||||
if (sdk.version10_ptr != 0) {
|
||||
search_buf[search_end] = Search{
|
||||
.path = path10_ptr[0..sdk.path10_len],
|
||||
.version = ver10_ptr[0..sdk.version10_len],
|
||||
.path = sdk.path10_ptr[0..sdk.path10_len],
|
||||
.version = sdk.version10_ptr[0..sdk.version10_len],
|
||||
};
|
||||
search_end += 1;
|
||||
}
|
||||
}
|
||||
if (sdk.path81_ptr) |path81_ptr| {
|
||||
if (sdk.version81_ptr) |ver81_ptr| {
|
||||
if (sdk.path81_ptr != 0) {
|
||||
if (sdk.version81_ptr != 0) {
|
||||
search_buf[search_end] = Search{
|
||||
.path = path81_ptr[0..sdk.path81_len],
|
||||
.version = ver81_ptr[0..sdk.version81_len],
|
||||
.path = sdk.path81_ptr[0..sdk.path81_len],
|
||||
.version = sdk.version81_ptr[0..sdk.version81_len],
|
||||
};
|
||||
search_end += 1;
|
||||
}
|
||||
|
||||
@ -11,45 +11,31 @@ const assert = @import("std").debug.assert;
|
||||
pub const AttributeIndex = c_uint;
|
||||
pub const Bool = c_int;
|
||||
|
||||
pub const BuilderRef = removeNullability(c.LLVMBuilderRef);
|
||||
pub const ContextRef = removeNullability(c.LLVMContextRef);
|
||||
pub const ModuleRef = removeNullability(c.LLVMModuleRef);
|
||||
pub const ValueRef = removeNullability(c.LLVMValueRef);
|
||||
pub const TypeRef = removeNullability(c.LLVMTypeRef);
|
||||
pub const BasicBlockRef = removeNullability(c.LLVMBasicBlockRef);
|
||||
pub const AttributeRef = removeNullability(c.LLVMAttributeRef);
|
||||
pub const TargetRef = removeNullability(c.LLVMTargetRef);
|
||||
pub const TargetMachineRef = removeNullability(c.LLVMTargetMachineRef);
|
||||
pub const TargetDataRef = removeNullability(c.LLVMTargetDataRef);
|
||||
pub const Builder = c.LLVMBuilderRef.Child.Child;
|
||||
pub const Context = c.LLVMContextRef.Child.Child;
|
||||
pub const Module = c.LLVMModuleRef.Child.Child;
|
||||
pub const Value = c.LLVMValueRef.Child.Child;
|
||||
pub const Type = c.LLVMTypeRef.Child.Child;
|
||||
pub const BasicBlock = c.LLVMBasicBlockRef.Child.Child;
|
||||
pub const Attribute = c.LLVMAttributeRef.Child.Child;
|
||||
pub const Target = c.LLVMTargetRef.Child.Child;
|
||||
pub const TargetMachine = c.LLVMTargetMachineRef.Child.Child;
|
||||
pub const TargetData = c.LLVMTargetDataRef.Child.Child;
|
||||
pub const DIBuilder = c.ZigLLVMDIBuilder;
|
||||
pub const DIFile = c.ZigLLVMDIFile;
|
||||
pub const DICompileUnit = c.ZigLLVMDICompileUnit;
|
||||
|
||||
pub const ABIAlignmentOfType = c.LLVMABIAlignmentOfType;
|
||||
pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex;
|
||||
pub const AddFunction = c.LLVMAddFunction;
|
||||
pub const AddGlobal = c.LLVMAddGlobal;
|
||||
pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag;
|
||||
pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;
|
||||
pub const ArrayType = c.LLVMArrayType;
|
||||
pub const BuildLoad = c.LLVMBuildLoad;
|
||||
pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;
|
||||
pub const ConstAllOnes = c.LLVMConstAllOnes;
|
||||
pub const ConstArray = c.LLVMConstArray;
|
||||
pub const ConstBitCast = c.LLVMConstBitCast;
|
||||
pub const ConstInt = c.LLVMConstInt;
|
||||
pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision;
|
||||
pub const ConstNeg = c.LLVMConstNeg;
|
||||
pub const ConstNull = c.LLVMConstNull;
|
||||
pub const ConstStringInContext = c.LLVMConstStringInContext;
|
||||
pub const ConstStructInContext = c.LLVMConstStructInContext;
|
||||
pub const CopyStringRepOfTargetData = c.LLVMCopyStringRepOfTargetData;
|
||||
pub const CreateBuilderInContext = c.LLVMCreateBuilderInContext;
|
||||
pub const CreateCompileUnit = c.ZigLLVMCreateCompileUnit;
|
||||
pub const CreateDIBuilder = c.ZigLLVMCreateDIBuilder;
|
||||
pub const CreateEnumAttribute = c.LLVMCreateEnumAttribute;
|
||||
pub const CreateFile = c.ZigLLVMCreateFile;
|
||||
pub const CreateStringAttribute = c.LLVMCreateStringAttribute;
|
||||
pub const CreateTargetDataLayout = c.LLVMCreateTargetDataLayout;
|
||||
pub const CreateTargetMachine = c.LLVMCreateTargetMachine;
|
||||
pub const DIBuilderFinalize = c.ZigLLVMDIBuilderFinalize;
|
||||
pub const DisposeBuilder = c.LLVMDisposeBuilder;
|
||||
pub const DisposeDIBuilder = c.ZigLLVMDisposeDIBuilder;
|
||||
@ -62,9 +48,7 @@ pub const DumpModule = c.LLVMDumpModule;
|
||||
pub const FP128TypeInContext = c.LLVMFP128TypeInContext;
|
||||
pub const FloatTypeInContext = c.LLVMFloatTypeInContext;
|
||||
pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName;
|
||||
pub const GetHostCPUName = c.ZigLLVMGetHostCPUName;
|
||||
pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext;
|
||||
pub const GetNativeFeatures = c.ZigLLVMGetNativeFeatures;
|
||||
pub const GetUndef = c.LLVMGetUndef;
|
||||
pub const HalfTypeInContext = c.LLVMHalfTypeInContext;
|
||||
pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers;
|
||||
@ -81,14 +65,11 @@ pub const Int64TypeInContext = c.LLVMInt64TypeInContext;
|
||||
pub const Int8TypeInContext = c.LLVMInt8TypeInContext;
|
||||
pub const IntPtrTypeForASInContext = c.LLVMIntPtrTypeForASInContext;
|
||||
pub const IntPtrTypeInContext = c.LLVMIntPtrTypeInContext;
|
||||
pub const IntTypeInContext = c.LLVMIntTypeInContext;
|
||||
pub const LabelTypeInContext = c.LLVMLabelTypeInContext;
|
||||
pub const MDNodeInContext = c.LLVMMDNodeInContext;
|
||||
pub const MDStringInContext = c.LLVMMDStringInContext;
|
||||
pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext;
|
||||
pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext;
|
||||
pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext;
|
||||
pub const PointerType = c.LLVMPointerType;
|
||||
pub const SetAlignment = c.LLVMSetAlignment;
|
||||
pub const SetDataLayout = c.LLVMSetDataLayout;
|
||||
pub const SetGlobalConstant = c.LLVMSetGlobalConstant;
|
||||
@ -99,50 +80,146 @@ pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr;
|
||||
pub const SetVolatile = c.LLVMSetVolatile;
|
||||
pub const StructTypeInContext = c.LLVMStructTypeInContext;
|
||||
pub const TokenTypeInContext = c.LLVMTokenTypeInContext;
|
||||
pub const VoidTypeInContext = c.LLVMVoidTypeInContext;
|
||||
pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;
|
||||
pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;
|
||||
|
||||
pub const AddGlobal = LLVMAddGlobal;
|
||||
extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*]const u8) ?*Value;
|
||||
|
||||
pub const ConstStringInContext = LLVMConstStringInContext;
|
||||
extern fn LLVMConstStringInContext(C: *Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value;
|
||||
|
||||
pub const ConstInt = LLVMConstInt;
|
||||
extern fn LLVMConstInt(IntTy: *Type, N: c_ulonglong, SignExtend: Bool) ?*Value;
|
||||
|
||||
pub const BuildLoad = LLVMBuildLoad;
|
||||
extern fn LLVMBuildLoad(arg0: *Builder, PointerVal: *Value, Name: [*]const u8) ?*Value;
|
||||
|
||||
pub const ConstNull = LLVMConstNull;
|
||||
extern fn LLVMConstNull(Ty: *Type) ?*Value;
|
||||
|
||||
pub const CreateStringAttribute = LLVMCreateStringAttribute;
|
||||
extern fn LLVMCreateStringAttribute(
|
||||
C: *Context,
|
||||
K: [*]const u8,
|
||||
KLength: c_uint,
|
||||
V: [*]const u8,
|
||||
VLength: c_uint,
|
||||
) ?*Attribute;
|
||||
|
||||
pub const CreateEnumAttribute = LLVMCreateEnumAttribute;
|
||||
extern fn LLVMCreateEnumAttribute(C: *Context, KindID: c_uint, Val: u64) ?*Attribute;
|
||||
|
||||
pub const AddFunction = LLVMAddFunction;
|
||||
extern fn LLVMAddFunction(M: *Module, Name: [*]const u8, FunctionTy: *Type) ?*Value;
|
||||
|
||||
pub const CreateCompileUnit = ZigLLVMCreateCompileUnit;
|
||||
extern fn ZigLLVMCreateCompileUnit(
|
||||
dibuilder: *DIBuilder,
|
||||
lang: c_uint,
|
||||
difile: *DIFile,
|
||||
producer: [*]const u8,
|
||||
is_optimized: bool,
|
||||
flags: [*]const u8,
|
||||
runtime_version: c_uint,
|
||||
split_name: [*]const u8,
|
||||
dwo_id: u64,
|
||||
emit_debug_info: bool,
|
||||
) ?*DICompileUnit;
|
||||
|
||||
pub const CreateFile = ZigLLVMCreateFile;
|
||||
extern fn ZigLLVMCreateFile(dibuilder: *DIBuilder, filename: [*]const u8, directory: [*]const u8) ?*DIFile;
|
||||
|
||||
pub const ArrayType = LLVMArrayType;
|
||||
extern fn LLVMArrayType(ElementType: *Type, ElementCount: c_uint) ?*Type;
|
||||
|
||||
pub const CreateDIBuilder = ZigLLVMCreateDIBuilder;
|
||||
extern fn ZigLLVMCreateDIBuilder(module: *Module, allow_unresolved: bool) ?*DIBuilder;
|
||||
|
||||
pub const PointerType = LLVMPointerType;
|
||||
extern fn LLVMPointerType(ElementType: *Type, AddressSpace: c_uint) ?*Type;
|
||||
|
||||
pub const CreateBuilderInContext = LLVMCreateBuilderInContext;
|
||||
extern fn LLVMCreateBuilderInContext(C: *Context) ?*Builder;
|
||||
|
||||
pub const IntTypeInContext = LLVMIntTypeInContext;
|
||||
extern fn LLVMIntTypeInContext(C: *Context, NumBits: c_uint) ?*Type;
|
||||
|
||||
pub const ModuleCreateWithNameInContext = LLVMModuleCreateWithNameInContext;
|
||||
extern fn LLVMModuleCreateWithNameInContext(ModuleID: [*]const u8, C: *Context) ?*Module;
|
||||
|
||||
pub const VoidTypeInContext = LLVMVoidTypeInContext;
|
||||
extern fn LLVMVoidTypeInContext(C: *Context) ?*Type;
|
||||
|
||||
pub const ContextCreate = LLVMContextCreate;
|
||||
extern fn LLVMContextCreate() ?*Context;
|
||||
|
||||
pub const ContextDispose = LLVMContextDispose;
|
||||
extern fn LLVMContextDispose(C: *Context) void;
|
||||
|
||||
pub const CopyStringRepOfTargetData = LLVMCopyStringRepOfTargetData;
|
||||
extern fn LLVMCopyStringRepOfTargetData(TD: *TargetData) ?[*]u8;
|
||||
|
||||
pub const CreateTargetDataLayout = LLVMCreateTargetDataLayout;
|
||||
extern fn LLVMCreateTargetDataLayout(T: *TargetMachine) ?*TargetData;
|
||||
|
||||
pub const CreateTargetMachine = LLVMCreateTargetMachine;
|
||||
extern fn LLVMCreateTargetMachine(
|
||||
T: *Target,
|
||||
Triple: [*]const u8,
|
||||
CPU: [*]const u8,
|
||||
Features: [*]const u8,
|
||||
Level: CodeGenOptLevel,
|
||||
Reloc: RelocMode,
|
||||
CodeModel: CodeModel,
|
||||
) ?*TargetMachine;
|
||||
|
||||
pub const GetHostCPUName = LLVMGetHostCPUName;
|
||||
extern fn LLVMGetHostCPUName() ?[*]u8;
|
||||
|
||||
pub const GetNativeFeatures = ZigLLVMGetNativeFeatures;
|
||||
extern fn ZigLLVMGetNativeFeatures() ?[*]u8;
|
||||
|
||||
pub const GetElementType = LLVMGetElementType;
|
||||
extern fn LLVMGetElementType(Ty: TypeRef) TypeRef;
|
||||
extern fn LLVMGetElementType(Ty: *Type) *Type;
|
||||
|
||||
pub const TypeOf = LLVMTypeOf;
|
||||
extern fn LLVMTypeOf(Val: ValueRef) TypeRef;
|
||||
extern fn LLVMTypeOf(Val: *Value) *Type;
|
||||
|
||||
pub const BuildStore = LLVMBuildStore;
|
||||
extern fn LLVMBuildStore(arg0: BuilderRef, Val: ValueRef, Ptr: ValueRef) ?ValueRef;
|
||||
extern fn LLVMBuildStore(arg0: *Builder, Val: *Value, Ptr: *Value) ?*Value;
|
||||
|
||||
pub const BuildAlloca = LLVMBuildAlloca;
|
||||
extern fn LLVMBuildAlloca(arg0: BuilderRef, Ty: TypeRef, Name: ?[*]const u8) ?ValueRef;
|
||||
extern fn LLVMBuildAlloca(arg0: *Builder, Ty: *Type, Name: ?[*]const u8) ?*Value;
|
||||
|
||||
pub const ConstInBoundsGEP = LLVMConstInBoundsGEP;
|
||||
pub extern fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, ConstantIndices: [*]ValueRef, NumIndices: c_uint) ?ValueRef;
|
||||
pub extern fn LLVMConstInBoundsGEP(ConstantVal: *Value, ConstantIndices: [*]*Value, NumIndices: c_uint) ?*Value;
|
||||
|
||||
pub const GetTargetFromTriple = LLVMGetTargetFromTriple;
|
||||
extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: *TargetRef, ErrorMessage: ?*[*]u8) Bool;
|
||||
extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: **Target, ErrorMessage: ?*[*]u8) Bool;
|
||||
|
||||
pub const VerifyModule = LLVMVerifyModule;
|
||||
extern fn LLVMVerifyModule(M: ModuleRef, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool;
|
||||
extern fn LLVMVerifyModule(M: *Module, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool;
|
||||
|
||||
pub const GetInsertBlock = LLVMGetInsertBlock;
|
||||
extern fn LLVMGetInsertBlock(Builder: BuilderRef) BasicBlockRef;
|
||||
extern fn LLVMGetInsertBlock(Builder: *Builder) *BasicBlock;
|
||||
|
||||
pub const FunctionType = LLVMFunctionType;
|
||||
extern fn LLVMFunctionType(
|
||||
ReturnType: TypeRef,
|
||||
ParamTypes: [*]TypeRef,
|
||||
ReturnType: *Type,
|
||||
ParamTypes: [*]*Type,
|
||||
ParamCount: c_uint,
|
||||
IsVarArg: Bool,
|
||||
) ?TypeRef;
|
||||
) ?*Type;
|
||||
|
||||
pub const GetParam = LLVMGetParam;
|
||||
extern fn LLVMGetParam(Fn: ValueRef, Index: c_uint) ValueRef;
|
||||
extern fn LLVMGetParam(Fn: *Value, Index: c_uint) *Value;
|
||||
|
||||
pub const AppendBasicBlockInContext = LLVMAppendBasicBlockInContext;
|
||||
extern fn LLVMAppendBasicBlockInContext(C: ContextRef, Fn: ValueRef, Name: [*]const u8) ?BasicBlockRef;
|
||||
extern fn LLVMAppendBasicBlockInContext(C: *Context, Fn: *Value, Name: [*]const u8) ?*BasicBlock;
|
||||
|
||||
pub const PositionBuilderAtEnd = LLVMPositionBuilderAtEnd;
|
||||
extern fn LLVMPositionBuilderAtEnd(Builder: BuilderRef, Block: BasicBlockRef) void;
|
||||
extern fn LLVMPositionBuilderAtEnd(Builder: *Builder, Block: *BasicBlock) void;
|
||||
|
||||
pub const AbortProcessAction = VerifierFailureAction.LLVMAbortProcessAction;
|
||||
pub const PrintMessageAction = VerifierFailureAction.LLVMPrintMessageAction;
|
||||
@ -190,17 +267,17 @@ pub const FnInline = extern enum {
|
||||
};
|
||||
|
||||
fn removeNullability(comptime T: type) type {
|
||||
comptime assert(@typeId(T) == builtin.TypeId.Optional);
|
||||
return T.Child;
|
||||
comptime assert(@typeInfo(T).Pointer.size == @import("builtin").TypeInfo.Pointer.Size.C);
|
||||
return *T.Child;
|
||||
}
|
||||
|
||||
pub const BuildRet = LLVMBuildRet;
|
||||
extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ?ValueRef;
|
||||
extern fn LLVMBuildRet(arg0: *Builder, V: ?*Value) ?*Value;
|
||||
|
||||
pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile;
|
||||
extern fn ZigLLVMTargetMachineEmitToFile(
|
||||
targ_machine_ref: TargetMachineRef,
|
||||
module_ref: ModuleRef,
|
||||
targ_machine_ref: *TargetMachine,
|
||||
module_ref: *Module,
|
||||
filename: [*]const u8,
|
||||
output_type: EmitOutputType,
|
||||
error_message: *[*]u8,
|
||||
@ -209,6 +286,6 @@ extern fn ZigLLVMTargetMachineEmitToFile(
|
||||
) bool;
|
||||
|
||||
pub const BuildCall = ZigLLVMBuildCall;
|
||||
extern fn ZigLLVMBuildCall(B: BuilderRef, Fn: ValueRef, Args: [*]ValueRef, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?ValueRef;
|
||||
extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?*Value;
|
||||
|
||||
pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage;
|
||||
|
||||
@ -362,7 +362,7 @@ pub const Scope = struct {
|
||||
pub const Param = struct {
|
||||
index: usize,
|
||||
typ: *Type,
|
||||
llvm_value: llvm.ValueRef,
|
||||
llvm_value: *llvm.Value,
|
||||
};
|
||||
|
||||
pub fn createParam(
|
||||
|
||||
@ -457,8 +457,8 @@ pub const Target = union(enum) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn llvmTargetFromTriple(triple: std.Buffer) !llvm.TargetRef {
|
||||
var result: llvm.TargetRef = undefined;
|
||||
pub fn llvmTargetFromTriple(triple: std.Buffer) !*llvm.Target {
|
||||
var result: *llvm.Target = undefined;
|
||||
var err_msg: [*]u8 = undefined;
|
||||
if (llvm.GetTargetFromTriple(triple.ptr(), &result, &err_msg) != 0) {
|
||||
std.debug.warn("triple: {s} error: {s}\n", triple.ptr(), err_msg);
|
||||
|
||||
@ -51,8 +51,8 @@ pub const Type = struct {
|
||||
pub fn getLlvmType(
|
||||
base: *Type,
|
||||
allocator: *Allocator,
|
||||
llvm_context: llvm.ContextRef,
|
||||
) (error{OutOfMemory}!llvm.TypeRef) {
|
||||
llvm_context: *llvm.Context,
|
||||
) (error{OutOfMemory}!*llvm.Type) {
|
||||
switch (base.id) {
|
||||
Id.Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context),
|
||||
Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context),
|
||||
@ -196,7 +196,7 @@ pub const Type = struct {
|
||||
}
|
||||
|
||||
/// If you have an llvm conext handy, you can use it here.
|
||||
pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 {
|
||||
pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 {
|
||||
if (await (async base.abi_alignment.start() catch unreachable)) |ptr| return ptr.*;
|
||||
|
||||
base.abi_alignment.data = await (async base.resolveAbiAlignment(comp, llvm_context) catch unreachable);
|
||||
@ -205,7 +205,7 @@ pub const Type = struct {
|
||||
}
|
||||
|
||||
/// Lower level function that does the work. See getAbiAlignment.
|
||||
async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 {
|
||||
async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 {
|
||||
const llvm_type = try base.getLlvmType(comp.gpa(), llvm_context);
|
||||
return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type));
|
||||
}
|
||||
@ -218,7 +218,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Struct, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Struct, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -496,13 +496,13 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
|
||||
const normal = &self.key.data.Normal;
|
||||
const llvm_return_type = switch (normal.return_type.id) {
|
||||
Type.Id.Void => llvm.VoidTypeInContext(llvm_context) orelse return error.OutOfMemory,
|
||||
else => try normal.return_type.getLlvmType(allocator, llvm_context),
|
||||
};
|
||||
const llvm_param_types = try allocator.alloc(llvm.TypeRef, normal.params.len);
|
||||
const llvm_param_types = try allocator.alloc(*llvm.Type, normal.params.len);
|
||||
defer allocator.free(llvm_param_types);
|
||||
for (llvm_param_types) |*llvm_param_type, i| {
|
||||
llvm_param_type.* = try normal.params[i].typ.getLlvmType(allocator, llvm_context);
|
||||
@ -559,7 +559,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Bool, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Bool, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -658,7 +658,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
|
||||
return llvm.IntTypeInContext(llvm_context, self.key.bit_count) orelse return error.OutOfMemory;
|
||||
}
|
||||
};
|
||||
@ -670,7 +670,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Float, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Float, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -794,6 +794,7 @@ pub const Type = struct {
|
||||
Size.One => "*",
|
||||
Size.Many => "[*]",
|
||||
Size.Slice => "[]",
|
||||
Size.C => "[*c]",
|
||||
};
|
||||
const mut_str = switch (self.key.mut) {
|
||||
Mut.Const => "const ",
|
||||
@ -835,7 +836,7 @@ pub const Type = struct {
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
|
||||
const elem_llvm_type = try self.key.child_type.getLlvmType(allocator, llvm_context);
|
||||
return llvm.PointerType(elem_llvm_type, 0) orelse return error.OutOfMemory;
|
||||
}
|
||||
@ -903,7 +904,7 @@ pub const Type = struct {
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Array, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Array, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
|
||||
const elem_llvm_type = try self.key.elem_type.getLlvmType(allocator, llvm_context);
|
||||
return llvm.ArrayType(elem_llvm_type, @intCast(c_uint, self.key.len)) orelse return error.OutOfMemory;
|
||||
}
|
||||
@ -916,7 +917,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -966,7 +967,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Optional, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Optional, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -978,7 +979,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *ErrorUnion, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *ErrorUnion, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -990,7 +991,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *ErrorSet, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *ErrorSet, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -1002,7 +1003,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Enum, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Enum, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -1014,7 +1015,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Union, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Union, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -1034,7 +1035,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *BoundFn, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *BoundFn, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -1054,7 +1055,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Opaque, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Opaque, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -1066,7 +1067,7 @@ pub const Type = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmType(self: *Promise, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
|
||||
pub fn getLlvmType(self: *Promise, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
|
||||
@panic("TODO");
|
||||
}
|
||||
};
|
||||
@ -1088,6 +1089,7 @@ fn hashAny(x: var, comptime seed: u64) u32 {
|
||||
builtin.TypeInfo.Pointer.Size.One => return hashAny(@ptrToInt(x), seed),
|
||||
builtin.TypeInfo.Pointer.Size.Many => @compileError("implement hash function"),
|
||||
builtin.TypeInfo.Pointer.Size.Slice => @compileError("implement hash function"),
|
||||
builtin.TypeInfo.Pointer.Size.C => unreachable,
|
||||
}
|
||||
},
|
||||
builtin.TypeId.Enum => return hashAny(@enumToInt(x), seed),
|
||||
|
||||
@ -57,7 +57,7 @@ pub const Value = struct {
|
||||
std.debug.warn("{}", @tagName(base.id));
|
||||
}
|
||||
|
||||
pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?llvm.ValueRef) {
|
||||
pub fn getLlvmConst(base: *Value, ofile: *ObjectFile) (error{OutOfMemory}!?*llvm.Value) {
|
||||
switch (base.id) {
|
||||
Id.Type => unreachable,
|
||||
Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmConst(ofile),
|
||||
@ -153,7 +153,7 @@ pub const Value = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmConst(self: *FnProto, ofile: *ObjectFile) !?llvm.ValueRef {
|
||||
pub fn getLlvmConst(self: *FnProto, ofile: *ObjectFile) !?*llvm.Value {
|
||||
const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
|
||||
const llvm_fn = llvm.AddFunction(
|
||||
ofile.module,
|
||||
@ -238,7 +238,7 @@ pub const Value = struct {
|
||||
/// We know that the function definition will end up in an .o file somewhere.
|
||||
/// Here, all we have to do is generate a global prototype.
|
||||
/// TODO cache the prototype per ObjectFile
|
||||
pub fn getLlvmConst(self: *Fn, ofile: *ObjectFile) !?llvm.ValueRef {
|
||||
pub fn getLlvmConst(self: *Fn, ofile: *ObjectFile) !?*llvm.Value {
|
||||
const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
|
||||
const llvm_fn = llvm.AddFunction(
|
||||
ofile.module,
|
||||
@ -283,8 +283,8 @@ pub const Value = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) ?llvm.ValueRef {
|
||||
const llvm_type = llvm.Int1TypeInContext(ofile.context);
|
||||
pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) !?*llvm.Value {
|
||||
const llvm_type = llvm.Int1TypeInContext(ofile.context) orelse return error.OutOfMemory;
|
||||
if (self.x) {
|
||||
return llvm.ConstAllOnes(llvm_type);
|
||||
} else {
|
||||
@ -381,7 +381,7 @@ pub const Value = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmConst(self: *Ptr, ofile: *ObjectFile) !?llvm.ValueRef {
|
||||
pub fn getLlvmConst(self: *Ptr, ofile: *ObjectFile) !?*llvm.Value {
|
||||
const llvm_type = self.base.typ.getLlvmType(ofile.arena, ofile.context);
|
||||
// TODO carefully port the logic from codegen.cpp:gen_const_val_ptr
|
||||
switch (self.special) {
|
||||
@ -391,7 +391,7 @@ pub const Value = struct {
|
||||
const array_llvm_value = (try base_array.val.getLlvmConst(ofile)).?;
|
||||
const ptr_bit_count = ofile.comp.target_ptr_bits;
|
||||
const usize_llvm_type = llvm.IntTypeInContext(ofile.context, ptr_bit_count) orelse return error.OutOfMemory;
|
||||
const indices = []llvm.ValueRef{
|
||||
const indices = []*llvm.Value{
|
||||
llvm.ConstNull(usize_llvm_type) orelse return error.OutOfMemory,
|
||||
llvm.ConstInt(usize_llvm_type, base_array.elem_index, 0) orelse return error.OutOfMemory,
|
||||
};
|
||||
@ -459,7 +459,7 @@ pub const Value = struct {
|
||||
comp.gpa().destroy(self);
|
||||
}
|
||||
|
||||
pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?llvm.ValueRef {
|
||||
pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?*llvm.Value {
|
||||
switch (self.special) {
|
||||
Special.Undefined => {
|
||||
const llvm_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
|
||||
@ -534,7 +534,7 @@ pub const Value = struct {
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?llvm.ValueRef {
|
||||
pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?*llvm.Value {
|
||||
switch (self.base.typ.id) {
|
||||
Type.Id.Int => {
|
||||
const type_ref = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
|
||||
|
||||
@ -691,15 +691,17 @@ struct AstNodePointerType {
|
||||
AstNode *align_expr;
|
||||
BigInt *bit_offset_start;
|
||||
BigInt *host_int_bytes;
|
||||
AstNode *op_expr;
|
||||
Token *allow_zero_token;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
AstNode *op_expr;
|
||||
};
|
||||
|
||||
struct AstNodeArrayType {
|
||||
AstNode *size;
|
||||
AstNode *child_type;
|
||||
AstNode *align_expr;
|
||||
Token *allow_zero_token;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
};
|
||||
@ -1038,6 +1040,7 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b);
|
||||
enum PtrLen {
|
||||
PtrLenUnknown,
|
||||
PtrLenSingle,
|
||||
PtrLenC,
|
||||
};
|
||||
|
||||
struct ZigTypePointer {
|
||||
@ -1049,6 +1052,7 @@ struct ZigTypePointer {
|
||||
uint32_t host_int_bytes; // size of host integer. 0 means no host integer; this field is aligned
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
bool allow_zero;
|
||||
};
|
||||
|
||||
struct ZigTypeInt {
|
||||
@ -1484,6 +1488,7 @@ enum PanicMsgId {
|
||||
PanicMsgIdBadUnionField,
|
||||
PanicMsgIdBadEnumValue,
|
||||
PanicMsgIdFloatToInt,
|
||||
PanicMsgIdPtrCastNull,
|
||||
|
||||
PanicMsgIdCount,
|
||||
};
|
||||
@ -1498,11 +1503,12 @@ struct TypeId {
|
||||
struct {
|
||||
ZigType *child_type;
|
||||
PtrLen ptr_len;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
uint32_t alignment;
|
||||
uint32_t bit_offset_in_host;
|
||||
uint32_t host_int_bytes;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
bool allow_zero;
|
||||
} pointer;
|
||||
struct {
|
||||
ZigType *child_type;
|
||||
@ -2591,6 +2597,7 @@ struct IrInstructionPtrType {
|
||||
PtrLen ptr_len;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
bool allow_zero;
|
||||
};
|
||||
|
||||
struct IrInstructionPromiseType {
|
||||
@ -2606,6 +2613,7 @@ struct IrInstructionSliceType {
|
||||
IrInstruction *child_type;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
bool allow_zero;
|
||||
};
|
||||
|
||||
struct IrInstructionAsm {
|
||||
@ -2994,12 +3002,14 @@ struct IrInstructionPtrCastSrc {
|
||||
|
||||
IrInstruction *dest_type;
|
||||
IrInstruction *ptr;
|
||||
bool safety_check_on;
|
||||
};
|
||||
|
||||
struct IrInstructionPtrCastGen {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *ptr;
|
||||
bool safety_check_on;
|
||||
};
|
||||
|
||||
struct IrInstructionBitCast {
|
||||
|
||||
@ -417,10 +417,25 @@ ZigType *get_promise_type(CodeGen *g, ZigType *result_type) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
static const char *ptr_len_to_star_str(PtrLen ptr_len) {
|
||||
switch (ptr_len) {
|
||||
case PtrLenSingle:
|
||||
return "*";
|
||||
case PtrLenUnknown:
|
||||
return "[*]";
|
||||
case PtrLenC:
|
||||
return "[*c]";
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
|
||||
bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment,
|
||||
uint32_t bit_offset_in_host, uint32_t host_int_bytes)
|
||||
{
|
||||
// TODO when implementing https://github.com/ziglang/zig/issues/1953
|
||||
// move this to a parameter
|
||||
bool allow_zero = (ptr_len == PtrLenC);
|
||||
assert(!type_is_invalid(child_type));
|
||||
assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque);
|
||||
|
||||
@ -440,7 +455,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
|
||||
TypeId type_id = {};
|
||||
ZigType **parent_pointer = nullptr;
|
||||
if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle) {
|
||||
if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || allow_zero) {
|
||||
type_id.id = ZigTypeIdPointer;
|
||||
type_id.data.pointer.child_type = child_type;
|
||||
type_id.data.pointer.is_const = is_const;
|
||||
@ -449,6 +464,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
type_id.data.pointer.bit_offset_in_host = bit_offset_in_host;
|
||||
type_id.data.pointer.host_int_bytes = host_int_bytes;
|
||||
type_id.data.pointer.ptr_len = ptr_len;
|
||||
type_id.data.pointer.allow_zero = allow_zero;
|
||||
|
||||
auto existing_entry = g->type_table.maybe_get(type_id);
|
||||
if (existing_entry)
|
||||
@ -466,21 +482,31 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
|
||||
ZigType *entry = new_type_table_entry(ZigTypeIdPointer);
|
||||
|
||||
const char *star_str = ptr_len == PtrLenSingle ? "*" : "[*]";
|
||||
const char *star_str = ptr_len_to_star_str(ptr_len);
|
||||
const char *const_str = is_const ? "const " : "";
|
||||
const char *volatile_str = is_volatile ? "volatile " : "";
|
||||
const char *allow_zero_str;
|
||||
if (ptr_len == PtrLenC) {
|
||||
assert(allow_zero);
|
||||
allow_zero_str = "";
|
||||
} else {
|
||||
allow_zero_str = allow_zero ? "allowzero " : "";
|
||||
}
|
||||
buf_resize(&entry->name, 0);
|
||||
if (host_int_bytes == 0 && byte_alignment == 0) {
|
||||
buf_appendf(&entry->name, "%s%s%s%s", star_str, const_str, volatile_str, buf_ptr(&child_type->name));
|
||||
buf_appendf(&entry->name, "%s%s%s%s%s",
|
||||
star_str, const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name));
|
||||
} else if (host_int_bytes == 0) {
|
||||
buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s", star_str, byte_alignment,
|
||||
const_str, volatile_str, buf_ptr(&child_type->name));
|
||||
buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s%s", star_str, byte_alignment,
|
||||
const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name));
|
||||
} else if (byte_alignment == 0) {
|
||||
buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str,
|
||||
bit_offset_in_host, host_int_bytes, const_str, volatile_str, buf_ptr(&child_type->name));
|
||||
buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str,
|
||||
bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str,
|
||||
buf_ptr(&child_type->name));
|
||||
} else {
|
||||
buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, byte_alignment,
|
||||
bit_offset_in_host, host_int_bytes, const_str, volatile_str, buf_ptr(&child_type->name));
|
||||
buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str, byte_alignment,
|
||||
bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str,
|
||||
buf_ptr(&child_type->name));
|
||||
}
|
||||
|
||||
assert(child_type->id != ZigTypeIdInvalid);
|
||||
@ -488,7 +514,9 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
entry->zero_bits = !type_has_bits(child_type);
|
||||
|
||||
if (!entry->zero_bits) {
|
||||
if (is_const || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || bit_offset_in_host != 0) {
|
||||
if (is_const || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle ||
|
||||
bit_offset_in_host != 0 || allow_zero)
|
||||
{
|
||||
ZigType *peer_type = get_pointer_to_type_extra(g, child_type, false, false,
|
||||
PtrLenSingle, 0, 0, host_int_bytes);
|
||||
entry->type_ref = peer_type->type_ref;
|
||||
@ -522,6 +550,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
entry->data.pointer.explicit_alignment = byte_alignment;
|
||||
entry->data.pointer.bit_offset_in_host = bit_offset_in_host;
|
||||
entry->data.pointer.host_int_bytes = host_int_bytes;
|
||||
entry->data.pointer.allow_zero = allow_zero;
|
||||
|
||||
if (parent_pointer) {
|
||||
*parent_pointer = entry;
|
||||
@ -838,7 +867,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
|
||||
|
||||
ZigType *child_type = ptr_type->data.pointer.child_type;
|
||||
if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile ||
|
||||
ptr_type->data.pointer.explicit_alignment != 0)
|
||||
ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.allow_zero)
|
||||
{
|
||||
ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false,
|
||||
PtrLenUnknown, 0, 0, 0);
|
||||
@ -861,7 +890,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
|
||||
ZigType *child_ptr_type = child_type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
assert(child_ptr_type->id == ZigTypeIdPointer);
|
||||
if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile ||
|
||||
child_ptr_type->data.pointer.explicit_alignment != 0)
|
||||
child_ptr_type->data.pointer.explicit_alignment != 0 || child_ptr_type->data.pointer.allow_zero)
|
||||
{
|
||||
ZigType *grand_child_type = child_ptr_type->data.pointer.child_type;
|
||||
ZigType *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false,
|
||||
@ -1457,7 +1486,7 @@ static bool type_allowed_in_packed_struct(ZigType *type_entry) {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {
|
||||
bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {
|
||||
switch (type_entry->id) {
|
||||
case ZigTypeIdInvalid:
|
||||
zig_unreachable();
|
||||
@ -2650,6 +2679,13 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
|
||||
buf_sprintf("enums, not structs, support field assignment"));
|
||||
}
|
||||
|
||||
if (field_type->id == ZigTypeIdOpaque) {
|
||||
add_node_error(g, field_node->data.struct_field.type,
|
||||
buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in structs"));
|
||||
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (type_requires_comptime(g, field_type)) {
|
||||
case ReqCompTimeYes:
|
||||
struct_type->data.structure.requires_comptime = true;
|
||||
@ -2934,6 +2970,13 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
|
||||
}
|
||||
union_field->type_entry = field_type;
|
||||
|
||||
if (field_type->id == ZigTypeIdOpaque) {
|
||||
add_node_error(g, field_node->data.struct_field.type,
|
||||
buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in unions"));
|
||||
union_type->data.unionation.is_invalid = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (type_requires_comptime(g, field_type)) {
|
||||
case ReqCompTimeInvalid:
|
||||
union_type->data.unionation.is_invalid = true;
|
||||
@ -4041,7 +4084,9 @@ ZigType *get_src_ptr_type(ZigType *type) {
|
||||
if (type->id == ZigTypeIdFn) return type;
|
||||
if (type->id == ZigTypeIdPromise) return type;
|
||||
if (type->id == ZigTypeIdOptional) {
|
||||
if (type->data.maybe.child_type->id == ZigTypeIdPointer) return type->data.maybe.child_type;
|
||||
if (type->data.maybe.child_type->id == ZigTypeIdPointer) {
|
||||
return type->data.maybe.child_type->data.pointer.allow_zero ? nullptr : type->data.maybe.child_type;
|
||||
}
|
||||
if (type->data.maybe.child_type->id == ZigTypeIdFn) return type->data.maybe.child_type;
|
||||
if (type->data.maybe.child_type->id == ZigTypeIdPromise) return type->data.maybe.child_type;
|
||||
}
|
||||
@ -4055,6 +4100,10 @@ ZigType *get_codegen_ptr_type(ZigType *type) {
|
||||
return ty;
|
||||
}
|
||||
|
||||
bool type_is_nonnull_ptr(ZigType *type) {
|
||||
return type_is_codegen_pointer(type) && !ptr_allows_addr_zero(type);
|
||||
}
|
||||
|
||||
bool type_is_codegen_pointer(ZigType *type) {
|
||||
return get_codegen_ptr_type(type) == type;
|
||||
}
|
||||
@ -6300,6 +6349,7 @@ uint32_t type_id_hash(TypeId x) {
|
||||
((x.data.pointer.ptr_len == PtrLenSingle) ? (uint32_t)1120226602 : (uint32_t)3200913342) +
|
||||
(x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) +
|
||||
(x.data.pointer.is_volatile ? (uint32_t)536730450 : (uint32_t)1685612214) +
|
||||
(x.data.pointer.allow_zero ? (uint32_t)3324284834 : (uint32_t)3584904923) +
|
||||
(((uint32_t)x.data.pointer.alignment) ^ (uint32_t)0x777fbe0e) +
|
||||
(((uint32_t)x.data.pointer.bit_offset_in_host) ^ (uint32_t)2639019452) +
|
||||
(((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881);
|
||||
@ -6350,6 +6400,7 @@ bool type_id_eql(TypeId a, TypeId b) {
|
||||
a.data.pointer.ptr_len == b.data.pointer.ptr_len &&
|
||||
a.data.pointer.is_const == b.data.pointer.is_const &&
|
||||
a.data.pointer.is_volatile == b.data.pointer.is_volatile &&
|
||||
a.data.pointer.allow_zero == b.data.pointer.allow_zero &&
|
||||
a.data.pointer.alignment == b.data.pointer.alignment &&
|
||||
a.data.pointer.bit_offset_in_host == b.data.pointer.bit_offset_in_host &&
|
||||
a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes;
|
||||
@ -6883,3 +6934,21 @@ Error ensure_const_val_repr(IrAnalyze *ira, CodeGen *codegen, AstNode *source_no
|
||||
|
||||
return ErrorNone;
|
||||
}
|
||||
|
||||
const char *container_string(ContainerKind kind) {
|
||||
switch (kind) {
|
||||
case ContainerKindEnum: return "enum";
|
||||
case ContainerKindStruct: return "struct";
|
||||
case ContainerKindUnion: return "union";
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
bool ptr_allows_addr_zero(ZigType *ptr_type) {
|
||||
if (ptr_type->id == ZigTypeIdPointer) {
|
||||
return ptr_type->data.pointer.allow_zero;
|
||||
} else if (ptr_type->id == ZigTypeIdOptional) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -44,7 +44,9 @@ void find_libc_include_path(CodeGen *g);
|
||||
void find_libc_lib_path(CodeGen *g);
|
||||
|
||||
bool type_has_bits(ZigType *type_entry);
|
||||
|
||||
bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry);
|
||||
bool ptr_allows_addr_zero(ZigType *ptr_type);
|
||||
bool type_is_nonnull_ptr(ZigType *type);
|
||||
|
||||
ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code);
|
||||
|
||||
@ -215,6 +217,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk);
|
||||
X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty);
|
||||
bool type_is_c_abi_int(CodeGen *g, ZigType *ty);
|
||||
bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id);
|
||||
const char *container_string(ContainerKind kind);
|
||||
|
||||
uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *field);
|
||||
|
||||
|
||||
@ -136,13 +136,19 @@ static const char *thread_local_string(Token *tok) {
|
||||
return (tok == nullptr) ? "" : "threadlocal ";
|
||||
}
|
||||
|
||||
const char *container_string(ContainerKind kind) {
|
||||
switch (kind) {
|
||||
case ContainerKindEnum: return "enum";
|
||||
case ContainerKindStruct: return "struct";
|
||||
case ContainerKindUnion: return "union";
|
||||
static const char *token_to_ptr_len_str(Token *tok) {
|
||||
assert(tok != nullptr);
|
||||
switch (tok->id) {
|
||||
case TokenIdStar:
|
||||
case TokenIdStarStar:
|
||||
return "*";
|
||||
case TokenIdBracketStarBracket:
|
||||
return "[*]";
|
||||
case TokenIdBracketStarCBracket:
|
||||
return "[*c]";
|
||||
default:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static const char *node_type_str(NodeType node_type) {
|
||||
@ -644,13 +650,8 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
case NodeTypePointerType:
|
||||
{
|
||||
if (!grouped) fprintf(ar->f, "(");
|
||||
const char *star = "[*]";
|
||||
if (node->data.pointer_type.star_token != nullptr &&
|
||||
(node->data.pointer_type.star_token->id == TokenIdStar || node->data.pointer_type.star_token->id == TokenIdStarStar))
|
||||
{
|
||||
star = "*";
|
||||
}
|
||||
fprintf(ar->f, "%s", star);
|
||||
const char *ptr_len_str = token_to_ptr_len_str(node->data.pointer_type.star_token);
|
||||
fprintf(ar->f, "%s", ptr_len_str);
|
||||
if (node->data.pointer_type.align_expr != nullptr) {
|
||||
fprintf(ar->f, "align(");
|
||||
render_node_grouped(ar, node->data.pointer_type.align_expr);
|
||||
|
||||
@ -17,7 +17,4 @@ void ast_print(FILE *f, AstNode *node, int indent);
|
||||
|
||||
void ast_render(CodeGen *codegen, FILE *f, AstNode *node, int indent_size);
|
||||
|
||||
const char *container_string(ContainerKind kind);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -617,9 +617,10 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
|
||||
unsigned init_gen_i = 0;
|
||||
if (!type_has_bits(return_type)) {
|
||||
// nothing to do
|
||||
} else if (type_is_codegen_pointer(return_type)) {
|
||||
} else if (type_is_nonnull_ptr(return_type)) {
|
||||
addLLVMAttr(fn_table_entry->llvm_value, 0, "nonnull");
|
||||
} else if (want_first_arg_sret(g, &fn_type->data.fn.fn_type_id)) {
|
||||
// Sret pointers must not be address 0
|
||||
addLLVMArgAttr(fn_table_entry->llvm_value, 0, "nonnull");
|
||||
addLLVMArgAttr(fn_table_entry->llvm_value, 0, "sret");
|
||||
if (cc_want_sret_attr(cc)) {
|
||||
@ -637,6 +638,8 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
|
||||
|
||||
uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
|
||||
if (err_ret_trace_arg_index != UINT32_MAX) {
|
||||
// Error return trace memory is in the stack, which is impossible to be at address 0
|
||||
// on any architecture.
|
||||
addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)err_ret_trace_arg_index, "nonnull");
|
||||
}
|
||||
|
||||
@ -950,6 +953,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) {
|
||||
return buf_create_from_str("invalid enum value");
|
||||
case PanicMsgIdFloatToInt:
|
||||
return buf_create_from_str("integer part of floating point value out of bounds");
|
||||
case PanicMsgIdPtrCastNull:
|
||||
return buf_create_from_str("cast causes pointer to be null");
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -1244,6 +1249,8 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
|
||||
LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
|
||||
addLLVMFnAttr(fn_val, "nounwind");
|
||||
add_uwtable_attr(g, fn_val);
|
||||
// Error return trace memory is in the stack, which is impossible to be at address 0
|
||||
// on any architecture.
|
||||
addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
|
||||
if (g->build_mode == BuildModeDebug) {
|
||||
ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
|
||||
@ -1318,9 +1325,13 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
|
||||
LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
|
||||
addLLVMFnAttr(fn_val, "nounwind");
|
||||
add_uwtable_attr(g, fn_val);
|
||||
// Error return trace memory is in the stack, which is impossible to be at address 0
|
||||
// on any architecture.
|
||||
addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
|
||||
addLLVMArgAttr(fn_val, (unsigned)0, "noalias");
|
||||
addLLVMArgAttr(fn_val, (unsigned)0, "writeonly");
|
||||
// Error return trace memory is in the stack, which is impossible to be at address 0
|
||||
// on any architecture.
|
||||
addLLVMArgAttr(fn_val, (unsigned)1, "nonnull");
|
||||
addLLVMArgAttr(fn_val, (unsigned)1, "noalias");
|
||||
addLLVMArgAttr(fn_val, (unsigned)1, "readonly");
|
||||
@ -1448,6 +1459,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
|
||||
LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
|
||||
addLLVMFnAttr(fn_val, "nounwind");
|
||||
add_uwtable_attr(g, fn_val);
|
||||
// Error return trace memory is in the stack, which is impossible to be at address 0
|
||||
// on any architecture.
|
||||
addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
|
||||
if (g->build_mode == BuildModeDebug) {
|
||||
ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
|
||||
@ -2049,7 +2062,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
|
||||
case FnWalkIdAttrs: {
|
||||
ZigType *ptr_type = get_codegen_ptr_type(ty);
|
||||
if (ptr_type != nullptr) {
|
||||
if (ty->id != ZigTypeIdOptional) {
|
||||
if (type_is_nonnull_ptr(ty)) {
|
||||
addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
|
||||
}
|
||||
if (ptr_type->data.pointer.is_const) {
|
||||
@ -2093,6 +2106,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
|
||||
assert(handle_is_ptr(ty));
|
||||
switch (fn_walk->id) {
|
||||
case FnWalkIdAttrs:
|
||||
// arrays passed to C ABI functions may not be at address 0
|
||||
addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
|
||||
addLLVMArgAttrInt(llvm_fn, fn_walk->data.attrs.gen_i, "align", get_abi_alignment(g, ty));
|
||||
fn_walk->data.attrs.gen_i += 1;
|
||||
@ -2132,6 +2146,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
|
||||
case FnWalkIdAttrs:
|
||||
addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "byval");
|
||||
addLLVMArgAttrInt(llvm_fn, fn_walk->data.attrs.gen_i, "align", get_abi_alignment(g, ty));
|
||||
// Byvalue parameters must not have address 0
|
||||
addLLVMArgAttr(llvm_fn, fn_walk->data.attrs.gen_i, "nonnull");
|
||||
fn_walk->data.attrs.gen_i += 1;
|
||||
break;
|
||||
@ -2264,7 +2279,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) {
|
||||
if ((param_type->id == ZigTypeIdPointer && param_type->data.pointer.is_const) || is_byval) {
|
||||
addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "readonly");
|
||||
}
|
||||
if (param_type->id == ZigTypeIdPointer) {
|
||||
if (type_is_nonnull_ptr(param_type)) {
|
||||
addLLVMArgAttr(llvm_fn, (unsigned)gen_index, "nonnull");
|
||||
}
|
||||
break;
|
||||
@ -2657,7 +2672,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
|
||||
(op1->value.type->id == ZigTypeIdErrorSet && op2->value.type->id == ZigTypeIdErrorSet) ||
|
||||
(op1->value.type->id == ZigTypeIdPointer &&
|
||||
(op_id == IrBinOpAdd || op_id == IrBinOpSub) &&
|
||||
op1->value.type->data.pointer.ptr_len == PtrLenUnknown)
|
||||
op1->value.type->data.pointer.ptr_len != PtrLenSingle)
|
||||
);
|
||||
ZigType *operand_type = op1->value.type;
|
||||
ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type;
|
||||
@ -2716,7 +2731,7 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
|
||||
AddSubMulMul;
|
||||
|
||||
if (scalar_type->id == ZigTypeIdPointer) {
|
||||
assert(scalar_type->data.pointer.ptr_len == PtrLenUnknown);
|
||||
assert(scalar_type->data.pointer.ptr_len != PtrLenSingle);
|
||||
LLVMValueRef subscript_value;
|
||||
if (operand_type->id == ZigTypeIdVector)
|
||||
zig_panic("TODO: Implement vector operations on pointers.");
|
||||
@ -3028,7 +3043,22 @@ static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable,
|
||||
return nullptr;
|
||||
}
|
||||
LLVMValueRef ptr = ir_llvm_value(g, instruction->ptr);
|
||||
return LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, "");
|
||||
LLVMValueRef result_ptr = LLVMBuildBitCast(g->builder, ptr, wanted_type->type_ref, "");
|
||||
bool want_safety_check = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base);
|
||||
if (!want_safety_check || ptr_allows_addr_zero(wanted_type))
|
||||
return result_ptr;
|
||||
|
||||
LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(result_ptr));
|
||||
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntNE, result_ptr, zero, "");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrCastFail");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrCastOk");
|
||||
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
||||
gen_safety_crash(g, PanicMsgIdPtrCastNull);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, ok_block);
|
||||
return result_ptr;
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_bit_cast(CodeGen *g, IrExecutable *executable,
|
||||
@ -7294,6 +7324,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
|
||||
" One,\n"
|
||||
" Many,\n"
|
||||
" Slice,\n"
|
||||
" C,\n"
|
||||
" };\n"
|
||||
" };\n"
|
||||
"\n"
|
||||
|
||||
643
src/ir.cpp
643
src/ir.cpp
File diff suppressed because it is too large
Load Diff
@ -2778,7 +2778,8 @@ static AstNode *ast_parse_array_type_start(ParseContext *pc) {
|
||||
// PtrTypeStart
|
||||
// <- ASTERISK
|
||||
// / ASTERISK2
|
||||
// / LBRACKET ASTERISK RBRACKET
|
||||
// / PTRUNKNOWN
|
||||
// / PTRC
|
||||
static AstNode *ast_parse_ptr_type_start(ParseContext *pc) {
|
||||
Token *asterisk = eat_token_if(pc, TokenIdStar);
|
||||
if (asterisk != nullptr) {
|
||||
@ -2804,6 +2805,13 @@ static AstNode *ast_parse_ptr_type_start(ParseContext *pc) {
|
||||
return res;
|
||||
}
|
||||
|
||||
Token *cptr = eat_token_if(pc, TokenIdBracketStarCBracket);
|
||||
if (cptr != nullptr) {
|
||||
AstNode *res = ast_create_node(pc, NodeTypePointerType, cptr);
|
||||
res->data.pointer_type.star_token = cptr;
|
||||
return res;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@ -807,6 +807,10 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
bool target_allows_addr_zero(const ZigTarget *target) {
|
||||
return target->os == OsFreestanding;
|
||||
}
|
||||
|
||||
const char *target_o_file_ext(ZigTarget *target) {
|
||||
if (target->env_type == ZigLLVM_MSVC || target->os == OsWindows || target->os == OsUefi) {
|
||||
return ".obj";
|
||||
|
||||
@ -135,5 +135,6 @@ bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target
|
||||
ZigLLVM_OSType get_llvm_os_type(Os os_type);
|
||||
|
||||
bool target_is_arm(const ZigTarget *target);
|
||||
bool target_allows_addr_zero(const ZigTarget *target);
|
||||
|
||||
#endif
|
||||
|
||||
@ -221,6 +221,7 @@ enum TokenizeState {
|
||||
TokenizeStateError,
|
||||
TokenizeStateLBracket,
|
||||
TokenizeStateLBracketStar,
|
||||
TokenizeStateLBracketStarC,
|
||||
};
|
||||
|
||||
|
||||
@ -846,7 +847,6 @@ void tokenize(Buf *buf, Tokenization *out) {
|
||||
switch (c) {
|
||||
case '*':
|
||||
t.state = TokenizeStateLBracketStar;
|
||||
set_token_id(&t, t.cur_tok, TokenIdBracketStarBracket);
|
||||
break;
|
||||
default:
|
||||
// reinterpret as just an lbracket
|
||||
@ -857,6 +857,21 @@ void tokenize(Buf *buf, Tokenization *out) {
|
||||
}
|
||||
break;
|
||||
case TokenizeStateLBracketStar:
|
||||
switch (c) {
|
||||
case 'c':
|
||||
t.state = TokenizeStateLBracketStarC;
|
||||
set_token_id(&t, t.cur_tok, TokenIdBracketStarCBracket);
|
||||
break;
|
||||
case ']':
|
||||
set_token_id(&t, t.cur_tok, TokenIdBracketStarBracket);
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
default:
|
||||
invalid_char_error(&t, c);
|
||||
}
|
||||
break;
|
||||
case TokenizeStateLBracketStarC:
|
||||
switch (c) {
|
||||
case ']':
|
||||
end_token(&t);
|
||||
@ -1491,6 +1506,7 @@ void tokenize(Buf *buf, Tokenization *out) {
|
||||
case TokenizeStateLineStringContinue:
|
||||
case TokenizeStateLineStringContinueC:
|
||||
case TokenizeStateLBracketStar:
|
||||
case TokenizeStateLBracketStarC:
|
||||
tokenize_error(&t, "unexpected EOF");
|
||||
break;
|
||||
case TokenizeStateLineComment:
|
||||
@ -1528,6 +1544,7 @@ const char * token_name(TokenId id) {
|
||||
case TokenIdBitShiftRightEq: return ">>=";
|
||||
case TokenIdBitXorEq: return "^=";
|
||||
case TokenIdBracketStarBracket: return "[*]";
|
||||
case TokenIdBracketStarCBracket: return "[*c]";
|
||||
case TokenIdCharLiteral: return "CharLiteral";
|
||||
case TokenIdCmpEq: return "==";
|
||||
case TokenIdCmpGreaterOrEq: return ">=";
|
||||
|
||||
@ -29,6 +29,7 @@ enum TokenId {
|
||||
TokenIdBitShiftRightEq,
|
||||
TokenIdBitXorEq,
|
||||
TokenIdBracketStarBracket,
|
||||
TokenIdBracketStarCBracket,
|
||||
TokenIdCharLiteral,
|
||||
TokenIdCmpEq,
|
||||
TokenIdCmpGreaterOrEq,
|
||||
|
||||
@ -291,11 +291,22 @@ static AstNode *maybe_suppress_result(Context *c, ResultUsed result_used, AstNod
|
||||
node);
|
||||
}
|
||||
|
||||
static TokenId ptr_len_to_token_id(PtrLen ptr_len) {
|
||||
switch (ptr_len) {
|
||||
case PtrLenSingle:
|
||||
return TokenIdStar;
|
||||
case PtrLenUnknown:
|
||||
return TokenIdBracketStarBracket;
|
||||
case PtrLenC:
|
||||
return TokenIdBracketStarCBracket;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static AstNode *trans_create_node_ptr_type(Context *c, bool is_const, bool is_volatile, AstNode *child_node, PtrLen ptr_len) {
|
||||
AstNode *node = trans_create_node(c, NodeTypePointerType);
|
||||
node->data.pointer_type.star_token = allocate<ZigToken>(1);
|
||||
node->data.pointer_type.star_token->id = (ptr_len == PtrLenSingle) ? TokenIdStar: TokenIdBracketStarBracket;
|
||||
node->data.pointer_type.is_const = is_const;
|
||||
node->data.pointer_type.star_token->id = ptr_len_to_token_id(ptr_len);
|
||||
node->data.pointer_type.is_const = is_const;
|
||||
node->data.pointer_type.is_volatile = is_volatile;
|
||||
node->data.pointer_type.op_expr = child_node;
|
||||
@ -925,11 +936,14 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
|
||||
return trans_create_node_prefix_op(c, PrefixOpOptional, child_node);
|
||||
}
|
||||
|
||||
PtrLen ptr_len = type_is_opaque(c, child_qt.getTypePtr(), source_loc) ? PtrLenSingle : PtrLenUnknown;
|
||||
|
||||
AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(),
|
||||
child_qt.isVolatileQualified(), child_node, ptr_len);
|
||||
return trans_create_node_prefix_op(c, PrefixOpOptional, pointer_node);
|
||||
if (type_is_opaque(c, child_qt.getTypePtr(), source_loc)) {
|
||||
AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(),
|
||||
child_qt.isVolatileQualified(), child_node, PtrLenSingle);
|
||||
return trans_create_node_prefix_op(c, PrefixOpOptional, pointer_node);
|
||||
} else {
|
||||
return trans_create_node_ptr_type(c, child_qt.isConstQualified(),
|
||||
child_qt.isVolatileQualified(), child_node, PtrLenC);
|
||||
}
|
||||
}
|
||||
case Type::Typedef:
|
||||
{
|
||||
@ -1113,7 +1127,7 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
|
||||
return nullptr;
|
||||
}
|
||||
AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(),
|
||||
child_qt.isVolatileQualified(), child_type_node, PtrLenUnknown);
|
||||
child_qt.isVolatileQualified(), child_type_node, PtrLenC);
|
||||
return pointer_node;
|
||||
}
|
||||
case Type::BlockPointer:
|
||||
@ -1693,7 +1707,7 @@ static AstNode *trans_implicit_cast_expr(Context *c, TransScope *scope, const Im
|
||||
return node;
|
||||
}
|
||||
case CK_NullToPointer:
|
||||
return trans_create_node(c, NodeTypeNullLiteral);
|
||||
return trans_create_node_unsigned(c, 0);
|
||||
case CK_Dependent:
|
||||
emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dependent");
|
||||
return nullptr;
|
||||
@ -2425,7 +2439,8 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *
|
||||
case BuiltinType::Float16:
|
||||
return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node_unsigned_negative(c, 0, false));
|
||||
case BuiltinType::NullPtr:
|
||||
return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node(c, NodeTypeNullLiteral));
|
||||
return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq,
|
||||
trans_create_node_unsigned(c, 0));
|
||||
|
||||
case BuiltinType::Void:
|
||||
case BuiltinType::Half:
|
||||
@ -2510,7 +2525,8 @@ static AstNode *trans_bool_expr(Context *c, ResultUsed result_used, TransScope *
|
||||
break;
|
||||
}
|
||||
case Type::Pointer:
|
||||
return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq, trans_create_node(c, NodeTypeNullLiteral));
|
||||
return trans_create_node_bin_op(c, res, BinOpTypeCmpNotEq,
|
||||
trans_create_node_unsigned(c, 0));
|
||||
|
||||
case Type::Typedef:
|
||||
{
|
||||
@ -4568,7 +4584,7 @@ static AstNode *parse_ctok_suffix_op_expr(Context *c, CTokenize *ctok, size_t *t
|
||||
} else if (first_tok->id == CTokIdAsterisk) {
|
||||
*tok_i += 1;
|
||||
|
||||
node = trans_create_node_ptr_type(c, false, false, node, PtrLenUnknown);
|
||||
node = trans_create_node_ptr_type(c, false, false, node, PtrLenC);
|
||||
} else {
|
||||
return node;
|
||||
}
|
||||
|
||||
@ -236,6 +236,9 @@ pub fn formatType(
|
||||
const casted_value = ([]const u8)(value);
|
||||
return output(context, casted_value);
|
||||
},
|
||||
builtin.TypeInfo.Pointer.Size.C => {
|
||||
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(value));
|
||||
},
|
||||
},
|
||||
builtin.TypeId.Array => |info| {
|
||||
if (info.child == u8) {
|
||||
|
||||
@ -496,6 +496,7 @@ pub fn autoHash(key: var, comptime rng: *std.rand.Random, comptime HashInt: type
|
||||
builtin.TypeId.Pointer => |info| switch (info.size) {
|
||||
builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto hash for single item pointers"),
|
||||
builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto hash for many item pointers"),
|
||||
builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto hash C pointers"),
|
||||
builtin.TypeInfo.Pointer.Size.Slice => {
|
||||
const interval = std.math.max(1, key.len / 256);
|
||||
var i: usize = 0;
|
||||
@ -543,6 +544,7 @@ pub fn autoEql(a: var, b: @typeOf(a)) bool {
|
||||
builtin.TypeId.Pointer => |info| switch (info.size) {
|
||||
builtin.TypeInfo.Pointer.Size.One => @compileError("TODO auto eql for single item pointers"),
|
||||
builtin.TypeInfo.Pointer.Size.Many => @compileError("TODO auto eql for many item pointers"),
|
||||
builtin.TypeInfo.Pointer.Size.C => @compileError("TODO auto eql for C pointers"),
|
||||
builtin.TypeInfo.Pointer.Size.Slice => {
|
||||
if (a.len != b.len) return false;
|
||||
for (a) |a_item, i| {
|
||||
|
||||
@ -463,13 +463,16 @@ pub fn eql(a: var, b: @typeOf(a)) bool {
|
||||
builtin.TypeId.Pointer => {
|
||||
const info = @typeInfo(T).Pointer;
|
||||
switch (info.size) {
|
||||
builtin.TypeInfo.Pointer.Size.One, builtin.TypeInfo.Pointer.Size.Many => return a == b,
|
||||
builtin.TypeInfo.Pointer.Size.One,
|
||||
builtin.TypeInfo.Pointer.Size.Many,
|
||||
builtin.TypeInfo.Pointer.Size.C,
|
||||
=> return a == b,
|
||||
builtin.TypeInfo.Pointer.Size.Slice => return a.ptr == b.ptr and a.len == b.len,
|
||||
}
|
||||
},
|
||||
builtin.TypeId.Optional => {
|
||||
if(a == null and b == null) return true;
|
||||
if(a == null or b == null) return false;
|
||||
if (a == null and b == null) return true;
|
||||
if (a == null or b == null) return false;
|
||||
return eql(a.?, b.?);
|
||||
},
|
||||
else => return a == b,
|
||||
|
||||
@ -665,7 +665,7 @@ pub fn pwrite(fd: i32, buf: [*]const u8, nbyte: usize, offset: u64) usize {
|
||||
|
||||
pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
|
||||
const ptr_result = c.mmap(
|
||||
@ptrCast(*c_void, address),
|
||||
@ptrCast(?*c_void, address),
|
||||
length,
|
||||
@bitCast(c_int, @intCast(c_uint, prot)),
|
||||
@bitCast(c_int, c_uint(flags)),
|
||||
|
||||
@ -65,7 +65,7 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
|
||||
}
|
||||
},
|
||||
|
||||
builtin.TypeInfo.Pointer.Size.Slice => {
|
||||
builtin.TypeInfo.Pointer.Size.Slice => {
|
||||
if (actual.ptr != expected.ptr) {
|
||||
std.debug.panic("expected slice ptr {}, found {}", expected.ptr, actual.ptr);
|
||||
}
|
||||
@ -118,7 +118,6 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3525,7 +3525,12 @@ fn tokenIdToPrefixOp(id: Token.Id) ?ast.Node.PrefixOp.Op {
|
||||
Token.Id.Minus => ast.Node.PrefixOp.Op{ .Negation = void{} },
|
||||
Token.Id.MinusPercent => ast.Node.PrefixOp.Op{ .NegationWrap = void{} },
|
||||
Token.Id.Ampersand => ast.Node.PrefixOp.Op{ .AddressOf = void{} },
|
||||
Token.Id.Asterisk, Token.Id.AsteriskAsterisk, Token.Id.BracketStarBracket => ast.Node.PrefixOp.Op{
|
||||
|
||||
Token.Id.Asterisk,
|
||||
Token.Id.AsteriskAsterisk,
|
||||
Token.Id.BracketStarBracket,
|
||||
Token.Id.BracketStarCBracket,
|
||||
=> ast.Node.PrefixOp.Op{
|
||||
.PtrType = ast.Node.PrefixOp.PtrInfo{
|
||||
.align_info = null,
|
||||
.const_token = null,
|
||||
|
||||
@ -1,3 +1,10 @@
|
||||
test "zig fmt: C pointers" {
|
||||
try testCanonical(
|
||||
\\const Ptr = [*c]i32;
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: threadlocal" {
|
||||
try testCanonical(
|
||||
\\threadlocal var x: i32 = 1234;
|
||||
|
||||
@ -141,6 +141,7 @@ pub const Token = struct {
|
||||
LineComment,
|
||||
DocComment,
|
||||
BracketStarBracket,
|
||||
BracketStarCBracket,
|
||||
ShebangLine,
|
||||
Keyword_align,
|
||||
Keyword_and,
|
||||
@ -279,6 +280,7 @@ pub const Tokenizer = struct {
|
||||
SawAtSign,
|
||||
LBracket,
|
||||
LBracketStar,
|
||||
LBracketStarC,
|
||||
};
|
||||
|
||||
pub fn next(self: *Tokenizer) Token {
|
||||
@ -456,6 +458,9 @@ pub const Tokenizer = struct {
|
||||
},
|
||||
|
||||
State.LBracketStar => switch (c) {
|
||||
'c' => {
|
||||
state = State.LBracketStarC;
|
||||
},
|
||||
']' => {
|
||||
result.id = Token.Id.BracketStarBracket;
|
||||
self.index += 1;
|
||||
@ -467,6 +472,18 @@ pub const Tokenizer = struct {
|
||||
},
|
||||
},
|
||||
|
||||
State.LBracketStarC => switch (c) {
|
||||
']' => {
|
||||
result.id = Token.Id.BracketStarCBracket;
|
||||
self.index += 1;
|
||||
break;
|
||||
},
|
||||
else => {
|
||||
result.id = Token.Id.Invalid;
|
||||
break;
|
||||
},
|
||||
},
|
||||
|
||||
State.Ampersand => switch (c) {
|
||||
'=' => {
|
||||
result.id = Token.Id.AmpersandEqual;
|
||||
@ -1035,6 +1052,7 @@ pub const Tokenizer = struct {
|
||||
State.CharLiteralEnd,
|
||||
State.StringLiteralBackslash,
|
||||
State.LBracketStar,
|
||||
State.LBracketStarC,
|
||||
=> {
|
||||
result.id = Token.Id.Invalid;
|
||||
},
|
||||
@ -1169,12 +1187,15 @@ test "tokenizer" {
|
||||
testTokenize("test", []Token.Id{Token.Id.Keyword_test});
|
||||
}
|
||||
|
||||
test "tokenizer - unknown length pointer" {
|
||||
test "tokenizer - unknown length pointer and then c pointer" {
|
||||
testTokenize(
|
||||
\\[*]u8
|
||||
\\[*c]u8
|
||||
, []Token.Id{
|
||||
Token.Id.BracketStarBracket,
|
||||
Token.Id.Identifier,
|
||||
Token.Id.BracketStarCBracket,
|
||||
Token.Id.Identifier,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -1,13 +1,149 @@
|
||||
const tests = @import("tests.zig");
|
||||
|
||||
pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
cases.addTest(
|
||||
"C pointer to c_void",
|
||||
\\export fn a() void {
|
||||
\\ var x: *c_void = undefined;
|
||||
\\ var y: [*c]c_void = x;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:12: error: C pointers cannot point opaque types",
|
||||
);
|
||||
|
||||
cases.addTest(
|
||||
"directly embedding opaque type in struct and union",
|
||||
\\const O = @OpaqueType();
|
||||
\\const Foo = struct {
|
||||
\\ o: O,
|
||||
\\};
|
||||
\\const Bar = union {
|
||||
\\ One: i32,
|
||||
\\ Two: O,
|
||||
\\};
|
||||
\\export fn a() void {
|
||||
\\ var foo: Foo = undefined;
|
||||
\\}
|
||||
\\export fn b() void {
|
||||
\\ var bar: Bar = undefined;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:8: error: opaque types have unknown size and therefore cannot be directly embedded in structs",
|
||||
".tmp_source.zig:7:10: error: opaque types have unknown size and therefore cannot be directly embedded in unions",
|
||||
);
|
||||
|
||||
cases.addTest(
|
||||
"implicit cast between C pointer and Zig pointer - bad const/align/child",
|
||||
\\export fn a() void {
|
||||
\\ var x: [*c]u8 = undefined;
|
||||
\\ var y: *align(4) u8 = x;
|
||||
\\}
|
||||
\\export fn b() void {
|
||||
\\ var x: [*c]const u8 = undefined;
|
||||
\\ var y: *u8 = x;
|
||||
\\}
|
||||
\\export fn c() void {
|
||||
\\ var x: [*c]u8 = undefined;
|
||||
\\ var y: *u32 = x;
|
||||
\\}
|
||||
\\export fn d() void {
|
||||
\\ var y: *align(1) u32 = undefined;
|
||||
\\ var x: [*c]u32 = y;
|
||||
\\}
|
||||
\\export fn e() void {
|
||||
\\ var y: *const u8 = undefined;
|
||||
\\ var x: [*c]u8 = y;
|
||||
\\}
|
||||
\\export fn f() void {
|
||||
\\ var y: *u8 = undefined;
|
||||
\\ var x: [*c]u32 = y;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:27: error: cast increases pointer alignment",
|
||||
".tmp_source.zig:7:18: error: cast discards const qualifier",
|
||||
".tmp_source.zig:11:19: error: expected type '*u32', found '[*c]u8'",
|
||||
".tmp_source.zig:11:19: note: pointer type child 'u8' cannot cast into pointer type child 'u32'",
|
||||
".tmp_source.zig:15:22: error: cast increases pointer alignment",
|
||||
".tmp_source.zig:19:21: error: cast discards const qualifier",
|
||||
".tmp_source.zig:23:22: error: expected type '[*c]u32', found '*u8'",
|
||||
);
|
||||
|
||||
cases.addTest(
|
||||
"implicit casting null c pointer to zig pointer",
|
||||
\\comptime {
|
||||
\\ var c_ptr: [*c]u8 = 0;
|
||||
\\ var zig_ptr: *u8 = c_ptr;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:24: error: null pointer casted to type '*u8'",
|
||||
);
|
||||
|
||||
cases.addTest(
|
||||
"implicit casting undefined c pointer to zig pointer",
|
||||
\\comptime {
|
||||
\\ var c_ptr: [*c]u8 = undefined;
|
||||
\\ var zig_ptr: *u8 = c_ptr;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:24: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.addTest(
|
||||
"implicit casting C pointers which would mess up null semantics",
|
||||
\\export fn entry() void {
|
||||
\\ var slice: []const u8 = "aoeu";
|
||||
\\ const opt_many_ptr: [*]const u8 = slice.ptr;
|
||||
\\ var ptr_opt_many_ptr = &opt_many_ptr;
|
||||
\\ var c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr;
|
||||
\\ ptr_opt_many_ptr = c_ptr;
|
||||
\\}
|
||||
\\export fn entry2() void {
|
||||
\\ var buf: [4]u8 = "aoeu";
|
||||
\\ var slice: []u8 = &buf;
|
||||
\\ var opt_many_ptr: [*]u8 = slice.ptr;
|
||||
\\ var ptr_opt_many_ptr = &opt_many_ptr;
|
||||
\\ var c_ptr: [*c][*c]const u8 = ptr_opt_many_ptr;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:6:24: error: expected type '*const [*]const u8', found '[*c]const [*c]const u8'",
|
||||
".tmp_source.zig:6:24: note: pointer type child '[*c]const u8' cannot cast into pointer type child '[*]const u8'",
|
||||
".tmp_source.zig:6:24: note: '[*c]const u8' could have null values which are illegal in type '[*]const u8'",
|
||||
".tmp_source.zig:13:35: error: expected type '[*c][*c]const u8', found '*[*]u8'",
|
||||
".tmp_source.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]const u8'",
|
||||
".tmp_source.zig:13:35: note: mutable '[*c]const u8' allows illegal null values stored to type '[*]u8'",
|
||||
);
|
||||
|
||||
cases.addTest(
|
||||
"implicit casting too big integers to C pointers",
|
||||
\\export fn a() void {
|
||||
\\ var ptr: [*c]u8 = (1 << 64) + 1;
|
||||
\\}
|
||||
\\export fn b() void {
|
||||
\\ var x: @IntType(false, 65) = 0x1234;
|
||||
\\ var ptr: [*c]u8 = x;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:2:33: error: integer value 71615590737044764481 cannot be implicitly casted to type 'usize'",
|
||||
".tmp_source.zig:6:23: error: integer type 'u65' too big for implicit @intToPtr to type '[*c]u8'",
|
||||
);
|
||||
|
||||
cases.addTest(
|
||||
"C pointer pointing to non C ABI compatible type or has align attr",
|
||||
\\const Foo = struct {};
|
||||
\\export fn a() void {
|
||||
\\ const T = [*c]Foo;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:15: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'",
|
||||
);
|
||||
|
||||
cases.addTest(
|
||||
"@truncate undefined value",
|
||||
\\export fn entry() void {
|
||||
\\ var z = @truncate(u8, u16(undefined));
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:2:30: error: use of undefined value",
|
||||
".tmp_source.zig:2:30: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.addTest(
|
||||
@ -368,7 +504,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ f(i32);
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:4:5: error: use of undefined value",
|
||||
".tmp_source.zig:4:5: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -768,7 +904,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ command.exec();
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:6:12: error: use of undefined value",
|
||||
".tmp_source.zig:6:12: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -781,7 +917,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ command.exec();
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:6:12: error: use of undefined value",
|
||||
".tmp_source.zig:6:12: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2752,7 +2888,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\
|
||||
\\export fn entry() usize { return @sizeOf(@typeOf(x)); }
|
||||
,
|
||||
".tmp_source.zig:1:15: error: use of undefined value",
|
||||
".tmp_source.zig:1:15: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2762,7 +2898,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a / a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2772,7 +2908,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ a /= a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:5: error: use of undefined value",
|
||||
".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2782,7 +2918,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a % a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2792,7 +2928,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ a %= a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:5: error: use of undefined value",
|
||||
".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2802,7 +2938,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a + a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2812,7 +2948,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ a += a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:5: error: use of undefined value",
|
||||
".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2822,7 +2958,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a +% a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2832,7 +2968,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ a +%= a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:5: error: use of undefined value",
|
||||
".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2842,7 +2978,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a - a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2852,7 +2988,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ a -= a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:5: error: use of undefined value",
|
||||
".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2862,7 +2998,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a -% a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2872,7 +3008,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ a -%= a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:5: error: use of undefined value",
|
||||
".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2882,7 +3018,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a * a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2892,7 +3028,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ a *= a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:5: error: use of undefined value",
|
||||
".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2902,7 +3038,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a *% a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2912,7 +3048,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ a *%= a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:5: error: use of undefined value",
|
||||
".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2922,7 +3058,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a << 2;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2932,7 +3068,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ a <<= 2;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:5: error: use of undefined value",
|
||||
".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2942,7 +3078,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a >> 2;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2952,7 +3088,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ a >>= 2;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:5: error: use of undefined value",
|
||||
".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2962,7 +3098,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a & a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2972,7 +3108,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ a &= a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:5: error: use of undefined value",
|
||||
".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2982,7 +3118,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a | a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2992,7 +3128,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ a |= a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:5: error: use of undefined value",
|
||||
".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3002,7 +3138,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a ^ a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3012,7 +3148,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ a ^= a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:5: error: use of undefined value",
|
||||
".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3022,7 +3158,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a == a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3032,7 +3168,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a != a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3042,7 +3178,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a > a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3052,7 +3188,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a >= a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3062,7 +3198,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a < a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3072,7 +3208,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a <= a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3082,7 +3218,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a and a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3092,7 +3228,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a or a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:9: error: use of undefined value",
|
||||
".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3102,7 +3238,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = -a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:10: error: use of undefined value",
|
||||
".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3112,7 +3248,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = -%a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:11: error: use of undefined value",
|
||||
".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3122,7 +3258,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = ~a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:10: error: use of undefined value",
|
||||
".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3132,7 +3268,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = !a;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:10: error: use of undefined value",
|
||||
".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3142,7 +3278,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a orelse false;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:11: error: use of undefined value",
|
||||
".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3152,7 +3288,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ _ = a catch |err| false;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:11: error: use of undefined value",
|
||||
".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
|
||||
@ -1,6 +1,16 @@
|
||||
const tests = @import("tests.zig");
|
||||
|
||||
pub fn addCases(cases: *tests.CompareOutputContext) void {
|
||||
cases.addRuntimeSafety("pointer casting null to non-optional pointer",
|
||||
\\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
|
||||
\\ @import("std").os.exit(126);
|
||||
\\}
|
||||
\\pub fn main() void {
|
||||
\\ var c_ptr: [*c]u8 = 0;
|
||||
\\ var zig_ptr: *u8 = c_ptr;
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.addRuntimeSafety("@intToEnum - no matching tag value",
|
||||
\\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
|
||||
\\ @import("std").os.exit(126);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
const std = @import("std");
|
||||
const expect = std.testing.expect;
|
||||
const expectError = std.testing.expectError;
|
||||
|
||||
test "dereference pointer" {
|
||||
comptime testDerefPtr();
|
||||
@ -42,3 +43,84 @@ test "double pointer parsing" {
|
||||
fn PtrOf(comptime T: type) type {
|
||||
return *T;
|
||||
}
|
||||
|
||||
test "assigning integer to C pointer" {
|
||||
var x: i32 = 0;
|
||||
var ptr: [*c]u8 = 0;
|
||||
var ptr2: [*c]u8 = x;
|
||||
}
|
||||
|
||||
test "implicit cast single item pointer to C pointer and back" {
|
||||
var y: u8 = 11;
|
||||
var x: [*c]u8 = &y;
|
||||
var z: *u8 = x;
|
||||
z.* += 1;
|
||||
expect(y == 12);
|
||||
}
|
||||
|
||||
test "C pointer comparison and arithmetic" {
|
||||
const S = struct {
|
||||
fn doTheTest() void {
|
||||
var one: usize = 1;
|
||||
var ptr1: [*c]u32 = 0;
|
||||
var ptr2 = ptr1 + 10;
|
||||
expect(ptr1 == 0);
|
||||
expect(ptr1 >= 0);
|
||||
expect(ptr1 <= 0);
|
||||
expect(ptr1 < 1);
|
||||
expect(ptr1 < one);
|
||||
expect(1 > ptr1);
|
||||
expect(one > ptr1);
|
||||
expect(ptr1 < ptr2);
|
||||
expect(ptr2 > ptr1);
|
||||
expect(ptr2 >= 40);
|
||||
expect(ptr2 == 40);
|
||||
expect(ptr2 <= 40);
|
||||
ptr2 -= 10;
|
||||
expect(ptr1 == ptr2);
|
||||
}
|
||||
};
|
||||
S.doTheTest();
|
||||
comptime S.doTheTest();
|
||||
}
|
||||
|
||||
test "peer type resolution with C pointers" {
|
||||
var ptr_one: *u8 = undefined;
|
||||
var ptr_many: [*]u8 = undefined;
|
||||
var ptr_c: [*c]u8 = undefined;
|
||||
var t = true;
|
||||
var x1 = if (t) ptr_one else ptr_c;
|
||||
var x2 = if (t) ptr_many else ptr_c;
|
||||
var x3 = if (t) ptr_c else ptr_one;
|
||||
var x4 = if (t) ptr_c else ptr_many;
|
||||
expect(@typeOf(x1) == [*c]u8);
|
||||
expect(@typeOf(x2) == [*c]u8);
|
||||
expect(@typeOf(x3) == [*c]u8);
|
||||
expect(@typeOf(x4) == [*c]u8);
|
||||
}
|
||||
|
||||
test "implicit casting between C pointer and optional non-C pointer" {
|
||||
var slice: []const u8 = "aoeu";
|
||||
const opt_many_ptr: ?[*]const u8 = slice.ptr;
|
||||
var ptr_opt_many_ptr = &opt_many_ptr;
|
||||
var c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr;
|
||||
expect(c_ptr.*.* == 'a');
|
||||
ptr_opt_many_ptr = c_ptr;
|
||||
expect(ptr_opt_many_ptr.*.?[1] == 'o');
|
||||
}
|
||||
|
||||
test "implicit cast error unions with non-optional to optional pointer" {
|
||||
const S = struct {
|
||||
fn doTheTest() void {
|
||||
expectError(error.Fail, foo());
|
||||
}
|
||||
fn foo() anyerror!?*u8 {
|
||||
return bar() orelse error.Fail;
|
||||
}
|
||||
fn bar() ?*u8 {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
S.doTheTest();
|
||||
comptime S.doTheTest();
|
||||
}
|
||||
|
||||
@ -61,6 +61,21 @@ fn testUnknownLenPtr() void {
|
||||
expect(u32_ptr_info.Pointer.child == f64);
|
||||
}
|
||||
|
||||
test "type info: C pointer type info" {
|
||||
testCPtr();
|
||||
comptime testCPtr();
|
||||
}
|
||||
|
||||
fn testCPtr() void {
|
||||
const ptr_info = @typeInfo([*c]align(4) const i8);
|
||||
expect(TypeId(ptr_info) == TypeId.Pointer);
|
||||
expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.C);
|
||||
expect(ptr_info.Pointer.is_const);
|
||||
expect(!ptr_info.Pointer.is_volatile);
|
||||
expect(ptr_info.Pointer.alignment == 4);
|
||||
expect(ptr_info.Pointer.child == i8);
|
||||
}
|
||||
|
||||
test "type info: slice type info" {
|
||||
testSlice();
|
||||
comptime testSlice();
|
||||
|
||||
@ -117,11 +117,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\};
|
||||
,
|
||||
\\pub const struct_Foo = extern struct {
|
||||
\\ a: ?[*]Foo,
|
||||
\\ a: [*c]Foo,
|
||||
\\};
|
||||
\\pub const Foo = struct_Foo;
|
||||
\\pub const struct_Bar = extern struct {
|
||||
\\ a: ?[*]Foo,
|
||||
\\ a: [*c]Foo,
|
||||
\\};
|
||||
);
|
||||
|
||||
@ -213,7 +213,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
,
|
||||
\\const struct_Foo = extern struct {
|
||||
\\ x: c_int,
|
||||
\\ y: ?[*]u8,
|
||||
\\ y: [*c]u8,
|
||||
\\};
|
||||
,
|
||||
\\pub const Foo = struct_Foo;
|
||||
@ -244,7 +244,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
,
|
||||
\\pub const BarB = enum_Bar.B;
|
||||
,
|
||||
\\pub extern fn func(a: ?[*]struct_Foo, b: ?[*](?[*]enum_Bar)) void;
|
||||
\\pub extern fn func(a: [*c]struct_Foo, b: [*c]([*c]enum_Bar)) void;
|
||||
,
|
||||
\\pub const Foo = struct_Foo;
|
||||
,
|
||||
@ -254,7 +254,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
cases.add("constant size array",
|
||||
\\void func(int array[20]);
|
||||
,
|
||||
\\pub extern fn func(array: ?[*]c_int) void;
|
||||
\\pub extern fn func(array: [*c]c_int) void;
|
||||
);
|
||||
|
||||
cases.add("self referential struct with function pointer",
|
||||
@ -263,7 +263,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\};
|
||||
,
|
||||
\\pub const struct_Foo = extern struct {
|
||||
\\ derp: ?extern fn(?[*]struct_Foo) void,
|
||||
\\ derp: ?extern fn([*c]struct_Foo) void,
|
||||
\\};
|
||||
,
|
||||
\\pub const Foo = struct_Foo;
|
||||
@ -322,11 +322,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\};
|
||||
,
|
||||
\\pub const struct_Bar = extern struct {
|
||||
\\ next: ?[*]struct_Foo,
|
||||
\\ next: [*c]struct_Foo,
|
||||
\\};
|
||||
,
|
||||
\\pub const struct_Foo = extern struct {
|
||||
\\ next: ?[*]struct_Bar,
|
||||
\\ next: [*c]struct_Bar,
|
||||
\\};
|
||||
);
|
||||
|
||||
@ -610,11 +610,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
,
|
||||
\\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
|
||||
\\ if ((a != 0) and (b != 0)) return 0;
|
||||
\\ if ((b != 0) and (c != null)) return 1;
|
||||
\\ if ((a != 0) and (c != null)) return 2;
|
||||
\\ if ((b != 0) and (c != 0)) return 1;
|
||||
\\ if ((a != 0) and (c != 0)) return 2;
|
||||
\\ if ((a != 0) or (b != 0)) return 3;
|
||||
\\ if ((b != 0) or (c != null)) return 4;
|
||||
\\ if ((a != 0) or (c != null)) return 5;
|
||||
\\ if ((b != 0) or (c != 0)) return 4;
|
||||
\\ if ((a != 0) or (c != 0)) return 5;
|
||||
\\ return 6;
|
||||
\\}
|
||||
);
|
||||
@ -710,7 +710,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\pub const struct_Foo = extern struct {
|
||||
\\ field: c_int,
|
||||
\\};
|
||||
\\pub export fn read_field(foo: ?[*]struct_Foo) c_int {
|
||||
\\pub export fn read_field(foo: [*c]struct_Foo) c_int {
|
||||
\\ return foo.?.field;
|
||||
\\}
|
||||
);
|
||||
@ -756,7 +756,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ return x;
|
||||
\\}
|
||||
,
|
||||
\\pub export fn foo(x: ?[*]c_ushort) ?*c_void {
|
||||
\\pub export fn foo(x: [*c]c_ushort) ?*c_void {
|
||||
\\ return @ptrCast(?*c_void, x);
|
||||
\\}
|
||||
);
|
||||
@ -777,8 +777,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ return 0;
|
||||
\\}
|
||||
,
|
||||
\\pub export fn foo() ?[*]c_int {
|
||||
\\ return null;
|
||||
\\pub export fn foo() [*c]c_int {
|
||||
\\ return 0;
|
||||
\\}
|
||||
);
|
||||
|
||||
@ -1086,7 +1086,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ *x = 1;
|
||||
\\}
|
||||
,
|
||||
\\pub export fn foo(x: ?[*]c_int) void {
|
||||
\\pub export fn foo(x: [*c]c_int) void {
|
||||
\\ x.?.* = 1;
|
||||
\\}
|
||||
);
|
||||
@ -1114,7 +1114,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
,
|
||||
\\pub fn foo() c_int {
|
||||
\\ var x: c_int = 1234;
|
||||
\\ var ptr: ?[*]c_int = &x;
|
||||
\\ var ptr: [*c]c_int = &x;
|
||||
\\ return ptr.?.*;
|
||||
\\}
|
||||
);
|
||||
@ -1124,7 +1124,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ return "bar";
|
||||
\\}
|
||||
,
|
||||
\\pub fn foo() ?[*]const u8 {
|
||||
\\pub fn foo() [*c]const u8 {
|
||||
\\ return c"bar";
|
||||
\\}
|
||||
);
|
||||
@ -1253,8 +1253,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ return (float *)a;
|
||||
\\}
|
||||
,
|
||||
\\fn ptrcast(a: ?[*]c_int) ?[*]f32 {
|
||||
\\ return @ptrCast(?[*]f32, a);
|
||||
\\fn ptrcast(a: [*c]c_int) [*c]f32 {
|
||||
\\ return @ptrCast([*c]f32, a);
|
||||
\\}
|
||||
);
|
||||
|
||||
@ -1280,7 +1280,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ return !(a == 0);
|
||||
\\ return !(a != 0);
|
||||
\\ return !(b != 0);
|
||||
\\ return !(c != null);
|
||||
\\ return !(c != 0);
|
||||
\\}
|
||||
);
|
||||
|
||||
@ -1297,7 +1297,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
cases.add("const ptr initializer",
|
||||
\\static const char *v0 = "0.0.0";
|
||||
,
|
||||
\\pub var v0: ?[*]const u8 = c"0.0.0";
|
||||
\\pub var v0: [*c]const u8 = c"0.0.0";
|
||||
);
|
||||
|
||||
cases.add("static incomplete array inside function",
|
||||
@ -1306,17 +1306,17 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\}
|
||||
,
|
||||
\\pub fn foo() void {
|
||||
\\ const v2: [*]const u8 = c"2.2.2";
|
||||
\\ const v2: [*c]const u8 = c"2.2.2";
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.add("macro pointer cast",
|
||||
\\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE)
|
||||
,
|
||||
\\pub const NRF_GPIO = if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*]NRF_GPIO_Type, NRF_GPIO_BASE) else ([*]NRF_GPIO_Type)(NRF_GPIO_BASE);
|
||||
\\pub const NRF_GPIO = if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Pointer) @ptrCast([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else if (@typeId(@typeOf(NRF_GPIO_BASE)) == @import("builtin").TypeId.Int) @intToPtr([*c]NRF_GPIO_Type, NRF_GPIO_BASE) else ([*c]NRF_GPIO_Type)(NRF_GPIO_BASE);
|
||||
);
|
||||
|
||||
cases.add("if on none bool",
|
||||
cases.add("if on non-bool",
|
||||
\\enum SomeEnum { A, B, C };
|
||||
\\int if_none_bool(int a, float b, void *c, enum SomeEnum d) {
|
||||
\\ if (a) return 0;
|
||||
@ -1337,13 +1337,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\pub fn if_none_bool(a: c_int, b: f32, c: ?*c_void, d: enum_SomeEnum) c_int {
|
||||
\\ if (a != 0) return 0;
|
||||
\\ if (b != 0) return 1;
|
||||
\\ if (c != null) return 2;
|
||||
\\ if (c != 0) return 2;
|
||||
\\ if (d != @bitCast(enum_SomeEnum, @TagType(enum_SomeEnum)(0))) return 3;
|
||||
\\ return 4;
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.add("while on none bool",
|
||||
cases.add("while on non-bool",
|
||||
\\int while_none_bool(int a, float b, void *c) {
|
||||
\\ while (a) return 0;
|
||||
\\ while (b) return 1;
|
||||
@ -1354,12 +1354,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\pub fn while_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
|
||||
\\ while (a != 0) return 0;
|
||||
\\ while (b != 0) return 1;
|
||||
\\ while (c != null) return 2;
|
||||
\\ while (c != 0) return 2;
|
||||
\\ return 3;
|
||||
\\}
|
||||
);
|
||||
|
||||
cases.add("for on none bool",
|
||||
cases.add("for on non-bool",
|
||||
\\int for_none_bool(int a, float b, void *c) {
|
||||
\\ for (;a;) return 0;
|
||||
\\ for (;b;) return 1;
|
||||
@ -1370,7 +1370,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\pub fn for_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
|
||||
\\ while (a != 0) return 0;
|
||||
\\ while (b != 0) return 1;
|
||||
\\ while (c != null) return 2;
|
||||
\\ while (c != 0) return 2;
|
||||
\\ return 3;
|
||||
\\}
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user