Commit 3f30897fdc

Andrew Kelley <superjoe30@gmail.com>
2018-07-11 19:23:37
add compile error for disallowed types in extern structs
closes #1218
1 parent 3aaf814
Changed files (3)
src/analyze.cpp
@@ -1430,10 +1430,10 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
         case TypeTableEntryIdBoundFn:
         case TypeTableEntryIdArgTuple:
         case TypeTableEntryIdPromise:
+        case TypeTableEntryIdVoid:
             return false;
         case TypeTableEntryIdOpaque:
         case TypeTableEntryIdUnreachable:
-        case TypeTableEntryIdVoid:
         case TypeTableEntryIdBool:
             return true;
         case TypeTableEntryIdInt:
@@ -1460,7 +1460,10 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) {
         case TypeTableEntryIdOptional:
             {
                 TypeTableEntry *child_type = type_entry->data.maybe.child_type;
-                return child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn;
+                if (child_type->id != TypeTableEntryIdPointer && child_type->id != TypeTableEntryIdFn) {
+                    return false;
+                }
+                return type_allowed_in_extern(g, child_type);
             }
         case TypeTableEntryIdEnum:
             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
         fn_type_id.return_type = specified_return_type;
     }
 
-    if (!calling_convention_allows_zig_types(fn_type_id.cc) && !type_allowed_in_extern(g, fn_type_id.return_type)) {
+    if (!calling_convention_allows_zig_types(fn_type_id.cc) &&
+        fn_type_id.return_type->id != TypeTableEntryIdVoid &&
+        !type_allowed_in_extern(g, fn_type_id.return_type))
+    {
         add_node_error(g, fn_proto->return_type,
                 buf_sprintf("return type '%s' not allowed in function with calling convention '%s'",
                     buf_ptr(&fn_type_id.return_type->name),
@@ -1939,6 +1945,17 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
             break;
         }
 
+        if (struct_type->data.structure.layout == ContainerLayoutExtern) {
+            if (!type_allowed_in_extern(g, field_type)) {
+                AstNode *field_source_node = decl_node->data.container_decl.fields.at(i);
+                add_node_error(g, field_source_node,
+                        buf_sprintf("extern structs cannot contain fields of type '%s'",
+                            buf_ptr(&field_type->name)));
+                struct_type->data.structure.is_invalid = true;
+                break;
+            }
+        }
+
         if (!type_has_bits(field_type))
             continue;
 
std/c/darwin.zig
@@ -44,7 +44,7 @@ pub const timezone = extern struct {
     tz_dsttime: i32,
 };
 
-pub const mach_timebase_info_data = struct {
+pub const mach_timebase_info_data = extern struct {
     numer: u32,
     denom: u32,
 };
test/compile_errors.zig
@@ -1,6 +1,33 @@
 const tests = @import("tests.zig");
 
 pub fn addCases(cases: *tests.CompileErrorContext) void {
+    cases.add(
+        "optional pointer to void in extern struct",
+        \\const Foo = extern struct {
+        \\    x: ?*const void,
+        \\};
+        \\const Bar = extern struct {
+        \\    foo: Foo,
+        \\    y: i32,
+        \\};
+        \\export fn entry(bar: *Bar) void {}
+    ,
+        ".tmp_source.zig:2:5: error: extern structs cannot contain fields of type '?*const void'",
+    );
+
+    cases.add(
+        "use of comptime-known undefined function value",
+        \\const Cmd = struct {
+        \\    exec: fn () void,
+        \\};
+        \\export fn entry() void {
+        \\    const command = Cmd{ .exec = undefined };
+        \\    command.exec();
+        \\}
+    ,
+        ".tmp_source.zig:6:12: error: use of undefined value",
+    );
+
     cases.add(
         "use of comptime-known undefined function value",
         \\const Cmd = struct {