authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-03-25 12:55:45-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-03-25 12:55:45-04:00
log5eaead6a56ed95c200e249737c4ecf3c7cacf794
tree70fe5c0238d6f1d72fc8504a4aaec710f059db37
parent3306e43984a8b17472ecc4b13a2f2815d6630eef
signaturelock-open Commit is signed but in an unrecognized format.

implement allowzero pointer attribute

closes #1953 only needed for freestanding targets. also adds safety for `@intToPtr` when the address is zero.

18 files changed, 225 insertions(+), 78 deletions(-)

doc/docgen.zig+1
......@@ -779,6 +779,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
779779 std.zig.Token.Id.Keyword_use,
780780 std.zig.Token.Id.Keyword_var,
781781 std.zig.Token.Id.Keyword_volatile,
782 std.zig.Token.Id.Keyword_allowzero,
782783 std.zig.Token.Id.Keyword_while,
783784 => {
784785 try out.write("<span class=\"tok-kw\">");
doc/langref.html.in+36-8
......@@ -1721,7 +1721,7 @@ test "comptime @intToPtr" {
17211721 }
17221722}
17231723 {#code_end#}
1724 {#see_also|Optional Pointers|@intToPtr|@ptrToInt#}
1724 {#see_also|Optional Pointers|@intToPtr|@ptrToInt|C Pointers|Pointers to Zero Bit Types#}
17251725 {#header_open|volatile#}
17261726 <p>Loads and stores are assumed to not have side effects. If a given load or store
17271727 should have side effects, such as Memory Mapped Input/Output (MMIO), use {#syntax#}volatile{#endsyntax#}.
......@@ -1850,7 +1850,25 @@ fn foo(bytes: []u8) u32 {
18501850}
18511851 {#code_end#}
18521852 {#header_close#}
1853 {#see_also|C Pointers|Pointers to Zero Bit Types#}
1853
1854 {#header_open|allowzero#}
1855 <p>
1856 This pointer attribute allows a pointer to have address zero. This is only ever needed on the
1857 freestanding OS target, where the address zero is mappable. In this code example, if the pointer
1858 did not have the {#syntax#}allowzero{#endsyntax#} attribute, this would be a
1859 {#link|Pointer Cast Invalid Null#} panic:
1860 </p>
1861 {#code_begin|test|allowzero#}
1862const std = @import("std");
1863const assert = std.debug.assert;
1864
1865test "allowzero" {
1866 var zero: usize = 0;
1867 var ptr = @intToPtr(*allowzero i32, zero);
1868 assert(@ptrToInt(ptr) == 0);
1869}
1870 {#code_end#}
1871 {#header_close#}
18541872 {#header_close#}
18551873
18561874 {#header_open|Slices#}
......@@ -6635,9 +6653,13 @@ fn add(a: i32, b: i32) i32 { return a + b; }
66356653 {#header_close#}
66366654
66376655 {#header_open|@intToPtr#}
6638 <pre>{#syntax#}@intToPtr(comptime DestType: type, int: usize) DestType{#endsyntax#}</pre>
6656 <pre>{#syntax#}@intToPtr(comptime DestType: type, address: usize) DestType{#endsyntax#}</pre>
6657 <p>
6658 Converts an integer to a {#link|pointer|Pointers#}. To convert the other way, use {#link|@ptrToInt#}.
6659 </p>
66396660 <p>
6640 Converts an integer to a pointer. To convert the other way, use {#link|@ptrToInt#}.
6661 If the destination pointer type does not allow address zero and {#syntax#}address{#endsyntax#}
6662 is zero, this invokes safety-checked {#link|Undefined Behavior#}.
66416663 </p>
66426664 {#header_close#}
66436665
......@@ -8128,6 +8150,11 @@ fn bar(f: *Foo) void {
81288150 {#header_close#}
81298151
81308152 {#header_open|Pointer Cast Invalid Null#}
8153 <p>
8154 This happens when casting a pointer with the address 0 to a pointer which may not have the address 0.
8155 For example, {#link|C Pointers#}, {#link|Optional Pointers#}, and {#link|allowzero#} pointers
8156 allow address zero, but normal {#link|Pointers#} do not.
8157 </p>
81318158 <p>At compile-time:</p>
81328159 {#code_begin|test_err|null pointer casted to type#}
81338160comptime {
......@@ -8988,7 +9015,7 @@ Available libcs:
89889015 <ul>
89899016 <li>Linux x86_64</li>
89909017 <li>Windows x86_64</li>
8991 <li>MacOS x86_64</li>
9018 <li>macOS x86_64</li>
89929019 </ul>
89939020 {#header_close#}
89949021 {#header_open|Style Guide#}
......@@ -9412,8 +9439,8 @@ PrefixOp
94129439PrefixTypeOp
94139440 &lt;- QUESTIONMARK
94149441 / KEYWORD_promise MINUSRARROW
9415 / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile)*
9416 / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile)*
9442 / ArrayTypeStart (ByteAlign / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
9443 / PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN / KEYWORD_const / KEYWORD_volatile / KEYWORD_allowzero)*
94179444
94189445SuffixOp
94199446 &lt;- LBRACKET Expr (DOT2 Expr?)? RBRACKET
......@@ -9564,6 +9591,7 @@ TILDE &lt;- '~' skip
95649591
95659592end_of_word &lt;- ![a-zA-Z0-9_] skip
95669593KEYWORD_align &lt;- 'align' end_of_word
9594KEYWORD_allowzero &lt;- 'allowzero' end_of_word
95679595KEYWORD_and &lt;- 'and' end_of_word
95689596KEYWORD_anyerror &lt;- 'anyerror' end_of_word
95699597KEYWORD_asm &lt;- 'asm' end_of_word
......@@ -9614,7 +9642,7 @@ KEYWORD_var &lt;- 'var' end_of_word
96149642KEYWORD_volatile &lt;- 'volatile' end_of_word
96159643KEYWORD_while &lt;- 'while' end_of_word
96169644
9617keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_anyerror / KEYWORD_asm
9645keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_allowzero / KEYWORD_anyerror / KEYWORD_asm
96189646 / KEYWORD_async / KEYWORD_await / KEYWORD_break / KEYWORD_cancel
96199647 / KEYWORD_catch / KEYWORD_comptime / KEYWORD_const / KEYWORD_continue
96209648 / KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer
src/all_types.hpp+2-2
......@@ -2668,7 +2668,7 @@ struct IrInstructionPtrType {
26682668 PtrLen ptr_len;
26692669 bool is_const;
26702670 bool is_volatile;
2671 bool allow_zero;
2671 bool is_allow_zero;
26722672};
26732673
26742674struct IrInstructionPromiseType {
......@@ -2684,7 +2684,7 @@ struct IrInstructionSliceType {
26842684 IrInstruction *child_type;
26852685 bool is_const;
26862686 bool is_volatile;
2687 bool allow_zero;
2687 bool is_allow_zero;
26882688};
26892689
26902690struct IrInstructionGlobalAsm {
src/analyze.cpp+11-13
......@@ -418,11 +418,9 @@ static const char *ptr_len_to_star_str(PtrLen ptr_len) {
418418
419419ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
420420 bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment,
421 uint32_t bit_offset_in_host, uint32_t host_int_bytes)
421 uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero)
422422{
423 // TODO when implementing https://github.com/ziglang/zig/issues/1953
424 // move this to a parameter
425 bool allow_zero = (ptr_len == PtrLenC);
423 assert(ptr_len != PtrLenC || allow_zero);
426424 assert(!type_is_invalid(child_type));
427425 assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque);
428426
......@@ -505,7 +503,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
505503 bit_offset_in_host != 0 || allow_zero)
506504 {
507505 ZigType *peer_type = get_pointer_to_type_extra(g, child_type, false, false,
508 PtrLenSingle, 0, 0, host_int_bytes);
506 PtrLenSingle, 0, 0, host_int_bytes, false);
509507 entry->type_ref = peer_type->type_ref;
510508 entry->di_type = peer_type->di_type;
511509 } else {
......@@ -548,7 +546,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons
548546}
549547
550548ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const) {
551 return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0);
549 return get_pointer_to_type_extra(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0, false);
552550}
553551
554552ZigType *get_promise_frame_type(CodeGen *g, ZigType *return_type) {
......@@ -857,7 +855,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
857855 ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.allow_zero)
858856 {
859857 ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false,
860 PtrLenUnknown, 0, 0, 0);
858 PtrLenUnknown, 0, 0, 0, false);
861859 ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type);
862860
863861 slice_type_common_init(g, ptr_type, entry);
......@@ -881,10 +879,10 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
881879 {
882880 ZigType *grand_child_type = child_ptr_type->data.pointer.child_type;
883881 ZigType *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false,
884 PtrLenUnknown, 0, 0, 0);
882 PtrLenUnknown, 0, 0, 0, false);
885883 ZigType *bland_child_slice = get_slice_type(g, bland_child_ptr_type);
886884 ZigType *peer_ptr_type = get_pointer_to_type_extra(g, bland_child_slice, false, false,
887 PtrLenUnknown, 0, 0, 0);
885 PtrLenUnknown, 0, 0, 0, false);
888886 ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type);
889887
890888 entry->type_ref = peer_slice_type->type_ref;
......@@ -1419,7 +1417,7 @@ static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_
14191417
14201418static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **out_buffer) {
14211419 ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
1422 PtrLenUnknown, 0, 0, 0);
1420 PtrLenUnknown, 0, 0, 0, false);
14231421 ZigType *str_type = get_slice_type(g, ptr_type);
14241422 ConstExprValue *result_val = analyze_const_value(g, scope, node, str_type, nullptr);
14251423 if (type_is_invalid(result_val->type))
......@@ -5336,7 +5334,7 @@ void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
53365334 const_val->special = ConstValSpecialStatic;
53375335 // TODO make this `[*]null u8` instead of `[*]u8`
53385336 const_val->type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
5339 PtrLenUnknown, 0, 0, 0);
5337 PtrLenUnknown, 0, 0, 0, false);
53405338 const_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
53415339 const_val->data.x_ptr.data.base_array.array_val = array_val;
53425340 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
54815479 assert(array_val->type->id == ZigTypeIdArray);
54825480
54835481 ZigType *ptr_type = get_pointer_to_type_extra(g, array_val->type->data.array.child_type,
5484 is_const, false, PtrLenUnknown, 0, 0, 0);
5482 is_const, false, PtrLenUnknown, 0, 0, 0, false);
54855483
54865484 const_val->special = ConstValSpecialStatic;
54875485 const_val->type = get_slice_type(g, ptr_type);
......@@ -5506,7 +5504,7 @@ void init_const_ptr_array(CodeGen *g, ConstExprValue *const_val, ConstExprValue
55065504
55075505 const_val->special = ConstValSpecialStatic;
55085506 const_val->type = get_pointer_to_type_extra(g, child_type, is_const, false,
5509 ptr_len, 0, 0, 0);
5507 ptr_len, 0, 0, 0, false);
55105508 const_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
55115509 const_val->data.x_ptr.data.base_array.array_val = array_val;
55125510 const_val->data.x_ptr.data.base_array.elem_index = elem_index;
src/analyze.hpp+3-1
......@@ -18,7 +18,9 @@ void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg);
1818ZigType *new_type_table_entry(ZigTypeId id);
1919ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const);
2020ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
21 bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count);
21 bool is_volatile, PtrLen ptr_len,
22 uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count,
23 bool allow_zero);
2224uint64_t type_size(CodeGen *g, ZigType *type_entry);
2325uint64_t type_size_bits(CodeGen *g, ZigType *type_entry);
2426ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits);
src/codegen.cpp+22-9
......@@ -956,7 +956,7 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) {
956956 }
957957
958958 ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
959 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
959 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false);
960960 ZigType *str_type = get_slice_type(g, u8_ptr_type);
961961 return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(str_type->type_ref, 0));
962962}
......@@ -1515,7 +1515,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
15151515
15161516
15171517 ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
1518 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
1518 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false);
15191519 ZigType *str_type = get_slice_type(g, u8_ptr_type);
15201520 LLVMValueRef global_slice_fields[] = {
15211521 full_buf_ptr,
......@@ -3103,6 +3103,18 @@ static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executa
31033103static LLVMValueRef ir_render_int_to_ptr(CodeGen *g, IrExecutable *executable, IrInstructionIntToPtr *instruction) {
31043104 ZigType *wanted_type = instruction->base.value.type;
31053105 LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
3106 if (!ptr_allows_addr_zero(wanted_type) && ir_want_runtime_safety(g, &instruction->base)) {
3107 LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(target_val));
3108 LLVMValueRef is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, target_val, zero, "");
3109 LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrToIntBad");
3110 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "PtrToIntOk");
3111 LLVMBuildCondBr(g->builder, is_zero_bit, bad_block, ok_block);
3112
3113 LLVMPositionBuilderAtEnd(g->builder, bad_block);
3114 gen_safety_crash(g, PanicMsgIdPtrCastNull);
3115
3116 LLVMPositionBuilderAtEnd(g->builder, ok_block);
3117 }
31063118 return LLVMBuildIntToPtr(g->builder, target_val, wanted_type->type_ref, "");
31073119}
31083120
......@@ -3270,7 +3282,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
32703282
32713283 if (have_init_expr) {
32723284 ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->var_type, false, false,
3273 PtrLenSingle, var->align_bytes, 0, 0);
3285 PtrLenSingle, var->align_bytes, 0, 0, false);
32743286 LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value);
32753287 gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val);
32763288 } 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) {
41604172 return enum_type->data.enumeration.name_function;
41614173
41624174 ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, false, false,
4163 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
4175 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false);
41644176 ZigType *u8_slice_type = get_slice_type(g, u8_ptr_type);
41654177 ZigType *tag_int_type = enum_type->data.enumeration.tag_int_type;
41664178
......@@ -4953,7 +4965,7 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable,
49534965
49544966 ZigType *ptr_type = get_pointer_to_type_extra(g, type_struct_field->type_entry,
49554967 false, false, PtrLenSingle, field_align_bytes,
4956 (uint32_t)type_struct_field->bit_offset_in_host, host_int_bytes);
4968 (uint32_t)type_struct_field->bit_offset_in_host, host_int_bytes, false);
49574969
49584970 gen_assign_raw(g, field_ptr, ptr_type, value);
49594971 }
......@@ -4969,7 +4981,7 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I
49694981 uint32_t field_align_bytes = get_abi_alignment(g, type_union_field->type_entry);
49704982 ZigType *ptr_type = get_pointer_to_type_extra(g, type_union_field->type_entry,
49714983 false, false, PtrLenSingle, field_align_bytes,
4972 0, 0);
4984 0, 0, false);
49734985
49744986 LLVMValueRef uncasted_union_ptr;
49754987 // 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
52245236 LLVMPositionBuilderAtEnd(g->builder, ok_block);
52255237 LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, sret_ptr, err_union_payload_index, "");
52265238 ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, false, false,
5227 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
5239 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false);
52285240 ZigType *slice_type = get_slice_type(g, u8_ptr_type);
52295241 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
52305242 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, payload_ptr, ptr_field_index, "");
......@@ -6470,7 +6482,7 @@ static void generate_error_name_table(CodeGen *g) {
64706482 assert(g->errors_by_index.length > 0);
64716483
64726484 ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
6473 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
6485 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false);
64746486 ZigType *str_type = get_slice_type(g, u8_ptr_type);
64756487
64766488 LLVMValueRef *values = allocate<LLVMValueRef>(g->errors_by_index.length);
......@@ -7551,6 +7563,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
75517563 " is_volatile: bool,\n"
75527564 " alignment: comptime_int,\n"
75537565 " child: type,\n"
7566 " is_allowzero: bool,\n"
75547567 "\n"
75557568 " pub const Size = enum {\n"
75567569 " One,\n"
......@@ -8158,7 +8171,7 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
81588171 }
81598172
81608173 ZigType *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false,
8161 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0);
8174 PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0, false);
81628175 ZigType *str_type = get_slice_type(g, u8_ptr_type);
81638176 ZigType *fn_type = get_test_fn_type(g);
81648177
src/ir.cpp+71-43
......@@ -1348,7 +1348,7 @@ static IrInstruction *ir_build_br(IrBuilder *irb, Scope *scope, AstNode *source_
13481348
13491349static IrInstruction *ir_build_ptr_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
13501350 IrInstruction *child_type, bool is_const, bool is_volatile, PtrLen ptr_len,
1351 IrInstruction *align_value, uint32_t bit_offset_start, uint32_t host_int_bytes)
1351 IrInstruction *align_value, uint32_t bit_offset_start, uint32_t host_int_bytes, bool is_allow_zero)
13521352{
13531353 IrInstructionPtrType *ptr_type_of_instruction = ir_build_instruction<IrInstructionPtrType>(irb, scope, source_node);
13541354 ptr_type_of_instruction->align_value = align_value;
......@@ -1358,6 +1358,7 @@ static IrInstruction *ir_build_ptr_type(IrBuilder *irb, Scope *scope, AstNode *s
13581358 ptr_type_of_instruction->ptr_len = ptr_len;
13591359 ptr_type_of_instruction->bit_offset_start = bit_offset_start;
13601360 ptr_type_of_instruction->host_int_bytes = host_int_bytes;
1361 ptr_type_of_instruction->is_allow_zero = is_allow_zero;
13611362
13621363 if (align_value) ir_ref_instruction(align_value, irb->current_basic_block);
13631364 ir_ref_instruction(child_type, irb->current_basic_block);
......@@ -1627,13 +1628,14 @@ static IrInstruction *ir_build_promise_type(IrBuilder *irb, Scope *scope, AstNod
16271628}
16281629
16291630static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
1630 IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value)
1631 IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value, bool is_allow_zero)
16311632{
16321633 IrInstructionSliceType *instruction = ir_build_instruction<IrInstructionSliceType>(irb, scope, source_node);
16331634 instruction->is_const = is_const;
16341635 instruction->is_volatile = is_volatile;
16351636 instruction->child_type = child_type;
16361637 instruction->align_value = align_value;
1638 instruction->is_allow_zero = is_allow_zero;
16371639
16381640 ir_ref_instruction(child_type, irb->current_basic_block);
16391641 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
51925194 PtrLen ptr_len = star_token_to_ptr_len(node->data.pointer_type.star_token->id);
51935195 bool is_const = node->data.pointer_type.is_const;
51945196 bool is_volatile = node->data.pointer_type.is_volatile;
5197 bool is_allow_zero = node->data.pointer_type.allow_zero_token != nullptr;
51955198 AstNode *expr_node = node->data.pointer_type.op_expr;
51965199 AstNode *align_expr = node->data.pointer_type.align_expr;
51975200
......@@ -5239,7 +5242,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode
52395242 }
52405243
52415244 return ir_build_ptr_type(irb, scope, node, child_type, is_const, is_volatile,
5242 ptr_len, align_value, bit_offset_start, host_int_bytes);
5245 ptr_len, align_value, bit_offset_start, host_int_bytes, is_allow_zero);
52435246}
52445247
52455248static 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
58265829 AstNode *child_type_node = node->data.array_type.child_type;
58275830 bool is_const = node->data.array_type.is_const;
58285831 bool is_volatile = node->data.array_type.is_volatile;
5832 bool is_allow_zero = node->data.array_type.allow_zero_token != nullptr;
58295833 AstNode *align_expr = node->data.array_type.align_expr;
58305834
58315835 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
58385842 add_node_error(irb->codegen, node, buf_create_from_str("volatile qualifier invalid on array type"));
58395843 return irb->codegen->invalid_instruction;
58405844 }
5845 if (is_allow_zero) {
5846 add_node_error(irb->codegen, node, buf_create_from_str("allowzero qualifier invalid on array type"));
5847 return irb->codegen->invalid_instruction;
5848 }
58415849 if (align_expr != nullptr) {
58425850 add_node_error(irb->codegen, node, buf_create_from_str("align qualifier invalid on array type"));
58435851 return irb->codegen->invalid_instruction;
......@@ -5866,7 +5874,7 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n
58665874 if (child_type == irb->codegen->invalid_instruction)
58675875 return child_type;
58685876
5869 return ir_build_slice_type(irb, scope, node, child_type, is_const, is_volatile, align_value);
5877 return ir_build_slice_type(irb, scope, node, child_type, is_const, is_volatile, align_value, is_allow_zero);
58705878 }
58715879}
58725880
......@@ -7760,7 +7768,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
77607768 if (type_has_bits(return_type)) {
77617769 IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
77627770 get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
7763 false, false, PtrLenUnknown, 0, 0, 0));
7771 false, false, PtrLenUnknown, 0, 0, 0, false));
77647772 IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr);
77657773 IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len,
77667774 result_ptr, false);
......@@ -7814,7 +7822,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
78147822 IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle);
78157823 IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
78167824 get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
7817 false, false, PtrLenUnknown, 0, 0, 0));
7825 false, false, PtrLenUnknown, 0, 0, 0, false));
78187826 IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len,
78197827 coro_mem_ptr_maybe, false);
78207828 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
98189826 ZigType *ptr_type = get_pointer_to_type_extra(
98199827 ira->codegen, prev_inst->value.type->data.array.child_type,
98209828 true, false, PtrLenUnknown,
9821 0, 0, 0);
9829 0, 0, 0, false);
98229830 ZigType *slice_type = get_slice_type(ira->codegen, ptr_type);
98239831 if (err_set_type != nullptr) {
98249832 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
1024310251 ConstPtrMut ptr_mut, bool ptr_is_const, bool ptr_is_volatile, uint32_t ptr_align)
1024410252{
1024510253 ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, pointee_type,
10246 ptr_is_const, ptr_is_volatile, PtrLenSingle, ptr_align, 0, 0);
10254 ptr_is_const, ptr_is_volatile, PtrLenSingle, ptr_align, 0, 0, false);
1024710255 IrInstruction *const_instr = ir_const(ira, instruction, ptr_type);
1024810256 ConstExprValue *const_val = &const_instr->value;
1024910257 const_val->data.x_ptr.special = ConstPtrSpecialRef;
......@@ -10576,7 +10584,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
1057610584 }
1057710585
1057810586 ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type,
10579 is_const, is_volatile, PtrLenSingle, 0, 0, 0);
10587 is_const, is_volatile, PtrLenSingle, 0, 0, 0, false);
1058010588 IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instruction->scope,
1058110589 source_instruction->source_node, value, is_const, is_volatile);
1058210590 new_instruction->value.type = ptr_type;
......@@ -11983,7 +11991,7 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {
1198311991 return nullptr;
1198411992
1198511993 ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
11986 true, false, PtrLenUnknown, 0, 0, 0);
11994 true, false, PtrLenUnknown, 0, 0, 0, false);
1198711995 ZigType *str_type = get_slice_type(ira->codegen, ptr_type);
1198811996 IrInstruction *casted_value = ir_implicit_cast(ira, value, str_type);
1198911997 if (type_is_invalid(casted_value->value.type))
......@@ -13154,7 +13162,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
1315413162 out_array_val = out_val;
1315513163 } else if (is_slice(op1_type) || is_slice(op2_type)) {
1315613164 ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, child_type,
13157 true, false, PtrLenUnknown, 0, 0, 0);
13165 true, false, PtrLenUnknown, 0, 0, 0, false);
1315813166 result->value.type = get_slice_type(ira->codegen, ptr_type);
1315913167 out_array_val = create_const_vals(1);
1316013168 out_array_val->special = ConstValSpecialStatic;
......@@ -13175,7 +13183,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i
1317513183 new_len += 1; // null byte
1317613184
1317713185 // TODO make this `[*]null T` instead of `[*]T`
13178 result->value.type = get_pointer_to_type_extra(ira->codegen, child_type, true, false, PtrLenUnknown, 0, 0, 0);
13186 result->value.type = get_pointer_to_type_extra(ira->codegen, child_type, true, false, PtrLenUnknown, 0, 0, 0, false);
1317913187
1318013188 out_array_val = create_const_vals(1);
1318113189 out_array_val->special = ConstValSpecialStatic;
......@@ -14033,7 +14041,7 @@ no_mem_slot:
1403314041 IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb,
1403414042 instruction->scope, instruction->source_node, var);
1403514043 var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->var_type,
14036 var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0);
14044 var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0, false);
1403714045
1403814046 bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr);
1403914047 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
1432814336 IrInstruction *casted_new_stack = nullptr;
1432914337 if (call_instruction->new_stack != nullptr) {
1433014338 ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
14331 false, false, PtrLenUnknown, 0, 0, 0);
14339 false, false, PtrLenUnknown, 0, 0, 0, false);
1433214340 ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr);
1433314341 IrInstruction *new_stack = call_instruction->new_stack->child;
1433414342 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
1526215270 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
1526315271 ptr_type->data.pointer.ptr_len,
1526415272 new_align,
15265 ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes);
15273 ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes,
15274 ptr_type->data.pointer.allow_zero);
1526615275}
1526715276
1526815277static 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) {
1527915288 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
1528015289 ptr_len,
1528115290 ptr_type->data.pointer.explicit_alignment,
15282 ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes);
15291 ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes,
15292 ptr_type->data.pointer.allow_zero);
1528315293}
1528415294
1528515295static 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
1533015340 return_type = get_pointer_to_type_extra(ira->codegen, child_type,
1533115341 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
1533215342 elem_ptr_instruction->ptr_len,
15333 ptr_type->data.pointer.explicit_alignment, 0, 0);
15343 ptr_type->data.pointer.explicit_alignment, 0, 0, false);
1533415344 } else {
1533515345 uint64_t elem_val_scalar;
1533615346 if (!ir_resolve_usize(ira, elem_index, &elem_val_scalar))
......@@ -15342,7 +15352,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
1534215352 return_type = get_pointer_to_type_extra(ira->codegen, child_type,
1534315353 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
1534415354 elem_ptr_instruction->ptr_len,
15345 1, (uint32_t)bit_offset, ptr_type->data.pointer.host_int_bytes);
15355 1, (uint32_t)bit_offset, ptr_type->data.pointer.host_int_bytes, false);
1534615356 }
1534715357 } else if (array_type->id == ZigTypeIdPointer) {
1534815358 if (array_type->data.pointer.ptr_len == PtrLenSingle) {
......@@ -15693,7 +15703,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
1569315703 ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry,
1569415704 is_const, is_volatile, PtrLenSingle, align_bytes,
1569515705 (uint32_t)(ptr_bit_offset + field->bit_offset_in_host),
15696 (uint32_t)host_int_bytes_for_result_type);
15706 (uint32_t)host_int_bytes_for_result_type, false);
1569715707 IrInstruction *result = ir_const(ira, source_instr, ptr_type);
1569815708 ConstExprValue *const_val = &result->value;
1569915709 const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct;
......@@ -15709,7 +15719,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
1570915719 PtrLenSingle,
1571015720 align_bytes,
1571115721 (uint32_t)(ptr_bit_offset + field->bit_offset_in_host),
15712 host_int_bytes_for_result_type);
15722 host_int_bytes_for_result_type, false);
1571315723 return result;
1571415724 } else {
1571515725 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_
1574815758
1574915759 ZigType *field_type = field->type_entry;
1575015760 ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type,
15751 is_const, is_volatile, PtrLenSingle, 0, 0, 0);
15761 is_const, is_volatile, PtrLenSingle, 0, 0, 0, false);
1575215762
1575315763 IrInstruction *result = ir_const(ira, source_instr, ptr_type);
1575415764 ConstExprValue *const_val = &result->value;
......@@ -15761,7 +15771,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
1576115771
1576215772 IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, container_ptr, field);
1576315773 result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
15764 PtrLenSingle, 0, 0, 0);
15774 PtrLenSingle, 0, 0, 0, false);
1576515775 return result;
1576615776 } else {
1576715777 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,
1648016490
1648116491 bool is_const = slice_type_instruction->is_const;
1648216492 bool is_volatile = slice_type_instruction->is_volatile;
16493 bool is_allow_zero = slice_type_instruction->is_allow_zero;
1648316494
1648416495 switch (child_type->id) {
1648516496 case ZigTypeIdInvalid: // handled above
......@@ -16516,7 +16527,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
1651616527 if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown)))
1651716528 return ira->codegen->invalid_instruction;
1651816529 ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type,
16519 is_const, is_volatile, PtrLenUnknown, align_bytes, 0, 0);
16530 is_const, is_volatile, PtrLenUnknown, align_bytes, 0, 0, is_allow_zero);
1652016531 ZigType *result_type = get_slice_type(ira->codegen, slice_ptr_type);
1652116532 return ir_const_type(ira, &slice_type_instruction->base, result_type);
1652216533 }
......@@ -16749,7 +16760,7 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr
1674916760
1675016761 ZigType *child_type = type_entry->data.maybe.child_type;
1675116762 ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
16752 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0);
16763 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0, false);
1675316764
1675416765 if (instr_is_comptime(base_ptr)) {
1675516766 ConstExprValue *val = ir_resolve_const(ira, base_ptr, UndefBad);
......@@ -17668,7 +17679,7 @@ static IrInstruction *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruct
1766817679 return ira->codegen->invalid_instruction;
1766917680
1767017681 ZigType *u8_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
17671 true, false, PtrLenUnknown, 0, 0, 0);
17682 true, false, PtrLenUnknown, 0, 0, 0, false);
1767217683 ZigType *str_type = get_slice_type(ira->codegen, u8_ptr_type);
1767317684 if (casted_value->value.special == ConstValSpecialStatic) {
1767417685 ErrorTableEntry *err = casted_value->value.data.x_err_set;
......@@ -17713,7 +17724,7 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns
1771317724 ZigType *u8_ptr_type = get_pointer_to_type_extra(
1771417725 ira->codegen, ira->codegen->builtin_types.entry_u8,
1771517726 true, false, PtrLenUnknown,
17716 0, 0, 0);
17727 0, 0, 0, false);
1771717728 result->value.type = get_slice_type(ira->codegen, u8_ptr_type);
1771817729 return result;
1771917730}
......@@ -17767,7 +17778,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira,
1776717778 field_ptr->value.type->data.pointer.is_const,
1776817779 field_ptr->value.type->data.pointer.is_volatile,
1776917780 PtrLenSingle,
17770 field_ptr_align, 0, 0);
17781 field_ptr_align, 0, 0, false);
1777117782 IrInstruction *casted_field_ptr = ir_implicit_cast(ira, field_ptr, field_ptr_type);
1777217783 if (type_is_invalid(casted_field_ptr->value.type))
1777317784 return ira->codegen->invalid_instruction;
......@@ -17776,7 +17787,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira,
1777617787 casted_field_ptr->value.type->data.pointer.is_const,
1777717788 casted_field_ptr->value.type->data.pointer.is_volatile,
1777817789 PtrLenSingle,
17779 parent_ptr_align, 0, 0);
17790 parent_ptr_align, 0, 0, false);
1778017791
1778117792 if (instr_is_comptime(casted_field_ptr)) {
1778217793 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,
1811218123 ZigType *u8_ptr = get_pointer_to_type_extra(
1811318124 ira->codegen, ira->codegen->builtin_types.entry_u8,
1811418125 true, false, PtrLenUnknown,
18115 0, 0, 0);
18126 0, 0, 0, false);
1811618127 fn_def_fields[6].type = get_optional_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr));
1811718128 if (fn_node->is_extern && buf_len(fn_node->lib_name) > 0) {
1811818129 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
1821618227 result->special = ConstValSpecialStatic;
1821718228 result->type = type_info_pointer_type;
1821818229
18219 ConstExprValue *fields = create_const_vals(5);
18230 ConstExprValue *fields = create_const_vals(6);
1822018231 result->data.x_struct.fields = fields;
1822118232
1822218233 // size: Size
......@@ -18247,6 +18258,11 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty
1824718258 fields[4].special = ConstValSpecialStatic;
1824818259 fields[4].type = ira->codegen->builtin_types.entry_type;
1824918260 fields[4].data.x_type = attrs_type->data.pointer.child_type;
18261 // is_allowzero: bool
18262 ensure_field_index(result->type, "is_allowzero", 5);
18263 fields[5].special = ConstValSpecialStatic;
18264 fields[5].type = ira->codegen->builtin_types.entry_bool;
18265 fields[5].data.x_bool = attrs_type->data.pointer.allow_zero;
1825018266
1825118267 return result;
1825218268};
......@@ -19473,12 +19489,12 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru
1947319489
1947419490 ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_child_type,
1947519491 src_ptr_const, src_ptr_volatile, PtrLenUnknown,
19476 src_ptr_align, 0, 0);
19492 src_ptr_align, 0, 0, false);
1947719493 ZigType *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type);
1947819494
1947919495 ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
1948019496 src_ptr_const, src_ptr_volatile, PtrLenUnknown,
19481 src_ptr_align, 0, 0);
19497 src_ptr_align, 0, 0, false);
1948219498 ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr);
1948319499
1948419500 IrInstruction *casted_value = ir_implicit_cast(ira, target, u8_slice);
......@@ -19545,7 +19561,7 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct
1954519561
1954619562 ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
1954719563 src_ptr_type->data.pointer.is_const, src_ptr_type->data.pointer.is_volatile, PtrLenUnknown,
19548 alignment, 0, 0);
19564 alignment, 0, 0, false);
1954919565 ZigType *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type);
1955019566
1955119567 if (instr_is_comptime(target)) {
......@@ -19773,7 +19789,7 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio
1977319789 dest_align = get_abi_alignment(ira->codegen, u8);
1977419790 }
1977519791 ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile,
19776 PtrLenUnknown, dest_align, 0, 0);
19792 PtrLenUnknown, dest_align, 0, 0, false);
1977719793
1977819794 IrInstruction *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr);
1977919795 if (type_is_invalid(casted_dest_ptr->value.type))
......@@ -19895,9 +19911,9 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio
1989519911
1989619912 ZigType *usize = ira->codegen->builtin_types.entry_usize;
1989719913 ZigType *u8_ptr_mut = get_pointer_to_type_extra(ira->codegen, u8, false, dest_is_volatile,
19898 PtrLenUnknown, dest_align, 0, 0);
19914 PtrLenUnknown, dest_align, 0, 0, false);
1989919915 ZigType *u8_ptr_const = get_pointer_to_type_extra(ira->codegen, u8, true, src_is_volatile,
19900 PtrLenUnknown, src_align, 0, 0);
19916 PtrLenUnknown, src_align, 0, 0, false);
1990119917
1990219918 IrInstruction *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr_mut);
1990319919 if (type_is_invalid(casted_dest_ptr->value.type))
......@@ -20061,7 +20077,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
2006120077 ptr_ptr_type->data.pointer.is_const || is_comptime_const,
2006220078 ptr_ptr_type->data.pointer.is_volatile,
2006320079 PtrLenUnknown,
20064 ptr_ptr_type->data.pointer.explicit_alignment, 0, 0);
20080 ptr_ptr_type->data.pointer.explicit_alignment, 0, 0, false);
2006520081 return_type = get_slice_type(ira->codegen, slice_ptr_type);
2006620082 } else if (array_type->id == ZigTypeIdPointer) {
2006720083 if (array_type->data.pointer.ptr_len == PtrLenSingle) {
......@@ -20071,7 +20087,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction
2007120087 main_type->data.pointer.child_type,
2007220088 array_type->data.pointer.is_const, array_type->data.pointer.is_volatile,
2007320089 PtrLenUnknown,
20074 array_type->data.pointer.explicit_alignment, 0, 0);
20090 array_type->data.pointer.explicit_alignment, 0, 0, false);
2007520091 return_type = get_slice_type(ira->codegen, slice_ptr_type);
2007620092 } else {
2007720093 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
2058620602 expected_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_type,
2058720603 false, result_ptr->value.type->data.pointer.is_volatile,
2058820604 PtrLenSingle,
20589 alignment, 0, 0);
20605 alignment, 0, 0, false);
2059020606 } else {
2059120607 expected_ptr_type = get_pointer_to_type(ira->codegen, dest_type, false);
2059220608 }
......@@ -20753,7 +20769,7 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
2075320769
2075420770 ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type,
2075520771 ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
20756 PtrLenSingle, 0, 0, 0);
20772 PtrLenSingle, 0, 0, 0, false);
2075720773 if (instr_is_comptime(value)) {
2075820774 ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
2075920775 if (!ptr_val)
......@@ -21125,7 +21141,7 @@ static IrInstruction *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstruction
2112521141 }
2112621142
2112721143 ZigType *u8_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
21128 true, false, PtrLenUnknown, 0, 0, 0);
21144 true, false, PtrLenUnknown, 0, 0, 0, false);
2112921145 ZigType *str_type = get_slice_type(ira->codegen, u8_ptr_type);
2113021146 IrInstruction *casted_msg = ir_implicit_cast(ira, msg, str_type);
2113121147 if (type_is_invalid(casted_msg->value.type))
......@@ -21794,10 +21810,17 @@ static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *sourc
2179421810 if (!val)
2179521811 return ira->codegen->invalid_instruction;
2179621812
21813 uint64_t addr = bigint_as_unsigned(&val->data.x_bigint);
21814 if (!ptr_allows_addr_zero(ptr_type) && addr == 0) {
21815 ir_add_error(ira, source_instr,
21816 buf_sprintf("pointer type '%s' does not allow address zero", buf_ptr(&ptr_type->name)));
21817 return ira->codegen->invalid_instruction;
21818 }
21819
2179721820 IrInstruction *result = ir_const(ira, source_instr, ptr_type);
2179821821 result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
2179921822 result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar;
21800 result->value.data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&val->data.x_bigint);
21823 result->value.data.x_ptr.data.hard_coded_addr.addr = addr;
2180121824 return result;
2180221825 }
2180321826
......@@ -21951,6 +21974,9 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct
2195121974 } else if (child_type->id == ZigTypeIdOpaque) {
2195221975 ir_add_error(ira, &instruction->base, buf_sprintf("C pointers cannot point opaque types"));
2195321976 return ira->codegen->invalid_instruction;
21977 } else if (instruction->is_allow_zero) {
21978 ir_add_error(ira, &instruction->base, buf_sprintf("C pointers always allow address zero"));
21979 return ira->codegen->invalid_instruction;
2195421980 }
2195521981 }
2195621982
......@@ -21969,10 +21995,12 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct
2196921995 align_bytes = 0;
2197021996 }
2197121997
21998 bool allow_zero = instruction->is_allow_zero || instruction->ptr_len == PtrLenC;
21999
2197222000 ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type,
2197322001 instruction->is_const, instruction->is_volatile,
2197422002 instruction->ptr_len, align_bytes,
21975 instruction->bit_offset_start, instruction->host_int_bytes);
22003 instruction->bit_offset_start, instruction->host_int_bytes, allow_zero);
2197622004 return ir_const_type(ira, &instruction->base, result_type);
2197722005}
2197822006
src/parser.cpp+12-1
......@@ -2530,6 +2530,12 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {
25302530 if (array != nullptr) {
25312531 assert(array->type == NodeTypeArrayType);
25322532 while (true) {
2533 Token *allowzero_token = eat_token_if(pc, TokenIdKeywordAllowZero);
2534 if (allowzero_token != nullptr) {
2535 array->data.array_type.allow_zero_token = allowzero_token;
2536 continue;
2537 }
2538
25332539 AstNode *align_expr = ast_parse_byte_align(pc);
25342540 if (align_expr != nullptr) {
25352541 array->data.array_type.align_expr = align_expr;
......@@ -2545,7 +2551,6 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {
25452551 array->data.array_type.is_volatile = true;
25462552 continue;
25472553 }
2548
25492554 break;
25502555 }
25512556
......@@ -2560,6 +2565,12 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) {
25602565 if (child == nullptr)
25612566 child = ptr;
25622567 while (true) {
2568 Token *allowzero_token = eat_token_if(pc, TokenIdKeywordAllowZero);
2569 if (allowzero_token != nullptr) {
2570 child->data.pointer_type.allow_zero_token = allowzero_token;
2571 continue;
2572 }
2573
25632574 if (eat_token_if(pc, TokenIdKeywordAlign) != nullptr) {
25642575 expect_token(pc, TokenIdLParen);
25652576 AstNode *align_expr = ast_parse_expr(pc);
src/tokenizer.cpp+2
......@@ -107,6 +107,7 @@ struct ZigKeyword {
107107
108108static const struct ZigKeyword zig_keywords[] = {
109109 {"align", TokenIdKeywordAlign},
110 {"allowzero", TokenIdKeywordAllowZero},
110111 {"and", TokenIdKeywordAnd},
111112 {"anyerror", TokenIdKeywordAnyerror},
112113 {"asm", TokenIdKeywordAsm},
......@@ -1495,6 +1496,7 @@ const char * token_name(TokenId id) {
14951496 case TokenIdIntLiteral: return "IntLiteral";
14961497 case TokenIdKeywordAsync: return "async";
14971498 case TokenIdKeywordAnyerror: return "anyerror";
1499 case TokenIdKeywordAllowZero: return "allowzero";
14981500 case TokenIdKeywordAwait: return "await";
14991501 case TokenIdKeywordResume: return "resume";
15001502 case TokenIdKeywordSuspend: return "suspend";
src/tokenizer.hpp+2-1
......@@ -50,6 +50,7 @@ enum TokenId {
5050 TokenIdFloatLiteral,
5151 TokenIdIntLiteral,
5252 TokenIdKeywordAlign,
53 TokenIdKeywordAllowZero,
5354 TokenIdKeywordAnd,
5455 TokenIdKeywordAnyerror,
5556 TokenIdKeywordAsm,
......@@ -73,6 +74,7 @@ enum TokenId {
7374 TokenIdKeywordFor,
7475 TokenIdKeywordIf,
7576 TokenIdKeywordInline,
77 TokenIdKeywordLinkSection,
7678 TokenIdKeywordNakedCC,
7779 TokenIdKeywordNoAlias,
7880 TokenIdKeywordNull,
......@@ -83,7 +85,6 @@ enum TokenId {
8385 TokenIdKeywordPub,
8486 TokenIdKeywordResume,
8587 TokenIdKeywordReturn,
86 TokenIdKeywordLinkSection,
8788 TokenIdKeywordStdcallCC,
8889 TokenIdKeywordStruct,
8990 TokenIdKeywordSuspend,
std/zig/ast.zig+5
......@@ -125,6 +125,7 @@ pub const Error = union(enum) {
125125 ExtraAlignQualifier: ExtraAlignQualifier,
126126 ExtraConstQualifier: ExtraConstQualifier,
127127 ExtraVolatileQualifier: ExtraVolatileQualifier,
128 ExtraAllowZeroQualifier: ExtraAllowZeroQualifier,
128129 ExpectedPrimaryExpr: ExpectedPrimaryExpr,
129130 ExpectedToken: ExpectedToken,
130131 ExpectedCommaOrEnd: ExpectedCommaOrEnd,
......@@ -149,6 +150,7 @@ pub const Error = union(enum) {
149150 @TagType(Error).ExtraAlignQualifier => |*x| return x.render(tokens, stream),
150151 @TagType(Error).ExtraConstQualifier => |*x| return x.render(tokens, stream),
151152 @TagType(Error).ExtraVolatileQualifier => |*x| return x.render(tokens, stream),
153 @TagType(Error).ExtraAllowZeroQualifier => |*x| return x.render(tokens, stream),
152154 @TagType(Error).ExpectedPrimaryExpr => |*x| return x.render(tokens, stream),
153155 @TagType(Error).ExpectedToken => |*x| return x.render(tokens, stream),
154156 @TagType(Error).ExpectedCommaOrEnd => |*x| return x.render(tokens, stream),
......@@ -175,6 +177,7 @@ pub const Error = union(enum) {
175177 @TagType(Error).ExtraAlignQualifier => |x| return x.token,
176178 @TagType(Error).ExtraConstQualifier => |x| return x.token,
177179 @TagType(Error).ExtraVolatileQualifier => |x| return x.token,
180 @TagType(Error).ExtraAllowZeroQualifier => |x| return x.token,
178181 @TagType(Error).ExpectedPrimaryExpr => |x| return x.token,
179182 @TagType(Error).ExpectedToken => |x| return x.token,
180183 @TagType(Error).ExpectedCommaOrEnd => |x| return x.token,
......@@ -198,6 +201,7 @@ pub const Error = union(enum) {
198201 pub const ExtraAlignQualifier = SimpleError("Extra align qualifier");
199202 pub const ExtraConstQualifier = SimpleError("Extra const qualifier");
200203 pub const ExtraVolatileQualifier = SimpleError("Extra volatile qualifier");
204 pub const ExtraAllowZeroQualifier = SimpleError("Extra allowzero qualifier");
201205
202206 pub const ExpectedCall = struct {
203207 node: *Node,
......@@ -1540,6 +1544,7 @@ pub const Node = struct {
15401544 };
15411545
15421546 pub const PtrInfo = struct {
1547 allowzero_token: ?TokenIndex,
15431548 align_info: ?Align,
15441549 const_token: ?TokenIndex,
15451550 volatile_token: ?TokenIndex,
std/zig/parse.zig+11
......@@ -1688,6 +1688,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
16881688 .align_info = null,
16891689 .const_token = null,
16901690 .volatile_token = null,
1691 .allowzero_token = null,
16911692 },
16921693 };
16931694 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 {
17431744 addr_of_info.volatile_token = token_index;
17441745 continue;
17451746 },
1747 Token.Id.Keyword_allowzero => {
1748 stack.append(state) catch unreachable;
1749 if (addr_of_info.allowzero_token != null) {
1750 ((try tree.errors.addOne())).* = Error{ .ExtraAllowZeroQualifier = Error.ExtraAllowZeroQualifier{ .token = token_index } };
1751 return tree;
1752 }
1753 addr_of_info.allowzero_token = token_index;
1754 continue;
1755 },
17461756 else => {
17471757 prevToken(&tok_it, &tree);
17481758 continue;
......@@ -3552,6 +3562,7 @@ fn tokenIdToPrefixOp(id: Token.Id) ?ast.Node.PrefixOp.Op {
35523562 .align_info = null,
35533563 .const_token = null,
35543564 .volatile_token = null,
3565 .allowzero_token = null,
35553566 },
35563567 },
35573568 Token.Id.QuestionMark => ast.Node.PrefixOp.Op{ .OptionalType = void{} },
std/zig/parser_test.zig+7
......@@ -1,3 +1,10 @@
1test "zig fmt: allowzero pointer" {
2 try testCanonical(
3 \\const T = [*]allowzero const u8;
4 \\
5 );
6}
7
18test "zig fmt: enum literal" {
29 try testCanonical(
310 \\const x = .hi;
std/zig/render.zig+6
......@@ -379,6 +379,9 @@ fn renderExpression(
379379 else => usize(0),
380380 };
381381 try renderTokenOffset(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None, star_offset); // *
382 if (ptr_info.allowzero_token) |allowzero_token| {
383 try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero
384 }
382385 if (ptr_info.align_info) |align_info| {
383386 const lparen_token = tree.prevToken(align_info.node.firstToken());
384387 const align_token = tree.prevToken(lparen_token);
......@@ -416,6 +419,9 @@ fn renderExpression(
416419 try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None); // [
417420 try renderToken(tree, stream, tree.nextToken(prefix_op_node.op_token), indent, start_col, Space.None); // ]
418421
422 if (ptr_info.allowzero_token) |allowzero_token| {
423 try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero
424 }
419425 if (ptr_info.align_info) |align_info| {
420426 const lparen_token = tree.prevToken(align_info.node.firstToken());
421427 const align_token = tree.prevToken(lparen_token);
std/zig/tokenizer.zig+2
......@@ -13,6 +13,7 @@ pub const Token = struct {
1313
1414 pub const keywords = []Keyword{
1515 Keyword{ .bytes = "align", .id = Id.Keyword_align },
16 Keyword{ .bytes = "allowzero", .id = Id.Keyword_allowzero },
1617 Keyword{ .bytes = "and", .id = Id.Keyword_and },
1718 Keyword{ .bytes = "anyerror", .id = Id.Keyword_anyerror },
1819 Keyword{ .bytes = "asm", .id = Id.Keyword_asm },
......@@ -143,6 +144,7 @@ pub const Token = struct {
143144 BracketStarCBracket,
144145 ShebangLine,
145146 Keyword_align,
147 Keyword_allowzero,
146148 Keyword_and,
147149 Keyword_anyerror,
148150 Keyword_asm,
test/compile_errors.zig+9
......@@ -2,6 +2,15 @@ const tests = @import("tests.zig");
22const builtin = @import("builtin");
33
44pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.add(
6 "@ptrToInt 0 to non optional pointer",
7 \\export fn entry() void {
8 \\ var b = @intToPtr(*i32, 0);
9 \\}
10 ,
11 "tmp.zig:2:13: error: pointer type '*i32' does not allow address zero",
12 );
13
514 cases.add(
615 "cast enum literal to enum but it doesn't match",
716 \\const Foo = enum {
test/runtime_safety.zig+10
......@@ -1,6 +1,16 @@
11const tests = @import("tests.zig");
22
33pub fn addCases(cases: *tests.CompareOutputContext) void {
4 cases.addRuntimeSafety("@ptrToInt address zero to non-optional pointer",
5 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
6 \\ @import("std").os.exit(126);
7 \\}
8 \\pub fn main() void {
9 \\ var zero: usize = 0;
10 \\ var b = @intToPtr(*i32, zero);
11 \\}
12 );
13
414 cases.addRuntimeSafety("pointer casting null to non-optional pointer",
515 \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn {
616 \\ @import("std").os.exit(126);
test/stage1/behavior/pointers.zig+13
......@@ -137,3 +137,16 @@ test "compare equality of optional and non-optional pointer" {
137137 expect(a == b);
138138 expect(b == a);
139139}
140
141test "allowzero pointer and slice" {
142 var ptr = @intToPtr([*]allowzero i32, 0);
143 var opt_ptr: ?[*]allowzero i32 = ptr;
144 expect(opt_ptr != null);
145 expect(@ptrToInt(ptr) == 0);
146 var slice = ptr[0..10];
147 expect(@typeOf(slice) == []allowzero i32);
148 expect(@ptrToInt(&slice[5]) == 20);
149
150 expect(@typeInfo(@typeOf(ptr)).Pointer.is_allowzero);
151 expect(@typeInfo(@typeOf(slice)).Pointer.is_allowzero);
152}