C backend: fix lowering of struct types

with fields which are function pointers.
Before the name was in the wrong place.
This commit is contained in:
Andrew Kelley 2021-10-03 13:11:55 -07:00
parent c79bf18044
commit a41f812bdb
2 changed files with 88 additions and 153 deletions

View File

@ -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);

View File

@ -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,