| author | |
| committer | |
| log | 8d0ac6dc4d32daea3561e7de8eeee9ce34d2c5cb |
| tree | 3c0b0da0ab8562da8899417bef24726407667b07 |
| parent | c896c5001f55c67ba2379505464f85dcabb3f3f2 |
| signature |
4 files changed, 86 insertions(+), 26 deletions(-)
lib/std/mem.zig+31-15| ... | ... | @@ -1750,34 +1750,50 @@ fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type { |
| 1750 | 1750 | } |
| 1751 | 1751 | |
| 1752 | 1752 | pub fn bytesAsSlice(comptime T: type, bytes: var) BytesAsSliceReturnType(T, @TypeOf(bytes)) { |
| 1753 | const bytesSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(bytes))) bytes[0..] else bytes; | |
| 1754 | ||
| 1755 | 1753 | // let's not give an undefined pointer to @ptrCast |
| 1756 | 1754 | // it may be equal to zero and fail a null check |
| 1757 | if (bytesSlice.len == 0) { | |
| 1755 | if (bytes.len == 0) { | |
| 1758 | 1756 | return &[0]T{}; |
| 1759 | 1757 | } |
| 1760 | 1758 | |
| 1761 | const bytesType = @TypeOf(bytesSlice); | |
| 1762 | const alignment = comptime meta.alignment(bytesType); | |
| 1759 | const Bytes = @TypeOf(bytes); | |
| 1760 | const alignment = comptime meta.alignment(Bytes); | |
| 1763 | 1761 | |
| 1764 | const castTarget = if (comptime trait.isConstPtr(bytesType)) [*]align(alignment) const T else [*]align(alignment) T; | |
| 1762 | const cast_target = if (comptime trait.isConstPtr(Bytes)) [*]align(alignment) const T else [*]align(alignment) T; | |
| 1765 | 1763 | |
| 1766 | return @ptrCast(castTarget, bytesSlice.ptr)[0..@divExact(bytes.len, @sizeOf(T))]; | |
| 1764 | return @ptrCast(cast_target, bytes)[0..@divExact(bytes.len, @sizeOf(T))]; | |
| 1767 | 1765 | } |
| 1768 | 1766 | |
| 1769 | 1767 | test "bytesAsSlice" { |
| 1770 | const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; | |
| 1771 | const slice = bytesAsSlice(u16, bytes[0..]); | |
| 1772 | testing.expect(slice.len == 2); | |
| 1773 | testing.expect(bigToNative(u16, slice[0]) == 0xDEAD); | |
| 1774 | testing.expect(bigToNative(u16, slice[1]) == 0xBEEF); | |
| 1768 | { | |
| 1769 | const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; | |
| 1770 | const slice = bytesAsSlice(u16, bytes[0..]); | |
| 1771 | testing.expect(slice.len == 2); | |
| 1772 | testing.expect(bigToNative(u16, slice[0]) == 0xDEAD); | |
| 1773 | testing.expect(bigToNative(u16, slice[1]) == 0xBEEF); | |
| 1774 | } | |
| 1775 | { | |
| 1776 | const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; | |
| 1777 | var runtime_zero: usize = 0; | |
| 1778 | const slice = bytesAsSlice(u16, bytes[runtime_zero..]); | |
| 1779 | testing.expect(slice.len == 2); | |
| 1780 | testing.expect(bigToNative(u16, slice[0]) == 0xDEAD); | |
| 1781 | testing.expect(bigToNative(u16, slice[1]) == 0xBEEF); | |
| 1782 | } | |
| 1775 | 1783 | } |
| 1776 | 1784 | |
| 1777 | 1785 | test "bytesAsSlice keeps pointer alignment" { |
| 1778 | var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 }; | |
| 1779 | const numbers = bytesAsSlice(u32, bytes[0..]); | |
| 1780 | comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32); | |
| 1786 | { | |
| 1787 | var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 }; | |
| 1788 | const numbers = bytesAsSlice(u32, bytes[0..]); | |
| 1789 | comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32); | |
| 1790 | } | |
| 1791 | { | |
| 1792 | var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 }; | |
| 1793 | var runtime_zero: usize = 0; | |
| 1794 | const numbers = bytesAsSlice(u32, bytes[runtime_zero..]); | |
| 1795 | comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32); | |
| 1796 | } | |
| 1781 | 1797 | } |
| 1782 | 1798 | |
| 1783 | 1799 | test "bytesAsSlice on a packed struct" { |
src/analyze.cpp+17-3| ... | ... | @@ -4486,7 +4486,14 @@ static uint32_t get_async_frame_align_bytes(CodeGen *g) { |
| 4486 | 4486 | } |
| 4487 | 4487 | |
| 4488 | 4488 | uint32_t get_ptr_align(CodeGen *g, ZigType *type) { |
| 4489 | ZigType *ptr_type = get_src_ptr_type(type); | |
| 4489 | ZigType *ptr_type; | |
| 4490 | if (type->id == ZigTypeIdStruct) { | |
| 4491 | assert(type->data.structure.special == StructSpecialSlice); | |
| 4492 | TypeStructField *ptr_field = type->data.structure.fields[slice_ptr_index]; | |
| 4493 | ptr_type = resolve_struct_field_type(g, ptr_field); | |
| 4494 | } else { | |
| 4495 | ptr_type = get_src_ptr_type(type); | |
| 4496 | } | |
| 4490 | 4497 | if (ptr_type->id == ZigTypeIdPointer) { |
| 4491 | 4498 | return (ptr_type->data.pointer.explicit_alignment == 0) ? |
| 4492 | 4499 | get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment; |
| ... | ... | @@ -4503,8 +4510,15 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) { |
| 4503 | 4510 | } |
| 4504 | 4511 | } |
| 4505 | 4512 | |
| 4506 | bool get_ptr_const(ZigType *type) { | |
| 4507 | ZigType *ptr_type = get_src_ptr_type(type); | |
| 4513 | bool get_ptr_const(CodeGen *g, ZigType *type) { | |
| 4514 | ZigType *ptr_type; | |
| 4515 | if (type->id == ZigTypeIdStruct) { | |
| 4516 | assert(type->data.structure.special == StructSpecialSlice); | |
| 4517 | TypeStructField *ptr_field = type->data.structure.fields[slice_ptr_index]; | |
| 4518 | ptr_type = resolve_struct_field_type(g, ptr_field); | |
| 4519 | } else { | |
| 4520 | ptr_type = get_src_ptr_type(type); | |
| 4521 | } | |
| 4508 | 4522 | if (ptr_type->id == ZigTypeIdPointer) { |
| 4509 | 4523 | return ptr_type->data.pointer.is_const; |
| 4510 | 4524 | } else if (ptr_type->id == ZigTypeIdFn) { |
src/analyze.hpp+1-1| ... | ... | @@ -76,7 +76,7 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool all |
| 76 | 76 | |
| 77 | 77 | ZigType *get_src_ptr_type(ZigType *type); |
| 78 | 78 | uint32_t get_ptr_align(CodeGen *g, ZigType *type); |
| 79 | bool get_ptr_const(ZigType *type); | |
| 79 | bool get_ptr_const(CodeGen *g, ZigType *type); | |
| 80 | 80 | ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry); |
| 81 | 81 | ZigType *container_ref_type(ZigType *type_entry); |
| 82 | 82 | bool type_is_complete(ZigType *type_entry); |
src/ir.cpp+37-7| ... | ... | @@ -25479,11 +25479,22 @@ static IrInstGen *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstSrcE |
| 25479 | 25479 | static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { |
| 25480 | 25480 | Error err; |
| 25481 | 25481 | |
| 25482 | ZigType *ptr_type = get_src_ptr_type(ty); | |
| 25482 | ZigType *ptr_type; | |
| 25483 | if (is_slice(ty)) { | |
| 25484 | TypeStructField *ptr_field = ty->data.structure.fields[slice_ptr_index]; | |
| 25485 | ptr_type = resolve_struct_field_type(ira->codegen, ptr_field); | |
| 25486 | } else { | |
| 25487 | ptr_type = get_src_ptr_type(ty); | |
| 25488 | } | |
| 25483 | 25489 | assert(ptr_type != nullptr); |
| 25484 | 25490 | if (ptr_type->id == ZigTypeIdPointer) { |
| 25485 | 25491 | if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) |
| 25486 | 25492 | return err; |
| 25493 | } else if (is_slice(ptr_type)) { | |
| 25494 | TypeStructField *ptr_field = ptr_type->data.structure.fields[slice_ptr_index]; | |
| 25495 | ZigType *slice_ptr_type = resolve_struct_field_type(ira->codegen, ptr_field); | |
| 25496 | if ((err = type_resolve(ira->codegen, slice_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) | |
| 25497 | return err; | |
| 25487 | 25498 | } |
| 25488 | 25499 | |
| 25489 | 25500 | *result_align = get_ptr_align(ira->codegen, ty); |
| ... | ... | @@ -27615,10 +27626,18 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn |
| 27615 | 27626 | // We have a check for zero bits later so we use get_src_ptr_type to |
| 27616 | 27627 | // validate src_type and dest_type. |
| 27617 | 27628 | |
| 27618 | ZigType *src_ptr_type = get_src_ptr_type(src_type); | |
| 27619 | if (src_ptr_type == nullptr) { | |
| 27620 | ir_add_error(ira, ptr_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); | |
| 27621 | return ira->codegen->invalid_inst_gen; | |
| 27629 | ZigType *if_slice_ptr_type; | |
| 27630 | if (is_slice(src_type)) { | |
| 27631 | TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index]; | |
| 27632 | if_slice_ptr_type = resolve_struct_field_type(ira->codegen, ptr_field); | |
| 27633 | } else { | |
| 27634 | if_slice_ptr_type = src_type; | |
| 27635 | ||
| 27636 | ZigType *src_ptr_type = get_src_ptr_type(src_type); | |
| 27637 | if (src_ptr_type == nullptr) { | |
| 27638 | ir_add_error(ira, ptr_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); | |
| 27639 | return ira->codegen->invalid_inst_gen; | |
| 27640 | } | |
| 27622 | 27641 | } |
| 27623 | 27642 | |
| 27624 | 27643 | ZigType *dest_ptr_type = get_src_ptr_type(dest_type); |
| ... | ... | @@ -27628,7 +27647,7 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn |
| 27628 | 27647 | return ira->codegen->invalid_inst_gen; |
| 27629 | 27648 | } |
| 27630 | 27649 | |
| 27631 | if (get_ptr_const(src_type) && !get_ptr_const(dest_type)) { | |
| 27650 | if (get_ptr_const(ira->codegen, src_type) && !get_ptr_const(ira->codegen, dest_type)) { | |
| 27632 | 27651 | ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier")); |
| 27633 | 27652 | return ira->codegen->invalid_inst_gen; |
| 27634 | 27653 | } |
| ... | ... | @@ -27646,7 +27665,10 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn |
| 27646 | 27665 | if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown))) |
| 27647 | 27666 | return ira->codegen->invalid_inst_gen; |
| 27648 | 27667 | |
| 27649 | if (type_has_bits(ira->codegen, dest_type) && !type_has_bits(ira->codegen, src_type) && safety_check_on) { | |
| 27668 | if (safety_check_on && | |
| 27669 | type_has_bits(ira->codegen, dest_type) && | |
| 27670 | !type_has_bits(ira->codegen, if_slice_ptr_type)) | |
| 27671 | { | |
| 27650 | 27672 | ErrorMsg *msg = ir_add_error(ira, source_instr, |
| 27651 | 27673 | buf_sprintf("'%s' and '%s' do not have the same in-memory representation", |
| 27652 | 27674 | buf_ptr(&src_type->name), buf_ptr(&dest_type->name))); |
| ... | ... | @@ -27657,6 +27679,14 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn |
| 27657 | 27679 | return ira->codegen->invalid_inst_gen; |
| 27658 | 27680 | } |
| 27659 | 27681 | |
| 27682 | // For slices, follow the `ptr` field. | |
| 27683 | if (is_slice(src_type)) { | |
| 27684 | TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index]; | |
| 27685 | IrInstGen *ptr_ref = ir_get_ref(ira, source_instr, ptr, true, false); | |
| 27686 | IrInstGen *ptr_ptr = ir_analyze_struct_field_ptr(ira, source_instr, ptr_field, ptr_ref, src_type, false); | |
| 27687 | ptr = ir_get_deref(ira, source_instr, ptr_ptr, nullptr); | |
| 27688 | } | |
| 27689 | ||
| 27660 | 27690 | if (instr_is_comptime(ptr)) { |
| 27661 | 27691 | bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type); |
| 27662 | 27692 | UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad; |