implement allowzero pointer attribute
closes #1953 only needed for freestanding targets. also adds safety for `@intToPtr` when the address is zero.
This commit is contained in:
parent
3306e43984
commit
5eaead6a56
@ -779,6 +779,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
|
||||
std.zig.Token.Id.Keyword_use,
|
||||
std.zig.Token.Id.Keyword_var,
|
||||
std.zig.Token.Id.Keyword_volatile,
|
||||
std.zig.Token.Id.Keyword_allowzero,
|
||||
std.zig.Token.Id.Keyword_while,
|
||||
=> {
|
||||
try out.write("<span class=\"tok-kw\">");
|
||||
|
@ -1721,7 +1721,7 @@ test "comptime @intToPtr" {
|
||||
}
|
||||
}
|
||||
{#code_end#}
|
||||
{#see_also|Optional Pointers|@intToPtr|@ptrToInt#}
|
||||
{#see_also|Optional Pointers|@intToPtr|@ptrToInt|C Pointers|Pointers to Zero Bit Types#}
|
||||
{#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#}.
|
||||
@ -1850,7 +1850,25 @@ fn foo(bytes: []u8) u32 {
|
||||
}
|
||||
{#code_end#}
|
||||
{#header_close#}
|
||||
{#see_also|C Pointers|Pointers to Zero Bit Types#}
|
||||
|
||||
{#header_open|allowzero#}
|
||||
<p>
|
||||
This pointer attribute allows a pointer to have address zero. This is only ever needed on the
|
||||
freestanding OS target, where the address zero is mappable. In this code example, if the pointer
|
||||
did not have the {#syntax#}allowzero{#endsyntax#} attribute, this would be a
|
||||
{#link|Pointer Cast Invalid Null#} panic:
|
||||
</p>
|
||||
{#code_begin|test|allowzero#}
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
|
||||
test "allowzero" {
|
||||
var zero: usize = 0;
|
||||
var ptr = @intToPtr(*allowzero i32, zero);
|
||||
assert(@ptrToInt(ptr) == 0);
|
||||
}
|
||||
{#code_end#}
|
||||
{#header_close#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Slices#}
|
||||
@ -6635,9 +6653,13 @@ fn add(a: i32, b: i32) i32 { return a + b; }
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@intToPtr#}
|
||||
<pre>{#syntax#}@intToPtr(comptime DestType: type, int: usize) DestType{#endsyntax#}</pre>
|
||||
<pre>{#syntax#}@intToPtr(comptime DestType: type, address: usize) DestType{#endsyntax#}</pre>
|
||||
<p>
|
||||
Converts an integer to a pointer. To convert the other way, use {#link|@ptrToInt#}.
|
||||
Converts an integer to a {#link|pointer|Pointers#}. To convert the other way, use {#link|@ptrToInt#}.
|
||||
</p>
|
||||
<p>
|
||||
If the destination pointer type does not allow address zero and {#syntax#}address{#endsyntax#}
|
||||
is zero, this invokes safety-checked {#link|Undefined Behavior#}.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
@ -8128,6 +8150,11 @@ fn bar(f: *Foo) void {
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|Pointer Cast Invalid Null#}
|
||||
<p>
|
||||
This happens when casting a pointer with the address 0 to a pointer which may not have the address 0.
|
||||
For example, {#link|C Pointers#}, {#link|Optional Pointers#}, and {#link|allowzero#} pointers
|
||||
allow address zero, but normal {#link|Pointers#} do not.
|
||||
</p>
|
||||
<p>At compile-time:</p>
|
||||
{#code_begin|test_err|null pointer casted to type#}
|
||||
comptime {
|
||||
@ -8988,7 +9015,7 @@ Available libcs:
|
||||
<ul>
|
||||
<li>Linux x86_64</li>
|
||||
<li>Windows x86_64</li>
|
||||
<li>MacOS x86_64</li>
|
||||
<li>macOS x86_64</li>
|
||||
</ul>
|
||||
{#header_close#}
|
||||
{#header_open|Style Guide#}
|
||||
@ -9412,8 +9439,8 @@ PrefixOp
|
||||
PrefixTypeOp
|
||||
<- QUESTIONMARK
|
||||
/ KEYWORD_promise MINUSRARROW
|
||||
/ ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile)*
|
||||
/ PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile)*
|
||||
/ ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
|
||||
/ PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
|
||||
|
||||
SuffixOp
|
||||
<- LBRACKET Expr (DOT2 Expr?)? RBRACKET
|
||||
@ -9564,6 +9591,7 @@ TILDE <- '~' skip
|
||||
|
||||
end_of_word <- ![a-zA-Z0-9_] skip
|
||||
KEYWORD_align <- 'align' end_of_word
|
||||
KEYWORD_allowzero <- 'allowzero' end_of_word
|
||||
KEYWORD_and <- 'and' end_of_word
|
||||
KEYWORD_anyerror <- 'anyerror' end_of_word
|
||||
KEYWORD_asm <- 'asm' end_of_word
|
||||
@ -9614,7 +9642,7 @@ KEYWORD_var <- 'var' end_of_word
|
||||
KEYWORD_volatile <- 'volatile' end_of_word
|
||||
KEYWORD_while <- 'while' end_of_word
|
||||
|
||||
keyword <- KEYWORD_align / KEYWORD_and / KEYWORD_anyerror / KEYWORD_asm
|
||||
keyword <- KEYWORD_align / KEYWORD_and / KEYWORD_allowzero / KEYWORD_anyerror / KEYWORD_asm
|
||||
/ KEYWORD_async / KEYWORD_await / KEYWORD_break / KEYWORD_cancel
|
||||
/ KEYWORD_catch / KEYWORD_comptime / KEYWORD_const / KEYWORD_continue
|
||||
/ KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer
|
||||
|
@ -2668,7 +2668,7 @@ struct IrInstructionPtrType {
|
||||
PtrLen ptr_len;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
bool allow_zero;
|
||||
bool is_allow_zero;
|
||||
};
|
||||
|
||||
struct IrInstructionPromiseType {
|
||||
@ -2684,7 +2684,7 @@ struct IrInstructionSliceType {
|
||||
IrInstruction *child_type;
|
||||
bool is_const;
|
||||
bool is_volatile;
|
||||
bool allow_zero;
|
||||
bool is_allow_zero;
|
||||
};
|
||||
|
||||
struct IrInstructionGlobalAsm {
|
||||
|
@ -418,11 +418,9 @@ static const char *ptr_len_to_star_str(PtrLen ptr_len) {
|
||||
|
||||
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)
|
||||
uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero)
|
||||
{
|
||||
// TODO when implementing https://github.com/ziglang/zig/issues/1953
|
||||
// move this to a parameter
|
||||
bool allow_zero = (ptr_len == PtrLenC);
|
||||
assert(ptr_len != PtrLenC || allow_zero);
|
||||
assert(!type_is_invalid(child_type));
|
||||
assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque);
|
||||
|
||||
@ -505,7 +503,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
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);
|
||||
PtrLenSingle, 0, 0, host_int_bytes, false);
|
||||
entry->type_ref = peer_type->type_ref;
|
||||
entry->di_type = peer_type->di_type;
|
||||
} else {
|
||||
@ -548,7 +546,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
|
||||
}
|
||||
|
||||
ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const) {
|
||||
return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0);
|
||||
return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0, false);
|
||||
}
|
||||
|
||||
ZigType *get_promise_frame_type(CodeGen *g, ZigType *return_type) {
|
||||
@ -857,7 +855,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
|
||||
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);
|
||||
PtrLenUnknown, 0, 0, 0, false);
|
||||
ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type);
|
||||
|
||||
slice_type_common_init(g, ptr_type, entry);
|
||||
@ -881,10 +879,10 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
|
||||
{
|
||||
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,
|
||||
PtrLenUnknown, 0, 0, 0);
|
||||
PtrLenUnknown, 0, 0, 0, false);
|
||||
ZigType *bland_child_slice = get_slice_type(g, bland_child_ptr_type);
|
||||
ZigType *peer_ptr_type = get_pointer_to_type_extra(g, bland_child_slice, false, false,
|
||||
PtrLenUnknown, 0, 0, 0);
|
||||
PtrLenUnknown, 0, 0, 0, false);
|
||||
ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type);
|
||||
|
||||
entry->type_ref = peer_slice_type->type_ref;
|
||||
@ -1419,7 +1417,7 @@ static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_
|
||||
|
||||
static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **out_buffer) {
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
|
||||
PtrLenUnknown, 0, 0, 0);
|
||||
PtrLenUnknown, 0, 0, 0, false);
|
||||
ZigType *str_type = get_slice_type(g, ptr_type);
|
||||
ConstExprValue *result_val = analyze_const_value(g, scope, node, str_type, nullptr);
|
||||
if (type_is_invalid(result_val->type))
|
||||
@ -5336,7 +5334,7 @@ void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
// TODO make this `[*]null u8` instead of `[*]u8`
|
||||
const_val->type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
|
||||
PtrLenUnknown, 0, 0, 0);
|
||||
PtrLenUnknown, 0, 0, 0, false);
|
||||
const_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
|
||||
const_val->data.x_ptr.data.base_array.array_val = array_val;
|
||||
const_val->data.x_ptr.data.base_array.elem_index = 0;
|
||||
@ -5481,7 +5479,7 @@ void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *arr
|
||||
assert(array_val->type->id == ZigTypeIdArray);
|
||||
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(g, array_val->type->data.array.child_type,
|
||||
is_const, false, PtrLenUnknown, 0, 0, 0);
|
||||
is_const, false, PtrLenUnknown, 0, 0, 0, false);
|
||||
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
const_val->type = get_slice_type(g, ptr_type);
|
||||
@ -5506,7 +5504,7 @@ void init_const_ptr_array(CodeGen *g, ConstExprValue *const_val, ConstExprValue
|
||||
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
const_val->type = get_pointer_to_type_extra(g, child_type, is_const, false,
|
||||
ptr_len, 0, 0, 0);
|
||||
ptr_len, 0, 0, 0, false);
|
||||
const_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
|
||||
const_val->data.x_ptr.data.base_array.array_val = array_val;
|
||||
const_val->data.x_ptr.data.base_array.elem_index = elem_index;
|
||||
|
@ -18,7 +18,9 @@ void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg);
|
||||
ZigType *new_type_table_entry(ZigTypeId id);
|
||||
ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const);
|
||||
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, uint32_t unaligned_bit_count);
|
||||
bool is_volatile, PtrLen ptr_len,
|
||||
uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count,
|
||||
bool allow_zero);
|
||||
uint64_t type_size(CodeGen *g, ZigType *type_entry);
|
||||
uint64_t type_size_bits(CodeGen *g, ZigType *type_entry);
|
||||
ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits);
|
||||
|
@ -956,7 +956,7 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
|
||||
}
|
||||
|
||||
ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
|
||||
PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
|
||||
PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false);
|
||||
ZigType *str_type = get_slice_type(g, u8_ptr_type);
|
||||
return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(str_type->type_ref, 0));
|
||||
}
|
||||
@ -1515,7 +1515,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
|
||||
|
||||
|
||||
ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
|
||||
PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
|
||||
PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false);
|
||||
ZigType *str_type = get_slice_type(g, u8_ptr_type);
|
||||
LLVMValueRef global_slice_fields[] = {
|
||||
full_buf_ptr,
|
||||
@ -3103,6 +3103,18 @@ static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executa
|
||||
static LLVMValueRef ir_render_int_to_ptr(CodeGen *g, IrExecutable *executable, IrInstructionIntToPtr *instruction) {
|
||||
ZigType *wanted_type = instruction->base.value.type;
|
||||
LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
|
||||
if (!ptr_allows_addr_zero(wanted_type) && ir_want_runtime_safety(g, &instruction->base)) {
|
||||
LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(target_val));
|
||||
LLVMValueRef is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, target_val, zero, "");
|
||||
LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrToIntBad");
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrToIntOk");
|
||||
LLVMBuildCondBr(g->builder, is_zero_bit, bad_block, ok_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, bad_block);
|
||||
gen_safety_crash(g, PanicMsgIdPtrCastNull);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, ok_block);
|
||||
}
|
||||
return LLVMBuildIntToPtr(g->builder, target_val, wanted_type->type_ref, "");
|
||||
}
|
||||
|
||||
@ -3270,7 +3282,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
|
||||
|
||||
if (have_init_expr) {
|
||||
ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->var_type, false, false,
|
||||
PtrLenSingle, var->align_bytes, 0, 0);
|
||||
PtrLenSingle, var->align_bytes, 0, 0, false);
|
||||
LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value);
|
||||
gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val);
|
||||
} else if (ir_want_runtime_safety(g, &decl_var_instruction->base)) {
|
||||
@ -4160,7 +4172,7 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
|
||||
return enum_type->data.enumeration.name_function;
|
||||
|
||||
ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, false, false,
|
||||
PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
|
||||
PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false);
|
||||
ZigType *u8_slice_type = get_slice_type(g, u8_ptr_type);
|
||||
ZigType *tag_int_type = enum_type->data.enumeration.tag_int_type;
|
||||
|
||||
@ -4953,7 +4965,7 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,
|
||||
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(g, type_struct_field->type_entry,
|
||||
false, false, PtrLenSingle, field_align_bytes,
|
||||
(uint32_t)type_struct_field->bit_offset_in_host, host_int_bytes);
|
||||
(uint32_t)type_struct_field->bit_offset_in_host, host_int_bytes, false);
|
||||
|
||||
gen_assign_raw(g, field_ptr, ptr_type, value);
|
||||
}
|
||||
@ -4969,7 +4981,7 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I
|
||||
uint32_t field_align_bytes = get_abi_alignment(g, type_union_field->type_entry);
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(g, type_union_field->type_entry,
|
||||
false, false, PtrLenSingle, field_align_bytes,
|
||||
0, 0);
|
||||
0, 0, false);
|
||||
|
||||
LLVMValueRef uncasted_union_ptr;
|
||||
// Even if safety is off in this block, if the union type has the safety field, we have to populate it
|
||||
@ -5224,7 +5236,7 @@ static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_f
|
||||
LLVMPositionBuilderAtEnd(g->builder, ok_block);
|
||||
LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, sret_ptr, err_union_payload_index, "");
|
||||
ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, false, false,
|
||||
PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
|
||||
PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false);
|
||||
ZigType *slice_type = get_slice_type(g, u8_ptr_type);
|
||||
size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
|
||||
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, payload_ptr, ptr_field_index, "");
|
||||
@ -6470,7 +6482,7 @@ static void generate_error_name_table(CodeGen *g) {
|
||||
assert(g->errors_by_index.length > 0);
|
||||
|
||||
ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
|
||||
PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
|
||||
PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false);
|
||||
ZigType *str_type = get_slice_type(g, u8_ptr_type);
|
||||
|
||||
LLVMValueRef *values = allocate<LLVMValueRef>(g->errors_by_index.length);
|
||||
@ -7551,6 +7563,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
|
||||
" is_volatile: bool,\n"
|
||||
" alignment: comptime_int,\n"
|
||||
" child: type,\n"
|
||||
" is_allowzero: bool,\n"
|
||||
"\n"
|
||||
" pub const Size = enum {\n"
|
||||
" One,\n"
|
||||
@ -8158,7 +8171,7 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
|
||||
}
|
||||
|
||||
ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
|
||||
PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
|
||||
PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false);
|
||||
ZigType *str_type = get_slice_type(g, u8_ptr_type);
|
||||
ZigType *fn_type = get_test_fn_type(g);
|
||||
|
||||
|
114
src/ir.cpp
114
src/ir.cpp
@ -1348,7 +1348,7 @@ static IrInstruction *ir_build_br(IrBuilder *irb, Scope *scope, AstNode *source_
|
||||
|
||||
static IrInstruction *ir_build_ptr_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction *child_type, bool is_const, bool is_volatile, PtrLen ptr_len,
|
||||
IrInstruction *align_value, uint32_t bit_offset_start, uint32_t host_int_bytes)
|
||||
IrInstruction *align_value, uint32_t bit_offset_start, uint32_t host_int_bytes, bool is_allow_zero)
|
||||
{
|
||||
IrInstructionPtrType *ptr_type_of_instruction = ir_build_instruction<IrInstructionPtrType>(irb, scope, source_node);
|
||||
ptr_type_of_instruction->align_value = align_value;
|
||||
@ -1358,6 +1358,7 @@ static IrInstruction *ir_build_ptr_type(IrBuilder *irb, Scope *scope, AstNode *s
|
||||
ptr_type_of_instruction->ptr_len = ptr_len;
|
||||
ptr_type_of_instruction->bit_offset_start = bit_offset_start;
|
||||
ptr_type_of_instruction->host_int_bytes = host_int_bytes;
|
||||
ptr_type_of_instruction->is_allow_zero = is_allow_zero;
|
||||
|
||||
if (align_value) ir_ref_instruction(align_value, irb->current_basic_block);
|
||||
ir_ref_instruction(child_type, irb->current_basic_block);
|
||||
@ -1627,13 +1628,14 @@ static IrInstruction *ir_build_promise_type(IrBuilder *irb, Scope *scope, AstNod
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value)
|
||||
IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value, bool is_allow_zero)
|
||||
{
|
||||
IrInstructionSliceType *instruction = ir_build_instruction<IrInstructionSliceType>(irb, scope, source_node);
|
||||
instruction->is_const = is_const;
|
||||
instruction->is_volatile = is_volatile;
|
||||
instruction->child_type = child_type;
|
||||
instruction->align_value = align_value;
|
||||
instruction->is_allow_zero = is_allow_zero;
|
||||
|
||||
ir_ref_instruction(child_type, irb->current_basic_block);
|
||||
if (align_value) ir_ref_instruction(align_value, irb->current_basic_block);
|
||||
@ -5192,6 +5194,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode
|
||||
PtrLen ptr_len = star_token_to_ptr_len(node->data.pointer_type.star_token->id);
|
||||
bool is_const = node->data.pointer_type.is_const;
|
||||
bool is_volatile = node->data.pointer_type.is_volatile;
|
||||
bool is_allow_zero = node->data.pointer_type.allow_zero_token != nullptr;
|
||||
AstNode *expr_node = node->data.pointer_type.op_expr;
|
||||
AstNode *align_expr = node->data.pointer_type.align_expr;
|
||||
|
||||
@ -5239,7 +5242,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode
|
||||
}
|
||||
|
||||
return ir_build_ptr_type(irb, scope, node, child_type, is_const, is_volatile,
|
||||
ptr_len, align_value, bit_offset_start, host_int_bytes);
|
||||
ptr_len, align_value, bit_offset_start, host_int_bytes, is_allow_zero);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_catch_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node,
|
||||
@ -5826,6 +5829,7 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
|
||||
AstNode *child_type_node = node->data.array_type.child_type;
|
||||
bool is_const = node->data.array_type.is_const;
|
||||
bool is_volatile = node->data.array_type.is_volatile;
|
||||
bool is_allow_zero = node->data.array_type.allow_zero_token != nullptr;
|
||||
AstNode *align_expr = node->data.array_type.align_expr;
|
||||
|
||||
Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope);
|
||||
@ -5838,6 +5842,10 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
|
||||
add_node_error(irb->codegen, node, buf_create_from_str("volatile qualifier invalid on array type"));
|
||||
return irb->codegen->invalid_instruction;
|
||||
}
|
||||
if (is_allow_zero) {
|
||||
add_node_error(irb->codegen, node, buf_create_from_str("allowzero qualifier invalid on array type"));
|
||||
return irb->codegen->invalid_instruction;
|
||||
}
|
||||
if (align_expr != nullptr) {
|
||||
add_node_error(irb->codegen, node, buf_create_from_str("align qualifier invalid on array type"));
|
||||
return irb->codegen->invalid_instruction;
|
||||
@ -5866,7 +5874,7 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
|
||||
if (child_type == irb->codegen->invalid_instruction)
|
||||
return child_type;
|
||||
|
||||
return ir_build_slice_type(irb, scope, node, child_type, is_const, is_volatile, align_value);
|
||||
return ir_build_slice_type(irb, scope, node, child_type, is_const, is_volatile, align_value, is_allow_zero);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7760,7 +7768,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
|
||||
if (type_has_bits(return_type)) {
|
||||
IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
|
||||
get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
|
||||
false, false, PtrLenUnknown, 0, 0, 0));
|
||||
false, false, PtrLenUnknown, 0, 0, 0, false));
|
||||
IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);
|
||||
IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len,
|
||||
result_ptr, false);
|
||||
@ -7814,7 +7822,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
|
||||
IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle);
|
||||
IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
|
||||
get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
|
||||
false, false, PtrLenUnknown, 0, 0, 0));
|
||||
false, false, PtrLenUnknown, 0, 0, 0, false));
|
||||
IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len,
|
||||
coro_mem_ptr_maybe, false);
|
||||
IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
|
||||
@ -9818,7 +9826,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(
|
||||
ira->codegen, prev_inst->value.type->data.array.child_type,
|
||||
true, false, PtrLenUnknown,
|
||||
0, 0, 0);
|
||||
0, 0, 0, false);
|
||||
ZigType *slice_type = get_slice_type(ira->codegen, ptr_type);
|
||||
if (err_set_type != nullptr) {
|
||||
return get_error_union_type(ira->codegen, err_set_type, slice_type);
|
||||
@ -10243,7 +10251,7 @@ static IrInstruction *ir_get_const_ptr(IrAnalyze *ira, IrInstruction *instructio
|
||||
ConstPtrMut ptr_mut, bool ptr_is_const, bool ptr_is_volatile, uint32_t ptr_align)
|
||||
{
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, pointee_type,
|
||||
ptr_is_const, ptr_is_volatile, PtrLenSingle, ptr_align, 0, 0);
|
||||
ptr_is_const, ptr_is_volatile, PtrLenSingle, ptr_align, 0, 0, false);
|
||||
IrInstruction *const_instr = ir_const(ira, instruction, ptr_type);
|
||||
ConstExprValue *const_val = &const_instr->value;
|
||||
const_val->data.x_ptr.special = ConstPtrSpecialRef;
|
||||
@ -10576,7 +10584,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
|
||||
}
|
||||
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type,
|
||||
is_const, is_volatile, PtrLenSingle, 0, 0, 0);
|
||||
is_const, is_volatile, PtrLenSingle, 0, 0, 0, false);
|
||||
IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instruction->scope,
|
||||
source_instruction->source_node, value, is_const, is_volatile);
|
||||
new_instruction->value.type = ptr_type;
|
||||
@ -11983,7 +11991,7 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {
|
||||
return nullptr;
|
||||
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
true, false, PtrLenUnknown, 0, 0, 0);
|
||||
true, false, PtrLenUnknown, 0, 0, 0, false);
|
||||
ZigType *str_type = get_slice_type(ira->codegen, ptr_type);
|
||||
IrInstruction *casted_value = ir_implicit_cast(ira, value, str_type);
|
||||
if (type_is_invalid(casted_value->value.type))
|
||||
@ -13154,7 +13162,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
|
||||
out_array_val = out_val;
|
||||
} else if (is_slice(op1_type) || is_slice(op2_type)) {
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, child_type,
|
||||
true, false, PtrLenUnknown, 0, 0, 0);
|
||||
true, false, PtrLenUnknown, 0, 0, 0, false);
|
||||
result->value.type = get_slice_type(ira->codegen, ptr_type);
|
||||
out_array_val = create_const_vals(1);
|
||||
out_array_val->special = ConstValSpecialStatic;
|
||||
@ -13175,7 +13183,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
|
||||
new_len += 1; // null byte
|
||||
|
||||
// TODO make this `[*]null T` instead of `[*]T`
|
||||
result->value.type = get_pointer_to_type_extra(ira->codegen, child_type, true, false, PtrLenUnknown, 0, 0, 0);
|
||||
result->value.type = get_pointer_to_type_extra(ira->codegen, child_type, true, false, PtrLenUnknown, 0, 0, 0, false);
|
||||
|
||||
out_array_val = create_const_vals(1);
|
||||
out_array_val->special = ConstValSpecialStatic;
|
||||
@ -14033,7 +14041,7 @@ no_mem_slot:
|
||||
IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb,
|
||||
instruction->scope, instruction->source_node, var);
|
||||
var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->var_type,
|
||||
var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0);
|
||||
var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0, false);
|
||||
|
||||
bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr);
|
||||
var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack;
|
||||
@ -14328,7 +14336,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call
|
||||
IrInstruction *casted_new_stack = nullptr;
|
||||
if (call_instruction->new_stack != nullptr) {
|
||||
ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
false, false, PtrLenUnknown, 0, 0, 0);
|
||||
false, false, PtrLenUnknown, 0, 0, 0, false);
|
||||
ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr);
|
||||
IrInstruction *new_stack = call_instruction->new_stack->child;
|
||||
if (type_is_invalid(new_stack->value.type))
|
||||
@ -15262,7 +15270,8 @@ static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_ali
|
||||
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
|
||||
ptr_type->data.pointer.ptr_len,
|
||||
new_align,
|
||||
ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes);
|
||||
ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes,
|
||||
ptr_type->data.pointer.allow_zero);
|
||||
}
|
||||
|
||||
static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align) {
|
||||
@ -15279,7 +15288,8 @@ static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) {
|
||||
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
|
||||
ptr_len,
|
||||
ptr_type->data.pointer.explicit_alignment,
|
||||
ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes);
|
||||
ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes,
|
||||
ptr_type->data.pointer.allow_zero);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionElemPtr *elem_ptr_instruction) {
|
||||
@ -15330,7 +15340,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
|
||||
return_type = get_pointer_to_type_extra(ira->codegen, child_type,
|
||||
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
|
||||
elem_ptr_instruction->ptr_len,
|
||||
ptr_type->data.pointer.explicit_alignment, 0, 0);
|
||||
ptr_type->data.pointer.explicit_alignment, 0, 0, false);
|
||||
} else {
|
||||
uint64_t elem_val_scalar;
|
||||
if (!ir_resolve_usize(ira, elem_index, &elem_val_scalar))
|
||||
@ -15342,7 +15352,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
|
||||
return_type = get_pointer_to_type_extra(ira->codegen, child_type,
|
||||
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
|
||||
elem_ptr_instruction->ptr_len,
|
||||
1, (uint32_t)bit_offset, ptr_type->data.pointer.host_int_bytes);
|
||||
1, (uint32_t)bit_offset, ptr_type->data.pointer.host_int_bytes, false);
|
||||
}
|
||||
} else if (array_type->id == ZigTypeIdPointer) {
|
||||
if (array_type->data.pointer.ptr_len == PtrLenSingle) {
|
||||
@ -15693,7 +15703,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry,
|
||||
is_const, is_volatile, PtrLenSingle, align_bytes,
|
||||
(uint32_t)(ptr_bit_offset + field->bit_offset_in_host),
|
||||
(uint32_t)host_int_bytes_for_result_type);
|
||||
(uint32_t)host_int_bytes_for_result_type, false);
|
||||
IrInstruction *result = ir_const(ira, source_instr, ptr_type);
|
||||
ConstExprValue *const_val = &result->value;
|
||||
const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct;
|
||||
@ -15709,7 +15719,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
|
||||
PtrLenSingle,
|
||||
align_bytes,
|
||||
(uint32_t)(ptr_bit_offset + field->bit_offset_in_host),
|
||||
host_int_bytes_for_result_type);
|
||||
host_int_bytes_for_result_type, false);
|
||||
return result;
|
||||
} else {
|
||||
return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
|
||||
@ -15748,7 +15758,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
|
||||
|
||||
ZigType *field_type = field->type_entry;
|
||||
ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type,
|
||||
is_const, is_volatile, PtrLenSingle, 0, 0, 0);
|
||||
is_const, is_volatile, PtrLenSingle, 0, 0, 0, false);
|
||||
|
||||
IrInstruction *result = ir_const(ira, source_instr, ptr_type);
|
||||
ConstExprValue *const_val = &result->value;
|
||||
@ -15761,7 +15771,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
|
||||
|
||||
IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, container_ptr, field);
|
||||
result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
|
||||
PtrLenSingle, 0, 0, 0);
|
||||
PtrLenSingle, 0, 0, 0, false);
|
||||
return result;
|
||||
} else {
|
||||
return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
|
||||
@ -16480,6 +16490,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
|
||||
|
||||
bool is_const = slice_type_instruction->is_const;
|
||||
bool is_volatile = slice_type_instruction->is_volatile;
|
||||
bool is_allow_zero = slice_type_instruction->is_allow_zero;
|
||||
|
||||
switch (child_type->id) {
|
||||
case ZigTypeIdInvalid: // handled above
|
||||
@ -16516,7 +16527,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
|
||||
if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown)))
|
||||
return ira->codegen->invalid_instruction;
|
||||
ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type,
|
||||
is_const, is_volatile, PtrLenUnknown, align_bytes, 0, 0);
|
||||
is_const, is_volatile, PtrLenUnknown, align_bytes, 0, 0, is_allow_zero);
|
||||
ZigType *result_type = get_slice_type(ira->codegen, slice_ptr_type);
|
||||
return ir_const_type(ira, &slice_type_instruction->base, result_type);
|
||||
}
|
||||
@ -16749,7 +16760,7 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr
|
||||
|
||||
ZigType *child_type = type_entry->data.maybe.child_type;
|
||||
ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
|
||||
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
|
||||
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0, false);
|
||||
|
||||
if (instr_is_comptime(base_ptr)) {
|
||||
ConstExprValue *val = ir_resolve_const(ira, base_ptr, UndefBad);
|
||||
@ -17668,7 +17679,7 @@ static IrInstruction *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruct
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
ZigType *u8_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
true, false, PtrLenUnknown, 0, 0, 0);
|
||||
true, false, PtrLenUnknown, 0, 0, 0, false);
|
||||
ZigType *str_type = get_slice_type(ira->codegen, u8_ptr_type);
|
||||
if (casted_value->value.special == ConstValSpecialStatic) {
|
||||
ErrorTableEntry *err = casted_value->value.data.x_err_set;
|
||||
@ -17713,7 +17724,7 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns
|
||||
ZigType *u8_ptr_type = get_pointer_to_type_extra(
|
||||
ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
true, false, PtrLenUnknown,
|
||||
0, 0, 0);
|
||||
0, 0, 0, false);
|
||||
result->value.type = get_slice_type(ira->codegen, u8_ptr_type);
|
||||
return result;
|
||||
}
|
||||
@ -17767,7 +17778,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira,
|
||||
field_ptr->value.type->data.pointer.is_const,
|
||||
field_ptr->value.type->data.pointer.is_volatile,
|
||||
PtrLenSingle,
|
||||
field_ptr_align, 0, 0);
|
||||
field_ptr_align, 0, 0, false);
|
||||
IrInstruction *casted_field_ptr = ir_implicit_cast(ira, field_ptr, field_ptr_type);
|
||||
if (type_is_invalid(casted_field_ptr->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
@ -17776,7 +17787,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira,
|
||||
casted_field_ptr->value.type->data.pointer.is_const,
|
||||
casted_field_ptr->value.type->data.pointer.is_volatile,
|
||||
PtrLenSingle,
|
||||
parent_ptr_align, 0, 0);
|
||||
parent_ptr_align, 0, 0, false);
|
||||
|
||||
if (instr_is_comptime(casted_field_ptr)) {
|
||||
ConstExprValue *field_ptr_val = ir_resolve_const(ira, casted_field_ptr, UndefBad);
|
||||
@ -18112,7 +18123,7 @@ static Error ir_make_type_info_defs(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
ZigType *u8_ptr = get_pointer_to_type_extra(
|
||||
ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
true, false, PtrLenUnknown,
|
||||
0, 0, 0);
|
||||
0, 0, 0, false);
|
||||
fn_def_fields[6].type = get_optional_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr));
|
||||
if (fn_node->is_extern && buf_len(fn_node->lib_name) > 0) {
|
||||
fn_def_fields[6].data.x_optional = create_const_vals(1);
|
||||
@ -18216,7 +18227,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty
|
||||
result->special = ConstValSpecialStatic;
|
||||
result->type = type_info_pointer_type;
|
||||
|
||||
ConstExprValue *fields = create_const_vals(5);
|
||||
ConstExprValue *fields = create_const_vals(6);
|
||||
result->data.x_struct.fields = fields;
|
||||
|
||||
// size: Size
|
||||
@ -18247,6 +18258,11 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty
|
||||
fields[4].special = ConstValSpecialStatic;
|
||||
fields[4].type = ira->codegen->builtin_types.entry_type;
|
||||
fields[4].data.x_type = attrs_type->data.pointer.child_type;
|
||||
// is_allowzero: bool
|
||||
ensure_field_index(result->type, "is_allowzero", 5);
|
||||
fields[5].special = ConstValSpecialStatic;
|
||||
fields[5].type = ira->codegen->builtin_types.entry_bool;
|
||||
fields[5].data.x_bool = attrs_type->data.pointer.allow_zero;
|
||||
|
||||
return result;
|
||||
};
|
||||
@ -19473,12 +19489,12 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru
|
||||
|
||||
ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_child_type,
|
||||
src_ptr_const, src_ptr_volatile, PtrLenUnknown,
|
||||
src_ptr_align, 0, 0);
|
||||
src_ptr_align, 0, 0, false);
|
||||
ZigType *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type);
|
||||
|
||||
ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
src_ptr_const, src_ptr_volatile, PtrLenUnknown,
|
||||
src_ptr_align, 0, 0);
|
||||
src_ptr_align, 0, 0, false);
|
||||
ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr);
|
||||
|
||||
IrInstruction *casted_value = ir_implicit_cast(ira, target, u8_slice);
|
||||
@ -19545,7 +19561,7 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct
|
||||
|
||||
ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
src_ptr_type->data.pointer.is_const, src_ptr_type->data.pointer.is_volatile, PtrLenUnknown,
|
||||
alignment, 0, 0);
|
||||
alignment, 0, 0, false);
|
||||
ZigType *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type);
|
||||
|
||||
if (instr_is_comptime(target)) {
|
||||
@ -19773,7 +19789,7 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio
|
||||
dest_align = get_abi_alignment(ira->codegen, u8);
|
||||
}
|
||||
ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile,
|
||||
PtrLenUnknown, dest_align, 0, 0);
|
||||
PtrLenUnknown, dest_align, 0, 0, false);
|
||||
|
||||
IrInstruction *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr);
|
||||
if (type_is_invalid(casted_dest_ptr->value.type))
|
||||
@ -19895,9 +19911,9 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio
|
||||
|
||||
ZigType *usize = ira->codegen->builtin_types.entry_usize;
|
||||
ZigType *u8_ptr_mut = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile,
|
||||
PtrLenUnknown, dest_align, 0, 0);
|
||||
PtrLenUnknown, dest_align, 0, 0, false);
|
||||
ZigType *u8_ptr_const = get_pointer_to_type_extra(ira->codegen, u8, true, src_is_volatile,
|
||||
PtrLenUnknown, src_align, 0, 0);
|
||||
PtrLenUnknown, src_align, 0, 0, false);
|
||||
|
||||
IrInstruction *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr_mut);
|
||||
if (type_is_invalid(casted_dest_ptr->value.type))
|
||||
@ -20061,7 +20077,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
|
||||
ptr_ptr_type->data.pointer.is_const || is_comptime_const,
|
||||
ptr_ptr_type->data.pointer.is_volatile,
|
||||
PtrLenUnknown,
|
||||
ptr_ptr_type->data.pointer.explicit_alignment, 0, 0);
|
||||
ptr_ptr_type->data.pointer.explicit_alignment, 0, 0, false);
|
||||
return_type = get_slice_type(ira->codegen, slice_ptr_type);
|
||||
} else if (array_type->id == ZigTypeIdPointer) {
|
||||
if (array_type->data.pointer.ptr_len == PtrLenSingle) {
|
||||
@ -20071,7 +20087,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
|
||||
main_type->data.pointer.child_type,
|
||||
array_type->data.pointer.is_const, array_type->data.pointer.is_volatile,
|
||||
PtrLenUnknown,
|
||||
array_type->data.pointer.explicit_alignment, 0, 0);
|
||||
array_type->data.pointer.explicit_alignment, 0, 0, false);
|
||||
return_type = get_slice_type(ira->codegen, slice_ptr_type);
|
||||
} else {
|
||||
ir_add_error(ira, &instruction->base, buf_sprintf("slice of single-item pointer"));
|
||||
@ -20586,7 +20602,7 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr
|
||||
expected_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_type,
|
||||
false, result_ptr->value.type->data.pointer.is_volatile,
|
||||
PtrLenSingle,
|
||||
alignment, 0, 0);
|
||||
alignment, 0, 0, false);
|
||||
} else {
|
||||
expected_ptr_type = get_pointer_to_type(ira->codegen, dest_type, false);
|
||||
}
|
||||
@ -20753,7 +20769,7 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
|
||||
|
||||
ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type,
|
||||
ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
|
||||
PtrLenSingle, 0, 0, 0);
|
||||
PtrLenSingle, 0, 0, 0, false);
|
||||
if (instr_is_comptime(value)) {
|
||||
ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
|
||||
if (!ptr_val)
|
||||
@ -21125,7 +21141,7 @@ static IrInstruction *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstruction
|
||||
}
|
||||
|
||||
ZigType *u8_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
true, false, PtrLenUnknown, 0, 0, 0);
|
||||
true, false, PtrLenUnknown, 0, 0, 0, false);
|
||||
ZigType *str_type = get_slice_type(ira->codegen, u8_ptr_type);
|
||||
IrInstruction *casted_msg = ir_implicit_cast(ira, msg, str_type);
|
||||
if (type_is_invalid(casted_msg->value.type))
|
||||
@ -21794,10 +21810,17 @@ static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *sourc
|
||||
if (!val)
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
uint64_t addr = bigint_as_unsigned(&val->data.x_bigint);
|
||||
if (!ptr_allows_addr_zero(ptr_type) && addr == 0) {
|
||||
ir_add_error(ira, source_instr,
|
||||
buf_sprintf("pointer type '%s' does not allow address zero", buf_ptr(&ptr_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
IrInstruction *result = ir_const(ira, source_instr, ptr_type);
|
||||
result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
|
||||
result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar;
|
||||
result->value.data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&val->data.x_bigint);
|
||||
result->value.data.x_ptr.data.hard_coded_addr.addr = addr;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -21951,6 +21974,9 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct
|
||||
} else if (child_type->id == ZigTypeIdOpaque) {
|
||||
ir_add_error(ira, &instruction->base, buf_sprintf("C pointers cannot point opaque types"));
|
||||
return ira->codegen->invalid_instruction;
|
||||
} else if (instruction->is_allow_zero) {
|
||||
ir_add_error(ira, &instruction->base, buf_sprintf("C pointers always allow address zero"));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
}
|
||||
|
||||
@ -21969,10 +21995,12 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct
|
||||
align_bytes = 0;
|
||||
}
|
||||
|
||||
bool allow_zero = instruction->is_allow_zero || instruction->ptr_len == PtrLenC;
|
||||
|
||||
ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
|
||||
instruction->is_const, instruction->is_volatile,
|
||||
instruction->ptr_len, align_bytes,
|
||||
instruction->bit_offset_start, instruction->host_int_bytes);
|
||||
instruction->bit_offset_start, instruction->host_int_bytes, allow_zero);
|
||||
return ir_const_type(ira, &instruction->base, result_type);
|
||||
}
|
||||
|
||||
|
@ -2530,6 +2530,12 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {
|
||||
if (array != nullptr) {
|
||||
assert(array->type == NodeTypeArrayType);
|
||||
while (true) {
|
||||
Token *allowzero_token = eat_token_if(pc, TokenIdKeywordAllowZero);
|
||||
if (allowzero_token != nullptr) {
|
||||
array->data.array_type.allow_zero_token = allowzero_token;
|
||||
continue;
|
||||
}
|
||||
|
||||
AstNode *align_expr = ast_parse_byte_align(pc);
|
||||
if (align_expr != nullptr) {
|
||||
array->data.array_type.align_expr = align_expr;
|
||||
@ -2545,7 +2551,6 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {
|
||||
array->data.array_type.is_volatile = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2560,6 +2565,12 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {
|
||||
if (child == nullptr)
|
||||
child = ptr;
|
||||
while (true) {
|
||||
Token *allowzero_token = eat_token_if(pc, TokenIdKeywordAllowZero);
|
||||
if (allowzero_token != nullptr) {
|
||||
child->data.pointer_type.allow_zero_token = allowzero_token;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (eat_token_if(pc, TokenIdKeywordAlign) != nullptr) {
|
||||
expect_token(pc, TokenIdLParen);
|
||||
AstNode *align_expr = ast_parse_expr(pc);
|
||||
|
@ -107,6 +107,7 @@ struct ZigKeyword {
|
||||
|
||||
static const struct ZigKeyword zig_keywords[] = {
|
||||
{"align", TokenIdKeywordAlign},
|
||||
{"allowzero", TokenIdKeywordAllowZero},
|
||||
{"and", TokenIdKeywordAnd},
|
||||
{"anyerror", TokenIdKeywordAnyerror},
|
||||
{"asm", TokenIdKeywordAsm},
|
||||
@ -1495,6 +1496,7 @@ const char * token_name(TokenId id) {
|
||||
case TokenIdIntLiteral: return "IntLiteral";
|
||||
case TokenIdKeywordAsync: return "async";
|
||||
case TokenIdKeywordAnyerror: return "anyerror";
|
||||
case TokenIdKeywordAllowZero: return "allowzero";
|
||||
case TokenIdKeywordAwait: return "await";
|
||||
case TokenIdKeywordResume: return "resume";
|
||||
case TokenIdKeywordSuspend: return "suspend";
|
||||
|
@ -50,6 +50,7 @@ enum TokenId {
|
||||
TokenIdFloatLiteral,
|
||||
TokenIdIntLiteral,
|
||||
TokenIdKeywordAlign,
|
||||
TokenIdKeywordAllowZero,
|
||||
TokenIdKeywordAnd,
|
||||
TokenIdKeywordAnyerror,
|
||||
TokenIdKeywordAsm,
|
||||
@ -73,6 +74,7 @@ enum TokenId {
|
||||
TokenIdKeywordFor,
|
||||
TokenIdKeywordIf,
|
||||
TokenIdKeywordInline,
|
||||
TokenIdKeywordLinkSection,
|
||||
TokenIdKeywordNakedCC,
|
||||
TokenIdKeywordNoAlias,
|
||||
TokenIdKeywordNull,
|
||||
@ -83,7 +85,6 @@ enum TokenId {
|
||||
TokenIdKeywordPub,
|
||||
TokenIdKeywordResume,
|
||||
TokenIdKeywordReturn,
|
||||
TokenIdKeywordLinkSection,
|
||||
TokenIdKeywordStdcallCC,
|
||||
TokenIdKeywordStruct,
|
||||
TokenIdKeywordSuspend,
|
||||
|
@ -125,6 +125,7 @@ pub const Error = union(enum) {
|
||||
ExtraAlignQualifier: ExtraAlignQualifier,
|
||||
ExtraConstQualifier: ExtraConstQualifier,
|
||||
ExtraVolatileQualifier: ExtraVolatileQualifier,
|
||||
ExtraAllowZeroQualifier: ExtraAllowZeroQualifier,
|
||||
ExpectedPrimaryExpr: ExpectedPrimaryExpr,
|
||||
ExpectedToken: ExpectedToken,
|
||||
ExpectedCommaOrEnd: ExpectedCommaOrEnd,
|
||||
@ -149,6 +150,7 @@ pub const Error = union(enum) {
|
||||
@TagType(Error).ExtraAlignQualifier => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExtraConstQualifier => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExtraVolatileQualifier => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExtraAllowZeroQualifier => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedPrimaryExpr => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedToken => |*x| return x.render(tokens, stream),
|
||||
@TagType(Error).ExpectedCommaOrEnd => |*x| return x.render(tokens, stream),
|
||||
@ -175,6 +177,7 @@ pub const Error = union(enum) {
|
||||
@TagType(Error).ExtraAlignQualifier => |x| return x.token,
|
||||
@TagType(Error).ExtraConstQualifier => |x| return x.token,
|
||||
@TagType(Error).ExtraVolatileQualifier => |x| return x.token,
|
||||
@TagType(Error).ExtraAllowZeroQualifier => |x| return x.token,
|
||||
@TagType(Error).ExpectedPrimaryExpr => |x| return x.token,
|
||||
@TagType(Error).ExpectedToken => |x| return x.token,
|
||||
@TagType(Error).ExpectedCommaOrEnd => |x| return x.token,
|
||||
@ -198,6 +201,7 @@ pub const Error = union(enum) {
|
||||
pub const ExtraAlignQualifier = SimpleError("Extra align qualifier");
|
||||
pub const ExtraConstQualifier = SimpleError("Extra const qualifier");
|
||||
pub const ExtraVolatileQualifier = SimpleError("Extra volatile qualifier");
|
||||
pub const ExtraAllowZeroQualifier = SimpleError("Extra allowzero qualifier");
|
||||
|
||||
pub const ExpectedCall = struct {
|
||||
node: *Node,
|
||||
@ -1540,6 +1544,7 @@ pub const Node = struct {
|
||||
};
|
||||
|
||||
pub const PtrInfo = struct {
|
||||
allowzero_token: ?TokenIndex,
|
||||
align_info: ?Align,
|
||||
const_token: ?TokenIndex,
|
||||
volatile_token: ?TokenIndex,
|
||||
|
@ -1688,6 +1688,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
||||
.align_info = null,
|
||||
.const_token = null,
|
||||
.volatile_token = null,
|
||||
.allowzero_token = null,
|
||||
},
|
||||
};
|
||||
stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &node.rhs } }) catch unreachable;
|
||||
@ -1743,6 +1744,15 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
|
||||
addr_of_info.volatile_token = token_index;
|
||||
continue;
|
||||
},
|
||||
Token.Id.Keyword_allowzero => {
|
||||
stack.append(state) catch unreachable;
|
||||
if (addr_of_info.allowzero_token != null) {
|
||||
((try tree.errors.addOne())).* = Error{ .ExtraAllowZeroQualifier = Error.ExtraAllowZeroQualifier{ .token = token_index } };
|
||||
return tree;
|
||||
}
|
||||
addr_of_info.allowzero_token = token_index;
|
||||
continue;
|
||||
},
|
||||
else => {
|
||||
prevToken(&tok_it, &tree);
|
||||
continue;
|
||||
@ -3552,6 +3562,7 @@ fn tokenIdToPrefixOp(id: Token.Id) ?ast.Node.PrefixOp.Op {
|
||||
.align_info = null,
|
||||
.const_token = null,
|
||||
.volatile_token = null,
|
||||
.allowzero_token = null,
|
||||
},
|
||||
},
|
||||
Token.Id.QuestionMark => ast.Node.PrefixOp.Op{ .OptionalType = void{} },
|
||||
|
@ -1,3 +1,10 @@
|
||||
test "zig fmt: allowzero pointer" {
|
||||
try testCanonical(
|
||||
\\const T = [*]allowzero const u8;
|
||||
\\
|
||||
);
|
||||
}
|
||||
|
||||
test "zig fmt: enum literal" {
|
||||
try testCanonical(
|
||||
\\const x = .hi;
|
||||
|
@ -379,6 +379,9 @@ fn renderExpression(
|
||||
else => usize(0),
|
||||
};
|
||||
try renderTokenOffset(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None, star_offset); // *
|
||||
if (ptr_info.allowzero_token) |allowzero_token| {
|
||||
try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero
|
||||
}
|
||||
if (ptr_info.align_info) |align_info| {
|
||||
const lparen_token = tree.prevToken(align_info.node.firstToken());
|
||||
const align_token = tree.prevToken(lparen_token);
|
||||
@ -416,6 +419,9 @@ fn renderExpression(
|
||||
try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None); // [
|
||||
try renderToken(tree, stream, tree.nextToken(prefix_op_node.op_token), indent, start_col, Space.None); // ]
|
||||
|
||||
if (ptr_info.allowzero_token) |allowzero_token| {
|
||||
try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero
|
||||
}
|
||||
if (ptr_info.align_info) |align_info| {
|
||||
const lparen_token = tree.prevToken(align_info.node.firstToken());
|
||||
const align_token = tree.prevToken(lparen_token);
|
||||
|
@ -13,6 +13,7 @@ pub const Token = struct {
|
||||
|
||||
pub const keywords = []Keyword{
|
||||
Keyword{ .bytes = "align", .id = Id.Keyword_align },
|
||||
Keyword{ .bytes = "allowzero", .id = Id.Keyword_allowzero },
|
||||
Keyword{ .bytes = "and", .id = Id.Keyword_and },
|
||||
Keyword{ .bytes = "anyerror", .id = Id.Keyword_anyerror },
|
||||
Keyword{ .bytes = "asm", .id = Id.Keyword_asm },
|
||||
@ -143,6 +144,7 @@ pub const Token = struct {
|
||||
BracketStarCBracket,
|
||||
ShebangLine,
|
||||
Keyword_align,
|
||||
Keyword_allowzero,
|
||||
Keyword_and,
|
||||
Keyword_anyerror,
|
||||
Keyword_asm,
|
||||
|
@ -2,6 +2,15 @@ const tests = @import("tests.zig");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
cases.add(
|
||||
"@ptrToInt 0 to non optional pointer",
|
||||
\\export fn entry() void {
|
||||
\\ var b = @intToPtr(*i32, 0);
|
||||
\\}
|
||||
,
|
||||
"tmp.zig:2:13: error: pointer type '*i32' does not allow address zero",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
"cast enum literal to enum but it doesn't match",
|
||||
\\const Foo = enum {
|
||||
|
@ -1,6 +1,16 @@
|
||||
const tests = @import("tests.zig");
|
||||
|
||||
pub fn addCases(cases: *tests.CompareOutputContext) void {
|
||||
cases.addRuntimeSafety("@ptrToInt address zero 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 zero: usize = 0;
|
||||
\\ var b = @intToPtr(*i32, zero);
|
||||
\\}
|
||||
);
|
||||
|
||||
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);
|
||||
|
@ -137,3 +137,16 @@ test "compare equality of optional and non-optional pointer" {
|
||||
expect(a == b);
|
||||
expect(b == a);
|
||||
}
|
||||
|
||||
test "allowzero pointer and slice" {
|
||||
var ptr = @intToPtr([*]allowzero i32, 0);
|
||||
var opt_ptr: ?[*]allowzero i32 = ptr;
|
||||
expect(opt_ptr != null);
|
||||
expect(@ptrToInt(ptr) == 0);
|
||||
var slice = ptr[0..10];
|
||||
expect(@typeOf(slice) == []allowzero i32);
|
||||
expect(@ptrToInt(&slice[5]) == 20);
|
||||
|
||||
expect(@typeInfo(@typeOf(ptr)).Pointer.is_allowzero);
|
||||
expect(@typeInfo(@typeOf(slice)).Pointer.is_allowzero);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user