Commit d2535c003c

LemonBoy <thatlemon@gmail.com>
2020-02-26 10:05:04
ir: Fix regression with self-referencing containers
1 parent b46efcd
Changed files (2)
src
test
stage1
src/analyze.cpp
@@ -1131,17 +1131,26 @@ Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent
     Error err;
     if (type_val->special != ConstValSpecialLazy) {
         assert(type_val->special == ConstValSpecialStatic);
-        if ((type_val->data.x_type->id == ZigTypeIdStruct &&
-             type_val->data.x_type->data.structure.resolve_loop_flag_zero_bits) ||
-            (type_val->data.x_type->id == ZigTypeIdUnion &&
-             type_val->data.x_type->data.unionation.resolve_loop_flag_zero_bits))
+
+        // Self-referencing types via pointers are allowed and have non-zero size
+        ZigType *ty = type_val->data.x_type;
+        while (ty->id == ZigTypeIdPointer &&
+               !ty->data.unionation.resolve_loop_flag_zero_bits)
+        {
+            ty = ty->data.pointer.child_type;
+        }
+
+        if ((ty->id == ZigTypeIdStruct && ty->data.structure.resolve_loop_flag_zero_bits) ||
+            (ty->id == ZigTypeIdUnion && ty->data.unionation.resolve_loop_flag_zero_bits) ||
+            (ty->id == ZigTypeIdPointer && ty->data.pointer.resolve_loop_flag_zero_bits))
         {
-            // Does a struct/union which contains a pointer field to itself have bits? Yes.
             *is_zero_bits = false;
             return ErrorNone;
         }
+
         if ((err = type_resolve(g, type_val->data.x_type, ResolveStatusZeroBitsKnown)))
             return err;
+
         *is_zero_bits = (type_val->data.x_type->abi_size == 0);
         return ErrorNone;
     }
test/stage1/behavior/sizeof_and_typeof.zig
@@ -145,6 +145,26 @@ test "@sizeOf comparison against zero" {
     const U0 = union {
         f: *@This(),
     };
+    const S1 = struct {
+        fn H(comptime T: type) type {
+            return struct {
+                x: T,
+            };
+        }
+        f0: H(*@This()),
+        f1: H(**@This()),
+        f2: H(***@This()),
+    };
+    const U1 = union {
+        fn H(comptime T: type) type {
+            return struct {
+                x: T,
+            };
+        }
+        f0: H(*@This()),
+        f1: H(**@This()),
+        f2: H(***@This()),
+    };
     const S = struct {
         fn doTheTest(comptime T: type, comptime result: bool) void {
             expectEqual(result, @sizeOf(T) > 0);
@@ -164,4 +184,6 @@ test "@sizeOf comparison against zero" {
     // Container with ptr pointing to themselves
     S.doTheTest(S0, true);
     S.doTheTest(U0, true);
+    S.doTheTest(S1, true);
+    S.doTheTest(U1, true);
 }