Commit 35c86984a6

kcbanner <kcbanner@gmail.com>
2023-10-27 07:30:04
cbe: support rendering union values that have no defined tag type
This was regressed in d657b6c0e2ab7c47f5416dc4df1abb2bfbecd4b6, when the comptime memory model for unions was changed to allow them to have no defined tag type.
1 parent f10499b
Changed files (1)
src
codegen
src/codegen/c.zig
@@ -1499,56 +1499,85 @@ pub const DeclGen = struct {
                 else => unreachable,
             },
             .un => |un| {
-                if (!location.isInitializer()) {
-                    try writer.writeByte('(');
-                    try dg.renderType(writer, ty);
-                    try writer.writeByte(')');
-                }
-
                 const union_obj = mod.typeToUnion(ty).?;
-                const field_i = mod.unionTagFieldIndex(union_obj, un.tag.toValue()).?;
-                const field_ty = union_obj.field_types.get(ip)[field_i].toType();
-                const field_name = union_obj.field_names.get(ip)[field_i];
-                if (union_obj.getLayout(ip) == .Packed) {
-                    if (field_ty.hasRuntimeBits(mod)) {
-                        if (field_ty.isPtrAtRuntime(mod)) {
-                            try writer.writeByte('(');
-                            try dg.renderType(writer, ty);
-                            try writer.writeByte(')');
-                        } else if (field_ty.zigTypeTag(mod) == .Float) {
-                            try writer.writeByte('(');
-                            try dg.renderType(writer, ty);
-                            try writer.writeByte(')');
+                if (un.tag == .none) {
+                    const backing_ty = try ty.unionBackingType(mod);
+                    switch (union_obj.getLayout(ip)) {
+                        .Packed => {
+                            if (!location.isInitializer()) {
+                                try writer.writeByte('(');
+                                try dg.renderType(writer, backing_ty);
+                                try writer.writeByte(')');
+                            }
+                            try dg.renderValue(writer, backing_ty, un.val.toValue(), initializer_type);
+                        },
+                        .Extern => {
+                            if (location == .StaticInitializer) {
+                                return dg.fail("TODO: C backend: implement extern union backing type rendering in static initializers", .{});
+                            }
+
+                            const ptr_ty = try mod.singleConstPtrType(ty);
+                            try writer.writeAll("*((");
+                            try dg.renderType(writer, ptr_ty);
+                            try writer.writeAll(")(");
+                            try dg.renderType(writer, backing_ty);
+                            try writer.writeAll("){");
+                            try dg.renderValue(writer, backing_ty, un.val.toValue(), initializer_type);
+                            try writer.writeAll("})");
+                        },
+                        else => unreachable,
+                    }
+                } else {
+                    if (!location.isInitializer()) {
+                        try writer.writeByte('(');
+                        try dg.renderType(writer, ty);
+                        try writer.writeByte(')');
+                    }
+
+                    const field_i = mod.unionTagFieldIndex(union_obj, un.tag.toValue()).?;
+                    const field_ty = union_obj.field_types.get(ip)[field_i].toType();
+                    const field_name = union_obj.field_names.get(ip)[field_i];
+                    if (union_obj.getLayout(ip) == .Packed) {
+                        if (field_ty.hasRuntimeBits(mod)) {
+                            if (field_ty.isPtrAtRuntime(mod)) {
+                                try writer.writeByte('(');
+                                try dg.renderType(writer, ty);
+                                try writer.writeByte(')');
+                            } else if (field_ty.zigTypeTag(mod) == .Float) {
+                                try writer.writeByte('(');
+                                try dg.renderType(writer, ty);
+                                try writer.writeByte(')');
+                            }
+                            try dg.renderValue(writer, field_ty, un.val.toValue(), initializer_type);
+                        } else {
+                            try writer.writeAll("0");
                         }
-                        try dg.renderValue(writer, field_ty, un.val.toValue(), initializer_type);
-                    } else {
-                        try writer.writeAll("0");
+                        return;
                     }
-                    return;
-                }
 
-                try writer.writeByte('{');
-                if (ty.unionTagTypeSafety(mod)) |tag_ty| {
-                    const layout = mod.getUnionLayout(union_obj);
-                    if (layout.tag_size != 0) {
-                        try writer.writeAll(" .tag = ");
-                        try dg.renderValue(writer, tag_ty, un.tag.toValue(), initializer_type);
+                    try writer.writeByte('{');
+                    if (ty.unionTagTypeSafety(mod)) |tag_ty| {
+                        const layout = mod.getUnionLayout(union_obj);
+                        if (layout.tag_size != 0) {
+                            try writer.writeAll(" .tag = ");
+                            try dg.renderValue(writer, tag_ty, un.tag.toValue(), initializer_type);
+                        }
+                        if (ty.unionHasAllZeroBitFieldTypes(mod)) return try writer.writeByte('}');
+                        if (layout.tag_size != 0) try writer.writeByte(',');
+                        try writer.writeAll(" .payload = {");
                     }
-                    if (ty.unionHasAllZeroBitFieldTypes(mod)) return try writer.writeByte('}');
-                    if (layout.tag_size != 0) try writer.writeByte(',');
-                    try writer.writeAll(" .payload = {");
-                }
-                if (field_ty.hasRuntimeBits(mod)) {
-                    try writer.print(" .{ } = ", .{fmtIdent(ip.stringToSlice(field_name))});
-                    try dg.renderValue(writer, field_ty, un.val.toValue(), initializer_type);
-                    try writer.writeByte(' ');
-                } else for (union_obj.field_types.get(ip)) |this_field_ty| {
-                    if (!this_field_ty.toType().hasRuntimeBits(mod)) continue;
-                    try dg.renderValue(writer, this_field_ty.toType(), Value.undef, initializer_type);
-                    break;
+                    if (field_ty.hasRuntimeBits(mod)) {
+                        try writer.print(" .{ } = ", .{fmtIdent(ip.stringToSlice(field_name))});
+                        try dg.renderValue(writer, field_ty, un.val.toValue(), initializer_type);
+                        try writer.writeByte(' ');
+                    } else for (union_obj.field_types.get(ip)) |this_field_ty| {
+                        if (!this_field_ty.toType().hasRuntimeBits(mod)) continue;
+                        try dg.renderValue(writer, this_field_ty.toType(), Value.undef, initializer_type);
+                        break;
+                    }
+                    if (ty.unionTagTypeSafety(mod)) |_| try writer.writeByte('}');
+                    try writer.writeByte('}');
                 }
-                if (ty.unionTagTypeSafety(mod)) |_| try writer.writeByte('}');
-                try writer.writeByte('}');
             },
         }
     }