Commit a41f812bdb

Andrew Kelley <andrew@ziglang.org>
2021-10-03 22:11:55
C backend: fix lowering of struct types
with fields which are function pointers. Before the name was in the wrong place.
1 parent c79bf18
Changed files (2)
src
src/codegen/c.zig
@@ -32,6 +32,9 @@ pub const CValue = union(enum) {
     /// By-value
     decl: *Decl,
     decl_ref: *Decl,
+    /// Render these bytes literally.
+    /// TODO make this a [*:0]const u8 to save memory
+    bytes: []const u8,
 };
 
 const BlockData = struct {
@@ -120,7 +123,7 @@ pub const Function = struct {
 
     fn allocLocal(f: *Function, ty: Type, mutability: Mutability) !CValue {
         const local_value = f.allocLocalValue();
-        try f.object.renderTypeAndName(f.object.writer(), ty, local_value, mutability);
+        try f.object.dg.renderTypeAndName(f.object.writer(), ty, local_value, mutability);
         return local_value;
     }
 
@@ -131,7 +134,7 @@ pub const Function = struct {
                 const val = f.air.value(inst).?;
                 return f.object.dg.renderValue(w, ty, val);
             },
-            else => return Object.writeCValue(w, c_value),
+            else => return DeclGen.writeCValue(w, c_value),
         }
     }
 
@@ -154,82 +157,6 @@ pub const Object = struct {
     fn writer(o: *Object) IndentWriter(std.ArrayList(u8).Writer).Writer {
         return o.indent_writer.writer();
     }
-
-    fn writeCValue(w: anytype, c_value: CValue) !void {
-        switch (c_value) {
-            .none => unreachable,
-            .local => |i| return w.print("t{d}", .{i}),
-            .local_ref => |i| return w.print("&t{d}", .{i}),
-            .constant => unreachable,
-            .arg => |i| return w.print("a{d}", .{i}),
-            .decl => |decl| return w.writeAll(mem.span(decl.name)),
-            .decl_ref => |decl| return w.print("&{s}", .{decl.name}),
-        }
-    }
-
-    fn renderTypeAndName(
-        o: *Object,
-        w: anytype,
-        ty: Type,
-        name: CValue,
-        mutability: Mutability,
-    ) error{ OutOfMemory, AnalysisFail }!void {
-        var suffix = std.ArrayList(u8).init(o.dg.gpa);
-        defer suffix.deinit();
-
-        var render_ty = ty;
-        while (render_ty.zigTypeTag() == .Array) {
-            const sentinel_bit = @boolToInt(render_ty.sentinel() != null);
-            const c_len = render_ty.arrayLen() + sentinel_bit;
-            try suffix.writer().print("[{d}]", .{c_len});
-            render_ty = render_ty.elemType();
-        }
-
-        if (render_ty.zigTypeTag() == .Fn) {
-            const ret_ty = render_ty.fnReturnType();
-            if (ret_ty.zigTypeTag() == .NoReturn) {
-                // noreturn attribute is not allowed here.
-                try w.writeAll("void");
-            } else {
-                try o.dg.renderType(w, ret_ty);
-            }
-            try w.writeAll(" (*");
-            switch (mutability) {
-                .Const => try w.writeAll("const "),
-                .Mut => {},
-            }
-            try writeCValue(w, name);
-            try w.writeAll(")(");
-            const param_len = render_ty.fnParamLen();
-            const is_var_args = render_ty.fnIsVarArgs();
-            if (param_len == 0 and !is_var_args)
-                try w.writeAll("void")
-            else {
-                var index: usize = 0;
-                while (index < param_len) : (index += 1) {
-                    if (index > 0) {
-                        try w.writeAll(", ");
-                    }
-                    try o.dg.renderType(w, render_ty.fnParamType(index));
-                }
-            }
-            if (is_var_args) {
-                if (param_len != 0) try w.writeAll(", ");
-                try w.writeAll("...");
-            }
-            try w.writeByte(')');
-        } else {
-            try o.dg.renderType(w, render_ty);
-
-            const const_prefix = switch (mutability) {
-                .Const => "const ",
-                .Mut => "",
-            };
-            try w.print(" {s}", .{const_prefix});
-            try writeCValue(w, name);
-        }
-        try w.writeAll(suffix.items);
-    }
 };
 
 /// This data is available both when outputting .c code and when outputting an .h file.
