| author | |
| committer | |
| log | 26f3c2d0614f4fb37752b1931cb0b43aed2696d2 |
| tree | 18e51d6ed267ded8c6d87b5158c8866dcf1a2bf6 |
| parent | 51cbd968203f348051b8c2bdc005ca5294a79ceb |
| signature |
see #37709 files changed, 119 insertions(+), 39 deletions(-)
lib/std/buffer.zig+2-2| ... | @@ -82,11 +82,11 @@ pub const Buffer = struct { | ... | @@ -82,11 +82,11 @@ pub const Buffer = struct { |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | pub fn toSlice(self: Buffer) [:0]u8 { | 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 | pub fn toSliceConst(self: Buffer) [:0]const u8 { | 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 | pub fn shrink(self: *Buffer, new_len: usize) void { | 92 | pub fn shrink(self: *Buffer, new_len: usize) void { |
lib/std/cstr.zig+10-2| ... | @@ -31,13 +31,21 @@ fn testCStrFnsImpl() void { | ... | @@ -31,13 +31,21 @@ fn testCStrFnsImpl() void { |
| 31 | testing.expect(mem.len(u8, "123456789") == 9); | 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 | /// Caller owns the returned memory. | 35 | /// Caller owns the returned memory. |
| 36 | pub fn addNullByte(allocator: *mem.Allocator, slice: []const u8) ![:0]u8 { | 36 | pub fn addNullByte(allocator: *mem.Allocator, slice: []const u8) ![:0]u8 { |
| 37 | const result = try allocator.alloc(u8, slice.len + 1); | 37 | const result = try allocator.alloc(u8, slice.len + 1); |
| 38 | mem.copy(u8, result, slice); | 38 | mem.copy(u8, result, slice); |
| 39 | result[slice.len] = 0; | 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 | pub const NullTerminated2DArray = struct { | 51 | pub const NullTerminated2DArray = struct { |
lib/std/fs.zig+4-5| ... | @@ -221,16 +221,16 @@ pub const AtomicFile = struct { | ... | @@ -221,16 +221,16 @@ pub const AtomicFile = struct { |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | tmp_path_buf[tmp_path_len] = 0; | 223 | tmp_path_buf[tmp_path_len] = 0; |
| 224 | const tmp_path_slice = tmp_path_buf[0..tmp_path_len :0]; | ||
| 224 | 225 | ||
| 225 | const my_cwd = cwd(); | 226 | const my_cwd = cwd(); |
| 226 | 227 | ||
| 227 | while (true) { | 228 | while (true) { |
| 228 | try crypto.randomBytes(rand_buf[0..]); | 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 | const file = my_cwd.createFileC( | 232 | const file = my_cwd.createFileC( |
| 233 | @ptrCast([*:0]u8, &tmp_path_buf), | 233 | tmp_path_slice, |
| 234 | .{ .mode = mode, .exclusive = true }, | 234 | .{ .mode = mode, .exclusive = true }, |
| 235 | ) catch |err| switch (err) { | 235 | ) catch |err| switch (err) { |
| 236 | error.PathAlreadyExists => continue, | 236 | error.PathAlreadyExists => continue, |
| ... | @@ -1488,8 +1488,7 @@ pub fn openSelfExe() OpenSelfExeError!File { | ... | @@ -1488,8 +1488,7 @@ pub fn openSelfExe() OpenSelfExeError!File { |
| 1488 | var buf: [MAX_PATH_BYTES]u8 = undefined; | 1488 | var buf: [MAX_PATH_BYTES]u8 = undefined; |
| 1489 | const self_exe_path = try selfExePath(&buf); | 1489 | const self_exe_path = try selfExePath(&buf); |
| 1490 | buf[self_exe_path.len] = 0; | 1490 | buf[self_exe_path.len] = 0; |
| 1491 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 | 1491 | return openFileAbsoluteC(self_exe_path[0..self_exe_path.len :0].ptr, .{}); |
| 1492 | return openFileAbsoluteC(@ptrCast([*:0]u8, self_exe_path.ptr), .{}); | ||
| 1493 | } | 1492 | } |
| 1494 | 1493 | ||
| 1495 | test "openSelfExe" { | 1494 | test "openSelfExe" { |
lib/std/mem.zig+3-2| ... | @@ -231,9 +231,10 @@ pub const Allocator = struct { | ... | @@ -231,9 +231,10 @@ pub const Allocator = struct { |
| 231 | pub fn free(self: *Allocator, memory: var) void { | 231 | pub fn free(self: *Allocator, memory: var) void { |
| 232 | const Slice = @typeInfo(@TypeOf(memory)).Pointer; | 232 | const Slice = @typeInfo(@TypeOf(memory)).Pointer; |
| 233 | const bytes = @sliceToBytes(memory); | 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 | const non_const_ptr = @intToPtr([*]u8, @ptrToInt(bytes.ptr)); | 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 | assert(shrink_result.len == 0); | 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,9 +805,9 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, e |
| 805 | mem.copy(u8, &path_buf, search_path); | 805 | mem.copy(u8, &path_buf, search_path); |
| 806 | path_buf[search_path.len] = '/'; | 806 | path_buf[search_path.len] = '/'; |
| 807 | mem.copy(u8, path_buf[search_path.len + 1 ..], file_slice); | 807 | mem.copy(u8, path_buf[search_path.len + 1 ..], file_slice); |
| 808 | path_buf[search_path.len + file_slice.len + 1] = 0; | 808 | const path_len = search_path.len + file_slice.len + 1; |
| 809 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 | 809 | path_buf[path_len] = 0; |
| 810 | err = execveC(@ptrCast([*:0]u8, &path_buf), child_argv, envp); | 810 | err = execveC(path_buf[0..path_len :0].ptr, child_argv, envp); |
| 811 | switch (err) { | 811 | switch (err) { |
| 812 | error.AccessDenied => seen_eacces = true, | 812 | error.AccessDenied => seen_eacces = true, |
| 813 | error.FileNotFound, error.NotDir => {}, | 813 | error.FileNotFound, error.NotDir => {}, |
| ... | @@ -841,18 +841,14 @@ pub fn execvpe( | ... | @@ -841,18 +841,14 @@ pub fn execvpe( |
| 841 | const arg_buf = try allocator.alloc(u8, arg.len + 1); | 841 | const arg_buf = try allocator.alloc(u8, arg.len + 1); |
| 842 | @memcpy(arg_buf.ptr, arg.ptr, arg.len); | 842 | @memcpy(arg_buf.ptr, arg.ptr, arg.len); |
| 843 | arg_buf[arg.len] = 0; | 843 | arg_buf[arg.len] = 0; |
| 844 | 844 | argv_buf[i] = arg_buf[0..arg.len :0].ptr; | |
| 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); | ||
| 847 | } | 845 | } |
| 848 | argv_buf[argv_slice.len] = null; | 846 | argv_buf[argv_slice.len] = null; |
| 847 | const argv_ptr = argv_buf[0..argv_slice.len :null].ptr; | ||
| 849 | 848 | ||
| 850 | const envp_buf = try createNullDelimitedEnvMap(allocator, env_map); | 849 | const envp_buf = try createNullDelimitedEnvMap(allocator, env_map); |
| 851 | defer freeNullDelimitedEnvMap(allocator, envp_buf); | 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 | return execvpeC(argv_buf.ptr[0].?, argv_ptr, envp_buf.ptr); | 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,16 +865,13 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std. |
| 869 | @memcpy(env_buf.ptr, pair.key.ptr, pair.key.len); | 865 | @memcpy(env_buf.ptr, pair.key.ptr, pair.key.len); |
| 870 | env_buf[pair.key.len] = '='; | 866 | env_buf[pair.key.len] = '='; |
| 871 | @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len); | 867 | @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len); |
| 872 | env_buf[env_buf.len - 1] = 0; | 868 | const len = env_buf.len - 1; |
| 873 | 869 | env_buf[len] = 0; | |
| 874 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 | 870 | envp_buf[i] = env_buf[0..len :0].ptr; |
| 875 | envp_buf[i] = @ptrCast([*:0]u8, env_buf.ptr); | ||
| 876 | } | 871 | } |
| 877 | assert(i == envp_count); | 872 | assert(i == envp_count); |
| 878 | } | 873 | } |
| 879 | // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770 | 874 | return envp_buf[0..envp_count :null]; |
| 880 | assert(envp_buf[envp_count] == null); | ||
| 881 | return @ptrCast([*:null]?[*:0]u8, envp_buf.ptr)[0..envp_count]; | ||
| 882 | } | 875 | } |
| 883 | 876 | ||
| 884 | pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) void { | 877 | pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) void { |
src/all_types.hpp+2| ... | @@ -810,6 +810,7 @@ struct AstNodeSliceExpr { | ... | @@ -810,6 +810,7 @@ struct AstNodeSliceExpr { |
| 810 | AstNode *array_ref_expr; | 810 | AstNode *array_ref_expr; |
| 811 | AstNode *start; | 811 | AstNode *start; |
| 812 | AstNode *end; | 812 | AstNode *end; |
| 813 | AstNode *sentinel; // can be null | ||
| 813 | }; | 814 | }; |
| 814 | 815 | ||
| 815 | struct AstNodeFieldAccessExpr { | 816 | struct AstNodeFieldAccessExpr { |
| ... | @@ -3388,6 +3389,7 @@ struct IrInstructionSliceSrc { | ... | @@ -3388,6 +3389,7 @@ struct IrInstructionSliceSrc { |
| 3388 | IrInstruction *ptr; | 3389 | IrInstruction *ptr; |
| 3389 | IrInstruction *start; | 3390 | IrInstruction *start; |
| 3390 | IrInstruction *end; | 3391 | IrInstruction *end; |
| 3392 | IrInstruction *sentinel; | ||
| 3391 | ResultLoc *result_loc; | 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,18 +2967,21 @@ static IrInstruction *ir_build_memcpy(IrBuilder *irb, Scope *scope, AstNode *sou |
| 2967 | } | 2967 | } |
| 2968 | 2968 | ||
| 2969 | static IrInstruction *ir_build_slice_src(IrBuilder *irb, Scope *scope, AstNode *source_node, | 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 | IrInstructionSliceSrc *instruction = ir_build_instruction<IrInstructionSliceSrc>(irb, scope, source_node); | 2973 | IrInstructionSliceSrc *instruction = ir_build_instruction<IrInstructionSliceSrc>(irb, scope, source_node); |
| 2973 | instruction->ptr = ptr; | 2974 | instruction->ptr = ptr; |
| 2974 | instruction->start = start; | 2975 | instruction->start = start; |
| 2975 | instruction->end = end; | 2976 | instruction->end = end; |
| 2977 | instruction->sentinel = sentinel; | ||
| 2976 | instruction->safety_check_on = safety_check_on; | 2978 | instruction->safety_check_on = safety_check_on; |
| 2977 | instruction->result_loc = result_loc; | 2979 | instruction->result_loc = result_loc; |
| 2978 | 2980 | ||
| 2979 | ir_ref_instruction(ptr, irb->current_basic_block); | 2981 | ir_ref_instruction(ptr, irb->current_basic_block); |
| 2980 | ir_ref_instruction(start, irb->current_basic_block); | 2982 | ir_ref_instruction(start, irb->current_basic_block); |
| 2981 | if (end) ir_ref_instruction(end, irb->current_basic_block); | 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 | return &instruction->base; | 2986 | return &instruction->base; |
| 2984 | } | 2987 | } |
| ... | @@ -8483,6 +8486,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node, | ... | @@ -8483,6 +8486,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node, |
| 8483 | AstNode *array_node = slice_expr->array_ref_expr; | 8486 | AstNode *array_node = slice_expr->array_ref_expr; |
| 8484 | AstNode *start_node = slice_expr->start; | 8487 | AstNode *start_node = slice_expr->start; |
| 8485 | AstNode *end_node = slice_expr->end; | 8488 | AstNode *end_node = slice_expr->end; |
| 8489 | AstNode *sentinel_node = slice_expr->sentinel; | ||
| 8486 | 8490 | ||
| 8487 | IrInstruction *ptr_value = ir_gen_node_extra(irb, array_node, scope, LValPtr, nullptr); | 8491 | IrInstruction *ptr_value = ir_gen_node_extra(irb, array_node, scope, LValPtr, nullptr); |
| 8488 | if (ptr_value == irb->codegen->invalid_instruction) | 8492 | if (ptr_value == irb->codegen->invalid_instruction) |
| ... | @@ -8501,7 +8505,17 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node, | ... | @@ -8501,7 +8505,17 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node, |
| 8501 | end_value = nullptr; | 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 | return ir_lval_wrap(irb, scope, slice, lval, result_loc); | 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,6 +10547,18 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted |
| 10533 | result.id = ConstCastResultIdInvalid; | 10547 | result.id = ConstCastResultIdInvalid; |
| 10534 | return result; | 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 | if ((!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) && | 10562 | if ((!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) && |
| 10537 | (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) && | 10563 | (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) && |
| 10538 | actual_ptr_type->data.pointer.bit_offset_in_host == wanted_ptr_type->data.pointer.bit_offset_in_host && | 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,6 +19339,20 @@ static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_ali |
| 19313 | ptr_type->data.pointer.sentinel); | 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 | static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align) { | 19356 | static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align) { |
| 19317 | assert(is_slice(slice_type)); | 19357 | assert(is_slice(slice_type)); |
| 19318 | ZigType *ptr_type = adjust_ptr_align(g, slice_type->data.structure.fields[slice_ptr_index]->type_entry, | 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,50 +25091,70 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 25051 | end = nullptr; | 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 | if (array_type->id == ZigTypeIdArray) { | 25097 | if (array_type->id == ZigTypeIdArray) { |
| 25098 | elem_type = array_type->data.array.child_type; | ||
| 25057 | bool is_comptime_const = ptr_ptr->value->special == ConstValSpecialStatic && | 25099 | bool is_comptime_const = ptr_ptr->value->special == ConstValSpecialStatic && |
| 25058 | ptr_ptr->value->data.x_ptr.mut == ConstPtrMutComptimeConst; | 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 | ptr_ptr_type->data.pointer.is_const || is_comptime_const, | 25102 | ptr_ptr_type->data.pointer.is_const || is_comptime_const, |
| 25061 | ptr_ptr_type->data.pointer.is_volatile, | 25103 | ptr_ptr_type->data.pointer.is_volatile, |
| 25062 | PtrLenUnknown, | 25104 | PtrLenUnknown, |
| 25063 | ptr_ptr_type->data.pointer.explicit_alignment, 0, 0, false); | 25105 | ptr_ptr_type->data.pointer.explicit_alignment, 0, 0, false); |
| 25064 | return_type = get_slice_type(ira->codegen, slice_ptr_type); | ||
| 25065 | } else if (array_type->id == ZigTypeIdPointer) { | 25106 | } else if (array_type->id == ZigTypeIdPointer) { |
| 25066 | if (array_type->data.pointer.ptr_len == PtrLenSingle) { | 25107 | if (array_type->data.pointer.ptr_len == PtrLenSingle) { |
| 25067 | ZigType *main_type = array_type->data.pointer.child_type; | 25108 | ZigType *main_type = array_type->data.pointer.child_type; |
| 25068 | if (main_type->id == ZigTypeIdArray) { | 25109 | if (main_type->id == ZigTypeIdArray) { |
| 25069 | ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, | 25110 | elem_type = main_type->data.pointer.child_type; |
| 25070 | main_type->data.pointer.child_type, | 25111 | non_sentinel_slice_ptr_type = get_pointer_to_type_extra(ira->codegen, |
| 25112 | elem_type, | ||
| 25071 | array_type->data.pointer.is_const, array_type->data.pointer.is_volatile, | 25113 | array_type->data.pointer.is_const, array_type->data.pointer.is_volatile, |
| 25072 | PtrLenUnknown, | 25114 | PtrLenUnknown, |
| 25073 | array_type->data.pointer.explicit_alignment, 0, 0, false); | 25115 | array_type->data.pointer.explicit_alignment, 0, 0, false); |
| 25074 | return_type = get_slice_type(ira->codegen, slice_ptr_type); | ||
| 25075 | } else { | 25116 | } else { |
| 25076 | ir_add_error(ira, &instruction->base, buf_sprintf("slice of single-item pointer")); | 25117 | ir_add_error(ira, &instruction->base, buf_sprintf("slice of single-item pointer")); |
| 25077 | return ira->codegen->invalid_instruction; | 25118 | return ira->codegen->invalid_instruction; |
| 25078 | } | 25119 | } |
| 25079 | } else { | 25120 | } else { |
| 25121 | elem_type = array_type->data.pointer.child_type; | ||
| 25080 | if (array_type->data.pointer.ptr_len == PtrLenC) { | 25122 | if (array_type->data.pointer.ptr_len == PtrLenC) { |
| 25081 | array_type = adjust_ptr_len(ira->codegen, array_type, PtrLenUnknown); | 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 | if (!end) { | 25126 | if (!end) { |
| 25085 | ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value")); | 25127 | ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value")); |
| 25086 | return ira->codegen->invalid_instruction; | 25128 | return ira->codegen->invalid_instruction; |
| 25087 | } | 25129 | } |
| 25088 | } | 25130 | } |
| 25089 | } else if (is_slice(array_type)) { | 25131 | } else if (is_slice(array_type)) { |
| 25090 | ZigType *ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; | 25132 | non_sentinel_slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; |
| 25091 | return_type = get_slice_type(ira->codegen, ptr_type); | 25133 | elem_type = non_sentinel_slice_ptr_type->data.pointer.child_type; |
| 25092 | } else { | 25134 | } else { |
| 25093 | ir_add_error(ira, &instruction->base, | 25135 | ir_add_error(ira, &instruction->base, |
| 25094 | buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name))); | 25136 | buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name))); |
| 25095 | return ira->codegen->invalid_instruction; | 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 | if (instr_is_comptime(ptr_ptr) && | 25158 | if (instr_is_comptime(ptr_ptr) && |
| 25099 | value_is_comptime(casted_start->value) && | 25159 | value_is_comptime(casted_start->value) && |
| 25100 | (!end || value_is_comptime(end->value))) | 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,7 +2723,7 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) { |
| 2723 | } | 2723 | } |
| 2724 | 2724 | ||
| 2725 | // SuffixOp | 2725 | // SuffixOp |
| 2726 | // <- LBRACKET Expr (DOT2 Expr?)? RBRACKET | 2726 | // <- LBRACKET Expr (DOT2 (Expr (COLON Expr)?)?)? RBRACKET |
| 2727 | // / DOT IDENTIFIER | 2727 | // / DOT IDENTIFIER |
| 2728 | // / DOTASTERISK | 2728 | // / DOTASTERISK |
| 2729 | // / DOTQUESTIONMARK | 2729 | // / DOTQUESTIONMARK |
| ... | @@ -2733,12 +2733,17 @@ static AstNode *ast_parse_suffix_op(ParseContext *pc) { | ... | @@ -2733,12 +2733,17 @@ static AstNode *ast_parse_suffix_op(ParseContext *pc) { |
| 2733 | AstNode *start = ast_expect(pc, ast_parse_expr); | 2733 | AstNode *start = ast_expect(pc, ast_parse_expr); |
| 2734 | AstNode *end = nullptr; | 2734 | AstNode *end = nullptr; |
| 2735 | if (eat_token_if(pc, TokenIdEllipsis2) != nullptr) { | 2735 | if (eat_token_if(pc, TokenIdEllipsis2) != nullptr) { |
| 2736 | AstNode *sentinel = nullptr; | ||
| 2736 | end = ast_parse_expr(pc); | 2737 | end = ast_parse_expr(pc); |
| 2738 | if (eat_token_if(pc, TokenIdColon) != nullptr) { | ||
| 2739 | sentinel = ast_parse_expr(pc); | ||
| 2740 | } | ||
| 2737 | expect_token(pc, TokenIdRBracket); | 2741 | expect_token(pc, TokenIdRBracket); |
| 2738 | 2742 | ||
| 2739 | AstNode *res = ast_create_node(pc, NodeTypeSliceExpr, lbracket); | 2743 | AstNode *res = ast_create_node(pc, NodeTypeSliceExpr, lbracket); |
| 2740 | res->data.slice_expr.start = start; | 2744 | res->data.slice_expr.start = start; |
| 2741 | res->data.slice_expr.end = end; | 2745 | res->data.slice_expr.end = end; |
| 2746 | res->data.slice_expr.sentinel = sentinel; | ||
| 2742 | return res; | 2747 | return res; |
| 2743 | } | 2748 | } |
| 2744 | 2749 | ||
| ... | @@ -3041,6 +3046,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont | ... | @@ -3041,6 +3046,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 3041 | visit_field(&node->data.slice_expr.array_ref_expr, visit, context); | 3046 | visit_field(&node->data.slice_expr.array_ref_expr, visit, context); |
| 3042 | visit_field(&node->data.slice_expr.start, visit, context); | 3047 | visit_field(&node->data.slice_expr.start, visit, context); |
| 3043 | visit_field(&node->data.slice_expr.end, visit, context); | 3048 | visit_field(&node->data.slice_expr.end, visit, context); |
| 3049 | visit_field(&node->data.slice_expr.sentinel, visit, context); | ||
| 3044 | break; | 3050 | break; |
| 3045 | case NodeTypeFieldAccessExpr: | 3051 | case NodeTypeFieldAccessExpr: |
| 3046 | visit_field(&node->data.field_access_expr.struct_expr, visit, context); | 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,6 +2,17 @@ const tests = @import("tests.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | 3 | ||
| 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { | 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 | cases.add("intToPtr with misaligned address", | 16 | cases.add("intToPtr with misaligned address", |
| 6 | \\pub fn main() void { | 17 | \\pub fn main() void { |
| 7 | \\ var y = @intToPtr([*]align(4) u8, 5); | 18 | \\ var y = @intToPtr([*]align(4) u8, 5); |