| author | |
| committer | |
| log | 26f3c2d0614f4fb37752b1931cb0b43aed2696d2 |
| tree | 18e51d6ed267ded8c6d87b5158c8866dcf1a2bf6 |
| parent | 51cbd968203f348051b8c2bdc005ca5294a79ceb |
| signature | Commit is signed but in an unrecognized format. |
see #37709 files changed, 119 insertions(+), 39 deletions(-)
lib/std/buffer.zig+2-2| ... | ... | @@ -82,11 +82,11 @@ pub const Buffer = struct { |
| 82 | 82 | } |
| 83 | 83 | |
| 84 | 84 | pub fn toSlice(self: Buffer) [:0]u8 { |
| 85 | return self.list.toSlice()[0..self.len()]; | |
| 85 | return self.list.toSlice()[0..self.len() :0]; | |
| 86 | 86 | } |
| 87 | 87 | |
| 88 | 88 | pub fn toSliceConst(self: Buffer) [:0]const u8 { |
| 89 | return self.list.toSliceConst()[0..self.len()]; | |
| 89 | return self.list.toSliceConst()[0..self.len() :0]; | |
| 90 | 90 | } |
| 91 | 91 | |
| 92 | 92 | pub fn shrink(self: *Buffer, new_len: usize) void { |
lib/std/cstr.zig+10-2| ... | ... | @@ -31,13 +31,21 @@ fn testCStrFnsImpl() void { |
| 31 | 31 | testing.expect(mem.len(u8, "123456789") == 9); |
| 32 | 32 | } |
| 33 | 33 | |
| 34 | /// Returns a mutable slice with 1 more byte of length which is a null byte. | |
| 34 | /// Returns a mutable, null-terminated slice with the same length as `slice`. | |
| 35 | 35 | /// Caller owns the returned memory. |
| 36 | 36 | pub fn addNullByte(allocator: *mem.Allocator, slice: []const u8) ![:0]u8 { |
| 37 | 37 | const result = try allocator.alloc(u8, slice.len + 1); |
| 38 | 38 | mem.copy(u8, result, slice); |
| 39 | 39 | result[slice.len] = 0; |
| 40 | return result; | |
| 40 | return result[0..slice.len :0]; | |
| 41 | } | |
| 42 | ||
| 43 | test "addNullByte" { | |
| 44 | var buf: [30]u8 = undefined; | |
| 45 | const allocator = &std.heap.FixedBufferAllocator.init(&buf).allocator; | |
| 46 | const slice = try addNullByte(allocator, "hello"[0..4]); | |
| 47 | testing.expect(slice.len == 4); | |
| 48 | testing.expect(slice[4] == 0); | |
| 41 | 49 | } |
| 42 | 50 | |
| 43 | 51 | pub const NullTerminated2DArray = struct { |
lib/std/fs.zig+4-5| ... | ... | @@ -221,16 +221,16 @@ pub const AtomicFile = struct { |
| 221 | 221 | } |
| 222 | 222 | |
| 223 | 223 | tmp_path_buf[tmp_path_len] = 0; |
| 224 | const tmp_path_slice = tmp_path_buf[0..tmp_path_len :0]; | |
| 224 | 225 | |
| 225 | 226 | const my_cwd = cwd(); |
| 226 | 227 | |
| 227 | 228 | while (true) { |
| 228 | 229 | try crypto.randomBytes(rand_buf[0..]); |
| 229 | b64_fs_encoder.encode(tmp_path_buf[dirname_component_len..tmp_path_len], &rand_buf); | |
| 230 | b64_fs_encoder.encode(tmp_path_slice[dirname_component_len..tmp_path_len], &rand_buf); | |
| 230 | 231 | |
| 231 | // TODO https://github.com/ziglang/zig/issues/3770 to clean up this @ptrCast | |
| 232 | 232 | const file = my_cwd.createFileC( |
| 233 | @ptrCast([*:0]u8, &tmp_path_buf), | |
| 233 | tmp_path_slice, | |
| 234 | 234 | .{ .mode = mode, .exclusive = true }, |
| 235 | 235 | ) catch |err| switch (err) { |
| 236 | 236 | error.PathAlreadyExists => continue, |
| ... | ... | @@ -1488,8 +1488,7 @@ pub fn openSelfExe() OpenSelfExeError!File { |
| 1488 | 1488 | var buf: [MAX_PATH_BYTES]u8 = undefined; |
| 1489 | 1489 | const self_exe_path = try selfExePath(&buf); |
| 1490 | 1490 | buf[self_exe_path.len] = 0; |
| 1491 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 | |
| 1492 | return openFileAbsoluteC(@ptrCast([*:0]u8, self_exe_path.ptr), .{}); | |
| 1491 | return openFileAbsoluteC(self_exe_path[0..self_exe_path.len :0].ptr, .{}); | |
| 1493 | 1492 | } |
| 1494 | 1493 | |
| 1495 | 1494 | test "openSelfExe" { |
lib/std/mem.zig+3-2| ... | ... | @@ -231,9 +231,10 @@ pub const Allocator = struct { |
| 231 | 231 | pub fn free(self: *Allocator, memory: var) void { |
| 232 | 232 | const Slice = @typeInfo(@TypeOf(memory)).Pointer; |
| 233 | 233 | const bytes = @sliceToBytes(memory); |
| 234 | if (bytes.len == 0) return; | |
| 234 | const bytes_len = bytes.len + @boolToInt(Slice.sentinel != null); | |
| 235 | if (bytes_len == 0) return; | |
| 235 | 236 | const non_const_ptr = @intToPtr([*]u8, @ptrToInt(bytes.ptr)); |
| 236 | const shrink_result = self.shrinkFn(self, non_const_ptr[0..bytes.len], Slice.alignment, 0, 1); | |
| 237 | const shrink_result = self.shrinkFn(self, non_const_ptr[0..bytes_len], Slice.alignment, 0, 1); | |
| 237 | 238 | assert(shrink_result.len == 0); |
| 238 | 239 | } |
| 239 | 240 | }; |
lib/std/os.zig+9-16| ... | ... | @@ -805,9 +805,9 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, e |
| 805 | 805 | mem.copy(u8, &path_buf, search_path); |
| 806 | 806 | path_buf[search_path.len] = '/'; |
| 807 | 807 | mem.copy(u8, path_buf[search_path.len + 1 ..], file_slice); |
| 808 | path_buf[search_path.len + file_slice.len + 1] = 0; | |
| 809 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 | |
| 810 | err = execveC(@ptrCast([*:0]u8, &path_buf), child_argv, envp); | |
| 808 | const path_len = search_path.len + file_slice.len + 1; | |
| 809 | path_buf[path_len] = 0; | |
| 810 | err = execveC(path_buf[0..path_len :0].ptr, child_argv, envp); | |
| 811 | 811 | switch (err) { |
| 812 | 812 | error.AccessDenied => seen_eacces = true, |
| 813 | 813 | error.FileNotFound, error.NotDir => {}, |
| ... | ... | @@ -841,18 +841,14 @@ pub fn execvpe( |
| 841 | 841 | const arg_buf = try allocator.alloc(u8, arg.len + 1); |
| 842 | 842 | @memcpy(arg_buf.ptr, arg.ptr, arg.len); |
| 843 | 843 | arg_buf[arg.len] = 0; |
| 844 | ||
| 845 | // TODO avoid @ptrCast using slice syntax with https://github.com/ziglang/zig/issues/3770 | |
| 846 | argv_buf[i] = @ptrCast([*:0]u8, arg_buf.ptr); | |
| 844 | argv_buf[i] = arg_buf[0..arg.len :0].ptr; | |
| 847 | 845 | } |
| 848 | 846 | argv_buf[argv_slice.len] = null; |
| 847 | const argv_ptr = argv_buf[0..argv_slice.len :null].ptr; | |
| 849 | 848 | |
| 850 | 849 | const envp_buf = try createNullDelimitedEnvMap(allocator, env_map); |
| 851 | 850 | defer freeNullDelimitedEnvMap(allocator, envp_buf); |
| 852 | 851 | |
| 853 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 | |
| 854 | const argv_ptr = @ptrCast([*:null]?[*:0]u8, argv_buf.ptr); | |
| 855 | ||
| 856 | 852 | return execvpeC(argv_buf.ptr[0].?, argv_ptr, envp_buf.ptr); |
| 857 | 853 | } |
| 858 | 854 | |
| ... | ... | @@ -869,16 +865,13 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std. |
| 869 | 865 | @memcpy(env_buf.ptr, pair.key.ptr, pair.key.len); |
| 870 | 866 | env_buf[pair.key.len] = '='; |
| 871 | 867 | @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len); |
| 872 | env_buf[env_buf.len - 1] = 0; | |
| 873 | ||
| 874 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 | |
| 875 | envp_buf[i] = @ptrCast([*:0]u8, env_buf.ptr); | |
| 868 | const len = env_buf.len - 1; | |
| 869 | env_buf[len] = 0; | |
| 870 | envp_buf[i] = env_buf[0..len :0].ptr; | |
| 876 | 871 | } |
| 877 | 872 | assert(i == envp_count); |
| 878 | 873 | } |
| 879 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 | |
| 880 | assert(envp_buf[envp_count] == null); | |
| 881 | return @ptrCast([*:null]?[*:0]u8, envp_buf.ptr)[0..envp_count]; | |
| 874 | return envp_buf[0..envp_count :null]; | |
| 882 | 875 | } |
| 883 | 876 | |
| 884 | 877 | pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) void { |
src/all_types.hpp+2| ... | ... | @@ -810,6 +810,7 @@ struct AstNodeSliceExpr { |
| 810 | 810 | AstNode *array_ref_expr; |
| 811 | 811 | AstNode *start; |
| 812 | 812 | AstNode *end; |
| 813 | AstNode *sentinel; // can be null | |
| 813 | 814 | }; |
| 814 | 815 | |
| 815 | 816 | struct AstNodeFieldAccessExpr { |
| ... | ... | @@ -3388,6 +3389,7 @@ struct IrInstructionSliceSrc { |
| 3388 | 3389 | IrInstruction *ptr; |
| 3389 | 3390 | IrInstruction *start; |
| 3390 | 3391 | IrInstruction *end; |
| 3392 | IrInstruction *sentinel; | |
| 3391 | 3393 | ResultLoc *result_loc; |
| 3392 | 3394 | }; |
| 3393 | 3395 |
src/ir.cpp+71-11| ... | ... | @@ -2967,18 +2967,21 @@ static IrInstruction *ir_build_memcpy(IrBuilder *irb, Scope *scope, AstNode *sou |
| 2967 | 2967 | } |
| 2968 | 2968 | |
| 2969 | 2969 | static IrInstruction *ir_build_slice_src(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2970 | IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool safety_check_on, ResultLoc *result_loc) | |
| 2970 | IrInstruction *ptr, IrInstruction *start, IrInstruction *end, IrInstruction *sentinel, | |
| 2971 | bool safety_check_on, ResultLoc *result_loc) | |
| 2971 | 2972 | { |
| 2972 | 2973 | IrInstructionSliceSrc *instruction = ir_build_instruction<IrInstructionSliceSrc>(irb, scope, source_node); |
| 2973 | 2974 | instruction->ptr = ptr; |
| 2974 | 2975 | instruction->start = start; |
| 2975 | 2976 | instruction->end = end; |
| 2977 | instruction->sentinel = sentinel; | |
| 2976 | 2978 | instruction->safety_check_on = safety_check_on; |
| 2977 | 2979 | instruction->result_loc = result_loc; |
| 2978 | 2980 | |
| 2979 | 2981 | ir_ref_instruction(ptr, irb->current_basic_block); |
| 2980 | 2982 | ir_ref_instruction(start, irb->current_basic_block); |
| 2981 | 2983 | if (end) ir_ref_instruction(end, irb->current_basic_block); |
| 2984 | if (sentinel) ir_ref_instruction(sentinel, irb->current_basic_block); | |
| 2982 | 2985 | |
| 2983 | 2986 | return &instruction->base; |
| 2984 | 2987 | } |
| ... | ... | @@ -8483,6 +8486,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node, |
| 8483 | 8486 | AstNode *array_node = slice_expr->array_ref_expr; |
| 8484 | 8487 | AstNode *start_node = slice_expr->start; |
| 8485 | 8488 | AstNode *end_node = slice_expr->end; |
| 8489 | AstNode *sentinel_node = slice_expr->sentinel; | |
| 8486 | 8490 | |
| 8487 | 8491 | IrInstruction *ptr_value = ir_gen_node_extra(irb, array_node, scope, LValPtr, nullptr); |
| 8488 | 8492 | if (ptr_value == irb->codegen->invalid_instruction) |
| ... | ... | @@ -8501,7 +8505,17 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node, |
| 8501 | 8505 | end_value = nullptr; |
| 8502 | 8506 | } |
| 8503 | 8507 | |
| 8504 | IrInstruction *slice = ir_build_slice_src(irb, scope, node, ptr_value, start_value, end_value, true, result_loc); | |
| 8508 | IrInstruction *sentinel_value; | |
| 8509 | if (sentinel_node) { | |
| 8510 | sentinel_value = ir_gen_node(irb, sentinel_node, scope); | |
| 8511 | if (sentinel_value == irb->codegen->invalid_instruction) | |
| 8512 | return irb->codegen->invalid_instruction; | |
| 8513 | } else { | |
| 8514 | sentinel_value = nullptr; | |
| 8515 | } | |
| 8516 | ||
| 8517 | IrInstruction *slice = ir_build_slice_src(irb, scope, node, ptr_value, start_value, end_value, | |
| 8518 | sentinel_value, true, result_loc); | |
| 8505 | 8519 | return ir_lval_wrap(irb, scope, slice, lval, result_loc); |
| 8506 | 8520 | } |
| 8507 | 8521 | |
| ... | ... | @@ -10533,6 +10547,18 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted |
| 10533 | 10547 | result.id = ConstCastResultIdInvalid; |
| 10534 | 10548 | return result; |
| 10535 | 10549 | } |
| 10550 | bool ok_sentinels = | |
| 10551 | wanted_ptr_type->data.pointer.sentinel == nullptr || | |
| 10552 | (actual_ptr_type->data.pointer.sentinel != nullptr && | |
| 10553 | const_values_equal(ira->codegen, wanted_ptr_type->data.pointer.sentinel, | |
| 10554 | actual_ptr_type->data.pointer.sentinel)); | |
| 10555 | if (!ok_sentinels) { | |
| 10556 | result.id = ConstCastResultIdPtrSentinel; | |
| 10557 | result.data.bad_ptr_sentinel = allocate_nonzero<ConstCastPtrSentinel>(1); | |
| 10558 | result.data.bad_ptr_sentinel->wanted_type = wanted_ptr_type; | |
| 10559 | result.data.bad_ptr_sentinel->actual_type = actual_ptr_type; | |
| 10560 | return result; | |
| 10561 | } | |
| 10536 | 10562 | if ((!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) && |
| 10537 | 10563 | (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) && |
| 10538 | 10564 | actual_ptr_type->data.pointer.bit_offset_in_host == wanted_ptr_type->data.pointer.bit_offset_in_host && |
| ... | ... | @@ -19313,6 +19339,20 @@ static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_ali |
| 19313 | 19339 | ptr_type->data.pointer.sentinel); |
| 19314 | 19340 | } |
| 19315 | 19341 | |
| 19342 | static ZigType *adjust_ptr_sentinel(CodeGen *g, ZigType *ptr_type, ZigValue *new_sentinel) { | |
| 19343 | assert(ptr_type->id == ZigTypeIdPointer); | |
| 19344 | return get_pointer_to_type_extra2(g, | |
| 19345 | ptr_type->data.pointer.child_type, | |
| 19346 | ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, | |
| 19347 | ptr_type->data.pointer.ptr_len, | |
| 19348 | ptr_type->data.pointer.explicit_alignment, | |
| 19349 | ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes, | |
| 19350 | ptr_type->data.pointer.allow_zero, | |
| 19351 | ptr_type->data.pointer.vector_index, | |
| 19352 | ptr_type->data.pointer.inferred_struct_field, | |
| 19353 | new_sentinel); | |
| 19354 | } | |
| 19355 | ||
| 19316 | 19356 | static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align) { |
| 19317 | 19357 | assert(is_slice(slice_type)); |
| 19318 | 19358 | ZigType *ptr_type = adjust_ptr_align(g, slice_type->data.structure.fields[slice_ptr_index]->type_entry, |
| ... | ... | @@ -25051,50 +25091,70 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 25051 | 25091 | end = nullptr; |
| 25052 | 25092 | } |
| 25053 | 25093 | |
| 25054 | ZigType *return_type; | |
| 25094 | ZigType *non_sentinel_slice_ptr_type; | |
| 25095 | ZigType *elem_type; | |
| 25055 | 25096 | |
| 25056 | 25097 | if (array_type->id == ZigTypeIdArray) { |
| 25098 | elem_type = array_type->data.array.child_type; | |
| 25057 | 25099 | bool is_comptime_const = ptr_ptr->value->special == ConstValSpecialStatic && |
| 25058 | 25100 | ptr_ptr->value->data.x_ptr.mut == ConstPtrMutComptimeConst; |
| 25059 | ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.array.child_type, | |
| 25101 | non_sentinel_slice_ptr_type = get_pointer_to_type_extra(ira->codegen, elem_type, | |
| 25060 | 25102 | ptr_ptr_type->data.pointer.is_const || is_comptime_const, |
| 25061 | 25103 | ptr_ptr_type->data.pointer.is_volatile, |
| 25062 | 25104 | PtrLenUnknown, |
| 25063 | 25105 | ptr_ptr_type->data.pointer.explicit_alignment, 0, 0, false); |
| 25064 | return_type = get_slice_type(ira->codegen, slice_ptr_type); | |
| 25065 | 25106 | } else if (array_type->id == ZigTypeIdPointer) { |
| 25066 | 25107 | if (array_type->data.pointer.ptr_len == PtrLenSingle) { |
| 25067 | 25108 | ZigType *main_type = array_type->data.pointer.child_type; |
| 25068 | 25109 | if (main_type->id == ZigTypeIdArray) { |
| 25069 | ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, | |
| 25070 | main_type->data.pointer.child_type, | |
| 25110 | elem_type = main_type->data.pointer.child_type; | |
| 25111 | non_sentinel_slice_ptr_type = get_pointer_to_type_extra(ira->codegen, | |
| 25112 | elem_type, | |
| 25071 | 25113 | array_type->data.pointer.is_const, array_type->data.pointer.is_volatile, |
| 25072 | 25114 | PtrLenUnknown, |
| 25073 | 25115 | array_type->data.pointer.explicit_alignment, 0, 0, false); |
| 25074 | return_type = get_slice_type(ira->codegen, slice_ptr_type); | |
| 25075 | 25116 | } else { |
| 25076 | 25117 | ir_add_error(ira, &instruction->base, buf_sprintf("slice of single-item pointer")); |
| 25077 | 25118 | return ira->codegen->invalid_instruction; |
| 25078 | 25119 | } |
| 25079 | 25120 | } else { |
| 25121 | elem_type = array_type->data.pointer.child_type; | |
| 25080 | 25122 | if (array_type->data.pointer.ptr_len == PtrLenC) { |
| 25081 | 25123 | array_type = adjust_ptr_len(ira->codegen, array_type, PtrLenUnknown); |
| 25082 | 25124 | } |
| 25083 | return_type = get_slice_type(ira->codegen, array_type); | |
| 25125 | non_sentinel_slice_ptr_type = array_type; | |
| 25084 | 25126 | if (!end) { |
| 25085 | 25127 | ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value")); |
| 25086 | 25128 | return ira->codegen->invalid_instruction; |
| 25087 | 25129 | } |
| 25088 | 25130 | } |
| 25089 | 25131 | } else if (is_slice(array_type)) { |
| 25090 | ZigType *ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; | |
| 25091 | return_type = get_slice_type(ira->codegen, ptr_type); | |
| 25132 | non_sentinel_slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; | |
| 25133 | elem_type = non_sentinel_slice_ptr_type->data.pointer.child_type; | |
| 25092 | 25134 | } else { |
| 25093 | 25135 | ir_add_error(ira, &instruction->base, |
| 25094 | 25136 | buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name))); |
| 25095 | 25137 | return ira->codegen->invalid_instruction; |
| 25096 | 25138 | } |
| 25097 | 25139 | |
| 25140 | ZigType *return_type; | |
| 25141 | ZigValue *sentinel_val = nullptr; | |
| 25142 | if (instruction->sentinel) { | |
| 25143 | IrInstruction *uncasted_sentinel = instruction->sentinel->child; | |
| 25144 | if (type_is_invalid(uncasted_sentinel->value->type)) | |
| 25145 | return ira->codegen->invalid_instruction; | |
| 25146 | IrInstruction *sentinel = ir_implicit_cast(ira, uncasted_sentinel, elem_type); | |
| 25147 | if (type_is_invalid(sentinel->value->type)) | |
| 25148 | return ira->codegen->invalid_instruction; | |
| 25149 | sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); | |
| 25150 | if (sentinel_val == nullptr) | |
| 25151 | return ira->codegen->invalid_instruction; | |
| 25152 | ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, sentinel_val); | |
| 25153 | return_type = get_slice_type(ira->codegen, slice_ptr_type); | |
| 25154 | } else { | |
| 25155 | return_type = get_slice_type(ira->codegen, non_sentinel_slice_ptr_type); | |
| 25156 | } | |
| 25157 | ||
| 25098 | 25158 | if (instr_is_comptime(ptr_ptr) && |
| 25099 | 25159 | value_is_comptime(casted_start->value) && |
| 25100 | 25160 | (!end || value_is_comptime(end->value))) |
src/parser.cpp+7-1| ... | ... | @@ -2723,7 +2723,7 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) { |
| 2723 | 2723 | } |
| 2724 | 2724 | |
| 2725 | 2725 | // SuffixOp |
| 2726 | // <- LBRACKET Expr (DOT2 Expr?)? RBRACKET | |
| 2726 | // <- LBRACKET Expr (DOT2 (Expr (COLON Expr)?)?)? RBRACKET | |
| 2727 | 2727 | // / DOT IDENTIFIER |
| 2728 | 2728 | // / DOTASTERISK |
| 2729 | 2729 | // / DOTQUESTIONMARK |
| ... | ... | @@ -2733,12 +2733,17 @@ static AstNode *ast_parse_suffix_op(ParseContext *pc) { |
| 2733 | 2733 | AstNode *start = ast_expect(pc, ast_parse_expr); |
| 2734 | 2734 | AstNode *end = nullptr; |
| 2735 | 2735 | if (eat_token_if(pc, TokenIdEllipsis2) != nullptr) { |
| 2736 | AstNode *sentinel = nullptr; | |
| 2736 | 2737 | end = ast_parse_expr(pc); |
| 2738 | if (eat_token_if(pc, TokenIdColon) != nullptr) { | |
| 2739 | sentinel = ast_parse_expr(pc); | |
| 2740 | } | |
| 2737 | 2741 | expect_token(pc, TokenIdRBracket); |
| 2738 | 2742 | |
| 2739 | 2743 | AstNode *res = ast_create_node(pc, NodeTypeSliceExpr, lbracket); |
| 2740 | 2744 | res->data.slice_expr.start = start; |
| 2741 | 2745 | res->data.slice_expr.end = end; |
| 2746 | res->data.slice_expr.sentinel = sentinel; | |
| 2742 | 2747 | return res; |
| 2743 | 2748 | } |
| 2744 | 2749 | |
| ... | ... | @@ -3041,6 +3046,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 3041 | 3046 | visit_field(&node->data.slice_expr.array_ref_expr, visit, context); |
| 3042 | 3047 | visit_field(&node->data.slice_expr.start, visit, context); |
| 3043 | 3048 | visit_field(&node->data.slice_expr.end, visit, context); |
| 3049 | visit_field(&node->data.slice_expr.sentinel, visit, context); | |
| 3044 | 3050 | break; |
| 3045 | 3051 | case NodeTypeFieldAccessExpr: |
| 3046 | 3052 | visit_field(&node->data.field_access_expr.struct_expr, visit, context); |
test/compile_errors.zig+11| ... | ... | @@ -2,6 +2,17 @@ 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("slice sentinel mismatch", | |
| 6 | \\fn foo() [:0]u8 { | |
| 7 | \\ var x: []u8 = undefined; | |
| 8 | \\ return x; | |
| 9 | \\} | |
| 10 | \\comptime { _ = foo; } | |
| 11 | , &[_][]const u8{ | |
| 12 | "tmp.zig:3:12: error: expected type '[:0]u8', found '[]u8'", | |
| 13 | "tmp.zig:3:12: note: destination pointer requires a terminating '0' sentinel", | |
| 14 | }); | |
| 15 | ||
| 5 | 16 | cases.add("intToPtr with misaligned address", |
| 6 | 17 | \\pub fn main() void { |
| 7 | 18 | \\ var y = @intToPtr([*]align(4) u8, 5); |