Commit 74d0b5bf7c

Sahnvour <sahnvour@pm.me>
2019-09-01 12:46:02
reject types of automatic container layout in packed unions
1 parent c9a5a6b
Changed files (2)
src/analyze.cpp
@@ -1432,8 +1432,8 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf **
     return true;
 }
 
-static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType *type_entry,
-        AstNode *source_node)
+static Error emit_error_unless_type_allowed_in_packed_container(CodeGen *g, ZigType *type_entry,
+        AstNode *source_node, const char* container_name)
 {
     Error err;
     switch (type_entry->id) {
@@ -1454,8 +1454,8 @@ static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType
         case ZigTypeIdFnFrame:
         case ZigTypeIdAnyFrame:
             add_node_error(g, source_node,
-                    buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation",
-                        buf_ptr(&type_entry->name)));
+                    buf_sprintf("type '%s' not allowed in packed %s; no guaranteed in-memory representation",
+                        buf_ptr(&type_entry->name), container_name));
             return ErrorSemanticAnalyzeFail;
         case ZigTypeIdVoid:
         case ZigTypeIdBool:
@@ -1467,14 +1467,14 @@ static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType
             return ErrorNone;
         case ZigTypeIdArray: {
             ZigType *elem_type = type_entry->data.array.child_type;
-            if ((err = emit_error_unless_type_allowed_in_packed_struct(g, elem_type, source_node)))
+            if ((err = emit_error_unless_type_allowed_in_packed_container(g, elem_type, source_node, container_name)))
                 return err;
             // TODO revisit this when doing https://github.com/ziglang/zig/issues/1512
             if (type_size(g, type_entry) * 8 == type_size_bits(g, type_entry))
                 return ErrorNone;
             add_node_error(g, source_node,
-                buf_sprintf("array of '%s' not allowed in packed struct due to padding bits",
-                    buf_ptr(&elem_type->name)));
+                buf_sprintf("array of '%s' not allowed in packed %s due to padding bits",
+                    buf_ptr(&elem_type->name), container_name));
             return ErrorSemanticAnalyzeFail;
         }
         case ZigTypeIdStruct:
@@ -1484,8 +1484,8 @@ static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType
                     return ErrorNone;
                 case ContainerLayoutAuto:
                     add_node_error(g, source_node,
-                        buf_sprintf("non-packed, non-extern struct '%s' not allowed in packed struct; no guaranteed in-memory representation",
-                            buf_ptr(&type_entry->name)));
+                        buf_sprintf("non-packed, non-extern struct '%s' not allowed in packed %s; no guaranteed in-memory representation",
+                            buf_ptr(&type_entry->name), container_name));
                     return ErrorSemanticAnalyzeFail;
             }
             zig_unreachable();
@@ -1496,8 +1496,8 @@ static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType
                     return ErrorNone;
                 case ContainerLayoutAuto:
                     add_node_error(g, source_node,
-                        buf_sprintf("non-packed, non-extern union '%s' not allowed in packed struct; no guaranteed in-memory representation",
-                            buf_ptr(&type_entry->name)));
+                        buf_sprintf("non-packed, non-extern union '%s' not allowed in packed %s; no guaranteed in-memory representation",
+                            buf_ptr(&type_entry->name), container_name));
                     return ErrorSemanticAnalyzeFail;
             }
             zig_unreachable();
@@ -1506,8 +1506,8 @@ static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType
                 return ErrorNone;
             } else {
                 add_node_error(g, source_node,
-                    buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation",
-                        buf_ptr(&type_entry->name)));
+                    buf_sprintf("type '%s' not allowed in packed %s; no guaranteed in-memory representation",
+                        buf_ptr(&type_entry->name), container_name));
                 return ErrorSemanticAnalyzeFail;
             }
         case ZigTypeIdEnum: {
@@ -1516,8 +1516,8 @@ static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType
                 return ErrorNone;
             }
             ErrorMsg *msg = add_node_error(g, source_node,
-                buf_sprintf("type '%s' not allowed in packed struct; no guaranteed in-memory representation",
-                    buf_ptr(&type_entry->name)));
+                buf_sprintf("type '%s' not allowed in packed %s; no guaranteed in-memory representation",
+                    buf_ptr(&type_entry->name), container_name));
             add_error_note(g, msg, decl_node,
                     buf_sprintf("enum declaration does not specify an integer tag type"));
             return ErrorSemanticAnalyzeFail;
@@ -1526,6 +1526,18 @@ static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType
     zig_unreachable();
 }
 
+static Error emit_error_unless_type_allowed_in_packed_struct(CodeGen *g, ZigType *type_entry,
+    AstNode *source_node)
+{
+    return emit_error_unless_type_allowed_in_packed_container(g, type_entry, source_node, "struct");
+}
+
+static Error emit_error_unless_type_allowed_in_packed_union(CodeGen *g, ZigType *type_entry,
+    AstNode *source_node)
+{
+    return emit_error_unless_type_allowed_in_packed_container(g, type_entry, source_node, "union");
+}
+
 bool type_allowed_in_extern(CodeGen *g, ZigType *type_entry) {
     switch (type_entry->id) {
         case ZigTypeIdInvalid:
@@ -2286,6 +2298,8 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
     // set temporary flag
     union_type->data.unionation.resolve_loop_flag_other = true;
 
+    const bool is_packed = union_type->data.unionation.layout == ContainerLayoutPacked;
+
     for (uint32_t i = 0; i < field_count; i += 1) {
         TypeUnionField *union_field = &union_type->data.unionation.fields[i];
         ZigType *field_type = resolve_union_field_type(g, union_field);
@@ -2298,6 +2312,12 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) {
             union_type->data.unionation.resolve_status = ResolveStatusInvalid;
             return ErrorSemanticAnalyzeFail;
         }
+        if (is_packed) {
+            if ((err = emit_error_unless_type_allowed_in_packed_union(g, field_type, union_field->decl_node))) {
+                union_type->data.unionation.resolve_status = ResolveStatusInvalid;
+                return err;
+            }
+        }
 
         if (type_is_invalid(union_type))
             return ErrorSemanticAnalyzeFail;
test/compile_errors.zig
@@ -6308,6 +6308,23 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         "tmp.zig:6:30: error: packed union does not support enum tag type",
     );
 
+    cases.add(
+        "packed union with automatic layout field",
+        \\const Foo = struct {
+        \\    a: u32,
+        \\    b: f32,
+        \\};
+        \\const Payload = packed union {
+        \\    A: Foo,
+        \\    B: bool,
+        \\};
+        \\export fn entry() void {
+        \\    var a = Payload { .B = true };
+        \\}
+    ,
+        "tmp.zig:6:5: error: non-packed, non-extern struct 'Foo' not allowed in packed union; no guaranteed in-memory representation",
+    );
+
     cases.add(
         "switch on union with no attached enum",
         \\const Payload = union {