@@ -486,7 +413,7 @@ pub const DeclGen = struct {
             .Struct => {
                 const field_vals = val.castTag(.@"struct").?.data;
 
-                try ty.renderFullyQualifiedName(writer);
+                try dg.renderType(writer, ty);
                 try writer.writeAll("{");
 
                 for (field_vals) |field_val, i| {
@@ -740,9 +667,11 @@ pub const DeclGen = struct {
                 {
                     var it = struct_obj.fields.iterator();
                     while (it.next()) |entry| {
+                        const field_ty = entry.value_ptr.ty;
+                        const name: CValue = .{ .bytes = entry.key_ptr.* };
                         try buffer.append(' ');
-                        try dg.renderType(buffer.writer(), entry.value_ptr.ty);
-                        try buffer.writer().print(" {s};\n", .{fmtIdent(entry.key_ptr.*)});
+                        try dg.renderTypeAndName(buffer.writer(), field_ty, name, .Mut);
+                        try buffer.appendSlice(";\n");
                     }
                 }
                 try buffer.appendSlice("} ");
@@ -808,6 +737,70 @@ pub const DeclGen = struct {
         }
     }
 
+    fn renderTypeAndName(
+        dg: *DeclGen,
+        w: anytype,
+        ty: Type,
+        name: CValue,
+        mutability: Mutability,
+    ) error{ OutOfMemory, AnalysisFail }!void {
+        var suffix = std.ArrayList(u8).init(dg.gpa);
+        defer suffix.deinit();
+
+        var render_ty = ty;
+        while (render_ty.zigTypeTag() == .Array) {
+            const sentinel_bit = @boolToInt(render_ty.sentinel() != null);
+            const c_len = render_ty.arrayLen() + sentinel_bit;
+            try suffix.writer().print("[{d}]", .{c_len});
+            render_ty = render_ty.elemType();
+        }
+
+        if (render_ty.zigTypeTag() == .Fn) {
+            const ret_ty = render_ty.fnReturnType();
+            if (ret_ty.zigTypeTag() == .NoReturn) {
+                // noreturn attribute is not allowed here.
+                try w.writeAll("void");
+            } else {
+                try dg.renderType(w, ret_ty);
+            }
+            try w.writeAll(" (*");
+            switch (mutability) {
+                .Const => try w.writeAll("const "),
+                .Mut => {},
+            }
+            try writeCValue(w, name);
+            try w.writeAll(")(");
+            const param_len = render_ty.fnParamLen();
+            const is_var_args = render_ty.fnIsVarArgs();
+            if (param_len == 0 and !is_var_args)
+                try w.writeAll("void")
+            else {
+                var index: usize = 0;
+                while (index < param_len) : (index += 1) {
+                    if (index > 0) {
+                        try w.writeAll(", ");
+                    }
+                    try dg.renderType(w, render_ty.fnParamType(index));
+                }
+            }
+            if (is_var_args) {
+                if (param_len != 0) try w.writeAll(", ");
+                try w.writeAll("...");
+            }
+            try w.writeByte(')');
+        } else {
+            try dg.renderType(w, render_ty);
+
+            const const_prefix = switch (mutability) {
+                .Const => "const ",
+                .Mut => "",
+            };
+            try w.print(" {s}", .{const_prefix});
+            try writeCValue(w, name);
+        }
+        try w.writeAll(suffix.items);
+    }
+
     fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool {
         switch (tv.val.tag()) {
             .extern_fn => return true,
@@ -822,6 +815,19 @@ pub const DeclGen = struct {
             else => unreachable,
         }
     }
+
+    fn writeCValue(w: anytype, c_value: CValue) !void {
+        switch (c_value) {
+            .none => unreachable,
+            .local => |i| return w.print("t{d}", .{i}),
+            .local_ref => |i| return w.print("&t{d}", .{i}),
+            .constant => unreachable,
+            .arg => |i| return w.print("a{d}", .{i}),
+            .decl => |decl| return w.writeAll(mem.span(decl.name)),
+            .decl_ref => |decl| return w.print("&{s}", .{decl.name}),
+            .bytes => |bytes| return w.writeAll(bytes),
+        }
+    }
 };
 
 pub fn genFunc(f: *Function) !void {
@@ -891,7 +897,7 @@ pub fn genDecl(o: *Object) !void {
         // https://github.com/ziglang/zig/issues/7582
 
         const decl_c_value: CValue = .{ .decl = o.dg.decl };
-        try o.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut);
+        try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut);
 
         try writer.writeAll(" = ");
         try o.dg.renderValue(writer, tv.ty, tv.val);
src/type.zig
@@ -896,77 +896,6 @@ pub const Type = extern union {
         return Type{ .ptr_otherwise = &new_payload.base };
     }
 
-    pub fn renderFullyQualifiedName(ty: Type, writer: anytype) !void {
-        const t = ty.tag();
-        switch (t) {
-            .u1,
-            .u8,
-            .i8,
-            .u16,
-            .i16,
-            .u32,
-            .i32,
-            .u64,
-            .i64,
-            .u128,
-            .i128,
-            .usize,
-            .isize,
-            .c_short,
-            .c_ushort,
-            .c_int,
-            .c_uint,
-            .c_long,
-            .c_ulong,
-            .c_longlong,
-            .c_ulonglong,
-            .c_longdouble,
-            .c_void,
-            .f16,
-            .f32,
-            .f64,
-            .f128,
-            .bool,
-            .void,
-            .type,
-            .anyerror,
-            .@"anyframe",
-            .comptime_int,
-            .comptime_float,
-            .noreturn,
-            .var_args_param,
-            .bound_fn,
-            => return writer.writeAll(@tagName(t)),
-
-            .enum_literal => return writer.writeAll("@Type(.EnumLiteral)"),
-            .@"null" => return writer.writeAll("@Type(.Null)"),
-            .@"undefined" => return writer.writeAll("@Type(.Undefined)"),
-
-            .@"struct" => {
-                const struct_obj = ty.castTag(.@"struct").?.data;
-                return struct_obj.owner_decl.renderFullyQualifiedName(writer);
-            },
-            .@"union", .union_tagged => {
-                const union_obj = ty.cast(Payload.Union).?.data;
-                return union_obj.owner_decl.renderFullyQualifiedName(writer);
-            },
-            .enum_full, .enum_nonexhaustive => {
-                const enum_full = ty.cast(Payload.EnumFull).?.data;
-                return enum_full.owner_decl.renderFullyQualifiedName(writer);
-            },
-            .enum_simple => {
-                const enum_simple = ty.castTag(.enum_simple).?.data;
-                return enum_simple.owner_decl.renderFullyQualifiedName(writer);
-            },
-            .enum_numbered => {
-                const enum_numbered = ty.castTag(.enum_numbered).?.data;
-                return enum_numbered.owner_decl.renderFullyQualifiedName(writer);
-            },
-            .@"opaque" => @panic("TODO"),
-            else => unreachable,
-        }
-    }
-
     pub fn format(
         start_type: Type,
         comptime fmt: []const u8,