authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-23 15:02:38-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-23 15:02:38-04:00
log53ae03ebe9e0aa56bca1c9219a47d124b0435258
tree2f69fc4aeb6bdbc9567338b033337c4556f5c0c0
parent29b82d20a4534fc7e3393c21ad637d44d20449a2
signaturelock-open Commit is signed but in an unrecognized format.

make type_allowed_in_extern more robust

Previously if the type parameter was a pointer, it would assert that the size of the type was resolved. It used to be that the size of pointers was always resolved, however with lazy values, pointers gained the possibility of not having their size resolved. Now, type_allowed_in_extern triggers the resolution of whether a pointer is zero bits, and returns a possible error if the resolution fails. This fixes a compiler assertion when building the [zootdeck project](https://github.com/donpdonp/zootdeck). I do not have a test case reduction for the issue.

3 files changed, 105 insertions(+), 53 deletions(-)

src/analyze.cpp+91-49
...@@ -1538,7 +1538,8 @@ static Error emit_error_unless_type_allowed_in_packed_union(CodeGen *g, ZigType...@@ -1538,7 +1538,8 @@ static Error emit_error_unless_type_allowed_in_packed_union(CodeGen *g, ZigType
1538 return emit_error_unless_type_allowed_in_packed_container(g, type_entry, source_node, "union");1538 return emit_error_unless_type_allowed_in_packed_container(g, type_entry, source_node, "union");
1539}1539}
15401540
1541bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {1541Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result) {
1542 Error err;
1542 switch (type_entry->id) {1543 switch (type_entry->id) {
1543 case ZigTypeIdInvalid:1544 case ZigTypeIdInvalid:
1544 zig_unreachable();1545 zig_unreachable();
...@@ -1555,11 +1556,13 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {...@@ -1555,11 +1556,13 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {
1555 case ZigTypeIdVoid:1556 case ZigTypeIdVoid:
1556 case ZigTypeIdFnFrame:1557 case ZigTypeIdFnFrame:
1557 case ZigTypeIdAnyFrame:1558 case ZigTypeIdAnyFrame:
1558 return false;1559 *result = false;
1560 return ErrorNone;
1559 case ZigTypeIdOpaque:1561 case ZigTypeIdOpaque:
1560 case ZigTypeIdUnreachable:1562 case ZigTypeIdUnreachable:
1561 case ZigTypeIdBool:1563 case ZigTypeIdBool:
1562 return true;1564 *result = true;
1565 return ErrorNone;
1563 case ZigTypeIdInt:1566 case ZigTypeIdInt:
1564 switch (type_entry->data.integral.bit_count) {1567 switch (type_entry->data.integral.bit_count) {
1565 case 8:1568 case 8:
...@@ -1567,37 +1570,52 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {...@@ -1567,37 +1570,52 @@ bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {
1567 case 32:1570 case 32:
1568 case 64:1571 case 64:
1569 case 128:1572 case 128:
1570 return true;1573 *result = true;
1574 return ErrorNone;
1571 default:1575 default:
1572 return false;1576 *result = false;
1577 return ErrorNone;
1573 }1578 }
1574 case ZigTypeIdVector:1579 case ZigTypeIdVector:
1575 return type_allowed_in_extern(g, type_entry->data.vector.elem_type);1580 return type_allowed_in_extern(g, type_entry->data.vector.elem_type, result);
1576 case ZigTypeIdFloat:1581 case ZigTypeIdFloat:
1577 return true;1582 *result = true;
1583 return ErrorNone;
1578 case ZigTypeIdArray:1584 case ZigTypeIdArray:
1579 return type_allowed_in_extern(g, type_entry->data.array.child_type);1585 return type_allowed_in_extern(g, type_entry->data.array.child_type, result);
1580 case ZigTypeIdFn:1586 case ZigTypeIdFn:
1581 return type_entry->data.fn.fn_type_id.cc == CallingConventionC ||1587 *result = type_entry->data.fn.fn_type_id.cc == CallingConventionC ||
1582 type_entry->data.fn.fn_type_id.cc == CallingConventionStdcall;1588 type_entry->data.fn.fn_type_id.cc == CallingConventionStdcall;
1589 return ErrorNone;
1583 case ZigTypeIdPointer:1590 case ZigTypeIdPointer:
1584 if (type_size(g, type_entry) == 0)1591 if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
1585 return false;1592 return err;
1586 return true;1593 if (!type_has_bits(type_entry)) {
1594 *result = false;
1595 return ErrorNone;
1596 }
1597 *result = true;
1598 return ErrorNone;
1587 case ZigTypeIdStruct:1599 case ZigTypeIdStruct:
1588 return type_entry->data.structure.layout == ContainerLayoutExtern || type_entry->data.structure.layout == ContainerLayoutPacked;1600 *result = type_entry->data.structure.layout == ContainerLayoutExtern ||
1589 case ZigTypeIdOptional:1601 type_entry->data.structure.layout == ContainerLayoutPacked;
1590 {1602 return ErrorNone;
1591 ZigType *child_type = type_entry->data.maybe.child_type;1603 case ZigTypeIdOptional: {
1592 if (child_type->id != ZigTypeIdPointer && child_type->id != ZigTypeIdFn) {1604 ZigType *child_type = type_entry->data.maybe.child_type;
1593 return false;1605 if (child_type->id != ZigTypeIdPointer && child_type->id != ZigTypeIdFn) {
1594 }1606 *result = false;
1595 return type_allowed_in_extern(g, child_type);1607 return ErrorNone;
1596 }1608 }
1609 return type_allowed_in_extern(g, child_type, result);
1610 }
1597 case ZigTypeIdEnum:1611 case ZigTypeIdEnum:
1598 return type_entry->data.enumeration.layout == ContainerLayoutExtern || type_entry->data.enumeration.layout == ContainerLayoutPacked;1612 *result = type_entry->data.enumeration.layout == ContainerLayoutExtern ||
1613 type_entry->data.enumeration.layout == ContainerLayoutPacked;
1614 return ErrorNone;
1599 case ZigTypeIdUnion:1615 case ZigTypeIdUnion:
1600 return type_entry->data.unionation.layout == ContainerLayoutExtern || type_entry->data.unionation.layout == ContainerLayoutPacked;1616 *result = type_entry->data.unionation.layout == ContainerLayoutExtern ||
1617 type_entry->data.unionation.layout == ContainerLayoutPacked;
1618 return ErrorNone;
1601 }1619 }
1602 zig_unreachable();1620 zig_unreachable();
1603}1621}
...@@ -1687,12 +1705,17 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc...@@ -1687,12 +1705,17 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
1687 }1705 }
1688 }1706 }
16891707
1690 if (!calling_convention_allows_zig_types(fn_type_id.cc) && !type_allowed_in_extern(g, type_entry)) {1708 if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
1691 add_node_error(g, param_node->data.param_decl.type,1709 bool ok_type;
1692 buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'",1710 if ((err = type_allowed_in_extern(g, type_entry, &ok_type)))
1693 buf_ptr(&type_entry->name),1711 return g->builtin_types.entry_invalid;
1694 calling_convention_name(fn_type_id.cc)));1712 if (!ok_type) {
1695 return g->builtin_types.entry_invalid;1713 add_node_error(g, param_node->data.param_decl.type,
1714 buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'",
1715 buf_ptr(&type_entry->name),
1716 calling_convention_name(fn_type_id.cc)));
1717 return g->builtin_types.entry_invalid;
1718 }
1696 }1719 }
16971720
1698 switch (type_entry->id) {1721 switch (type_entry->id) {
...@@ -1809,7 +1832,10 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc...@@ -1809,7 +1832,10 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
1809 {1832 {
1810 if ((err = type_resolve(g, fn_type_id.return_type, ResolveStatusSizeKnown)))1833 if ((err = type_resolve(g, fn_type_id.return_type, ResolveStatusSizeKnown)))
1811 return g->builtin_types.entry_invalid;1834 return g->builtin_types.entry_invalid;
1812 if (!type_allowed_in_extern(g, fn_type_id.return_type)) {1835 bool ok_type;
1836 if ((err = type_allowed_in_extern(g, fn_type_id.return_type, &ok_type)))
1837 return g->builtin_types.entry_invalid;
1838 if (!ok_type) {
1813 add_node_error(g, fn_proto->return_type,1839 add_node_error(g, fn_proto->return_type,
1814 buf_sprintf("return type '%s' not allowed in function with calling convention '%s'",1840 buf_sprintf("return type '%s' not allowed in function with calling convention '%s'",
1815 buf_ptr(&fn_type_id.return_type->name),1841 buf_ptr(&fn_type_id.return_type->name),
...@@ -2128,14 +2154,19 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {...@@ -2128,14 +2154,19 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
2128 return err;2154 return err;
2129 }2155 }
21302156
2131 if (struct_type->data.structure.layout == ContainerLayoutExtern &&2157 if (struct_type->data.structure.layout == ContainerLayoutExtern) {
2132 !type_allowed_in_extern(g, field_type))2158 bool ok_type;
2133 {2159 if ((err = type_allowed_in_extern(g, field_type, &ok_type))) {
2134 add_node_error(g, field->decl_node,2160 struct_type->data.structure.resolve_status = ResolveStatusInvalid;
2135 buf_sprintf("extern structs cannot contain fields of type '%s'",2161 return ErrorSemanticAnalyzeFail;
2136 buf_ptr(&field_type->name)));2162 }
2137 struct_type->data.structure.resolve_status = ResolveStatusInvalid;2163 if (!ok_type) {
2138 return ErrorSemanticAnalyzeFail;2164 add_node_error(g, field->decl_node,
2165 buf_sprintf("extern structs cannot contain fields of type '%s'",
2166 buf_ptr(&field_type->name)));
2167 struct_type->data.structure.resolve_status = ResolveStatusInvalid;
2168 return ErrorSemanticAnalyzeFail;
2169 }
2139 }2170 }
2140 }2171 }
21412172
...@@ -2368,19 +2399,22 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {...@@ -2368,19 +2399,22 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
2368 return ErrorNone;2399 return ErrorNone;
2369}2400}
23702401
2371static bool type_is_valid_extern_enum_tag(CodeGen *g, ZigType *ty) {2402static Error type_is_valid_extern_enum_tag(CodeGen *g, ZigType *ty, bool *result) {
2372 // Only integer types are allowed by the C ABI2403 // Only integer types are allowed by the C ABI
2373 if(ty->id != ZigTypeIdInt)2404 if(ty->id != ZigTypeIdInt) {
2374 return false;2405 *result = false;
2406 return ErrorNone;
2407 }
23752408
2376 // According to the ANSI C standard the enumeration type should be either a2409 // According to the ANSI C standard the enumeration type should be either a
2377 // signed char, a signed integer or an unsigned one. But GCC/Clang allow2410 // signed char, a signed integer or an unsigned one. But GCC/Clang allow
2378 // other integral types as a compiler extension so let's accomodate them2411 // other integral types as a compiler extension so let's accomodate them
2379 // aswell.2412 // aswell.
2380 return type_allowed_in_extern(g, ty);2413 return type_allowed_in_extern(g, ty, result);
2381}2414}
23822415
2383static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {2416static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
2417 Error err;
2384 assert(enum_type->id == ZigTypeIdEnum);2418 assert(enum_type->id == ZigTypeIdEnum);
23852419
2386 if (enum_type->data.enumeration.resolve_status == ResolveStatusInvalid)2420 if (enum_type->data.enumeration.resolve_status == ResolveStatusInvalid)
...@@ -2443,15 +2477,23 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {...@@ -2443,15 +2477,23 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
2443 enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;2477 enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
2444 add_node_error(g, decl_node->data.container_decl.init_arg_expr,2478 add_node_error(g, decl_node->data.container_decl.init_arg_expr,
2445 buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name)));2479 buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name)));
2446 } else if (enum_type->data.enumeration.layout == ContainerLayoutExtern &&
2447 !type_is_valid_extern_enum_tag(g, wanted_tag_int_type)) {
2448 enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
2449 ErrorMsg *msg = add_node_error(g, decl_node->data.container_decl.init_arg_expr,
2450 buf_sprintf("'%s' is not a valid tag type for an extern enum",
2451 buf_ptr(&wanted_tag_int_type->name)));
2452 add_error_note(g, msg, decl_node->data.container_decl.init_arg_expr,
2453 buf_sprintf("any integral type of size 8, 16, 32, 64 or 128 bit is valid"));
2454 } else {2480 } else {
2481 if (enum_type->data.enumeration.layout == ContainerLayoutExtern) {
2482 bool ok_type;
2483 if ((err = type_is_valid_extern_enum_tag(g, wanted_tag_int_type, &ok_type))) {
2484 enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
2485 return err;
2486 }
2487 if (!ok_type) {
2488 enum_type->data.enumeration.resolve_status = ResolveStatusInvalid;
2489 ErrorMsg *msg = add_node_error(g, decl_node->data.container_decl.init_arg_expr,
2490 buf_sprintf("'%s' is not a valid tag type for an extern enum",
2491 buf_ptr(&wanted_tag_int_type->name)));
2492 add_error_note(g, msg, decl_node->data.container_decl.init_arg_expr,
2493 buf_sprintf("any integral type of size 8, 16, 32, 64 or 128 bit is valid"));
2494 return ErrorNone;
2495 }
2496 }
2455 tag_int_type = wanted_tag_int_type;2497 tag_int_type = wanted_tag_int_type;
2456 }2498 }
2457 }2499 }
src/analyze.hpp+1-1
...@@ -42,7 +42,7 @@ ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type);...@@ -42,7 +42,7 @@ ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type);
42bool handle_is_ptr(ZigType *type_entry);42bool handle_is_ptr(ZigType *type_entry);
4343
44bool type_has_bits(ZigType *type_entry);44bool type_has_bits(ZigType *type_entry);
45bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry);45Error type_allowed_in_extern(CodeGen *g, ZigType *type_entry, bool *result);
46bool ptr_allows_addr_zero(ZigType *ptr_type);46bool ptr_allows_addr_zero(ZigType *ptr_type);
47bool type_is_nonnull_ptr(ZigType *type);47bool type_is_nonnull_ptr(ZigType *type);
4848
src/ir.cpp+13-3
...@@ -14837,6 +14837,8 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,...@@ -14837,6 +14837,8 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
14837}14837}
1483814838
14839static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExport *instruction) {14839static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExport *instruction) {
14840 Error err;
14841
14840 IrInstruction *name = instruction->name->child;14842 IrInstruction *name = instruction->name->child;
14841 Buf *symbol_name = ir_resolve_str(ira, name);14843 Buf *symbol_name = ir_resolve_str(ira, name);
14842 if (symbol_name == nullptr) {14844 if (symbol_name == nullptr) {
...@@ -14933,8 +14935,12 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio...@@ -14933,8 +14935,12 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
14933 want_var_export = true;14935 want_var_export = true;
14934 }14936 }
14935 break;14937 break;
14936 case ZigTypeIdArray:14938 case ZigTypeIdArray: {
14937 if (!type_allowed_in_extern(ira->codegen, target->value.type->data.array.child_type)) {14939 bool ok_type;
14940 if ((err = type_allowed_in_extern(ira->codegen, target->value.type->data.array.child_type, &ok_type)))
14941 return ira->codegen->invalid_instruction;
14942
14943 if (!ok_type) {
14938 ir_add_error(ira, target,14944 ir_add_error(ira, target,
14939 buf_sprintf("array element type '%s' not extern-compatible",14945 buf_sprintf("array element type '%s' not extern-compatible",
14940 buf_ptr(&target->value.type->data.array.child_type->name)));14946 buf_ptr(&target->value.type->data.array.child_type->name)));
...@@ -14942,6 +14948,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio...@@ -14942,6 +14948,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
14942 want_var_export = true;14948 want_var_export = true;
14943 }14949 }
14944 break;14950 break;
14951 }
14945 case ZigTypeIdMetaType: {14952 case ZigTypeIdMetaType: {
14946 ZigType *type_value = target->value.data.x_type;14953 ZigType *type_value = target->value.data.x_type;
14947 switch (type_value->id) {14954 switch (type_value->id) {
...@@ -26720,7 +26727,10 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {...@@ -26720,7 +26727,10 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) {
26720 buf_create_from_str("unknown-length pointer to opaque"));26727 buf_create_from_str("unknown-length pointer to opaque"));
26721 return ErrorSemanticAnalyzeFail;26728 return ErrorSemanticAnalyzeFail;
26722 } else if (lazy_ptr_type->ptr_len == PtrLenC) {26729 } else if (lazy_ptr_type->ptr_len == PtrLenC) {
26723 if (!type_allowed_in_extern(ira->codegen, elem_type)) {26730 bool ok_type;
26731 if ((err = type_allowed_in_extern(ira->codegen, elem_type, &ok_type)))
26732 return err;
26733 if (!ok_type) {
26724 ir_add_error(ira, lazy_ptr_type->elem_type,26734 ir_add_error(ira, lazy_ptr_type->elem_type,
26725 buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'",26735 buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'",
26726 buf_ptr(&elem_type->name)));26736 buf_ptr(&elem_type->name)));