Commit ec3116f573

Jacob Young <jacobly0@users.noreply.github.com>
2022-12-03 13:20:42
cbe: fix zero-bit struct field pointer
1 parent 7fb6eb3
Changed files (2)
src
codegen
test
behavior
src/codegen/c.zig
@@ -4568,9 +4568,18 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
         else => .none,
     };
 
-    const field_name: CValue = switch (struct_ty.tag()) {
+    const FieldLoc = union(enum) {
+        begin: void,
+        field: CValue,
+        end: void,
+    };
+    const field_loc = switch (struct_ty.tag()) {
         .@"struct" => switch (struct_ty.containerLayout()) {
-            .Auto, .Extern => CValue{ .identifier = struct_ty.structFieldName(index) },
+            .Auto, .Extern => for (struct_ty.structFields().values()[index..]) |field, offset| {
+                if (field.ty.hasRuntimeBitsIgnoreComptime()) break FieldLoc{ .field = .{
+                    .identifier = struct_ty.structFieldName(index + offset),
+                } };
+            } else @as(FieldLoc, .end),
             .Packed => if (field_ptr_info.data.host_size == 0) {
                 const target = f.object.dg.module.getTarget();
 
@@ -4595,40 +4604,43 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
                 try f.writeCValue(writer, struct_ptr, .Other);
                 try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)});
                 return local;
-            } else @as(CValue, CValue.none), // this @as is needed because of a stage1 bug
+            } else @as(FieldLoc, .begin),
         },
         .@"union", .union_safety_tagged, .union_tagged => if (struct_ty.containerLayout() == .Packed) {
             try f.writeCValue(writer, struct_ptr, .Other);
             try writer.writeAll(";\n");
             return local;
-        } else .{
+        } else if (field_ty.hasRuntimeBitsIgnoreComptime()) FieldLoc{ .field = .{
             .identifier = struct_ty.unionFields().keys()[index],
-        },
+        } } else @as(FieldLoc, .end),
         .tuple, .anon_struct => field_name: {
             const tuple = struct_ty.tupleFields();
             if (tuple.values[index].tag() != .unreachable_value) return CValue.none;
 
             var id: usize = 0;
-            for (tuple.values[0..index]) |value|
-                id += @boolToInt(value.tag() == .unreachable_value);
-            break :field_name .{ .field = id };
+            break :field_name for (tuple.values) |value, i| {
+                if (value.tag() != .unreachable_value) continue;
+                if (!tuple.types[i].hasRuntimeBitsIgnoreComptime()) continue;
+                if (i >= index) break FieldLoc{ .field = .{ .field = id } };
+                id += 1;
+            } else @as(FieldLoc, .end);
         },
         else => unreachable,
     };
 
-    if (field_ty.hasRuntimeBitsIgnoreComptime()) {
-        try writer.writeByte('&');
-        if (extra_name != .none) {
+    try writer.writeByte('&');
+    switch (field_loc) {
+        .begin, .end => {
+            try writer.writeByte('(');
+            try f.writeCValue(writer, struct_ptr, .Other);
+            try writer.print(")[{}]", .{@boolToInt(field_loc == .end)});
+        },
+        .field => |field| if (extra_name != .none) {
             try f.writeCValueDerefMember(writer, struct_ptr, extra_name);
-            if (field_name != .none) {
-                try writer.writeByte('.');
-                try f.writeCValue(writer, field_name, .Other);
-            }
-        } else if (field_name != .none)
-            try f.writeCValueDerefMember(writer, struct_ptr, field_name)
-        else
-            try f.writeCValueDeref(writer, struct_ptr);
-    } else try f.writeCValue(writer, struct_ptr, .Other);
+            try writer.writeByte('.');
+            try f.writeCValue(writer, field, .Other);
+        } else try f.writeCValueDerefMember(writer, struct_ptr, field),
+    }
     try writer.writeAll(";\n");
     return local;
 }
test/behavior/struct.zig
@@ -1390,7 +1390,6 @@ test "address of zero-bit field is equal to address of only field" {
     if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
 
     {
         const A = struct { b: void = {}, u: u8 };