authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-21 14:44:14-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-21 14:44:14-05:00
log1066004b79d014b4c3d10da19c84c679e21b88e5
treedb8c1c83788a624d1fab720073255e8c556d59a0
parent2bb795dc455823e76ef3e0c9b3fcee6bcb15fddb
signature Commit is signed but in an unrecognized format.

better handling of arrays in packed structs

* Separate LoadPtr IR instructions into pass1 and pass2 variants. * Define `type_size_bits` for extern structs to be the same as their `@sizeOf(T) * 8` and allow them in packed structs. * More helpful error messages when trying to use types in packed structs that are not allowed. * Support arrays in packed structs even when they are not byte-aligned. * Add compile error for using arrays in packed structs when the padding bits would be problematic. This is necessary since we do not have packed arrays. closes #677

7 files changed, 246 insertions(+), 50 deletions(-)

src/all_types.hpp+8
...@@ -2119,6 +2119,7 @@ enum IrInstructionId {...@@ -2119,6 +2119,7 @@ enum IrInstructionId {
2119 IrInstructionIdUnOp,2119 IrInstructionIdUnOp,
2120 IrInstructionIdBinOp,2120 IrInstructionIdBinOp,
2121 IrInstructionIdLoadPtr,2121 IrInstructionIdLoadPtr,
2122 IrInstructionIdLoadPtrGen,
2122 IrInstructionIdStorePtr,2123 IrInstructionIdStorePtr,
2123 IrInstructionIdFieldPtr,2124 IrInstructionIdFieldPtr,
2124 IrInstructionIdStructFieldPtr,2125 IrInstructionIdStructFieldPtr,
...@@ -2414,6 +2415,13 @@ struct IrInstructionLoadPtr {...@@ -2414,6 +2415,13 @@ struct IrInstructionLoadPtr {
2414 IrInstruction *ptr;2415 IrInstruction *ptr;
2415};2416};
24162417
2418struct IrInstructionLoadPtrGen {
2419 IrInstruction base;
2420
2421 IrInstruction *ptr;
2422 LLVMValueRef tmp_ptr;
2423};
2424
2417struct IrInstructionStorePtr {2425struct IrInstructionStorePtr {
2418 IrInstruction base;2426 IrInstruction base;
24192427
src/analyze.cpp+73-26
...@@ -365,19 +365,19 @@ uint64_t type_size_bits(CodeGen *g, ZigType *type_entry) {...@@ -365,19 +365,19 @@ uint64_t type_size_bits(CodeGen *g, ZigType *type_entry) {
365 if (!type_has_bits(type_entry))365 if (!type_has_bits(type_entry))
366 return 0;366 return 0;
367367
368 if (type_entry->id == ZigTypeIdStruct && type_entry->data.structure.layout == ContainerLayoutPacked) {368 if (type_entry->id == ZigTypeIdStruct) {
369 uint64_t result = 0;369 if (type_entry->data.structure.layout == ContainerLayoutPacked) {
370 for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {370 uint64_t result = 0;
371 result += type_size_bits(g, type_entry->data.structure.fields[i].type_entry);371 for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
372 result += type_size_bits(g, type_entry->data.structure.fields[i].type_entry);
373 }
374 return result;
375 } else if (type_entry->data.structure.layout == ContainerLayoutExtern) {
376 return type_size(g, type_entry) * 8;
372 }377 }
373 return result;
374 } else if (type_entry->id == ZigTypeIdArray) {378 } else if (type_entry->id == ZigTypeIdArray) {
375 ZigType *child_type = type_entry->data.array.child_type;379 ZigType *child_type = type_entry->data.array.child_type;
376 if (child_type->id == ZigTypeIdStruct &&380 return type_entry->data.array.len * type_size_bits(g, child_type);
377 child_type->data.structure.layout == ContainerLayoutPacked)
378 {
379 return type_entry->data.array.len * type_size_bits(g, child_type);
380 }
381 }381 }
382382
383 return LLVMSizeOfTypeInBits(g->target_data_ref, type_entry->type_ref);383 return LLVMSizeOfTypeInBits(g->target_data_ref, type_entry->type_ref);
...@@ -1444,7 +1444,10 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **...@@ -1444,7 +1444,10 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **
1444 return true;1444 return true;
1445}1445}
14461446
1447static bool type_allowed_in_packed_struct(ZigType *type_entry) {1447static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType *type_entry,
1448 AstNode *source_node)
1449{
1450 Error err;
1448 switch (type_entry->id) {1451 switch (type_entry->id) {
1449 case ZigTypeIdInvalid:1452 case ZigTypeIdInvalid:
1450 zig_unreachable();1453 zig_unreachable();
...@@ -1461,27 +1464,74 @@ static bool type_allowed_in_packed_struct(ZigType *type_entry) {...@@ -1461,27 +1464,74 @@ static bool type_allowed_in_packed_struct(ZigType *type_entry) {
1461 case ZigTypeIdArgTuple:1464 case ZigTypeIdArgTuple:
1462 case ZigTypeIdOpaque:1465 case ZigTypeIdOpaque:
1463 case ZigTypeIdPromise:1466 case ZigTypeIdPromise:
1464 return false;1467 add_node_error(g, source_node,
1468 buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation",
1469 buf_ptr(&type_entry->name)));
1470 return ErrorSemanticAnalyzeFail;
1465 case ZigTypeIdVoid:1471 case ZigTypeIdVoid:
1466 case ZigTypeIdBool:1472 case ZigTypeIdBool:
1467 case ZigTypeIdInt:1473 case ZigTypeIdInt:
1468 case ZigTypeIdFloat:1474 case ZigTypeIdFloat:
1469 case ZigTypeIdPointer:1475 case ZigTypeIdPointer:
1470 case ZigTypeIdArray:
1471 case ZigTypeIdFn:1476 case ZigTypeIdFn:
1472 case ZigTypeIdVector:1477 case ZigTypeIdVector:
1473 return true;1478 return ErrorNone;
1479 case ZigTypeIdArray: {
1480 ZigType *elem_type = type_entry->data.array.child_type;
1481 if ((err = emit_error_unless_type_allowed_in_packed_struct(g, elem_type, source_node)))
1482 return err;
1483 if (type_size(g, type_entry) * 8 == type_size_bits(g, type_entry))
1484 return ErrorNone;
1485 add_node_error(g, source_node,
1486 buf_sprintf("array of '%s' not allowed in packed struct due to padding bits",
1487 buf_ptr(&elem_type->name)));
1488 return ErrorSemanticAnalyzeFail;
1489 }
1474 case ZigTypeIdStruct:1490 case ZigTypeIdStruct:
1475 return type_entry->data.structure.layout == ContainerLayoutPacked;1491 switch (type_entry->data.structure.layout) {
1492 case ContainerLayoutPacked:
1493 case ContainerLayoutExtern:
1494 return ErrorNone;
1495 case ContainerLayoutAuto:
1496 add_node_error(g, source_node,
1497 buf_sprintf("non-packed, non-extern struct '%s' not allowed in packed struct; no guaranteed in-memory representation",
1498 buf_ptr(&type_entry->name)));
1499 return ErrorSemanticAnalyzeFail;
1500 }
1501 zig_unreachable();
1476 case ZigTypeIdUnion:1502 case ZigTypeIdUnion:
1477 return type_entry->data.unionation.layout == ContainerLayoutPacked;1503 switch (type_entry->data.unionation.layout) {
1504 case ContainerLayoutPacked:
1505 case ContainerLayoutExtern:
1506 return ErrorNone;
1507 case ContainerLayoutAuto:
1508 add_node_error(g, source_node,
1509 buf_sprintf("non-packed, non-extern union '%s' not allowed in packed struct; no guaranteed in-memory representation",
1510 buf_ptr(&type_entry->name)));
1511 return ErrorSemanticAnalyzeFail;
1512 }
1513 zig_unreachable();
1478 case ZigTypeIdOptional:1514 case ZigTypeIdOptional:
1479 {1515 if (get_codegen_ptr_type(type_entry) != nullptr) {
1480 ZigType *child_type = type_entry->data.maybe.child_type;1516 return ErrorNone;
1481 return type_is_codegen_pointer(child_type);1517 } else {
1518 add_node_error(g, source_node,
1519 buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation",
1520 buf_ptr(&type_entry->name)));
1521 return ErrorSemanticAnalyzeFail;
1482 }1522 }
1483 case ZigTypeIdEnum:1523 case ZigTypeIdEnum: {
1484 return type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr;1524 AstNode *decl_node = type_entry->data.enumeration.decl_node;
1525 if (decl_node->data.container_decl.init_arg_expr != nullptr) {
1526 return ErrorNone;
1527 }
1528 ErrorMsg *msg = add_node_error(g, source_node,
1529 buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation",
1530 buf_ptr(&type_entry->name)));
1531 add_error_note(g, msg, decl_node,
1532 buf_sprintf("enum declaration does not specify an integer tag type"));
1533 return ErrorSemanticAnalyzeFail;
1534 }
1485 }1535 }
1486 zig_unreachable();1536 zig_unreachable();
1487}1537}
...@@ -2051,11 +2101,8 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {...@@ -2051,11 +2101,8 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
2051 type_struct_field->gen_index = gen_field_index;2101 type_struct_field->gen_index = gen_field_index;
20522102
2053 if (packed) {2103 if (packed) {
2054 if (!type_allowed_in_packed_struct(field_type)) {2104 AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);
2055 AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);2105 if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field_type, field_source_node))) {
2056 add_node_error(g, field_source_node,
2057 buf_sprintf("packed structs cannot contain fields of type '%s'",
2058 buf_ptr(&field_type->name)));
2059 struct_type->data.structure.resolve_status = ResolveStatusInvalid;2106 struct_type->data.structure.resolve_status = ResolveStatusInvalid;
2060 break;2107 break;
2061 }2108 }
src/codegen.cpp+43-7
...@@ -3281,7 +3281,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,...@@ -3281,7 +3281,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
3281 return nullptr;3281 return nullptr;
3282}3282}
32833283
3284static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrInstructionLoadPtr *instruction) {3284static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrInstructionLoadPtrGen *instruction) {
3285 ZigType *child_type = instruction->base.value.type;3285 ZigType *child_type = instruction->base.value.type;
3286 if (!type_has_bits(child_type))3286 if (!type_has_bits(child_type))
3287 return nullptr;3287 return nullptr;
...@@ -3296,7 +3296,6 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI...@@ -3296,7 +3296,6 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
32963296
3297 bool big_endian = g->is_big_endian;3297 bool big_endian = g->is_big_endian;
32983298
3299 assert(!handle_is_ptr(child_type));
3300 LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");3299 LLVMValueRef containing_int = gen_load(g, ptr, ptr_type, "");
3301 uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));3300 uint32_t host_bit_count = LLVMGetIntTypeWidth(LLVMTypeOf(containing_int));
3302 assert(host_bit_count == host_int_bytes * 8);3301 assert(host_bit_count == host_int_bytes * 8);
...@@ -3308,7 +3307,16 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI...@@ -3308,7 +3307,16 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI
3308 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);3307 LLVMValueRef shift_amt_val = LLVMConstInt(LLVMTypeOf(containing_int), shift_amt, false);
3309 LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");3308 LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, "");
33103309
3311 return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, "");3310 if (!handle_is_ptr(child_type))
3311 return LLVMBuildTrunc(g->builder, shifted_value, child_type->type_ref, "");
3312
3313 assert(instruction->tmp_ptr != nullptr);
3314 LLVMTypeRef same_size_int = LLVMIntType(size_in_bits);
3315 LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, shifted_value, same_size_int, "");
3316 LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr,
3317 LLVMPointerType(same_size_int, 0), "");
3318 LLVMBuildStore(g->builder, truncated_int, bitcasted_ptr);
3319 return instruction->tmp_ptr;
3312}3320}
33133321
3314static bool value_is_all_undef_array(ConstExprValue *const_val, size_t len) {3322static bool value_is_all_undef_array(ConstExprValue *const_val, size_t len) {
...@@ -5460,6 +5468,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5460,6 +5468,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5460 case IrInstructionIdDeclVarSrc:5468 case IrInstructionIdDeclVarSrc:
5461 case IrInstructionIdPtrCastSrc:5469 case IrInstructionIdPtrCastSrc:
5462 case IrInstructionIdCmpxchgSrc:5470 case IrInstructionIdCmpxchgSrc:
5471 case IrInstructionIdLoadPtr:
5463 zig_unreachable();5472 zig_unreachable();
54645473
5465 case IrInstructionIdDeclVarGen:5474 case IrInstructionIdDeclVarGen:
...@@ -5478,8 +5487,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -5478,8 +5487,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
5478 return ir_render_br(g, executable, (IrInstructionBr *)instruction);5487 return ir_render_br(g, executable, (IrInstructionBr *)instruction);
5479 case IrInstructionIdUnOp:5488 case IrInstructionIdUnOp:
5480 return ir_render_un_op(g, executable, (IrInstructionUnOp *)instruction);5489 return ir_render_un_op(g, executable, (IrInstructionUnOp *)instruction);
5481 case IrInstructionIdLoadPtr:5490 case IrInstructionIdLoadPtrGen:
5482 return ir_render_load_ptr(g, executable, (IrInstructionLoadPtr *)instruction);5491 return ir_render_load_ptr(g, executable, (IrInstructionLoadPtrGen *)instruction);
5483 case IrInstructionIdStorePtr:5492 case IrInstructionIdStorePtr:
5484 return ir_render_store_ptr(g, executable, (IrInstructionStorePtr *)instruction);5493 return ir_render_store_ptr(g, executable, (IrInstructionStorePtr *)instruction);
5485 case IrInstructionIdVarPtr:5494 case IrInstructionIdVarPtr:
...@@ -5836,8 +5845,32 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con...@@ -5836,8 +5845,32 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
5836 LLVMValueRef ptr_size_int_val = LLVMConstPtrToInt(ptr_val, g->builtin_types.entry_usize->type_ref);5845 LLVMValueRef ptr_size_int_val = LLVMConstPtrToInt(ptr_val, g->builtin_types.entry_usize->type_ref);
5837 return LLVMConstZExt(ptr_size_int_val, big_int_type_ref);5846 return LLVMConstZExt(ptr_size_int_val, big_int_type_ref);
5838 }5847 }
5839 case ZigTypeIdArray:5848 case ZigTypeIdArray: {
5840 zig_panic("TODO bit pack an array");5849 LLVMValueRef val = LLVMConstInt(big_int_type_ref, 0, false);
5850 if (const_val->data.x_array.special == ConstArraySpecialUndef) {
5851 return val;
5852 }
5853 expand_undef_array(g, const_val);
5854 bool is_big_endian = g->is_big_endian; // TODO get endianness from struct type
5855 uint32_t packed_bits_size = type_size_bits(g, type_entry->data.array.child_type);
5856 size_t used_bits = 0;
5857 for (size_t i = 0; i < type_entry->data.array.len; i += 1) {
5858 ConstExprValue *elem_val = &const_val->data.x_array.data.s_none.elements[i];
5859 LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, elem_val);
5860
5861 if (is_big_endian) {
5862 LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, packed_bits_size, false);
5863 val = LLVMConstShl(val, shift_amt);
5864 val = LLVMConstOr(val, child_val);
5865 } else {
5866 LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false);
5867 LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt);
5868 val = LLVMConstOr(val, child_val_shifted);
5869 used_bits += packed_bits_size;
5870 }
5871 }
5872 return val;
5873 }
5841 case ZigTypeIdVector:5874 case ZigTypeIdVector:
5842 zig_panic("TODO bit pack a vector");5875 zig_panic("TODO bit pack a vector");
5843 case ZigTypeIdUnion:5876 case ZigTypeIdUnion:
...@@ -6728,6 +6761,9 @@ static void do_code_gen(CodeGen *g) {...@@ -6728,6 +6761,9 @@ static void do_code_gen(CodeGen *g) {
6728 } else if (instruction->id == IrInstructionIdResizeSlice) {6761 } else if (instruction->id == IrInstructionIdResizeSlice) {
6729 IrInstructionResizeSlice *resize_slice_instruction = (IrInstructionResizeSlice *)instruction;6762 IrInstructionResizeSlice *resize_slice_instruction = (IrInstructionResizeSlice *)instruction;
6730 slot = &resize_slice_instruction->tmp_ptr;6763 slot = &resize_slice_instruction->tmp_ptr;
6764 } else if (instruction->id == IrInstructionIdLoadPtrGen) {
6765 IrInstructionLoadPtrGen *load_ptr_inst = (IrInstructionLoadPtrGen *)instruction;
6766 slot = &load_ptr_inst->tmp_ptr;
6731 } else if (instruction->id == IrInstructionIdVectorToArray) {6767 } else if (instruction->id == IrInstructionIdVectorToArray) {
6732 IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction;6768 IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction;
6733 alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type);6769 alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type);
src/ir.cpp+26-6
...@@ -416,6 +416,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionLoadPtr *) {...@@ -416,6 +416,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionLoadPtr *) {
416 return IrInstructionIdLoadPtr;416 return IrInstructionIdLoadPtr;
417}417}
418418
419static constexpr IrInstructionId ir_instruction_id(IrInstructionLoadPtrGen *) {
420 return IrInstructionIdLoadPtrGen;
421}
422
419static constexpr IrInstructionId ir_instruction_id(IrInstructionStorePtr *) {423static constexpr IrInstructionId ir_instruction_id(IrInstructionStorePtr *) {
420 return IrInstructionIdStorePtr;424 return IrInstructionIdStorePtr;
421}425}
...@@ -2292,6 +2296,19 @@ static IrInstruction *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInstruction *sourc...@@ -2292,6 +2296,19 @@ static IrInstruction *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInstruction *sourc
2292 return &instruction->base;2296 return &instruction->base;
2293}2297}
22942298
2299static IrInstruction *ir_build_load_ptr_gen(IrAnalyze *ira, IrInstruction *source_instruction,
2300 IrInstruction *ptr, ZigType *ty)
2301{
2302 IrInstructionLoadPtrGen *instruction = ir_build_instruction<IrInstructionLoadPtrGen>(
2303 &ira->new_irb, source_instruction->scope, source_instruction->source_node);
2304 instruction->base.value.type = ty;
2305 instruction->ptr = ptr;
2306
2307 ir_ref_instruction(ptr, ira->new_irb.current_basic_block);
2308
2309 return &instruction->base;
2310}
2311
2295static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,2312static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
2296 IrInstruction *dest_type, IrInstruction *value)2313 IrInstruction *dest_type, IrInstruction *value)
2297{2314{
...@@ -11534,10 +11551,11 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc...@@ -11534,10 +11551,11 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc
11534 IrInstructionRef *ref_inst = reinterpret_cast<IrInstructionRef *>(ptr);11551 IrInstructionRef *ref_inst = reinterpret_cast<IrInstructionRef *>(ptr);
11535 return ref_inst->value;11552 return ref_inst->value;
11536 }11553 }
11537 IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope,11554 IrInstruction *result = ir_build_load_ptr_gen(ira, source_instruction, ptr, child_type);
11538 source_instruction->source_node, ptr);11555 if (type_entry->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) {
11539 load_ptr_instruction->value.type = child_type;11556 ir_add_alloca(ira, result, child_type);
11540 return load_ptr_instruction;11557 }
11558 return result;
11541 } else {11559 } else {
11542 ir_add_error_node(ira, source_instruction->source_node,11560 ir_add_error_node(ira, source_instruction->source_node,
11543 buf_sprintf("attempt to dereference non-pointer type '%s'",11561 buf_sprintf("attempt to dereference non-pointer type '%s'",
...@@ -13398,8 +13416,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio...@@ -13398,8 +13416,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
13398 }13416 }
1339913417
13400 // TODO audit the various ways to use @export13418 // TODO audit the various ways to use @export
13401 if (want_var_export && target->id == IrInstructionIdLoadPtr) {13419 if (want_var_export && target->id == IrInstructionIdLoadPtrGen) {
13402 IrInstructionLoadPtr *load_ptr = reinterpret_cast<IrInstructionLoadPtr *>(target);13420 IrInstructionLoadPtrGen *load_ptr = reinterpret_cast<IrInstructionLoadPtrGen *>(target);
13403 if (load_ptr->ptr->id == IrInstructionIdVarPtr) {13421 if (load_ptr->ptr->id == IrInstructionIdVarPtr) {
13404 IrInstructionVarPtr *var_ptr = reinterpret_cast<IrInstructionVarPtr *>(load_ptr->ptr);13422 IrInstructionVarPtr *var_ptr = reinterpret_cast<IrInstructionVarPtr *>(load_ptr->ptr);
13405 ZigVar *var = var_ptr->var;13423 ZigVar *var = var_ptr->var;
...@@ -22316,6 +22334,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio...@@ -22316,6 +22334,7 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio
22316 case IrInstructionIdVectorToArray:22334 case IrInstructionIdVectorToArray:
22317 case IrInstructionIdAssertZero:22335 case IrInstructionIdAssertZero:
22318 case IrInstructionIdResizeSlice:22336 case IrInstructionIdResizeSlice:
22337 case IrInstructionIdLoadPtrGen:
22319 zig_unreachable();22338 zig_unreachable();
2232022339
22321 case IrInstructionIdReturn:22340 case IrInstructionIdReturn:
...@@ -22722,6 +22741,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -22722,6 +22741,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
22722 case IrInstructionIdUnOp:22741 case IrInstructionIdUnOp:
22723 case IrInstructionIdBinOp:22742 case IrInstructionIdBinOp:
22724 case IrInstructionIdLoadPtr:22743 case IrInstructionIdLoadPtr:
22744 case IrInstructionIdLoadPtrGen:
22725 case IrInstructionIdConst:22745 case IrInstructionIdConst:
22726 case IrInstructionIdCast:22746 case IrInstructionIdCast:
22727 case IrInstructionIdContainerInitList:22747 case IrInstructionIdContainerInitList:
src/ir_print.cpp+8
...@@ -336,6 +336,11 @@ static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) {...@@ -336,6 +336,11 @@ static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) {
336 fprintf(irp->f, ".*");336 fprintf(irp->f, ".*");
337}337}
338338
339static void ir_print_load_ptr_gen(IrPrint *irp, IrInstructionLoadPtrGen *instruction) {
340 ir_print_other_instruction(irp, instruction->ptr);
341 fprintf(irp->f, ".*");
342}
343
339static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) {344static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) {
340 fprintf(irp->f, "*");345 fprintf(irp->f, "*");
341 ir_print_var_instruction(irp, instruction->ptr);346 ir_print_var_instruction(irp, instruction->ptr);
...@@ -1468,6 +1473,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1468,6 +1473,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1468 case IrInstructionIdLoadPtr:1473 case IrInstructionIdLoadPtr:
1469 ir_print_load_ptr(irp, (IrInstructionLoadPtr *)instruction);1474 ir_print_load_ptr(irp, (IrInstructionLoadPtr *)instruction);
1470 break;1475 break;
1476 case IrInstructionIdLoadPtrGen:
1477 ir_print_load_ptr_gen(irp, (IrInstructionLoadPtrGen *)instruction);
1478 break;
1471 case IrInstructionIdStorePtr:1479 case IrInstructionIdStorePtr:
1472 ir_print_store_ptr(irp, (IrInstructionStorePtr *)instruction);1480 ir_print_store_ptr(irp, (IrInstructionStorePtr *)instruction);
1473 break;1481 break;
test/compile_errors.zig+54
...@@ -1,6 +1,60 @@...@@ -1,6 +1,60 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: *tests.CompileErrorContext) void {3pub fn addCases(cases: *tests.CompileErrorContext) void {
4 cases.addTest(
5 "packed struct with fields of not allowed types",
6 \\const A = packed struct {
7 \\ x: anyerror,
8 \\};
9 \\const B = packed struct {
10 \\ x: [2]u24,
11 \\};
12 \\const C = packed struct {
13 \\ x: [1]anyerror,
14 \\};
15 \\const D = packed struct {
16 \\ x: [1]S,
17 \\};
18 \\const E = packed struct {
19 \\ x: [1]U,
20 \\};
21 \\const F = packed struct {
22 \\ x: ?anyerror,
23 \\};
24 \\const G = packed struct {
25 \\ x: Enum,
26 \\};
27 \\export fn entry() void {
28 \\ var a: A = undefined;
29 \\ var b: B = undefined;
30 \\ var r: C = undefined;
31 \\ var d: D = undefined;
32 \\ var e: E = undefined;
33 \\ var f: F = undefined;
34 \\ var g: G = undefined;
35 \\}
36 \\const S = struct {
37 \\ x: i32,
38 \\};
39 \\const U = struct {
40 \\ A: i32,
41 \\ B: u32,
42 \\};
43 \\const Enum = enum {
44 \\ A,
45 \\ B,
46 \\};
47 ,
48 ".tmp_source.zig:2:5: error: type 'anyerror' not allowed in packed struct; no guaranteed in-memory representation",
49 ".tmp_source.zig:5:5: error: array of 'u24' not allowed in packed struct due to padding bits",
50 ".tmp_source.zig:8:5: error: type 'anyerror' not allowed in packed struct; no guaranteed in-memory representation",
51 ".tmp_source.zig:11:5: error: non-packed, non-extern struct 'S' not allowed in packed struct; no guaranteed in-memory representation",
52 ".tmp_source.zig:14:5: error: non-packed, non-extern struct 'U' not allowed in packed struct; no guaranteed in-memory representation",
53 ".tmp_source.zig:17:5: error: type '?anyerror' not allowed in packed struct; no guaranteed in-memory representation",
54 ".tmp_source.zig:20:5: error: type 'Enum' not allowed in packed struct; no guaranteed in-memory representation",
55 ".tmp_source.zig:38:14: note: enum declaration does not specify an integer tag type",
56 );
57
4 cases.addCase(x: {58 cases.addCase(x: {
5 var tc = cases.create(59 var tc = cases.create(
6 "deduplicate undeclared identifier",60 "deduplicate undeclared identifier",
test/stage1/behavior/struct.zig+34-11
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const expect = std.testing.expect;2const expect = std.testing.expect;
3const expectEqualSlices = std.testing.expectEqualSlices;
3const builtin = @import("builtin");4const builtin = @import("builtin");
4const maxInt = std.math.maxInt;5const maxInt = std.math.maxInt;
56
...@@ -103,19 +104,20 @@ fn structInitializer() void {...@@ -103,19 +104,20 @@ fn structInitializer() void {
103}104}
104105
105test "fn call of struct field" {106test "fn call of struct field" {
106 expect(callStructField(Foo{ .ptr = aFunc }) == 13);107 const Foo = struct {
107}108 ptr: fn () i32,
108109 };
109const Foo = struct {110 const S = struct {
110 ptr: fn () i32,111 fn aFunc() i32 {
111};112 return 13;
113 }
112114
113fn aFunc() i32 {115 fn callStructField(foo: Foo) i32 {
114 return 13;116 return foo.ptr();
115}117 }
118 };
116119
117fn callStructField(foo: Foo) i32 {120 expect(S.callStructField(Foo{ .ptr = S.aFunc }) == 13);
118 return foo.ptr();
119}121}
120122
121test "store member function in variable" {123test "store member function in variable" {
...@@ -468,3 +470,24 @@ test "pointer to packed struct member in a stack variable" {...@@ -468,3 +470,24 @@ test "pointer to packed struct member in a stack variable" {
468 b_ptr.* = 2;470 b_ptr.* = 2;
469 expect(s.b == 2);471 expect(s.b == 2);
470}472}
473
474test "non-byte-aligned array inside packed struct" {
475 const Foo = packed struct {
476 a: bool,
477 b: [0x16]u8,
478 };
479 const S = struct {
480 fn bar(slice: []const u8) void {
481 expectEqualSlices(u8, slice, "abcdefghijklmnopqurstu");
482 }
483 fn doTheTest() void {
484 var foo = Foo{
485 .a = true,
486 .b = "abcdefghijklmnopqurstu",
487 };
488 bar(foo.b);
489 }
490 };
491 S.doTheTest();
492 comptime S.doTheTest();
493}