authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-12-22 23:06:30-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-12-22 23:06:30-05:00
log218a4d4b30f320797121ad9900d48743da77a1b3
tree7053521d213997e49a4342dee28b7b583162897c
parentf301474531fc640729aaa52d66209317c76367c8
signature Commit is signed but in an unrecognized format.

comptime: ability to @ptrCast to an extern struct and read fields


2 files changed, 68 insertions(+), 15 deletions(-)

src/ir.cpp+49-15
......@@ -159,7 +159,7 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op
159159static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval);
160160static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align);
161161static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align);
162static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val);
162static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t *buf, ConstExprValue *val);
163163static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val);
164164static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node,
165165 ConstExprValue *out_val, ConstExprValue *ptr_val);
......@@ -13725,7 +13725,8 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node,
1372513725 Buf buf = BUF_INIT;
1372613726 buf_resize(&buf, src_size);
1372713727 buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), pointee);
13728 buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val);
13728 if ((err = buf_read_value_bytes(ira, source_node, (uint8_t*)buf_ptr(&buf), out_val)))
13729 return err;
1372913730 return ErrorNone;
1373013731 }
1373113732
......@@ -13759,7 +13760,8 @@ static Error ir_read_const_ptr(IrAnalyze *ira, AstNode *source_node,
1375913760 ConstExprValue *elem_val = &array_val->data.x_array.data.s_none.elements[elem_index + i];
1376013761 buf_write_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val);
1376113762 }
13762 buf_read_value_bytes(ira->codegen, (uint8_t*)buf_ptr(&buf), out_val);
13763 if ((err = buf_read_value_bytes(ira, source_node, (uint8_t*)buf_ptr(&buf), out_val)))
13764 return err;
1376313765 return ErrorNone;
1376413766 }
1376513767 case ConstPtrSpecialBaseStruct:
......@@ -20077,7 +20079,8 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
2007720079 zig_unreachable();
2007820080}
2007920081
20080static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) {
20082static Error buf_read_value_bytes(IrAnalyze *ira, AstNode *source_node, uint8_t *buf, ConstExprValue *val) {
20083 Error err;
2008120084 assert(val->special == ConstValSpecialStatic);
2008220085 switch (val->type->id) {
2008320086 case ZigTypeIdInvalid:
......@@ -20094,30 +20097,60 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
2009420097 case ZigTypeIdPromise:
2009520098 zig_unreachable();
2009620099 case ZigTypeIdVoid:
20097 return;
20100 return ErrorNone;
2009820101 case ZigTypeIdBool:
2009920102 val->data.x_bool = (buf[0] != 0);
20100 return;
20103 return ErrorNone;
2010120104 case ZigTypeIdInt:
2010220105 bigint_read_twos_complement(&val->data.x_bigint, buf, val->type->data.integral.bit_count,
20103 codegen->is_big_endian, val->type->data.integral.is_signed);
20104 return;
20106 ira->codegen->is_big_endian, val->type->data.integral.is_signed);
20107 return ErrorNone;
2010520108 case ZigTypeIdFloat:
20106 float_read_ieee597(val, buf, codegen->is_big_endian);
20107 return;
20109 float_read_ieee597(val, buf, ira->codegen->is_big_endian);
20110 return ErrorNone;
2010820111 case ZigTypeIdPointer:
2010920112 {
2011020113 val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr;
2011120114 BigInt bn;
20112 bigint_read_twos_complement(&bn, buf, codegen->builtin_types.entry_usize->data.integral.bit_count,
20113 codegen->is_big_endian, false);
20115 bigint_read_twos_complement(&bn, buf, ira->codegen->builtin_types.entry_usize->data.integral.bit_count,
20116 ira->codegen->is_big_endian, false);
2011420117 val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&bn);
20115 return;
20118 return ErrorNone;
2011620119 }
2011720120 case ZigTypeIdArray:
2011820121 zig_panic("TODO buf_read_value_bytes array type");
2011920122 case ZigTypeIdStruct:
20120 zig_panic("TODO buf_read_value_bytes struct type");
20123 switch (val->type->data.structure.layout) {
20124 case ContainerLayoutAuto: {
20125 ErrorMsg *msg = ir_add_error_node(ira, source_node,
20126 buf_sprintf("non-extern, non-packed struct '%s' cannot have its bytes reinterpreted",
20127 buf_ptr(&val->type->name)));
20128 add_error_note(ira->codegen, msg, val->type->data.structure.decl_node,
20129 buf_sprintf("declared here"));
20130 return ErrorSemanticAnalyzeFail;
20131 }
20132 case ContainerLayoutExtern: {
20133 size_t src_field_count = val->type->data.structure.src_field_count;
20134 val->data.x_struct.fields = create_const_vals(src_field_count);
20135 for (size_t field_i = 0; field_i < src_field_count; field_i += 1) {
20136 ConstExprValue *field_val = &val->data.x_struct.fields[field_i];
20137 field_val->special = ConstValSpecialStatic;
20138 TypeStructField *type_field = &val->type->data.structure.fields[field_i];
20139 field_val->type = type_field->type_entry;
20140 if (type_field->gen_index == SIZE_MAX)
20141 continue;
20142 size_t offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, val->type->type_ref,
20143 type_field->gen_index);
20144 uint8_t *new_buf = buf + offset;
20145 if ((err = buf_read_value_bytes(ira, source_node, new_buf, field_val)))
20146 return err;
20147 }
20148 return ErrorNone;
20149 }
20150 case ContainerLayoutPacked:
20151 zig_panic("TODO buf_read_value_bytes packed struct");
20152 }
20153 zig_unreachable();
2012120154 case ZigTypeIdOptional:
2012220155 zig_panic("TODO buf_read_value_bytes maybe type");
2012320156 case ZigTypeIdErrorUnion:
......@@ -20220,7 +20253,8 @@ static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstruct
2022020253 IrInstruction *result = ir_const(ira, &instruction->base, dest_type);
2022120254 uint8_t *buf = allocate_nonzero<uint8_t>(src_size_bytes);
2022220255 buf_write_value_bytes(ira->codegen, buf, val);
20223 buf_read_value_bytes(ira->codegen, buf, &result->value);
20256 if ((err = buf_read_value_bytes(ira, instruction->base.source_node, buf, &result->value)))
20257 return ira->codegen->invalid_instruction;
2022420258 return result;
2022520259 }
2022620260
test/cases/ptrcast.zig+19
......@@ -15,3 +15,22 @@ fn testReinterpretBytesAsInteger() void {
1515 };
1616 assertOrPanic(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected);
1717}
18
19test "reinterpret bytes of an array into an extern struct" {
20 testReinterpretBytesAsExternStruct();
21 comptime testReinterpretBytesAsExternStruct();
22}
23
24fn testReinterpretBytesAsExternStruct() void {
25 var bytes align(2) = []u8{ 1, 2, 3, 4, 5, 6 };
26
27 const S = extern struct {
28 a: u8,
29 b: u16,
30 c: u8,
31 };
32
33 var ptr = @ptrCast(*const S, &bytes);
34 var val = ptr.c;
35 assertOrPanic(val == 5);
36}