authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-11 13:23:37-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-11 14:08:56-04:00
log3f30897fdcdb6c5579bc5609dda9746f67551870
tree6f3eb8ce8761b6a5cf8ab7d5e8a4694664c6dca0
parent3aaf814b9df6eecb6be025c4c73b8e9c46a112ba

add compile error for disallowed types in extern structs

closes #1218

3 files changed, 48 insertions(+), 4 deletions(-)

src/analyze.cpp+20-3
...@@ -1430,10 +1430,10 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {...@@ -1430,10 +1430,10 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
1430 case TypeTableEntryIdBoundFn:1430 case TypeTableEntryIdBoundFn:
1431 case TypeTableEntryIdArgTuple:1431 case TypeTableEntryIdArgTuple:
1432 case TypeTableEntryIdPromise:1432 case TypeTableEntryIdPromise:
1433 case TypeTableEntryIdVoid:
1433 return false;1434 return false;
1434 case TypeTableEntryIdOpaque:1435 case TypeTableEntryIdOpaque:
1435 case TypeTableEntryIdUnreachable:1436 case TypeTableEntryIdUnreachable:
1436 case TypeTableEntryIdVoid:
1437 case TypeTableEntryIdBool:1437 case TypeTableEntryIdBool:
1438 return true;1438 return true;
1439 case TypeTableEntryIdInt:1439 case TypeTableEntryIdInt:
...@@ -1460,7 +1460,10 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {...@@ -1460,7 +1460,10 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
1460 case TypeTableEntryIdOptional:1460 case TypeTableEntryIdOptional:
1461 {1461 {
1462 TypeTableEntry *child_type = type_entry->data.maybe.child_type;1462 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
1463 return child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn;1463 if (child_type->id != TypeTableEntryIdPointer && child_type->id != TypeTableEntryIdFn) {
1464 return false;
1465 }
1466 return type_allowed_in_extern(g, child_type);
1464 }1467 }
1465 case TypeTableEntryIdEnum:1468 case TypeTableEntryIdEnum:
1466 return type_entry->data.enumeration.layout == ContainerLayoutExtern || type_entry->data.enumeration.layout == ContainerLayoutPacked;1469 return type_entry->data.enumeration.layout == ContainerLayoutExtern || type_entry->data.enumeration.layout == ContainerLayoutPacked;
...@@ -1637,7 +1640,10 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c...@@ -1637,7 +1640,10 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
1637 fn_type_id.return_type = specified_return_type;1640 fn_type_id.return_type = specified_return_type;
1638 }1641 }
16391642
1640 if (!calling_convention_allows_zig_types(fn_type_id.cc) && !type_allowed_in_extern(g, fn_type_id.return_type)) {1643 if (!calling_convention_allows_zig_types(fn_type_id.cc) &&
1644 fn_type_id.return_type->id != TypeTableEntryIdVoid &&
1645 !type_allowed_in_extern(g, fn_type_id.return_type))
1646 {
1641 add_node_error(g, fn_proto->return_type,1647 add_node_error(g, fn_proto->return_type,
1642 buf_sprintf("return type '%s' not allowed in function with calling convention '%s'",1648 buf_sprintf("return type '%s' not allowed in function with calling convention '%s'",
1643 buf_ptr(&fn_type_id.return_type->name),1649 buf_ptr(&fn_type_id.return_type->name),
...@@ -1939,6 +1945,17 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {...@@ -1939,6 +1945,17 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
1939 break;1945 break;
1940 }1946 }
19411947
1948 if (struct_type->data.structure.layout == ContainerLayoutExtern) {
1949 if (!type_allowed_in_extern(g, field_type)) {
1950 AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);
1951 add_node_error(g, field_source_node,
1952 buf_sprintf("extern structs cannot contain fields of type '%s'",
1953 buf_ptr(&field_type->name)));
1954 struct_type->data.structure.is_invalid = true;
1955 break;
1956 }
1957 }
1958
1942 if (!type_has_bits(field_type))1959 if (!type_has_bits(field_type))
1943 continue;1960 continue;
19441961
std/c/darwin.zig+1-1
...@@ -44,7 +44,7 @@ pub const timezone = extern struct {...@@ -44,7 +44,7 @@ pub const timezone = extern struct {
44 tz_dsttime: i32,44 tz_dsttime: i32,
45};45};
4646
47pub const mach_timebase_info_data = struct {47pub const mach_timebase_info_data = extern struct {
48 numer: u32,48 numer: u32,
49 denom: u32,49 denom: u32,
50};50};
test/compile_errors.zig+27
...@@ -1,6 +1,33 @@...@@ -1,6 +1,33 @@
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.add(
5 "optional pointer to void in extern struct",
6 \\const Foo = extern struct {
7 \\ x: ?*const void,
8 \\};
9 \\const Bar = extern struct {
10 \\ foo: Foo,
11 \\ y: i32,
12 \\};
13 \\export fn entry(bar: *Bar) void {}
14 ,
15 ".tmp_source.zig:2:5: error: extern structs cannot contain fields of type '?*const void'",
16 );
17
18 cases.add(
19 "use of comptime-known undefined function value",
20 \\const Cmd = struct {
21 \\ exec: fn () void,
22 \\};
23 \\export fn entry() void {
24 \\ const command = Cmd{ .exec = undefined };
25 \\ command.exec();
26 \\}
27 ,
28 ".tmp_source.zig:6:12: error: use of undefined value",
29 );
30
4 cases.add(31 cases.add(
5 "use of comptime-known undefined function value",32 "use of comptime-known undefined function value",
6 \\const Cmd = struct {33 \\const Cmd = struct {