authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-17 17:33:44-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-19 09:53:54-04:00
log8d0ac6dc4d32daea3561e7de8eeee9ce34d2c5cb
tree3c0b0da0ab8562da8899417bef24726407667b07
parentc896c5001f55c67ba2379505464f85dcabb3f3f2
signaturelock-open Commit is signed but in an unrecognized format.

`@ptrCast` supports casting a slice to pointer


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,34 +1750,50 @@ fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type {
1750}1750}
17511751
1752pub fn bytesAsSlice(comptime T: type, bytes: var) BytesAsSliceReturnType(T, @TypeOf(bytes)) {1752pub 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 // let's not give an undefined pointer to @ptrCast1753 // let's not give an undefined pointer to @ptrCast
1756 // it may be equal to zero and fail a null check1754 // it may be equal to zero and fail a null check
1757 if (bytesSlice.len == 0) {1755 if (bytes.len == 0) {
1758 return &[0]T{};1756 return &[0]T{};
1759 }1757 }
17601758
1761 const bytesType = @TypeOf(bytesSlice);1759 const Bytes = @TypeOf(bytes);
1762 const alignment = comptime meta.alignment(bytesType);1760 const alignment = comptime meta.alignment(Bytes);
17631761
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;
17651763
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}
17681766
1769test "bytesAsSlice" {1767test "bytesAsSlice" {
1770 const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };1768 {
1771 const slice = bytesAsSlice(u16, bytes[0..]);1769 const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF };
1772 testing.expect(slice.len == 2);1770 const slice = bytesAsSlice(u16, bytes[0..]);
1773 testing.expect(bigToNative(u16, slice[0]) == 0xDEAD);1771 testing.expect(slice.len == 2);
1774 testing.expect(bigToNative(u16, slice[1]) == 0xBEEF);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}
17761784
1777test "bytesAsSlice keeps pointer alignment" {1785test "bytesAsSlice keeps pointer alignment" {
1778 var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 };1786 {
1779 const numbers = bytesAsSlice(u32, bytes[0..]);1787 var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 };
1780 comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32);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}
17821798
1783test "bytesAsSlice on a packed struct" {1799test "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,7 +4486,14 @@ static uint32_t get_async_frame_align_bytes(CodeGen *g) {
4486}4486}
44874487
4488uint32_t get_ptr_align(CodeGen *g, ZigType *type) {4488uint32_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 if (ptr_type->id == ZigTypeIdPointer) {4497 if (ptr_type->id == ZigTypeIdPointer) {
4491 return (ptr_type->data.pointer.explicit_alignment == 0) ?4498 return (ptr_type->data.pointer.explicit_alignment == 0) ?
4492 get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment;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,8 +4510,15 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) {
4503 }4510 }
4504}4511}
45054512
4506bool get_ptr_const(ZigType *type) {4513bool get_ptr_const(CodeGen *g, ZigType *type) {
4507 ZigType *ptr_type = get_src_ptr_type(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 if (ptr_type->id == ZigTypeIdPointer) {4522 if (ptr_type->id == ZigTypeIdPointer) {
4509 return ptr_type->data.pointer.is_const;4523 return ptr_type->data.pointer.is_const;
4510 } else if (ptr_type->id == ZigTypeIdFn) {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,7 +76,7 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool all
7676
77ZigType *get_src_ptr_type(ZigType *type);77ZigType *get_src_ptr_type(ZigType *type);
78uint32_t get_ptr_align(CodeGen *g, ZigType *type);78uint32_t get_ptr_align(CodeGen *g, ZigType *type);
79bool get_ptr_const(ZigType *type);79bool get_ptr_const(CodeGen *g, ZigType *type);
80ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry);80ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry);
81ZigType *container_ref_type(ZigType *type_entry);81ZigType *container_ref_type(ZigType *type_entry);
82bool type_is_complete(ZigType *type_entry);82bool 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,11 +25479,22 @@ static IrInstGen *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstSrcE
25479static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) {25479static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) {
25480 Error err;25480 Error err;
2548125481
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 assert(ptr_type != nullptr);25489 assert(ptr_type != nullptr);
25484 if (ptr_type->id == ZigTypeIdPointer) {25490 if (ptr_type->id == ZigTypeIdPointer) {
25485 if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))25491 if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
25486 return err;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 }
2548825499
25489 *result_align = get_ptr_align(ira->codegen, ty);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,10 +27626,18 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
27615 // We have a check for zero bits later so we use get_src_ptr_type to27626 // We have a check for zero bits later so we use get_src_ptr_type to
27616 // validate src_type and dest_type.27627 // validate src_type and dest_type.
2761727628
27618 ZigType *src_ptr_type = get_src_ptr_type(src_type);27629 ZigType *if_slice_ptr_type;
27619 if (src_ptr_type == nullptr) {27630 if (is_slice(src_type)) {
27620 ir_add_error(ira, ptr_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name)));27631 TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index];
27621 return ira->codegen->invalid_inst_gen;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 }
2762327642
27624 ZigType *dest_ptr_type = get_src_ptr_type(dest_type);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,7 +27647,7 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
27628 return ira->codegen->invalid_inst_gen;27647 return ira->codegen->invalid_inst_gen;
27629 }27648 }
2763027649
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 ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier"));27651 ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier"));
27633 return ira->codegen->invalid_inst_gen;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,7 +27665,10 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
27646 if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown)))27665 if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown)))
27647 return ira->codegen->invalid_inst_gen;27666 return ira->codegen->invalid_inst_gen;
2764827667
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 ErrorMsg *msg = ir_add_error(ira, source_instr,27672 ErrorMsg *msg = ir_add_error(ira, source_instr,
27651 buf_sprintf("'%s' and '%s' do not have the same in-memory representation",27673 buf_sprintf("'%s' and '%s' do not have the same in-memory representation",
27652 buf_ptr(&src_type->name), buf_ptr(&dest_type->name)));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,6 +27679,14 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
27657 return ira->codegen->invalid_inst_gen;27679 return ira->codegen->invalid_inst_gen;
27658 }27680 }
2765927681
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 if (instr_is_comptime(ptr)) {27690 if (instr_is_comptime(ptr)) {
27661 bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type);27691 bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type);
27662 UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad;27692 UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad;