| author | |
| committer | |
| log | 5eaead6a56ed95c200e249737c4ecf3c7cacf794 |
| tree | 70fe5c0238d6f1d72fc8504a4aaec710f059db37 |
| parent | 3306e43984a8b17472ecc4b13a2f2815d6630eef |
| signature | Commit is signed but in an unrecognized format. |
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 |
| 779 | 779 | std.zig.Token.Id.Keyword_use, |
| 780 | 780 | std.zig.Token.Id.Keyword_var, |
| 781 | 781 | std.zig.Token.Id.Keyword_volatile, |
| 782 | std.zig.Token.Id.Keyword_allowzero, | |
| 782 | 783 | std.zig.Token.Id.Keyword_while, |
| 783 | 784 | => { |
| 784 | 785 | try out.write("<span class=\"tok-kw\">"); |
doc/langref.html.in+36-8| ... | ... | @@ -1721,7 +1721,7 @@ test "comptime @intToPtr" { |
| 1721 | 1721 | } |
| 1722 | 1722 | } |
| 1723 | 1723 | {#code_end#} |
| 1724 | {#see_also|Optional Pointers|@intToPtr|@ptrToInt#} | |
| 1724 | {#see_also|Optional Pointers|@intToPtr|@ptrToInt|C Pointers|Pointers to Zero Bit Types#} | |
| 1725 | 1725 | {#header_open|volatile#} |
| 1726 | 1726 | <p>Loads and stores are assumed to not have side effects. If a given load or store |
| 1727 | 1727 | should have side effects, such as Memory Mapped Input/Output (MMIO), use {#syntax#}volatile{#endsyntax#}. |
| ... | ... | @@ -1850,7 +1850,25 @@ fn foo(bytes: []u8) u32 { |
| 1850 | 1850 | } |
| 1851 | 1851 | {#code_end#} |
| 1852 | 1852 | {#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#} | |
| 1862 | const std = @import("std"); | |
| 1863 | const assert = std.debug.assert; | |
| 1864 | ||
| 1865 | test "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#} | |
| 1854 | 1872 | {#header_close#} |
| 1855 | 1873 | |
| 1856 | 1874 | {#header_open|Slices#} |
| ... | ... | @@ -6635,9 +6653,13 @@ fn add(a: i32, b: i32) i32 { return a + b; } |
| 6635 | 6653 | {#header_close#} |
| 6636 | 6654 | |
| 6637 | 6655 | {#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> | |
| 6639 | 6660 | <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#}. | |
| 6641 | 6663 | </p> |
| 6642 | 6664 | {#header_close#} |
| 6643 | 6665 | |
| ... | ... | @@ -8128,6 +8150,11 @@ fn bar(f: *Foo) void { |
| 8128 | 8150 | {#header_close#} |
| 8129 | 8151 | |
| 8130 | 8152 | {#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> | |
| 8131 | 8158 | <p>At compile-time:</p> |
| 8132 | 8159 | {#code_begin|test_err|null pointer casted to type#} |
| 8133 | 8160 | comptime { |
| ... | ... | @@ -8988,7 +9015,7 @@ Available libcs: |
| 8988 | 9015 | <ul> |
| 8989 | 9016 | <li>Linux x86_64</li> |
| 8990 | 9017 | <li>Windows x86_64</li> |
| 8991 | <li>MacOS x86_64</li> | |
| 9018 | <li>macOS x86_64</li> | |
| 8992 | 9019 | </ul> |
| 8993 | 9020 | {#header_close#} |
| 8994 | 9021 | {#header_open|Style Guide#} |
| ... | ... | @@ -9412,8 +9439,8 @@ PrefixOp |
| 9412 | 9439 | PrefixTypeOp |
| 9413 | 9440 | &lt;- QUESTIONMARK |
| 9414 | 9441 | / 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)* | |
| 9417 | 9444 | |
| 9418 | 9445 | SuffixOp |
| 9419 | 9446 | &lt;- LBRACKET Expr (DOT2 Expr?)? RBRACKET |
| ... | ... | @@ -9564,6 +9591,7 @@ TILDE &lt;- '~' skip |
| 9564 | 9591 | |
| 9565 | 9592 | end_of_word &lt;- ![a-zA-Z0-9_] skip |
| 9566 | 9593 | KEYWORD_align &lt;- 'align' end_of_word |
| 9594 | KEYWORD_allowzero &lt;- 'allowzero' end_of_word | |
| 9567 | 9595 | KEYWORD_and &lt;- 'and' end_of_word |
| 9568 | 9596 | KEYWORD_anyerror &lt;- 'anyerror' end_of_word |
| 9569 | 9597 | KEYWORD_asm &lt;- 'asm' end_of_word |
| ... | ... | @@ -9614,7 +9642,7 @@ KEYWORD_var &lt;- 'var' end_of_word |
| 9614 | 9642 | KEYWORD_volatile &lt;- 'volatile' end_of_word |
| 9615 | 9643 | KEYWORD_while &lt;- 'while' end_of_word |
| 9616 | 9644 | |
| 9617 | keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_anyerror / KEYWORD_asm | |
| 9645 | keyword &lt;- KEYWORD_align / KEYWORD_and / KEYWORD_allowzero / KEYWORD_anyerror / KEYWORD_asm | |
| 9618 | 9646 | / KEYWORD_async / KEYWORD_await / KEYWORD_break / KEYWORD_cancel |
| 9619 | 9647 | / KEYWORD_catch / KEYWORD_comptime / KEYWORD_const / KEYWORD_continue |
| 9620 | 9648 | / KEYWORD_defer / KEYWORD_else / KEYWORD_enum / KEYWORD_errdefer |
src/all_types.hpp+2-2| ... | ... | @@ -2668,7 +2668,7 @@ struct IrInstructionPtrType { |
| 2668 | 2668 | PtrLen ptr_len; |
| 2669 | 2669 | bool is_const; |
| 2670 | 2670 | bool is_volatile; |
| 2671 | bool allow_zero; | |
| 2671 | bool is_allow_zero; | |
| 2672 | 2672 | }; |
| 2673 | 2673 | |
| 2674 | 2674 | struct IrInstructionPromiseType { |
| ... | ... | @@ -2684,7 +2684,7 @@ struct IrInstructionSliceType { |
| 2684 | 2684 | IrInstruction *child_type; |
| 2685 | 2685 | bool is_const; |
| 2686 | 2686 | bool is_volatile; |
| 2687 | bool allow_zero; | |
| 2687 | bool is_allow_zero; | |
| 2688 | 2688 | }; |
| 2689 | 2689 | |
| 2690 | 2690 | struct IrInstructionGlobalAsm { |
src/analyze.cpp+11-13| ... | ... | @@ -418,11 +418,9 @@ static const char *ptr_len_to_star_str(PtrLen ptr_len) { |
| 418 | 418 | |
| 419 | 419 | ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const, |
| 420 | 420 | 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) | |
| 422 | 422 | { |
| 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); | |
| 426 | 424 | assert(!type_is_invalid(child_type)); |
| 427 | 425 | assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque); |
| 428 | 426 | |
| ... | ... | @@ -505,7 +503,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons |
| 505 | 503 | bit_offset_in_host != 0 || allow_zero) |
| 506 | 504 | { |
| 507 | 505 | 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); | |
| 509 | 507 | entry->type_ref = peer_type->type_ref; |
| 510 | 508 | entry->di_type = peer_type->di_type; |
| 511 | 509 | } else { |
| ... | ... | @@ -548,7 +546,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons |
| 548 | 546 | } |
| 549 | 547 | |
| 550 | 548 | ZigType *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); | |
| 552 | 550 | } |
| 553 | 551 | |
| 554 | 552 | ZigType *get_promise_frame_type(CodeGen *g, ZigType *return_type) { |
| ... | ... | @@ -857,7 +855,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { |
| 857 | 855 | ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.allow_zero) |
| 858 | 856 | { |
| 859 | 857 | 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); | |
| 861 | 859 | ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type); |
| 862 | 860 | |
| 863 | 861 | slice_type_common_init(g, ptr_type, entry); |
| ... | ... | @@ -881,10 +879,10 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { |
| 881 | 879 | { |
| 882 | 880 | ZigType *grand_child_type = child_ptr_type->data.pointer.child_type; |
| 883 | 881 | 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); | |
| 885 | 883 | ZigType *bland_child_slice = get_slice_type(g, bland_child_ptr_type); |
| 886 | 884 | 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); | |
| 888 | 886 | ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type); |
| 889 | 887 | |
| 890 | 888 | entry->type_ref = peer_slice_type->type_ref; |
| ... | ... | @@ -1419,7 +1417,7 @@ static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_ |
| 1419 | 1417 | |
| 1420 | 1418 | static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **out_buffer) { |
| 1421 | 1419 | 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); | |
| 1423 | 1421 | ZigType *str_type = get_slice_type(g, ptr_type); |
| 1424 | 1422 | ConstExprValue *result_val = analyze_const_value(g, scope, node, str_type, nullptr); |
| 1425 | 1423 | if (type_is_invalid(result_val->type)) |
| ... | ... | @@ -5336,7 +5334,7 @@ void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) { |
| 5336 | 5334 | const_val->special = ConstValSpecialStatic; |
| 5337 | 5335 | // TODO make this `[*]null u8` instead of `[*]u8` |
| 5338 | 5336 | 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); | |
| 5340 | 5338 | const_val->data.x_ptr.special = ConstPtrSpecialBaseArray; |
| 5341 | 5339 | const_val->data.x_ptr.data.base_array.array_val = array_val; |
| 5342 | 5340 | 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 |
| 5481 | 5479 | assert(array_val->type->id == ZigTypeIdArray); |
| 5482 | 5480 | |
| 5483 | 5481 | 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); | |
| 5485 | 5483 | |
| 5486 | 5484 | const_val->special = ConstValSpecialStatic; |
| 5487 | 5485 | const_val->type = get_slice_type(g, ptr_type); |
| ... | ... | @@ -5506,7 +5504,7 @@ void init_const_ptr_array(CodeGen *g, ConstExprValue *const_val, ConstExprValue |
| 5506 | 5504 | |
| 5507 | 5505 | const_val->special = ConstValSpecialStatic; |
| 5508 | 5506 | 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); | |
| 5510 | 5508 | const_val->data.x_ptr.special = ConstPtrSpecialBaseArray; |
| 5511 | 5509 | const_val->data.x_ptr.data.base_array.array_val = array_val; |
| 5512 | 5510 | 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); |
| 18 | 18 | ZigType *new_type_table_entry(ZigTypeId id); |
| 19 | 19 | ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const); |
| 20 | 20 | ZigType *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); | |
| 22 | 24 | uint64_t type_size(CodeGen *g, ZigType *type_entry); |
| 23 | 25 | uint64_t type_size_bits(CodeGen *g, ZigType *type_entry); |
| 24 | 26 | ZigType *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) { |
| 956 | 956 | } |
| 957 | 957 | |
| 958 | 958 | 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); | |
| 960 | 960 | ZigType *str_type = get_slice_type(g, u8_ptr_type); |
| 961 | 961 | return LLVMConstBitCast(val->global_refs->llvm_global, LLVMPointerType(str_type->type_ref, 0)); |
| 962 | 962 | } |
| ... | ... | @@ -1515,7 +1515,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { |
| 1515 | 1515 | |
| 1516 | 1516 | |
| 1517 | 1517 | 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); | |
| 1519 | 1519 | ZigType *str_type = get_slice_type(g, u8_ptr_type); |
| 1520 | 1520 | LLVMValueRef global_slice_fields[] = { |
| 1521 | 1521 | full_buf_ptr, |
| ... | ... | @@ -3103,6 +3103,18 @@ static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executa |
| 3103 | 3103 | static LLVMValueRef ir_render_int_to_ptr(CodeGen *g, IrExecutable *executable, IrInstructionIntToPtr *instruction) { |
| 3104 | 3104 | ZigType *wanted_type = instruction->base.value.type; |
| 3105 | 3105 | 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 | } | |
| 3106 | 3118 | return LLVMBuildIntToPtr(g->builder, target_val, wanted_type->type_ref, ""); |
| 3107 | 3119 | } |
| 3108 | 3120 | |
| ... | ... | @@ -3270,7 +3282,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, |
| 3270 | 3282 | |
| 3271 | 3283 | if (have_init_expr) { |
| 3272 | 3284 | 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); | |
| 3274 | 3286 | LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value); |
| 3275 | 3287 | gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val); |
| 3276 | 3288 | } 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) { |
| 4160 | 4172 | return enum_type->data.enumeration.name_function; |
| 4161 | 4173 | |
| 4162 | 4174 | 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); | |
| 4164 | 4176 | ZigType *u8_slice_type = get_slice_type(g, u8_ptr_type); |
| 4165 | 4177 | ZigType *tag_int_type = enum_type->data.enumeration.tag_int_type; |
| 4166 | 4178 | |
| ... | ... | @@ -4953,7 +4965,7 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, |
| 4953 | 4965 | |
| 4954 | 4966 | ZigType *ptr_type = get_pointer_to_type_extra(g, type_struct_field->type_entry, |
| 4955 | 4967 | 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); | |
| 4957 | 4969 | |
| 4958 | 4970 | gen_assign_raw(g, field_ptr, ptr_type, value); |
| 4959 | 4971 | } |
| ... | ... | @@ -4969,7 +4981,7 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I |
| 4969 | 4981 | uint32_t field_align_bytes = get_abi_alignment(g, type_union_field->type_entry); |
| 4970 | 4982 | ZigType *ptr_type = get_pointer_to_type_extra(g, type_union_field->type_entry, |
| 4971 | 4983 | false, false, PtrLenSingle, field_align_bytes, |
| 4972 | 0, 0); | |
| 4984 | 0, 0, false); | |
| 4973 | 4985 | |
| 4974 | 4986 | LLVMValueRef uncasted_union_ptr; |
| 4975 | 4987 | // 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 |
| 5224 | 5236 | LLVMPositionBuilderAtEnd(g->builder, ok_block); |
| 5225 | 5237 | LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, sret_ptr, err_union_payload_index, ""); |
| 5226 | 5238 | 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); | |
| 5228 | 5240 | ZigType *slice_type = get_slice_type(g, u8_ptr_type); |
| 5229 | 5241 | size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index; |
| 5230 | 5242 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, payload_ptr, ptr_field_index, ""); |
| ... | ... | @@ -6470,7 +6482,7 @@ static void generate_error_name_table(CodeGen *g) { |
| 6470 | 6482 | assert(g->errors_by_index.length > 0); |
| 6471 | 6483 | |
| 6472 | 6484 | 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); | |
| 6474 | 6486 | ZigType *str_type = get_slice_type(g, u8_ptr_type); |
| 6475 | 6487 | |
| 6476 | 6488 | LLVMValueRef *values = allocate<LLVMValueRef>(g->errors_by_index.length); |
| ... | ... | @@ -7551,6 +7563,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { |
| 7551 | 7563 | " is_volatile: bool,\n" |
| 7552 | 7564 | " alignment: comptime_int,\n" |
| 7553 | 7565 | " child: type,\n" |
| 7566 | " is_allowzero: bool,\n" | |
| 7554 | 7567 | "\n" |
| 7555 | 7568 | " pub const Size = enum {\n" |
| 7556 | 7569 | " One,\n" |
| ... | ... | @@ -8158,7 +8171,7 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) { |
| 8158 | 8171 | } |
| 8159 | 8172 | |
| 8160 | 8173 | 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); | |
| 8162 | 8175 | ZigType *str_type = get_slice_type(g, u8_ptr_type); |
| 8163 | 8176 | ZigType *fn_type = get_test_fn_type(g); |
| 8164 | 8177 |
src/ir.cpp+71-43| ... | ... | @@ -1348,7 +1348,7 @@ static IrInstruction *ir_build_br(IrBuilder *irb, Scope *scope, AstNode *source_ |
| 1348 | 1348 | |
| 1349 | 1349 | static IrInstruction *ir_build_ptr_type(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1350 | 1350 | 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) | |
| 1352 | 1352 | { |
| 1353 | 1353 | IrInstructionPtrType *ptr_type_of_instruction = ir_build_instruction<IrInstructionPtrType>(irb, scope, source_node); |
| 1354 | 1354 | ptr_type_of_instruction->align_value = align_value; |
| ... | ... | @@ -1358,6 +1358,7 @@ static IrInstruction *ir_build_ptr_type(IrBuilder *irb, Scope *scope, AstNode *s |
| 1358 | 1358 | ptr_type_of_instruction->ptr_len = ptr_len; |
| 1359 | 1359 | ptr_type_of_instruction->bit_offset_start = bit_offset_start; |
| 1360 | 1360 | ptr_type_of_instruction->host_int_bytes = host_int_bytes; |
| 1361 | ptr_type_of_instruction->is_allow_zero = is_allow_zero; | |
| 1361 | 1362 | |
| 1362 | 1363 | if (align_value) ir_ref_instruction(align_value, irb->current_basic_block); |
| 1363 | 1364 | ir_ref_instruction(child_type, irb->current_basic_block); |
| ... | ... | @@ -1627,13 +1628,14 @@ static IrInstruction *ir_build_promise_type(IrBuilder *irb, Scope *scope, AstNod |
| 1627 | 1628 | } |
| 1628 | 1629 | |
| 1629 | 1630 | static 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) | |
| 1631 | 1632 | { |
| 1632 | 1633 | IrInstructionSliceType *instruction = ir_build_instruction<IrInstructionSliceType>(irb, scope, source_node); |
| 1633 | 1634 | instruction->is_const = is_const; |
| 1634 | 1635 | instruction->is_volatile = is_volatile; |
| 1635 | 1636 | instruction->child_type = child_type; |
| 1636 | 1637 | instruction->align_value = align_value; |
| 1638 | instruction->is_allow_zero = is_allow_zero; | |
| 1637 | 1639 | |
| 1638 | 1640 | ir_ref_instruction(child_type, irb->current_basic_block); |
| 1639 | 1641 | 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 |
| 5192 | 5194 | PtrLen ptr_len = star_token_to_ptr_len(node->data.pointer_type.star_token->id); |
| 5193 | 5195 | bool is_const = node->data.pointer_type.is_const; |
| 5194 | 5196 | bool is_volatile = node->data.pointer_type.is_volatile; |
| 5197 | bool is_allow_zero = node->data.pointer_type.allow_zero_token != nullptr; | |
| 5195 | 5198 | AstNode *expr_node = node->data.pointer_type.op_expr; |
| 5196 | 5199 | AstNode *align_expr = node->data.pointer_type.align_expr; |
| 5197 | 5200 | |
| ... | ... | @@ -5239,7 +5242,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode |
| 5239 | 5242 | } |
| 5240 | 5243 | |
| 5241 | 5244 | 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); | |
| 5243 | 5246 | } |
| 5244 | 5247 | |
| 5245 | 5248 | 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 |
| 5826 | 5829 | AstNode *child_type_node = node->data.array_type.child_type; |
| 5827 | 5830 | bool is_const = node->data.array_type.is_const; |
| 5828 | 5831 | bool is_volatile = node->data.array_type.is_volatile; |
| 5832 | bool is_allow_zero = node->data.array_type.allow_zero_token != nullptr; | |
| 5829 | 5833 | AstNode *align_expr = node->data.array_type.align_expr; |
| 5830 | 5834 | |
| 5831 | 5835 | 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 |
| 5838 | 5842 | add_node_error(irb->codegen, node, buf_create_from_str("volatile qualifier invalid on array type")); |
| 5839 | 5843 | return irb->codegen->invalid_instruction; |
| 5840 | 5844 | } |
| 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 | } | |
| 5841 | 5849 | if (align_expr != nullptr) { |
| 5842 | 5850 | add_node_error(irb->codegen, node, buf_create_from_str("align qualifier invalid on array type")); |
| 5843 | 5851 | return irb->codegen->invalid_instruction; |
| ... | ... | @@ -5866,7 +5874,7 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n |
| 5866 | 5874 | if (child_type == irb->codegen->invalid_instruction) |
| 5867 | 5875 | return child_type; |
| 5868 | 5876 | |
| 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); | |
| 5870 | 5878 | } |
| 5871 | 5879 | } |
| 5872 | 5880 | |
| ... | ... | @@ -7760,7 +7768,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 7760 | 7768 | if (type_has_bits(return_type)) { |
| 7761 | 7769 | IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node, |
| 7762 | 7770 | 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)); | |
| 7764 | 7772 | IrInstruction *result_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr); |
| 7765 | 7773 | IrInstruction *result_ptr_as_u8_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, |
| 7766 | 7774 | result_ptr, false); |
| ... | ... | @@ -7814,7 +7822,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 7814 | 7822 | IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle); |
| 7815 | 7823 | IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node, |
| 7816 | 7824 | 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)); | |
| 7818 | 7826 | IrInstruction *coro_mem_ptr = ir_build_ptr_cast_src(irb, scope, node, u8_ptr_type_unknown_len, |
| 7819 | 7827 | coro_mem_ptr_maybe, false); |
| 7820 | 7828 | 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 |
| 9818 | 9826 | ZigType *ptr_type = get_pointer_to_type_extra( |
| 9819 | 9827 | ira->codegen, prev_inst->value.type->data.array.child_type, |
| 9820 | 9828 | true, false, PtrLenUnknown, |
| 9821 | 0, 0, 0); | |
| 9829 | 0, 0, 0, false); | |
| 9822 | 9830 | ZigType *slice_type = get_slice_type(ira->codegen, ptr_type); |
| 9823 | 9831 | if (err_set_type != nullptr) { |
| 9824 | 9832 | 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 |
| 10243 | 10251 | ConstPtrMut ptr_mut, bool ptr_is_const, bool ptr_is_volatile, uint32_t ptr_align) |
| 10244 | 10252 | { |
| 10245 | 10253 | 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); | |
| 10247 | 10255 | IrInstruction *const_instr = ir_const(ira, instruction, ptr_type); |
| 10248 | 10256 | ConstExprValue *const_val = &const_instr->value; |
| 10249 | 10257 | const_val->data.x_ptr.special = ConstPtrSpecialRef; |
| ... | ... | @@ -10576,7 +10584,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi |
| 10576 | 10584 | } |
| 10577 | 10585 | |
| 10578 | 10586 | 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); | |
| 10580 | 10588 | IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instruction->scope, |
| 10581 | 10589 | source_instruction->source_node, value, is_const, is_volatile); |
| 10582 | 10590 | new_instruction->value.type = ptr_type; |
| ... | ... | @@ -11983,7 +11991,7 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) { |
| 11983 | 11991 | return nullptr; |
| 11984 | 11992 | |
| 11985 | 11993 | 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); | |
| 11987 | 11995 | ZigType *str_type = get_slice_type(ira->codegen, ptr_type); |
| 11988 | 11996 | IrInstruction *casted_value = ir_implicit_cast(ira, value, str_type); |
| 11989 | 11997 | if (type_is_invalid(casted_value->value.type)) |
| ... | ... | @@ -13154,7 +13162,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i |
| 13154 | 13162 | out_array_val = out_val; |
| 13155 | 13163 | } else if (is_slice(op1_type) || is_slice(op2_type)) { |
| 13156 | 13164 | 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); | |
| 13158 | 13166 | result->value.type = get_slice_type(ira->codegen, ptr_type); |
| 13159 | 13167 | out_array_val = create_const_vals(1); |
| 13160 | 13168 | out_array_val->special = ConstValSpecialStatic; |
| ... | ... | @@ -13175,7 +13183,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i |
| 13175 | 13183 | new_len += 1; // null byte |
| 13176 | 13184 | |
| 13177 | 13185 | // 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); | |
| 13179 | 13187 | |
| 13180 | 13188 | out_array_val = create_const_vals(1); |
| 13181 | 13189 | out_array_val->special = ConstValSpecialStatic; |
| ... | ... | @@ -14033,7 +14041,7 @@ no_mem_slot: |
| 14033 | 14041 | IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb, |
| 14034 | 14042 | instruction->scope, instruction->source_node, var); |
| 14035 | 14043 | 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); | |
| 14037 | 14045 | |
| 14038 | 14046 | bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); |
| 14039 | 14047 | 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 |
| 14328 | 14336 | IrInstruction *casted_new_stack = nullptr; |
| 14329 | 14337 | if (call_instruction->new_stack != nullptr) { |
| 14330 | 14338 | 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); | |
| 14332 | 14340 | ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); |
| 14333 | 14341 | IrInstruction *new_stack = call_instruction->new_stack->child; |
| 14334 | 14342 | 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 |
| 15262 | 15270 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, |
| 15263 | 15271 | ptr_type->data.pointer.ptr_len, |
| 15264 | 15272 | 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); | |
| 15266 | 15275 | } |
| 15267 | 15276 | |
| 15268 | 15277 | 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) { |
| 15279 | 15288 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, |
| 15280 | 15289 | ptr_len, |
| 15281 | 15290 | 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); | |
| 15283 | 15293 | } |
| 15284 | 15294 | |
| 15285 | 15295 | 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 |
| 15330 | 15340 | return_type = get_pointer_to_type_extra(ira->codegen, child_type, |
| 15331 | 15341 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, |
| 15332 | 15342 | elem_ptr_instruction->ptr_len, |
| 15333 | ptr_type->data.pointer.explicit_alignment, 0, 0); | |
| 15343 | ptr_type->data.pointer.explicit_alignment, 0, 0, false); | |
| 15334 | 15344 | } else { |
| 15335 | 15345 | uint64_t elem_val_scalar; |
| 15336 | 15346 | if (!ir_resolve_usize(ira, elem_index, &elem_val_scalar)) |
| ... | ... | @@ -15342,7 +15352,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 15342 | 15352 | return_type = get_pointer_to_type_extra(ira->codegen, child_type, |
| 15343 | 15353 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, |
| 15344 | 15354 | 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); | |
| 15346 | 15356 | } |
| 15347 | 15357 | } else if (array_type->id == ZigTypeIdPointer) { |
| 15348 | 15358 | if (array_type->data.pointer.ptr_len == PtrLenSingle) { |
| ... | ... | @@ -15693,7 +15703,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ |
| 15693 | 15703 | ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry, |
| 15694 | 15704 | is_const, is_volatile, PtrLenSingle, align_bytes, |
| 15695 | 15705 | (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); | |
| 15697 | 15707 | IrInstruction *result = ir_const(ira, source_instr, ptr_type); |
| 15698 | 15708 | ConstExprValue *const_val = &result->value; |
| 15699 | 15709 | const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct; |
| ... | ... | @@ -15709,7 +15719,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ |
| 15709 | 15719 | PtrLenSingle, |
| 15710 | 15720 | align_bytes, |
| 15711 | 15721 | (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); | |
| 15713 | 15723 | return result; |
| 15714 | 15724 | } else { |
| 15715 | 15725 | 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_ |
| 15748 | 15758 | |
| 15749 | 15759 | ZigType *field_type = field->type_entry; |
| 15750 | 15760 | 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); | |
| 15752 | 15762 | |
| 15753 | 15763 | IrInstruction *result = ir_const(ira, source_instr, ptr_type); |
| 15754 | 15764 | ConstExprValue *const_val = &result->value; |
| ... | ... | @@ -15761,7 +15771,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ |
| 15761 | 15771 | |
| 15762 | 15772 | IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, container_ptr, field); |
| 15763 | 15773 | 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); | |
| 15765 | 15775 | return result; |
| 15766 | 15776 | } else { |
| 15767 | 15777 | 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, |
| 16480 | 16490 | |
| 16481 | 16491 | bool is_const = slice_type_instruction->is_const; |
| 16482 | 16492 | bool is_volatile = slice_type_instruction->is_volatile; |
| 16493 | bool is_allow_zero = slice_type_instruction->is_allow_zero; | |
| 16483 | 16494 | |
| 16484 | 16495 | switch (child_type->id) { |
| 16485 | 16496 | case ZigTypeIdInvalid: // handled above |
| ... | ... | @@ -16516,7 +16527,7 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, |
| 16516 | 16527 | if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown))) |
| 16517 | 16528 | return ira->codegen->invalid_instruction; |
| 16518 | 16529 | 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); | |
| 16520 | 16531 | ZigType *result_type = get_slice_type(ira->codegen, slice_ptr_type); |
| 16521 | 16532 | return ir_const_type(ira, &slice_type_instruction->base, result_type); |
| 16522 | 16533 | } |
| ... | ... | @@ -16749,7 +16760,7 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr |
| 16749 | 16760 | |
| 16750 | 16761 | ZigType *child_type = type_entry->data.maybe.child_type; |
| 16751 | 16762 | 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); | |
| 16753 | 16764 | |
| 16754 | 16765 | if (instr_is_comptime(base_ptr)) { |
| 16755 | 16766 | ConstExprValue *val = ir_resolve_const(ira, base_ptr, UndefBad); |
| ... | ... | @@ -17668,7 +17679,7 @@ static IrInstruction *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruct |
| 17668 | 17679 | return ira->codegen->invalid_instruction; |
| 17669 | 17680 | |
| 17670 | 17681 | 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); | |
| 17672 | 17683 | ZigType *str_type = get_slice_type(ira->codegen, u8_ptr_type); |
| 17673 | 17684 | if (casted_value->value.special == ConstValSpecialStatic) { |
| 17674 | 17685 | ErrorTableEntry *err = casted_value->value.data.x_err_set; |
| ... | ... | @@ -17713,7 +17724,7 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns |
| 17713 | 17724 | ZigType *u8_ptr_type = get_pointer_to_type_extra( |
| 17714 | 17725 | ira->codegen, ira->codegen->builtin_types.entry_u8, |
| 17715 | 17726 | true, false, PtrLenUnknown, |
| 17716 | 0, 0, 0); | |
| 17727 | 0, 0, 0, false); | |
| 17717 | 17728 | result->value.type = get_slice_type(ira->codegen, u8_ptr_type); |
| 17718 | 17729 | return result; |
| 17719 | 17730 | } |
| ... | ... | @@ -17767,7 +17778,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, |
| 17767 | 17778 | field_ptr->value.type->data.pointer.is_const, |
| 17768 | 17779 | field_ptr->value.type->data.pointer.is_volatile, |
| 17769 | 17780 | PtrLenSingle, |
| 17770 | field_ptr_align, 0, 0); | |
| 17781 | field_ptr_align, 0, 0, false); | |
| 17771 | 17782 | IrInstruction *casted_field_ptr = ir_implicit_cast(ira, field_ptr, field_ptr_type); |
| 17772 | 17783 | if (type_is_invalid(casted_field_ptr->value.type)) |
| 17773 | 17784 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -17776,7 +17787,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, |
| 17776 | 17787 | casted_field_ptr->value.type->data.pointer.is_const, |
| 17777 | 17788 | casted_field_ptr->value.type->data.pointer.is_volatile, |
| 17778 | 17789 | PtrLenSingle, |
| 17779 | parent_ptr_align, 0, 0); | |
| 17790 | parent_ptr_align, 0, 0, false); | |
| 17780 | 17791 | |
| 17781 | 17792 | if (instr_is_comptime(casted_field_ptr)) { |
| 17782 | 17793 | 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, |
| 18112 | 18123 | ZigType *u8_ptr = get_pointer_to_type_extra( |
| 18113 | 18124 | ira->codegen, ira->codegen->builtin_types.entry_u8, |
| 18114 | 18125 | true, false, PtrLenUnknown, |
| 18115 | 0, 0, 0); | |
| 18126 | 0, 0, 0, false); | |
| 18116 | 18127 | fn_def_fields[6].type = get_optional_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr)); |
| 18117 | 18128 | if (fn_node->is_extern && buf_len(fn_node->lib_name) > 0) { |
| 18118 | 18129 | 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 |
| 18216 | 18227 | result->special = ConstValSpecialStatic; |
| 18217 | 18228 | result->type = type_info_pointer_type; |
| 18218 | 18229 | |
| 18219 | ConstExprValue *fields = create_const_vals(5); | |
| 18230 | ConstExprValue *fields = create_const_vals(6); | |
| 18220 | 18231 | result->data.x_struct.fields = fields; |
| 18221 | 18232 | |
| 18222 | 18233 | // size: Size |
| ... | ... | @@ -18247,6 +18258,11 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty |
| 18247 | 18258 | fields[4].special = ConstValSpecialStatic; |
| 18248 | 18259 | fields[4].type = ira->codegen->builtin_types.entry_type; |
| 18249 | 18260 | 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; | |
| 18250 | 18266 | |
| 18251 | 18267 | return result; |
| 18252 | 18268 | }; |
| ... | ... | @@ -19473,12 +19489,12 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru |
| 19473 | 19489 | |
| 19474 | 19490 | ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_child_type, |
| 19475 | 19491 | src_ptr_const, src_ptr_volatile, PtrLenUnknown, |
| 19476 | src_ptr_align, 0, 0); | |
| 19492 | src_ptr_align, 0, 0, false); | |
| 19477 | 19493 | ZigType *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type); |
| 19478 | 19494 | |
| 19479 | 19495 | ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, |
| 19480 | 19496 | src_ptr_const, src_ptr_volatile, PtrLenUnknown, |
| 19481 | src_ptr_align, 0, 0); | |
| 19497 | src_ptr_align, 0, 0, false); | |
| 19482 | 19498 | ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); |
| 19483 | 19499 | |
| 19484 | 19500 | IrInstruction *casted_value = ir_implicit_cast(ira, target, u8_slice); |
| ... | ... | @@ -19545,7 +19561,7 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct |
| 19545 | 19561 | |
| 19546 | 19562 | ZigType *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, |
| 19547 | 19563 | src_ptr_type->data.pointer.is_const, src_ptr_type->data.pointer.is_volatile, PtrLenUnknown, |
| 19548 | alignment, 0, 0); | |
| 19564 | alignment, 0, 0, false); | |
| 19549 | 19565 | ZigType *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type); |
| 19550 | 19566 | |
| 19551 | 19567 | if (instr_is_comptime(target)) { |
| ... | ... | @@ -19773,7 +19789,7 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio |
| 19773 | 19789 | dest_align = get_abi_alignment(ira->codegen, u8); |
| 19774 | 19790 | } |
| 19775 | 19791 | 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); | |
| 19777 | 19793 | |
| 19778 | 19794 | IrInstruction *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr); |
| 19779 | 19795 | if (type_is_invalid(casted_dest_ptr->value.type)) |
| ... | ... | @@ -19895,9 +19911,9 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio |
| 19895 | 19911 | |
| 19896 | 19912 | ZigType *usize = ira->codegen->builtin_types.entry_usize; |
| 19897 | 19913 | 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); | |
| 19899 | 19915 | 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); | |
| 19901 | 19917 | |
| 19902 | 19918 | IrInstruction *casted_dest_ptr = ir_implicit_cast(ira, dest_ptr, u8_ptr_mut); |
| 19903 | 19919 | if (type_is_invalid(casted_dest_ptr->value.type)) |
| ... | ... | @@ -20061,7 +20077,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 20061 | 20077 | ptr_ptr_type->data.pointer.is_const || is_comptime_const, |
| 20062 | 20078 | ptr_ptr_type->data.pointer.is_volatile, |
| 20063 | 20079 | PtrLenUnknown, |
| 20064 | ptr_ptr_type->data.pointer.explicit_alignment, 0, 0); | |
| 20080 | ptr_ptr_type->data.pointer.explicit_alignment, 0, 0, false); | |
| 20065 | 20081 | return_type = get_slice_type(ira->codegen, slice_ptr_type); |
| 20066 | 20082 | } else if (array_type->id == ZigTypeIdPointer) { |
| 20067 | 20083 | if (array_type->data.pointer.ptr_len == PtrLenSingle) { |
| ... | ... | @@ -20071,7 +20087,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 20071 | 20087 | main_type->data.pointer.child_type, |
| 20072 | 20088 | array_type->data.pointer.is_const, array_type->data.pointer.is_volatile, |
| 20073 | 20089 | PtrLenUnknown, |
| 20074 | array_type->data.pointer.explicit_alignment, 0, 0); | |
| 20090 | array_type->data.pointer.explicit_alignment, 0, 0, false); | |
| 20075 | 20091 | return_type = get_slice_type(ira->codegen, slice_ptr_type); |
| 20076 | 20092 | } else { |
| 20077 | 20093 | 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 |
| 20586 | 20602 | expected_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_type, |
| 20587 | 20603 | false, result_ptr->value.type->data.pointer.is_volatile, |
| 20588 | 20604 | PtrLenSingle, |
| 20589 | alignment, 0, 0); | |
| 20605 | alignment, 0, 0, false); | |
| 20590 | 20606 | } else { |
| 20591 | 20607 | expected_ptr_type = get_pointer_to_type(ira->codegen, dest_type, false); |
| 20592 | 20608 | } |
| ... | ... | @@ -20753,7 +20769,7 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, |
| 20753 | 20769 | |
| 20754 | 20770 | ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type, |
| 20755 | 20771 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, |
| 20756 | PtrLenSingle, 0, 0, 0); | |
| 20772 | PtrLenSingle, 0, 0, 0, false); | |
| 20757 | 20773 | if (instr_is_comptime(value)) { |
| 20758 | 20774 | ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); |
| 20759 | 20775 | if (!ptr_val) |
| ... | ... | @@ -21125,7 +21141,7 @@ static IrInstruction *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstruction |
| 21125 | 21141 | } |
| 21126 | 21142 | |
| 21127 | 21143 | 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); | |
| 21129 | 21145 | ZigType *str_type = get_slice_type(ira->codegen, u8_ptr_type); |
| 21130 | 21146 | IrInstruction *casted_msg = ir_implicit_cast(ira, msg, str_type); |
| 21131 | 21147 | if (type_is_invalid(casted_msg->value.type)) |
| ... | ... | @@ -21794,10 +21810,17 @@ static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *sourc |
| 21794 | 21810 | if (!val) |
| 21795 | 21811 | return ira->codegen->invalid_instruction; |
| 21796 | 21812 | |
| 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 | ||
| 21797 | 21820 | IrInstruction *result = ir_const(ira, source_instr, ptr_type); |
| 21798 | 21821 | result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; |
| 21799 | 21822 | 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; | |
| 21801 | 21824 | return result; |
| 21802 | 21825 | } |
| 21803 | 21826 | |
| ... | ... | @@ -21951,6 +21974,9 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct |
| 21951 | 21974 | } else if (child_type->id == ZigTypeIdOpaque) { |
| 21952 | 21975 | ir_add_error(ira, &instruction->base, buf_sprintf("C pointers cannot point opaque types")); |
| 21953 | 21976 | 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; | |
| 21954 | 21980 | } |
| 21955 | 21981 | } |
| 21956 | 21982 | |
| ... | ... | @@ -21969,10 +21995,12 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct |
| 21969 | 21995 | align_bytes = 0; |
| 21970 | 21996 | } |
| 21971 | 21997 | |
| 21998 | bool allow_zero = instruction->is_allow_zero || instruction->ptr_len == PtrLenC; | |
| 21999 | ||
| 21972 | 22000 | ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type, |
| 21973 | 22001 | instruction->is_const, instruction->is_volatile, |
| 21974 | 22002 | 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); | |
| 21976 | 22004 | return ir_const_type(ira, &instruction->base, result_type); |
| 21977 | 22005 | } |
| 21978 | 22006 |
src/parser.cpp+12-1| ... | ... | @@ -2530,6 +2530,12 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) { |
| 2530 | 2530 | if (array != nullptr) { |
| 2531 | 2531 | assert(array->type == NodeTypeArrayType); |
| 2532 | 2532 | 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 | ||
| 2533 | 2539 | AstNode *align_expr = ast_parse_byte_align(pc); |
| 2534 | 2540 | if (align_expr != nullptr) { |
| 2535 | 2541 | array->data.array_type.align_expr = align_expr; |
| ... | ... | @@ -2545,7 +2551,6 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) { |
| 2545 | 2551 | array->data.array_type.is_volatile = true; |
| 2546 | 2552 | continue; |
| 2547 | 2553 | } |
| 2548 | ||
| 2549 | 2554 | break; |
| 2550 | 2555 | } |
| 2551 | 2556 | |
| ... | ... | @@ -2560,6 +2565,12 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) { |
| 2560 | 2565 | if (child == nullptr) |
| 2561 | 2566 | child = ptr; |
| 2562 | 2567 | 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 | ||
| 2563 | 2574 | if (eat_token_if(pc, TokenIdKeywordAlign) != nullptr) { |
| 2564 | 2575 | expect_token(pc, TokenIdLParen); |
| 2565 | 2576 | AstNode *align_expr = ast_parse_expr(pc); |
src/tokenizer.cpp+2| ... | ... | @@ -107,6 +107,7 @@ struct ZigKeyword { |
| 107 | 107 | |
| 108 | 108 | static const struct ZigKeyword zig_keywords[] = { |
| 109 | 109 | {"align", TokenIdKeywordAlign}, |
| 110 | {"allowzero", TokenIdKeywordAllowZero}, | |
| 110 | 111 | {"and", TokenIdKeywordAnd}, |
| 111 | 112 | {"anyerror", TokenIdKeywordAnyerror}, |
| 112 | 113 | {"asm", TokenIdKeywordAsm}, |
| ... | ... | @@ -1495,6 +1496,7 @@ const char * token_name(TokenId id) { |
| 1495 | 1496 | case TokenIdIntLiteral: return "IntLiteral"; |
| 1496 | 1497 | case TokenIdKeywordAsync: return "async"; |
| 1497 | 1498 | case TokenIdKeywordAnyerror: return "anyerror"; |
| 1499 | case TokenIdKeywordAllowZero: return "allowzero"; | |
| 1498 | 1500 | case TokenIdKeywordAwait: return "await"; |
| 1499 | 1501 | case TokenIdKeywordResume: return "resume"; |
| 1500 | 1502 | case TokenIdKeywordSuspend: return "suspend"; |
src/tokenizer.hpp+2-1| ... | ... | @@ -50,6 +50,7 @@ enum TokenId { |
| 50 | 50 | TokenIdFloatLiteral, |
| 51 | 51 | TokenIdIntLiteral, |
| 52 | 52 | TokenIdKeywordAlign, |
| 53 | TokenIdKeywordAllowZero, | |
| 53 | 54 | TokenIdKeywordAnd, |
| 54 | 55 | TokenIdKeywordAnyerror, |
| 55 | 56 | TokenIdKeywordAsm, |
| ... | ... | @@ -73,6 +74,7 @@ enum TokenId { |
| 73 | 74 | TokenIdKeywordFor, |
| 74 | 75 | TokenIdKeywordIf, |
| 75 | 76 | TokenIdKeywordInline, |
| 77 | TokenIdKeywordLinkSection, | |
| 76 | 78 | TokenIdKeywordNakedCC, |
| 77 | 79 | TokenIdKeywordNoAlias, |
| 78 | 80 | TokenIdKeywordNull, |
| ... | ... | @@ -83,7 +85,6 @@ enum TokenId { |
| 83 | 85 | TokenIdKeywordPub, |
| 84 | 86 | TokenIdKeywordResume, |
| 85 | 87 | TokenIdKeywordReturn, |
| 86 | TokenIdKeywordLinkSection, | |
| 87 | 88 | TokenIdKeywordStdcallCC, |
| 88 | 89 | TokenIdKeywordStruct, |
| 89 | 90 | TokenIdKeywordSuspend, |
std/zig/ast.zig+5| ... | ... | @@ -125,6 +125,7 @@ pub const Error = union(enum) { |
| 125 | 125 | ExtraAlignQualifier: ExtraAlignQualifier, |
| 126 | 126 | ExtraConstQualifier: ExtraConstQualifier, |
| 127 | 127 | ExtraVolatileQualifier: ExtraVolatileQualifier, |
| 128 | ExtraAllowZeroQualifier: ExtraAllowZeroQualifier, | |
| 128 | 129 | ExpectedPrimaryExpr: ExpectedPrimaryExpr, |
| 129 | 130 | ExpectedToken: ExpectedToken, |
| 130 | 131 | ExpectedCommaOrEnd: ExpectedCommaOrEnd, |
| ... | ... | @@ -149,6 +150,7 @@ pub const Error = union(enum) { |
| 149 | 150 | @TagType(Error).ExtraAlignQualifier => |*x| return x.render(tokens, stream), |
| 150 | 151 | @TagType(Error).ExtraConstQualifier => |*x| return x.render(tokens, stream), |
| 151 | 152 | @TagType(Error).ExtraVolatileQualifier => |*x| return x.render(tokens, stream), |
| 153 | @TagType(Error).ExtraAllowZeroQualifier => |*x| return x.render(tokens, stream), | |
| 152 | 154 | @TagType(Error).ExpectedPrimaryExpr => |*x| return x.render(tokens, stream), |
| 153 | 155 | @TagType(Error).ExpectedToken => |*x| return x.render(tokens, stream), |
| 154 | 156 | @TagType(Error).ExpectedCommaOrEnd => |*x| return x.render(tokens, stream), |
| ... | ... | @@ -175,6 +177,7 @@ pub const Error = union(enum) { |
| 175 | 177 | @TagType(Error).ExtraAlignQualifier => |x| return x.token, |
| 176 | 178 | @TagType(Error).ExtraConstQualifier => |x| return x.token, |
| 177 | 179 | @TagType(Error).ExtraVolatileQualifier => |x| return x.token, |
| 180 | @TagType(Error).ExtraAllowZeroQualifier => |x| return x.token, | |
| 178 | 181 | @TagType(Error).ExpectedPrimaryExpr => |x| return x.token, |
| 179 | 182 | @TagType(Error).ExpectedToken => |x| return x.token, |
| 180 | 183 | @TagType(Error).ExpectedCommaOrEnd => |x| return x.token, |
| ... | ... | @@ -198,6 +201,7 @@ pub const Error = union(enum) { |
| 198 | 201 | pub const ExtraAlignQualifier = SimpleError("Extra align qualifier"); |
| 199 | 202 | pub const ExtraConstQualifier = SimpleError("Extra const qualifier"); |
| 200 | 203 | pub const ExtraVolatileQualifier = SimpleError("Extra volatile qualifier"); |
| 204 | pub const ExtraAllowZeroQualifier = SimpleError("Extra allowzero qualifier"); | |
| 201 | 205 | |
| 202 | 206 | pub const ExpectedCall = struct { |
| 203 | 207 | node: *Node, |
| ... | ... | @@ -1540,6 +1544,7 @@ pub const Node = struct { |
| 1540 | 1544 | }; |
| 1541 | 1545 | |
| 1542 | 1546 | pub const PtrInfo = struct { |
| 1547 | allowzero_token: ?TokenIndex, | |
| 1543 | 1548 | align_info: ?Align, |
| 1544 | 1549 | const_token: ?TokenIndex, |
| 1545 | 1550 | volatile_token: ?TokenIndex, |
std/zig/parse.zig+11| ... | ... | @@ -1688,6 +1688,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { |
| 1688 | 1688 | .align_info = null, |
| 1689 | 1689 | .const_token = null, |
| 1690 | 1690 | .volatile_token = null, |
| 1691 | .allowzero_token = null, | |
| 1691 | 1692 | }, |
| 1692 | 1693 | }; |
| 1693 | 1694 | 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 { |
| 1743 | 1744 | addr_of_info.volatile_token = token_index; |
| 1744 | 1745 | continue; |
| 1745 | 1746 | }, |
| 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 | }, | |
| 1746 | 1756 | else => { |
| 1747 | 1757 | prevToken(&tok_it, &tree); |
| 1748 | 1758 | continue; |
| ... | ... | @@ -3552,6 +3562,7 @@ fn tokenIdToPrefixOp(id: Token.Id) ?ast.Node.PrefixOp.Op { |
| 3552 | 3562 | .align_info = null, |
| 3553 | 3563 | .const_token = null, |
| 3554 | 3564 | .volatile_token = null, |
| 3565 | .allowzero_token = null, | |
| 3555 | 3566 | }, |
| 3556 | 3567 | }, |
| 3557 | 3568 | Token.Id.QuestionMark => ast.Node.PrefixOp.Op{ .OptionalType = void{} }, |
std/zig/parser_test.zig+7| ... | ... | @@ -1,3 +1,10 @@ |
| 1 | test "zig fmt: allowzero pointer" { | |
| 2 | try testCanonical( | |
| 3 | \\const T = [*]allowzero const u8; | |
| 4 | \\ | |
| 5 | ); | |
| 6 | } | |
| 7 | ||
| 1 | 8 | test "zig fmt: enum literal" { |
| 2 | 9 | try testCanonical( |
| 3 | 10 | \\const x = .hi; |
std/zig/render.zig+6| ... | ... | @@ -379,6 +379,9 @@ fn renderExpression( |
| 379 | 379 | else => usize(0), |
| 380 | 380 | }; |
| 381 | 381 | 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 | } | |
| 382 | 385 | if (ptr_info.align_info) |align_info| { |
| 383 | 386 | const lparen_token = tree.prevToken(align_info.node.firstToken()); |
| 384 | 387 | const align_token = tree.prevToken(lparen_token); |
| ... | ... | @@ -416,6 +419,9 @@ fn renderExpression( |
| 416 | 419 | try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None); // [ |
| 417 | 420 | try renderToken(tree, stream, tree.nextToken(prefix_op_node.op_token), indent, start_col, Space.None); // ] |
| 418 | 421 | |
| 422 | if (ptr_info.allowzero_token) |allowzero_token| { | |
| 423 | try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero | |
| 424 | } | |
| 419 | 425 | if (ptr_info.align_info) |align_info| { |
| 420 | 426 | const lparen_token = tree.prevToken(align_info.node.firstToken()); |
| 421 | 427 | const align_token = tree.prevToken(lparen_token); |
std/zig/tokenizer.zig+2| ... | ... | @@ -13,6 +13,7 @@ pub const Token = struct { |
| 13 | 13 | |
| 14 | 14 | pub const keywords = []Keyword{ |
| 15 | 15 | Keyword{ .bytes = "align", .id = Id.Keyword_align }, |
| 16 | Keyword{ .bytes = "allowzero", .id = Id.Keyword_allowzero }, | |
| 16 | 17 | Keyword{ .bytes = "and", .id = Id.Keyword_and }, |
| 17 | 18 | Keyword{ .bytes = "anyerror", .id = Id.Keyword_anyerror }, |
| 18 | 19 | Keyword{ .bytes = "asm", .id = Id.Keyword_asm }, |
| ... | ... | @@ -143,6 +144,7 @@ pub const Token = struct { |
| 143 | 144 | BracketStarCBracket, |
| 144 | 145 | ShebangLine, |
| 145 | 146 | Keyword_align, |
| 147 | Keyword_allowzero, | |
| 146 | 148 | Keyword_and, |
| 147 | 149 | Keyword_anyerror, |
| 148 | 150 | Keyword_asm, |
test/compile_errors.zig+9| ... | ... | @@ -2,6 +2,15 @@ const tests = @import("tests.zig"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | 4 | pub 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 | ||
| 5 | 14 | cases.add( |
| 6 | 15 | "cast enum literal to enum but it doesn't match", |
| 7 | 16 | \\const Foo = enum { |
test/runtime_safety.zig+10| ... | ... | @@ -1,6 +1,16 @@ |
| 1 | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | |
| 3 | 3 | pub 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 | ||
| 4 | 14 | cases.addRuntimeSafety("pointer casting null to non-optional pointer", |
| 5 | 15 | \\pub fn panic(message: []const u8, stack_trace: ?*@import("builtin").StackTrace) noreturn { |
| 6 | 16 | \\ @import("std").os.exit(126); |
test/stage1/behavior/pointers.zig+13| ... | ... | @@ -137,3 +137,16 @@ test "compare equality of optional and non-optional pointer" { |
| 137 | 137 | expect(a == b); |
| 138 | 138 | expect(b == a); |
| 139 | 139 | } |
| 140 | ||
| 141 | test "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 | } |