cbe: fix typedef declaration order

This commit is contained in:
Jacob Young 2022-10-20 05:47:54 -04:00
parent 3d90ee50ff
commit 8b6a3ba74e
5 changed files with 153 additions and 150 deletions

View File

@ -48,6 +48,11 @@ const BlockData = struct {
result: CValue, result: CValue,
}; };
const TypedefKind = enum {
Forward,
Complete,
};
pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue); pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue);
pub const TypedefMap = std.ArrayHashMap( pub const TypedefMap = std.ArrayHashMap(
Type, Type,
@ -249,13 +254,7 @@ pub const Function = struct {
const decl_c_value = f.allocLocalValue(); const decl_c_value = f.allocLocalValue();
gop.value_ptr.* = decl_c_value; gop.value_ptr.* = decl_c_value;
try writer.writeAll("static "); try writer.writeAll("static ");
try f.object.dg.renderTypeAndName( try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, 0, .Complete);
writer,
ty,
decl_c_value,
.Const,
0,
);
try writer.writeAll(" = "); try writer.writeAll(" = ");
try f.object.dg.renderValue(writer, ty, val, .Initializer); try f.object.dg.renderValue(writer, ty, val, .Initializer);
try writer.writeAll(";\n "); try writer.writeAll(";\n ");
@ -294,6 +293,7 @@ pub const Function = struct {
local_value, local_value,
mutability, mutability,
alignment, alignment,
.Complete,
); );
return local_value; return local_value;
} }
@ -328,7 +328,7 @@ pub const Function = struct {
} }
fn renderType(f: *Function, w: anytype, t: Type) !void { fn renderType(f: *Function, w: anytype, t: Type) !void {
return f.object.dg.renderType(w, t); return f.object.dg.renderType(w, t, .Complete);
} }
fn renderTypecast(f: *Function, w: anytype, t: Type) !void { fn renderTypecast(f: *Function, w: anytype, t: Type) !void {
@ -1024,10 +1024,7 @@ pub const DeclGen = struct {
} }
} }
fn renderFunctionSignature(dg: *DeclGen, w: anytype, is_global: bool) !void { fn renderFunctionSignature(dg: *DeclGen, w: anytype, kind: TypedefKind) !void {
if (!is_global) {
try w.writeAll("static ");
}
const fn_info = dg.decl.ty.fnInfo(); const fn_info = dg.decl.ty.fnInfo();
if (fn_info.cc == .Naked) { if (fn_info.cc == .Naked) {
try w.writeAll("ZIG_NAKED "); try w.writeAll("ZIG_NAKED ");
@ -1039,9 +1036,9 @@ pub const DeclGen = struct {
} }
} }
if (fn_info.return_type.hasRuntimeBits()) { if (fn_info.return_type.hasRuntimeBits()) {
try dg.renderType(w, fn_info.return_type); try dg.renderType(w, fn_info.return_type, kind);
} else if (fn_info.return_type.isError()) { } else if (fn_info.return_type.isError()) {
try dg.renderType(w, Type.anyerror); try dg.renderType(w, Type.anyerror, kind);
} else if (fn_info.return_type.zigTypeTag() == .NoReturn) { } else if (fn_info.return_type.zigTypeTag() == .NoReturn) {
try w.writeAll("zig_noreturn void"); try w.writeAll("zig_noreturn void");
} else { } else {
@ -1058,7 +1055,7 @@ pub const DeclGen = struct {
try w.writeAll(", "); try w.writeAll(", ");
} }
const name = CValue{ .arg = index }; const name = CValue{ .arg = index };
try dg.renderTypeAndName(w, param_type, name, .Const, 0); try dg.renderTypeAndName(w, param_type, name, .Const, 0, kind);
index += 1; index += 1;
} }
@ -1071,15 +1068,15 @@ pub const DeclGen = struct {
try w.writeByte(')'); try w.writeByte(')');
} }
fn renderPtrToFnTypedef(dg: *DeclGen, t: Type, fn_ty: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { fn renderPtrToFnTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
defer buffer.deinit(); defer buffer.deinit();
const bw = buffer.writer(); const bw = buffer.writer();
const fn_info = fn_ty.fnInfo(); const fn_info = t.fnInfo();
try bw.writeAll("typedef "); try bw.writeAll("typedef ");
try dg.renderType(bw, fn_info.return_type); try dg.renderType(bw, fn_info.return_type, .Forward);
try bw.writeAll(" (*"); try bw.writeAll(" (*");
const name_begin = buffer.items.len; const name_begin = buffer.items.len;
@ -1092,11 +1089,12 @@ pub const DeclGen = struct {
var params_written: usize = 0; var params_written: usize = 0;
var index: usize = 0; var index: usize = 0;
while (index < param_len) : (index += 1) { while (index < param_len) : (index += 1) {
if (!fn_info.param_types[index].hasRuntimeBitsIgnoreComptime()) continue; const param_ty = fn_info.param_types[index];
if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue;
if (params_written > 0) { if (params_written > 0) {
try bw.writeAll(", "); try bw.writeAll(", ");
} }
try dg.renderTypecast(bw, fn_info.param_types[index]); try dg.renderTypeAndName(bw, param_ty, .{ .bytes = "" }, .Mut, 0, .Forward);
params_written += 1; params_written += 1;
} }
@ -1133,7 +1131,7 @@ pub const DeclGen = struct {
var ptr_type_buf: Type.SlicePtrFieldTypeBuffer = undefined; var ptr_type_buf: Type.SlicePtrFieldTypeBuffer = undefined;
const ptr_type = t.slicePtrFieldType(&ptr_type_buf); const ptr_type = t.slicePtrFieldType(&ptr_type_buf);
const ptr_name = CValue{ .bytes = "ptr" }; const ptr_name = CValue{ .bytes = "ptr" };
try dg.renderTypeAndName(bw, ptr_type, ptr_name, .Mut, 0); try dg.renderTypeAndName(bw, ptr_type, ptr_name, .Mut, 0, .Complete);
try bw.writeAll("; size_t len; } "); try bw.writeAll("; size_t len; } ");
const name_begin = buffer.items.len; const name_begin = buffer.items.len;
@ -1157,27 +1155,33 @@ pub const DeclGen = struct {
return name; return name;
} }
fn renderStructTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { fn renderFwdTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
const struct_obj = t.castTag(.@"struct").?.data; // Handle 0 bit types elsewhere. // The forward declaration for T is stored with a key of *const T.
const fqn = try struct_obj.getFullyQualifiedName(dg.module); const child_ty = t.childType();
defer dg.typedefs.allocator.free(fqn);
var fqn_buf = std.ArrayList(u8).init(dg.typedefs.allocator);
defer fqn_buf.deinit();
const owner_decl = dg.module.declPtr(child_ty.getOwnerDecl());
try owner_decl.renderFullyQualifiedName(dg.module, fqn_buf.writer());
var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
defer buffer.deinit(); defer buffer.deinit();
const tag = "struct"; const tag = switch (child_ty.zigTypeTag()) {
const tagged_name_begin = buffer.items.len + "typedef ".len + tag.len + " ".len; .Struct => "struct ",
try buffer.writer().print("typedef " ++ tag ++ " zig_S_{} ", .{fmtIdent(fqn)}); .Union => if (child_ty.unionTagTypeSafety()) |_| "struct " else "union ",
const tagged_name_end = buffer.items.len - " ".len; else => unreachable,
try buffer.ensureUnusedCapacity(tagged_name_end - tagged_name_begin + ";\n".len); };
const name_begin = buffer.items.len; const name_begin = buffer.items.len + "typedef ".len + tag.len;
buffer.appendSliceAssumeCapacity(buffer.items[tagged_name_begin..tagged_name_end]); try buffer.writer().print("typedef {s}zig_S_{} ", .{ tag, fmtIdent(fqn_buf.items) });
const name_end = buffer.items.len; const name_end = buffer.items.len - " ".len;
try buffer.ensureUnusedCapacity((name_end - name_begin) + ";\n".len);
buffer.appendSliceAssumeCapacity(buffer.items[name_begin..name_end]);
buffer.appendSliceAssumeCapacity(";\n"); buffer.appendSliceAssumeCapacity(";\n");
const rendered = buffer.toOwnedSlice(); const rendered = buffer.toOwnedSlice();
errdefer dg.typedefs.allocator.free(rendered); errdefer dg.typedefs.allocator.free(rendered);
const tagged_name = rendered[tagged_name_begin..tagged_name_end];
const name = rendered[name_begin..name_end]; const name = rendered[name_begin..name_end];
try dg.typedefs.ensureUnusedCapacity(1); try dg.typedefs.ensureUnusedCapacity(1);
@ -1186,20 +1190,32 @@ pub const DeclGen = struct {
.{ .name = name, .rendered = rendered }, .{ .name = name, .rendered = rendered },
); );
try buffer.appendSlice(tag ++ " "); return name;
try buffer.appendSlice(tagged_name); }
fn renderStructTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t };
const ptr_ty = Type.initPayload(&ptr_pl.base);
const name = dg.getTypedefName(ptr_ty) orelse
try dg.renderFwdTypedef(ptr_ty);
var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
defer buffer.deinit();
try buffer.appendSlice("struct ");
try buffer.appendSlice(name);
try buffer.appendSlice(" {\n"); try buffer.appendSlice(" {\n");
{ {
var it = struct_obj.fields.iterator(); var it = t.structFields().iterator();
var empty = true; var empty = true;
while (it.next()) |entry| { while (it.next()) |field| {
const field_ty = entry.value_ptr.ty; const field_ty = field.value_ptr.ty;
if (!field_ty.hasRuntimeBits()) continue; if (!field_ty.hasRuntimeBits()) continue;
const alignment = entry.value_ptr.abi_align; const alignment = field.value_ptr.abi_align;
const field_name: CValue = .{ .identifier = entry.key_ptr.* }; const field_name = CValue{ .identifier = field.key_ptr.* };
try buffer.append(' '); try buffer.append(' ');
try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment); try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment, .Complete);
try buffer.appendSlice(";\n"); try buffer.appendSlice(";\n");
empty = false; empty = false;
@ -1208,16 +1224,13 @@ pub const DeclGen = struct {
} }
try buffer.appendSlice("};\n"); try buffer.appendSlice("};\n");
const rendered_body = buffer.toOwnedSlice(); const rendered = buffer.toOwnedSlice();
errdefer dg.typedefs.allocator.free(rendered_body); errdefer dg.typedefs.allocator.free(rendered);
// We need to add another item to the TypedefMap, so we need a distinct
// type that is not used anywhere, but is still uniquely associated with
// this type, so use an empty struct which references our unique decls.
try dg.typedefs.ensureUnusedCapacity(1); try dg.typedefs.ensureUnusedCapacity(1);
dg.typedefs.putAssumeCapacityNoClobber( dg.typedefs.putAssumeCapacityNoClobber(
try Type.Tag.empty_struct.create(dg.typedefs_arena, &struct_obj.namespace), try t.copy(dg.typedefs_arena),
.{ .name = undefined, .rendered = rendered_body }, .{ .name = name, .rendered = rendered },
); );
return name; return name;
@ -1240,7 +1253,7 @@ pub const DeclGen = struct {
defer dg.typedefs.allocator.free(field_name); defer dg.typedefs.allocator.free(field_name);
try buffer.append(' '); try buffer.append(' ');
try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .identifier = field_name }, .Mut, 0); try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .identifier = field_name }, .Mut, 0, .Complete);
try buffer.appendSlice(";\n"); try buffer.appendSlice(";\n");
empty = false; empty = false;
@ -1265,37 +1278,16 @@ pub const DeclGen = struct {
} }
fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
const union_obj = t.cast(Type.Payload.Union).?.data; var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t };
const fqn = try union_obj.getFullyQualifiedName(dg.module); const ptr_ty = Type.initPayload(&ptr_pl.base);
defer dg.typedefs.allocator.free(fqn); const name = dg.getTypedefName(ptr_ty) orelse
try dg.renderFwdTypedef(ptr_ty);
var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
defer buffer.deinit(); defer buffer.deinit();
const tag: []const u8 = if (t.unionTagTypeSafety()) |_| "struct" else "union"; try buffer.appendSlice(if (t.unionTagTypeSafety()) |_| "struct " else "union ");
const tagged_name_begin = buffer.items.len + "typedef ".len + tag.len + " ".len; try buffer.appendSlice(name);
try buffer.writer().print("typedef {s} zig_S_{} ", .{ tag, fmtIdent(fqn) });
const tagged_name_end = buffer.items.len - " ".len;
try buffer.ensureUnusedCapacity(tagged_name_end - tagged_name_begin + ";\n".len);
const name_begin = buffer.items.len;
buffer.appendSliceAssumeCapacity(buffer.items[tagged_name_begin..tagged_name_end]);
const name_end = buffer.items.len;
buffer.appendSliceAssumeCapacity(";\n");
const rendered = buffer.toOwnedSlice();
errdefer dg.typedefs.allocator.free(rendered);
const tagged_name = rendered[tagged_name_begin..tagged_name_end];
const name = rendered[name_begin..name_end];
try dg.typedefs.ensureUnusedCapacity(1);
dg.typedefs.putAssumeCapacityNoClobber(
try t.copy(dg.typedefs_arena),
.{ .name = name, .rendered = rendered },
);
try buffer.appendSlice(tag);
try buffer.append(' ');
try buffer.appendSlice(tagged_name);
try buffer.appendSlice(" {\n"); try buffer.appendSlice(" {\n");
const indent = if (t.unionTagTypeSafety()) |tag_ty| indent: { const indent = if (t.unionTagTypeSafety()) |tag_ty| indent: {
@ -1303,7 +1295,7 @@ pub const DeclGen = struct {
const layout = t.unionGetLayout(target); const layout = t.unionGetLayout(target);
if (layout.tag_size != 0) { if (layout.tag_size != 0) {
try buffer.append(' '); try buffer.append(' ');
try dg.renderTypeAndName(buffer.writer(), tag_ty, .{ .identifier = "tag" }, .Mut, 0); try dg.renderTypeAndName(buffer.writer(), tag_ty, .{ .identifier = "tag" }, .Mut, 0, .Complete);
try buffer.appendSlice(";\n"); try buffer.appendSlice(";\n");
} }
try buffer.appendSlice(" union {\n"); try buffer.appendSlice(" union {\n");
@ -1313,14 +1305,14 @@ pub const DeclGen = struct {
{ {
var it = t.unionFields().iterator(); var it = t.unionFields().iterator();
var empty = true; var empty = true;
while (it.next()) |entry| { while (it.next()) |field| {
const field_ty = entry.value_ptr.ty; const field_ty = field.value_ptr.ty;
if (!field_ty.hasRuntimeBits()) continue; if (!field_ty.hasRuntimeBits()) continue;
const alignment = entry.value_ptr.abi_align; const alignment = field.value_ptr.abi_align;
const field_name: CValue = .{ .identifier = entry.key_ptr.* }; const field_name = CValue{ .identifier = field.key_ptr.* };
try buffer.appendSlice(indent); try buffer.appendSlice(indent);
try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment); try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment, .Complete);
try buffer.appendSlice(";\n"); try buffer.appendSlice(";\n");
empty = false; empty = false;
@ -1334,16 +1326,13 @@ pub const DeclGen = struct {
if (t.unionTagTypeSafety()) |_| try buffer.appendSlice(" } payload;\n"); if (t.unionTagTypeSafety()) |_| try buffer.appendSlice(" } payload;\n");
try buffer.appendSlice("};\n"); try buffer.appendSlice("};\n");
const rendered_body = buffer.toOwnedSlice(); const rendered = buffer.toOwnedSlice();
errdefer dg.typedefs.allocator.free(rendered_body); errdefer dg.typedefs.allocator.free(rendered);
// We need to add another item to the TypedefMap, so we need a distinct
// type that is not used anywhere, but is still uniquely associated with
// this type, so use an empty struct which references our unique decls.
try dg.typedefs.ensureUnusedCapacity(1); try dg.typedefs.ensureUnusedCapacity(1);
dg.typedefs.putAssumeCapacityNoClobber( dg.typedefs.putAssumeCapacityNoClobber(
try Type.Tag.empty_struct.create(dg.typedefs_arena, &union_obj.namespace), try t.copy(dg.typedefs_arena),
.{ .name = undefined, .rendered = rendered_body }, .{ .name = name, .rendered = rendered },
); );
return name; return name;
@ -1363,11 +1352,11 @@ pub const DeclGen = struct {
const error_align = Type.anyerror.abiAlignment(target); const error_align = Type.anyerror.abiAlignment(target);
if (error_align > payload_align) { if (error_align > payload_align) {
try bw.writeAll("typedef struct { "); try bw.writeAll("typedef struct { ");
try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0); try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete);
try bw.writeAll("; uint16_t error; } "); try bw.writeAll("; uint16_t error; } ");
} else { } else {
try bw.writeAll("typedef struct { uint16_t error; "); try bw.writeAll("typedef struct { uint16_t error; ");
try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0); try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete);
try bw.writeAll("; } "); try bw.writeAll("; } ");
} }
@ -1398,7 +1387,7 @@ pub const DeclGen = struct {
const bw = buffer.writer(); const bw = buffer.writer();
try bw.writeAll("typedef "); try bw.writeAll("typedef ");
try dg.renderType(bw, info.elem_type); try dg.renderType(bw, info.elem_type, .Complete);
const name_begin = buffer.items.len + " ".len; const name_begin = buffer.items.len + " ".len;
try bw.print(" zig_A_{}_{d}", .{ typeToCIdentifier(info.elem_type, dg.module), info.len }); try bw.print(" zig_A_{}_{d}", .{ typeToCIdentifier(info.elem_type, dg.module), info.len });
@ -1426,7 +1415,7 @@ pub const DeclGen = struct {
try bw.writeAll("typedef struct { "); try bw.writeAll("typedef struct { ");
const payload_name = CValue{ .bytes = "payload" }; const payload_name = CValue{ .bytes = "payload" };
try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0); try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0, .Complete);
try bw.writeAll("; bool is_null; } "); try bw.writeAll("; bool is_null; } ");
const name_begin = buffer.items.len; const name_begin = buffer.items.len;
@ -1488,7 +1477,12 @@ pub const DeclGen = struct {
/// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" | /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" |
/// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" | /// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" |
/// ///
fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void { fn renderType(
dg: *DeclGen,
w: anytype,
t: Type,
kind: TypedefKind,
) error{ OutOfMemory, AnalysisFail }!void {
const target = dg.module.getTarget(); const target = dg.module.getTarget();
switch (t.zigTypeTag()) { switch (t.zigTypeTag()) {
@ -1540,10 +1534,11 @@ pub const DeclGen = struct {
} }
}, },
.Pointer => { .Pointer => {
const child_ty = t.childType();
if (t.isSlice()) { if (t.isSlice()) {
var slice_pl = Type.Payload.ElemType{ var slice_pl = Type.Payload.ElemType{
.base = .{ .tag = if (t.ptrIsMutable()) .mut_slice else .const_slice }, .base = .{ .tag = if (t.ptrIsMutable()) .mut_slice else .const_slice },
.data = t.childType(), .data = child_ty,
}; };
const slice_ty = Type.initPayload(&slice_pl.base); const slice_ty = Type.initPayload(&slice_pl.base);
@ -1553,31 +1548,27 @@ pub const DeclGen = struct {
return w.writeAll(name); return w.writeAll(name);
} }
if (t.castPtrToFn()) |fn_ty| { if (child_ty.zigTypeTag() == .Fn) {
const name = dg.getTypedefName(t) orelse const name = dg.getTypedefName(child_ty) orelse
try dg.renderPtrToFnTypedef(t, fn_ty); try dg.renderPtrToFnTypedef(child_ty);
return w.writeAll(name); return w.writeAll(name);
} }
const child_ty = t.childType();
if (t.isCPtr() and child_ty.eql(Type.u8, dg.module) and if (t.isCPtr() and child_ty.eql(Type.u8, dg.module) and
(dg.decl.val.tag() == .extern_fn or std.mem.eql(u8, std.mem.span(dg.decl.name), "main"))) (dg.decl.val.tag() == .extern_fn or
std.mem.eql(u8, std.mem.span(dg.decl.name), "main")))
{ {
// This is a hack, since the c compiler expects a lot of external // This is a hack, since the c compiler expects a lot of external
// library functions to have char pointers in their signatures, but // library functions to have char pointers in their signatures, but
// u8 and i8 produce unsigned char and signed char respectively, // u8 and i8 produce unsigned char and signed char respectively,
// which in C are not very usefully different than char. // which in C are (not very usefully) different than char.
try w.writeAll("char"); try w.writeAll("char");
} else { } else {
try dg.renderType(w, child_ty); try dg.renderType(w, child_ty, .Forward);
}
if (t.isConstPtr()) {
try w.writeAll(" const");
}
if (t.isVolatilePtr()) {
try w.writeAll(" volatile");
} }
if (t.isConstPtr()) try w.writeAll(" const");
if (t.isVolatilePtr()) try w.writeAll(" volatile");
return w.writeAll(" *"); return w.writeAll(" *");
}, },
.Array => { .Array => {
@ -1601,7 +1592,7 @@ pub const DeclGen = struct {
} }
if (t.optionalReprIsPayload()) { if (t.optionalReprIsPayload()) {
return dg.renderType(w, child_type); return dg.renderType(w, child_type, .Complete);
} }
const name = dg.getTypedefName(t) orelse const name = dg.getTypedefName(t) orelse
@ -1617,7 +1608,7 @@ pub const DeclGen = struct {
const payload_ty = t.errorUnionPayload(); const payload_ty = t.errorUnionPayload();
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
return dg.renderType(w, Type.anyerror); return dg.renderType(w, Type.anyerror, .Complete);
} }
var error_union_pl = Type.Payload.ErrorUnion{ var error_union_pl = Type.Payload.ErrorUnion{
@ -1630,17 +1621,26 @@ pub const DeclGen = struct {
return w.writeAll(name); return w.writeAll(name);
}, },
.Struct => { .Struct, .Union => |tag| if (kind == .Complete or t.isTupleOrAnonStruct()) {
const name = dg.getTypedefName(t) orelse if (t.isTupleOrAnonStruct()) const name = dg.getTypedefName(t) orelse switch (tag) {
try dg.renderTupleTypedef(t) .Struct => if (t.isTupleOrAnonStruct())
else try dg.renderTupleTypedef(t)
try dg.renderStructTypedef(t); else
try dg.renderStructTypedef(t),
.Union => try dg.renderUnionTypedef(t),
else => unreachable,
};
return w.writeAll(name); return w.writeAll(name);
}, } else {
.Union => { var ptr_pl = Type.Payload.ElemType{
const name = dg.getTypedefName(t) orelse .base = .{ .tag = .single_const_pointer },
try dg.renderUnionTypedef(t); .data = t,
};
const ptr_ty = Type.initPayload(&ptr_pl.base);
const name = dg.getTypedefName(ptr_ty) orelse
try dg.renderFwdTypedef(ptr_ty);
return w.writeAll(name); return w.writeAll(name);
}, },
@ -1649,7 +1649,7 @@ pub const DeclGen = struct {
var int_tag_buf: Type.Payload.Bits = undefined; var int_tag_buf: Type.Payload.Bits = undefined;
const int_tag_ty = t.intTagType(&int_tag_buf); const int_tag_ty = t.intTagType(&int_tag_buf);
try dg.renderType(w, int_tag_ty); try dg.renderType(w, int_tag_ty, kind);
}, },
.Opaque => switch (t.tag()) { .Opaque => switch (t.tag()) {
.anyopaque => try w.writeAll("void"), .anyopaque => try w.writeAll("void"),
@ -1701,7 +1701,7 @@ pub const DeclGen = struct {
ty: Type, ty: Type,
) error{ OutOfMemory, AnalysisFail }!void { ) error{ OutOfMemory, AnalysisFail }!void {
const name = CValue{ .bytes = "" }; const name = CValue{ .bytes = "" };
return renderTypeAndName(dg, w, ty, name, .Mut, 0); return renderTypeAndName(dg, w, ty, name, .Mut, 0, .Complete);
} }
/// Renders a type and name in field declaration/definition format. /// Renders a type and name in field declaration/definition format.
@ -1720,6 +1720,7 @@ pub const DeclGen = struct {
name: CValue, name: CValue,
mutability: Mutability, mutability: Mutability,
alignment: u32, alignment: u32,
kind: TypedefKind,
) error{ OutOfMemory, AnalysisFail }!void { ) error{ OutOfMemory, AnalysisFail }!void {
var suffix = std.ArrayList(u8).init(dg.gpa); var suffix = std.ArrayList(u8).init(dg.gpa);
defer suffix.deinit(); defer suffix.deinit();
@ -1736,7 +1737,7 @@ pub const DeclGen = struct {
if (alignment != 0) if (alignment != 0)
try w.print("ZIG_ALIGN({}) ", .{alignment}); try w.print("ZIG_ALIGN({}) ", .{alignment});
try dg.renderType(w, render_ty); try dg.renderType(w, render_ty, kind);
const const_prefix = switch (mutability) { const const_prefix = switch (mutability) {
.Const => "const ", .Const => "const ",
@ -1755,11 +1756,11 @@ pub const DeclGen = struct {
const name_slice_ty = Type.initTag(.const_slice_u8_sentinel_0); const name_slice_ty = Type.initTag(.const_slice_u8_sentinel_0);
try buffer.appendSlice("static "); try buffer.appendSlice("static ");
try dg.renderType(bw, name_slice_ty); try dg.renderType(bw, name_slice_ty, .Complete);
const name_begin = buffer.items.len + " ".len; const name_begin = buffer.items.len + " ".len;
try bw.print(" zig_tagName_{}(", .{typeToCIdentifier(enum_ty, dg.module)}); try bw.print(" zig_tagName_{}(", .{typeToCIdentifier(enum_ty, dg.module)});
const name_end = buffer.items.len - "(".len; const name_end = buffer.items.len - "(".len;
try dg.renderTypeAndName(bw, enum_ty, .{ .identifier = "tag" }, .Const, 0); try dg.renderTypeAndName(bw, enum_ty, .{ .identifier = "tag" }, .Const, 0, .Complete);
try buffer.appendSlice(") {\n switch (tag) {\n"); try buffer.appendSlice(") {\n switch (tag) {\n");
for (enum_ty.enumFields().keys()) |name, index| { for (enum_ty.enumFields().keys()) |name, index| {
const name_z = try dg.typedefs.allocator.dupeZ(u8, name); const name_z = try dg.typedefs.allocator.dupeZ(u8, name);
@ -1785,7 +1786,7 @@ pub const DeclGen = struct {
const len_val = Value.initPayload(&len_pl.base); const len_val = Value.initPayload(&len_pl.base);
try bw.print(" case {}: {{\n static ", .{try dg.fmtIntLiteral(enum_ty, int_val)}); try bw.print(" case {}: {{\n static ", .{try dg.fmtIntLiteral(enum_ty, int_val)});
try dg.renderTypeAndName(bw, name_ty, .{ .identifier = "name" }, .Const, 0); try dg.renderTypeAndName(bw, name_ty, .{ .identifier = "name" }, .Const, 0, .Complete);
try buffer.appendSlice(" = "); try buffer.appendSlice(" = ");
try dg.renderValue(bw, name_ty, name_val, .Initializer); try dg.renderValue(bw, name_ty, name_val, .Initializer);
try buffer.appendSlice(";\n return ("); try buffer.appendSlice(";\n return (");
@ -1948,7 +1949,7 @@ pub fn genErrDecls(o: *Object) !void {
const name_val = Value.initPayload(&name_pl.base); const name_val = Value.initPayload(&name_pl.base);
try writer.writeAll("static "); try writer.writeAll("static ");
try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0); try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0, .Complete);
try writer.writeAll(" = "); try writer.writeAll(" = ");
try o.dg.renderValue(writer, name_ty, name_val, .Initializer); try o.dg.renderValue(writer, name_ty, name_val, .Initializer);
try writer.writeAll(";\n"); try writer.writeAll(";\n");
@ -1961,7 +1962,7 @@ pub fn genErrDecls(o: *Object) !void {
const name_array_ty = Type.initPayload(&name_array_ty_pl.base); const name_array_ty = Type.initPayload(&name_array_ty_pl.base);
try writer.writeAll("static "); try writer.writeAll("static ");
try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = name_prefix }, .Const, 0); try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = name_prefix }, .Const, 0, .Complete);
try writer.writeAll(" = {"); try writer.writeAll(" = {");
for (o.dg.module.error_name_list.items) |name, value| { for (o.dg.module.error_name_list.items) |name, value| {
if (value != 0) try writer.writeByte(','); if (value != 0) try writer.writeByte(',');
@ -1988,14 +1989,13 @@ pub fn genFunc(f: *Function) !void {
const is_global = o.dg.module.decl_exports.contains(f.func.owner_decl); const is_global = o.dg.module.decl_exports.contains(f.func.owner_decl);
const fwd_decl_writer = o.dg.fwd_decl.writer(); const fwd_decl_writer = o.dg.fwd_decl.writer();
if (is_global) { try fwd_decl_writer.writeAll(if (is_global) "ZIG_EXTERN_C " else "static ");
try fwd_decl_writer.writeAll("ZIG_EXTERN_C "); try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward);
}
try o.dg.renderFunctionSignature(fwd_decl_writer, is_global);
try fwd_decl_writer.writeAll(";\n"); try fwd_decl_writer.writeAll(";\n");
try o.indent_writer.insertNewline(); try o.indent_writer.insertNewline();
try o.dg.renderFunctionSignature(o.writer(), is_global); if (!is_global) try o.writer().writeAll("static ");
try o.dg.renderFunctionSignature(o.writer(), .Complete);
try o.writer().writeByte(' '); try o.writer().writeByte(' ');
// In case we need to use the header, populate it with a copy of the function // In case we need to use the header, populate it with a copy of the function
@ -2029,7 +2029,7 @@ pub fn genDecl(o: *Object) !void {
if (tv.val.tag() == .extern_fn) { if (tv.val.tag() == .extern_fn) {
const writer = o.writer(); const writer = o.writer();
try writer.writeAll("ZIG_EXTERN_C "); try writer.writeAll("ZIG_EXTERN_C ");
try o.dg.renderFunctionSignature(writer, true); try o.dg.renderFunctionSignature(writer, .Forward);
try writer.writeAll(";\n"); try writer.writeAll(";\n");
} else if (tv.val.castTag(.variable)) |var_payload| { } else if (tv.val.castTag(.variable)) |var_payload| {
const variable: *Module.Var = var_payload.data; const variable: *Module.Var = var_payload.data;
@ -2048,7 +2048,7 @@ pub fn genDecl(o: *Object) !void {
.decl = o.dg.decl_index, .decl = o.dg.decl_index,
}; };
try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align"); try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);
try fwd_decl_writer.writeAll(";\n"); try fwd_decl_writer.writeAll(";\n");
if (variable.is_extern or variable.init.isUndefDeep()) { if (variable.is_extern or variable.init.isUndefDeep()) {
@ -2057,7 +2057,7 @@ pub fn genDecl(o: *Object) !void {
try o.indent_writer.insertNewline(); try o.indent_writer.insertNewline();
const w = o.writer(); const w = o.writer();
try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align"); try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);
try w.writeAll(" = "); try w.writeAll(" = ");
if (variable.init.tag() != .unreachable_value) { if (variable.init.tag() != .unreachable_value) {
try o.dg.renderValue(w, tv.ty, variable.init, .Initializer); try o.dg.renderValue(w, tv.ty, variable.init, .Initializer);
@ -2072,7 +2072,7 @@ pub fn genDecl(o: *Object) !void {
// https://github.com/ziglang/zig/issues/7582 // https://github.com/ziglang/zig/issues/7582
const decl_c_value: CValue = .{ .decl = o.dg.decl_index }; const decl_c_value: CValue = .{ .decl = o.dg.decl_index };
try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align"); try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete);
try writer.writeAll(" = "); try writer.writeAll(" = ");
try o.dg.renderValue(writer, tv.ty, tv.val, .Initializer); try o.dg.renderValue(writer, tv.ty, tv.val, .Initializer);
@ -2095,7 +2095,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
const is_global = dg.declIsGlobal(tv); const is_global = dg.declIsGlobal(tv);
if (is_global) { if (is_global) {
try writer.writeAll("ZIG_EXTERN_C "); try writer.writeAll("ZIG_EXTERN_C ");
try dg.renderFunctionSignature(writer, is_global); try dg.renderFunctionSignature(writer, .Complete);
try dg.fwd_decl.appendSlice(";\n"); try dg.fwd_decl.appendSlice(";\n");
} }
}, },
@ -2760,8 +2760,10 @@ fn airWrapOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, fn_name:
const bits = int_info.bits; const bits = int_info.bits;
// if it's an unsigned int with non-arbitrary bit size then we can just add // if it's an unsigned int with non-arbitrary bit size then we can just add
if (int_info.signedness == .unsigned and bits == toCIntBits(bits)) { if (toCIntBits(bits)) |c_bits| {
return try airBinOp(f, inst, operator); if (int_info.signedness == .unsigned and bits == c_bits) {
return try airBinOp(f, inst, operator);
}
} }
if (bits > 64) return f.fail("TODO: C backend: airWrapOp for large integers", .{}); if (bits > 64) return f.fail("TODO: C backend: airWrapOp for large integers", .{});
@ -3899,9 +3901,11 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc
} }
const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else ""; const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else "";
// Ensure complete type definition is visible before accessing fields.
try f.renderType(std.io.null_writer, struct_ty);
const inst_ty = f.air.typeOfIndex(inst); const inst_ty = f.air.typeOfIndex(inst);
const local = try f.allocLocal(inst_ty, .Const); const local = try f.allocLocal(inst_ty, .Const);
if (field_val_ty.hasRuntimeBitsIgnoreComptime()) { if (field_val_ty.hasRuntimeBitsIgnoreComptime()) {
try writer.writeAll(" = &"); try writer.writeAll(" = &");
try f.writeCValueDeref(writer, struct_ptr); try f.writeCValueDeref(writer, struct_ptr);
@ -3941,6 +3945,9 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
}; };
const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else ""; const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else "";
// Ensure complete type definition is visible before accessing fields.
try f.renderType(std.io.null_writer, struct_ty);
const inst_ty = f.air.typeOfIndex(inst); const inst_ty = f.air.typeOfIndex(inst);
const is_array = inst_ty.zigTypeTag() == .Array; const is_array = inst_ty.zigTypeTag() == .Array;
const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const);
@ -4326,7 +4333,7 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
try writer.writeAll("if ("); try writer.writeAll("if (");
} }
try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor});
try f.object.dg.renderTypecast(writer, ptr_ty.elemType()); try f.renderTypecast(writer, ptr_ty.elemType());
try writer.writeByte(')'); try writer.writeByte(')');
if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
try writer.writeAll(" *)"); try writer.writeAll(" *)");
@ -4371,12 +4378,12 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
switch (extra.op()) { switch (extra.op()) {
else => { else => {
try writer.writeAll("zig_atomic("); try writer.writeAll("zig_atomic(");
try f.object.dg.renderTypecast(writer, ptr_ty.elemType()); try f.renderTypecast(writer, ptr_ty.elemType());
try writer.writeByte(')'); try writer.writeByte(')');
}, },
.Nand, .Min, .Max => { .Nand, .Min, .Max => {
// These are missing from stdatomic.h, so no atomic types for now. // These are missing from stdatomic.h, so no atomic types for now.
try f.object.dg.renderTypecast(writer, ptr_ty.elemType()); try f.renderTypecast(writer, ptr_ty.elemType());
}, },
} }
if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
@ -4403,7 +4410,7 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer(); const writer = f.object.writer();
try writer.writeAll(" = zig_atomic_load((zig_atomic("); try writer.writeAll(" = zig_atomic_load((zig_atomic(");
try f.object.dg.renderTypecast(writer, ptr_ty.elemType()); try f.renderTypecast(writer, ptr_ty.elemType());
try writer.writeByte(')'); try writer.writeByte(')');
if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
try writer.writeAll(" *)"); try writer.writeAll(" *)");
@ -4423,7 +4430,7 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
const writer = f.object.writer(); const writer = f.object.writer();
try writer.writeAll("zig_atomic_store((zig_atomic("); try writer.writeAll("zig_atomic_store((zig_atomic(");
try f.object.dg.renderTypecast(writer, ptr_ty.elemType()); try f.renderTypecast(writer, ptr_ty.elemType());
try writer.writeByte(')'); try writer.writeByte(')');
if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
try writer.writeAll(" *)"); try writer.writeAll(" *)");

View File

@ -43,7 +43,6 @@ const a = struct {
test "initialization" { test "initialization" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
var t = a.init(); var t = a.init();
try std.testing.expect(t.foo.len == 0); try std.testing.expect(t.foo.len == 0);
} }

View File

@ -12,7 +12,6 @@ const b_list: []B = &[_]B{};
const a = A{ .b_list_pointer = &b_list }; const a = A{ .b_list_pointer = &b_list };
test "segfault bug" { test "segfault bug" {
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
const assert = std.debug.assert; const assert = std.debug.assert;
const obj = B{ .a_pointer = &a }; const obj = B{ .a_pointer = &a };
assert(obj.a_pointer == &a); // this makes zig crash assert(obj.a_pointer == &a); // this makes zig crash

View File

@ -470,7 +470,6 @@ test "function pointer with return type that is error union with payload which i
return error.SkipZigTest; return error.SkipZigTest;
} }
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO 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_aarch64) return error.SkipZigTest; // TODO

View File

@ -8,7 +8,6 @@ test "saturating add" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO 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_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) 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 S = struct { const S = struct {
fn doTheTest() !void { fn doTheTest() !void {