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 {
17501750}
17511751
17521752pub 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
17551753 // let's not give an undefined pointer to @ptrCast
17561754 // it may be equal to zero and fail a null check
1757 if (bytesSlice.len == 0) {
1755 if (bytes.len == 0) {
17581756 return &[0]T{};
17591757 }
17601758
1761 const bytesType = @TypeOf(bytesSlice);
1762 const alignment = comptime meta.alignment(bytesType);
1759 const Bytes = @TypeOf(bytes);
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))];
17671765}
17681766
17691767test "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 }
17751783}
17761784
17771785test "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 }
17811797}
17821798
17831799test "bytesAsSlice on a packed struct" {
src/analyze.cpp+17-3
......@@ -4486,7 +4486,14 @@ static uint32_t get_async_frame_align_bytes(CodeGen *g) {
44864486}
44874487
44884488uint32_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 }
44904497 if (ptr_type->id == ZigTypeIdPointer) {
44914498 return (ptr_type->data.pointer.explicit_alignment == 0) ?
44924499 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) {
45034510 }
45044511}
45054512
4506bool get_ptr_const(ZigType *type) {
4507 ZigType *ptr_type = get_src_ptr_type(type);
4513bool 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 }
45084522 if (ptr_type->id == ZigTypeIdPointer) {
45094523 return ptr_type->data.pointer.is_const;
45104524 } 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
7676
7777ZigType *get_src_ptr_type(ZigType *type);
7878uint32_t get_ptr_align(CodeGen *g, ZigType *type);
79bool get_ptr_const(ZigType *type);
79bool get_ptr_const(CodeGen *g, ZigType *type);
8080ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry);
8181ZigType *container_ref_type(ZigType *type_entry);
8282bool 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
2547925479static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) {
2548025480 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 }
2548325489 assert(ptr_type != nullptr);
2548425490 if (ptr_type->id == ZigTypeIdPointer) {
2548525491 if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown)))
2548625492 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;
2548725498 }
2548825499
2548925500 *result_align = get_ptr_align(ira->codegen, ty);
......@@ -27615,10 +27626,18 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
2761527626 // We have a check for zero bits later so we use get_src_ptr_type to
2761627627 // validate src_type and dest_type.
2761727628
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 }
2762227641 }
2762327642
2762427643 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
2762827647 return ira->codegen->invalid_inst_gen;
2762927648 }
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)) {
2763227651 ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier"));
2763327652 return ira->codegen->invalid_inst_gen;
2763427653 }
......@@ -27646,7 +27665,10 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn
2764627665 if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown)))
2764727666 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 {
2765027672 ErrorMsg *msg = ir_add_error(ira, source_instr,
2765127673 buf_sprintf("'%s' and '%s' do not have the same in-memory representation",
2765227674 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
2765727679 return ira->codegen->invalid_inst_gen;
2765827680 }
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
2766027690 if (instr_is_comptime(ptr)) {
2766127691 bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type);
2766227692 UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad;