diff --git a/lib/include/zig.h b/lib/include/zig.h index 9568753345..e4a0c4cc59 100644 --- a/lib/include/zig.h +++ b/lib/include/zig.h @@ -162,6 +162,7 @@ #include #include #include +#include #define int128_t __int128 #define uint128_t unsigned __int128 diff --git a/src/Compilation.zig b/src/Compilation.zig index fc71da56f3..99332e5d2b 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3099,13 +3099,16 @@ fn processOneJob(comp: *Compilation, job: Job) !void { .decl_index = decl_index, .decl = decl, .fwd_decl = fwd_decl.toManaged(gpa), - .typedefs = c_codegen.TypedefMap.initContext(gpa, .{ - .mod = module, - }), + .typedefs = c_codegen.TypedefMap.initContext(gpa, .{ .mod = module }), .typedefs_arena = typedefs_arena.allocator(), }; - defer dg.fwd_decl.deinit(); - defer dg.typedefs.deinit(); + defer { + for (dg.typedefs.values()) |typedef| { + module.gpa.free(typedef.rendered); + } + dg.typedefs.deinit(); + dg.fwd_decl.deinit(); + } c_codegen.genHeader(&dg) catch |err| switch (err) { error.AnalysisFail => { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index e006c9c795..beafafc94f 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -372,8 +372,8 @@ pub const DeclGen = struct { } fn getTypedefName(dg: *DeclGen, t: Type) ?[]const u8 { - if (dg.typedefs.get(t)) |some| { - return some.name; + if (dg.typedefs.get(t)) |typedef| { + return typedef.name; } else { return null; } @@ -1025,9 +1025,10 @@ pub const DeclGen = struct { try dg.renderType(bw, fn_info.return_type); try bw.writeAll(" (*"); - const name_start = buffer.items.len; - try bw.print("zig_F_{})(", .{typeToCIdentifier(t, dg.module)}); - const name_end = buffer.items.len - 2; + const name_begin = buffer.items.len; + try bw.print("zig_F_{}", .{typeToCIdentifier(t, dg.module)}); + const name_end = buffer.items.len; + try bw.writeAll(")("); const param_len = fn_info.param_types.len; @@ -1052,7 +1053,7 @@ pub const DeclGen = struct { const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); - const name = rendered[name_start..name_end]; + const name = rendered[name_begin..name_end]; try dg.typedefs.ensureUnusedCapacity(1); dg.typedefs.putAssumeCapacityNoClobber( @@ -1079,12 +1080,11 @@ pub const DeclGen = struct { const child_type = t.childType(); try bw.writeAll("; size_t len; } "); - const name_index = buffer.items.len; - if (t.isConstPtr()) { - try bw.print("zig_L_{}", .{typeToCIdentifier(child_type, dg.module)}); - } else { - try bw.print("zig_M_{}", .{typeToCIdentifier(child_type, dg.module)}); - } + const name_begin = buffer.items.len; + try bw.print("zig_{c}_{}", .{ + @as(u8, if (t.isConstPtr()) 'L' else 'M'), + typeToCIdentifier(child_type, dg.module), + }); if (ptr_sentinel) |s| { var sentinel_buffer = std.ArrayList(u8).init(dg.typedefs.allocator); defer sentinel_buffer.deinit(); @@ -1092,11 +1092,12 @@ pub const DeclGen = struct { try dg.renderValue(sentinel_buffer.writer(), child_type, s, .Identifier); try bw.print("_s_{}", .{fmtIdent(sentinel_buffer.items)}); } + const name_end = buffer.items.len; try bw.writeAll(";\n"); const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); - const name = rendered[name_index .. rendered.len - 2]; + const name = rendered[name_begin..name_end]; try dg.typedefs.ensureUnusedCapacity(1); dg.typedefs.putAssumeCapacityNoClobber( @@ -1115,7 +1116,30 @@ pub const DeclGen = struct { var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); defer buffer.deinit(); - try buffer.appendSlice("typedef struct {\n"); + const tag = "struct"; + const tagged_name_begin = buffer.items.len + "typedef ".len + tag.len + " ".len; + try buffer.writer().print("typedef " ++ tag ++ " zig_S_{} ", .{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.appendSlice(tagged_name); + try buffer.appendSlice(" {\n"); { var it = struct_obj.fields.iterator(); var empty = true; @@ -1124,68 +1148,63 @@ pub const DeclGen = struct { if (!field_ty.hasRuntimeBits()) continue; const alignment = entry.value_ptr.abi_align; - const name: CValue = .{ .identifier = entry.key_ptr.* }; + const field_name: CValue = .{ .identifier = entry.key_ptr.* }; try buffer.append(' '); - try dg.renderTypeAndName(buffer.writer(), field_ty, name, .Mut, alignment); + try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment); try buffer.appendSlice(";\n"); empty = false; } if (empty) try buffer.appendSlice(" char empty_struct;\n"); } - try buffer.appendSlice("} "); + try buffer.appendSlice("};\n"); - const name_start = buffer.items.len; - try buffer.writer().print("zig_S_{};\n", .{fmtIdent(fqn)}); - - const rendered = buffer.toOwnedSlice(); - errdefer dg.typedefs.allocator.free(rendered); - const name = rendered[name_start .. rendered.len - 2]; + const rendered_body = buffer.toOwnedSlice(); + errdefer dg.typedefs.allocator.free(rendered_body); + // 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); dg.typedefs.putAssumeCapacityNoClobber( - try t.copy(dg.typedefs_arena), - .{ .name = name, .rendered = rendered }, + try Type.Tag.empty_struct.create(dg.typedefs_arena, &struct_obj.namespace), + .{ .name = undefined, .rendered = rendered_body }, ); return name; } fn renderTupleTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { - const tuple = t.tupleFields(); - var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); defer buffer.deinit(); - const writer = buffer.writer(); try buffer.appendSlice("typedef struct {\n"); { + const fields = t.tupleFields(); var empty = true; - for (tuple.types) |field_ty, i| { + for (fields.types) |field_ty, i| { if (!field_ty.hasRuntimeBits()) continue; - const val = tuple.values[i]; + const val = fields.values[i]; if (val.tag() != .unreachable_value) continue; - var name = std.ArrayList(u8).init(dg.gpa); - defer name.deinit(); - try name.writer().print("field_{d}", .{i}); + const field_name = try std.fmt.allocPrint(dg.typedefs.allocator, "field_{d}", .{i}); + defer dg.typedefs.allocator.free(field_name); try buffer.append(' '); - try dg.renderTypeAndName(writer, field_ty, .{ .bytes = name.items }, .Mut, 0); + try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .identifier = field_name }, .Mut, 0); try buffer.appendSlice(";\n"); empty = false; } if (empty) try buffer.appendSlice(" char empty_tuple;\n"); } - try buffer.appendSlice("} "); - - const name_start = buffer.items.len; - try writer.print("zig_T_{};\n", .{typeToCIdentifier(t, dg.module)}); + const name_begin = buffer.items.len + "} ".len; + try buffer.writer().print("}} zig_T_{};\n", .{typeToCIdentifier(t, dg.module)}); + const name_end = buffer.items.len - ";\n".len; const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); - const name = rendered[name_start .. rendered.len - 2]; + const name = rendered[name_begin..name_end]; try dg.typedefs.ensureUnusedCapacity(1); dg.typedefs.putAssumeCapacityNoClobber( @@ -1197,62 +1216,85 @@ pub const DeclGen = struct { } fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { - const union_ty = t.cast(Type.Payload.Union).?.data; - const fqn = try union_ty.getFullyQualifiedName(dg.module); + const union_obj = t.cast(Type.Payload.Union).?.data; + const fqn = try union_obj.getFullyQualifiedName(dg.module); defer dg.typedefs.allocator.free(fqn); - const target = dg.module.getTarget(); - const layout = t.unionGetLayout(target); - var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); defer buffer.deinit(); - try buffer.appendSlice("typedef "); - if (t.unionTagTypeSafety()) |tag_ty| { - const name: CValue = .{ .bytes = "tag" }; - try buffer.appendSlice("struct {\n "); + const tag: []const u8 = if (t.unionTagTypeSafety()) |_| "struct" else "union"; + const tagged_name_begin = buffer.items.len + "typedef ".len + tag.len + " ".len; + 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"); + + const indent = if (t.unionTagTypeSafety()) |tag_ty| indent: { + const target = dg.module.getTarget(); + const layout = t.unionGetLayout(target); if (layout.tag_size != 0) { - try dg.renderTypeAndName(buffer.writer(), tag_ty, name, .Mut, 0); + try buffer.append(' '); + try dg.renderTypeAndName(buffer.writer(), tag_ty, .{ .identifier = "tag" }, .Mut, 0); try buffer.appendSlice(";\n"); } - } + try buffer.appendSlice(" union {\n"); + break :indent " "; + } else " "; - try buffer.appendSlice("union {\n"); - const fields = t.unionFields(); { - var it = fields.iterator(); + var it = t.unionFields().iterator(); var empty = true; while (it.next()) |entry| { const field_ty = entry.value_ptr.ty; if (!field_ty.hasRuntimeBits()) continue; const alignment = entry.value_ptr.abi_align; - const name: CValue = .{ .identifier = entry.key_ptr.* }; - try buffer.append(' '); - try dg.renderTypeAndName(buffer.writer(), field_ty, name, .Mut, alignment); + const field_name: CValue = .{ .identifier = entry.key_ptr.* }; + try buffer.appendSlice(indent); + try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment); try buffer.appendSlice(";\n"); empty = false; } - if (empty) try buffer.appendSlice(" char empty_union;\n"); - } - try buffer.appendSlice("} "); - - if (t.unionTagTypeSafety()) |_| { - try buffer.appendSlice("payload;\n} "); + if (empty) { + try buffer.appendSlice(indent); + try buffer.appendSlice("char empty_union;\n"); + } } - const name_start = buffer.items.len; - try buffer.writer().print("zig_U_{};\n", .{fmtIdent(fqn)}); + if (t.unionTagTypeSafety()) |_| try buffer.appendSlice(" } payload;\n"); + try buffer.appendSlice("};\n"); - const rendered = buffer.toOwnedSlice(); - errdefer dg.typedefs.allocator.free(rendered); - const name = rendered[name_start .. rendered.len - 2]; + const rendered_body = buffer.toOwnedSlice(); + errdefer dg.typedefs.allocator.free(rendered_body); + // 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); dg.typedefs.putAssumeCapacityNoClobber( - try t.copy(dg.typedefs_arena), - .{ .name = name, .rendered = rendered }, + try Type.Tag.empty_struct.create(dg.typedefs_arena, &union_obj.namespace), + .{ .name = undefined, .rendered = rendered_body }, ); return name; @@ -1280,21 +1322,22 @@ pub const DeclGen = struct { try bw.writeAll("; } "); } - const name_index = buffer.items.len; + const name_begin = buffer.items.len; if (error_ty.castTag(.error_set_inferred)) |inf_err_set_payload| { const func = inf_err_set_payload.data.func; try bw.writeAll("zig_E_"); try dg.renderDeclName(bw, func.owner_decl); - try bw.writeAll(";\n"); } else { - try bw.print("zig_E_{}_{};\n", .{ + try bw.print("zig_E_{}_{}", .{ typeToCIdentifier(error_ty, dg.module), typeToCIdentifier(payload_ty, dg.module), }); } + const name_end = buffer.items.len; + try bw.writeAll(";\n"); const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); - const name = rendered[name_index .. rendered.len - 2]; + const name = rendered[name_begin..name_end]; try dg.typedefs.ensureUnusedCapacity(1); dg.typedefs.putAssumeCapacityNoClobber( @@ -1315,7 +1358,7 @@ pub const DeclGen = struct { try bw.writeAll("typedef "); try dg.renderType(bw, elem_type); - const name_start = buffer.items.len + 1; + const name_begin = buffer.items.len + " ".len; try bw.print(" zig_A_{}_{d}", .{ typeToCIdentifier(elem_type, dg.module), t.arrayLen() }); if (t.sentinel()) |s| { var sentinel_buffer = std.ArrayList(u8).init(dg.typedefs.allocator); @@ -1331,7 +1374,7 @@ pub const DeclGen = struct { const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); - const name = rendered[name_start..name_end]; + const name = rendered[name_begin..name_end]; try dg.typedefs.ensureUnusedCapacity(1); dg.typedefs.putAssumeCapacityNoClobber( @@ -1351,12 +1394,15 @@ pub const DeclGen = struct { const payload_name = CValue{ .bytes = "payload" }; try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0); try bw.writeAll("; bool is_null; } "); - const name_index = buffer.items.len; - try bw.print("zig_Q_{};\n", .{typeToCIdentifier(child_type, dg.module)}); + + const name_begin = buffer.items.len; + try bw.print("zig_Q_{}", .{typeToCIdentifier(child_type, dg.module)}); + const name_end = buffer.items.len; + try bw.writeAll(";\n"); const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); - const name = rendered[name_index .. rendered.len - 2]; + const name = rendered[name_begin..name_end]; try dg.typedefs.ensureUnusedCapacity(1); dg.typedefs.putAssumeCapacityNoClobber( @@ -1378,12 +1424,14 @@ pub const DeclGen = struct { try buffer.writer().print("typedef struct { } ", .{fmtIdent(std.mem.span(unqualified_name))}); - const name_start = buffer.items.len; - try buffer.writer().print("zig_O_{};\n", .{fmtIdent(fqn)}); + const name_begin = buffer.items.len; + try buffer.writer().print("zig_O_{}", .{fmtIdent(fqn)}); + const name_end = buffer.items.len; + try buffer.appendSlice(";\n"); const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); - const name = rendered[name_start .. rendered.len - 2]; + const name = rendered[name_begin..name_end]; try dg.typedefs.ensureUnusedCapacity(1); dg.typedefs.putAssumeCapacityNoClobber( @@ -1530,7 +1578,7 @@ pub const DeclGen = struct { return w.writeAll(name); }, .Struct => { - const name = dg.getTypedefName(t) orelse if (t.isTuple() or t.tag() == .anon_struct) + const name = dg.getTypedefName(t) orelse if (t.isTupleOrAnonStruct()) try dg.renderTupleTypedef(t) else try dg.renderStructTypedef(t); @@ -3597,8 +3645,8 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc var field_name: []const u8 = undefined; var field_val_ty: Type = undefined; - var buf = std.ArrayList(u8).init(f.object.dg.gpa); - defer buf.deinit(); + var field_name_buf: []const u8 = ""; + defer f.object.dg.gpa.free(field_name_buf); switch (struct_ty.tag()) { .@"struct" => { const fields = struct_ty.structFields(); @@ -3614,8 +3662,8 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc const tuple = struct_ty.tupleFields(); if (tuple.values[index].tag() != .unreachable_value) return CValue.none; - try buf.writer().print("field_{d}", .{index}); - field_name = buf.items; + field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index}); + field_name = field_name_buf; field_val_ty = tuple.types[index]; }, else => unreachable, @@ -3648,8 +3696,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { const writer = f.object.writer(); const struct_byval = try f.resolveInst(extra.struct_operand); const struct_ty = f.air.typeOf(extra.struct_operand); - var buf = std.ArrayList(u8).init(f.object.dg.gpa); - defer buf.deinit(); + var field_name_buf: []const u8 = ""; + defer f.object.dg.gpa.free(field_name_buf); const field_name = switch (struct_ty.tag()) { .@"struct" => struct_ty.structFields().keys()[extra.field_index], .@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[extra.field_index], @@ -3657,8 +3705,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { const tuple = struct_ty.tupleFields(); if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none; - try buf.writer().print("field_{d}", .{extra.field_index}); - break :blk buf.items; + field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{extra.field_index}); + break :blk field_name_buf; }, else => unreachable, }; @@ -4125,8 +4173,9 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { const layout = union_ty.unionGetLayout(target); if (layout.tag_size == 0) return CValue.none; + try writer.writeByte('('); try f.writeCValue(writer, union_ptr); - try writer.writeAll("->tag = "); + try writer.writeAll(")->tag = "); try f.writeCValue(writer, new_tag); try writer.writeAll(";\n"); diff --git a/src/link/C.zig b/src/link/C.zig index bb321c1e83..d7432eb015 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -108,10 +108,8 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes const typedefs = &gop.value_ptr.typedefs; const code = &gop.value_ptr.code; fwd_decl.shrinkRetainingCapacity(0); - { - for (typedefs.values()) |value| { - module.gpa.free(value.rendered); - } + for (typedefs.values()) |typedef| { + module.gpa.free(typedef.rendered); } typedefs.clearRetainingCapacity(); code.shrinkRetainingCapacity(0); @@ -139,14 +137,14 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() }; defer { - function.value_map.deinit(); function.blocks.deinit(module.gpa); + function.value_map.deinit(); function.object.code.deinit(); - function.object.dg.fwd_decl.deinit(); - for (function.object.dg.typedefs.values()) |value| { - module.gpa.free(value.rendered); + for (function.object.dg.typedefs.values()) |typedef| { + module.gpa.free(typedef.rendered); } function.object.dg.typedefs.deinit(); + function.object.dg.fwd_decl.deinit(); } codegen.genFunc(&function) catch |err| switch (err) { @@ -179,10 +177,8 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi const typedefs = &gop.value_ptr.typedefs; const code = &gop.value_ptr.code; fwd_decl.shrinkRetainingCapacity(0); - { - for (typedefs.values()) |value| { - module.gpa.free(value.rendered); - } + for (typedefs.values()) |value| { + module.gpa.free(value.rendered); } typedefs.clearRetainingCapacity(); code.shrinkRetainingCapacity(0); @@ -206,11 +202,11 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi object.indent_writer = .{ .underlying_writer = object.code.writer() }; defer { object.code.deinit(); - object.dg.fwd_decl.deinit(); - for (object.dg.typedefs.values()) |value| { - module.gpa.free(value.rendered); + for (object.dg.typedefs.values()) |typedef| { + module.gpa.free(typedef.rendered); } object.dg.typedefs.deinit(); + object.dg.fwd_decl.deinit(); } codegen.genDecl(&object) catch |err| switch (err) { @@ -307,10 +303,10 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) } const Flush = struct { + err_decls: DeclBlock = .{}, remaining_decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void) = .{}, typedefs: Typedefs = .{}, typedef_buf: std.ArrayListUnmanaged(u8) = .{}, - err_buf: std.ArrayListUnmanaged(u8) = .{}, /// We collect a list of buffers to write, and write them all at once with pwritev 😎 all_buffers: std.ArrayListUnmanaged(std.os.iovec_const) = .{}, /// Keeps track of the total bytes of `all_buffers`. @@ -332,10 +328,10 @@ const Flush = struct { fn deinit(f: *Flush, gpa: Allocator) void { f.all_buffers.deinit(gpa); - f.err_buf.deinit(gpa); f.typedef_buf.deinit(gpa); f.typedefs.deinit(gpa); f.remaining_decls.deinit(gpa); + f.err_decls.deinit(gpa); } }; @@ -365,6 +361,10 @@ fn flushTypedefs(self: *C, f: *Flush, typedefs: codegen.TypedefMap.Unmanaged) Fl fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void { const module = self.base.options.module.?; + const fwd_decl = &f.err_decls.fwd_decl; + const typedefs = &f.err_decls.typedefs; + const code = &f.err_decls.code; + var object = codegen.Object{ .dg = .{ .gpa = module.gpa, @@ -372,20 +372,21 @@ fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void { .error_msg = null, .decl_index = undefined, .decl = undefined, - .fwd_decl = undefined, - .typedefs = codegen.TypedefMap.initContext(module.gpa, .{ .mod = module }), + .fwd_decl = fwd_decl.toManaged(module.gpa), + .typedefs = typedefs.promoteContext(module.gpa, .{ .mod = module }), .typedefs_arena = self.arena.allocator(), }, - .code = f.err_buf.toManaged(module.gpa), + .code = code.toManaged(module.gpa), .indent_writer = undefined, // set later so we can get a pointer to object.code }; object.indent_writer = .{ .underlying_writer = object.code.writer() }; defer { - f.err_buf = object.code.moveToUnmanaged(); - for (object.dg.typedefs.values()) |value| { - module.gpa.free(value.rendered); + object.code.deinit(); + for (object.dg.typedefs.values()) |typedef| { + module.gpa.free(typedef.rendered); } object.dg.typedefs.deinit(); + object.dg.fwd_decl.deinit(); } codegen.genErrDecls(&object) catch |err| switch (err) { @@ -393,11 +394,15 @@ fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void { else => |e| return e, }; - const gpa = self.base.allocator; + fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged(); + typedefs.* = object.dg.typedefs.unmanaged; + object.dg.typedefs.unmanaged = .{}; + code.* = object.code.moveToUnmanaged(); - try self.flushTypedefs(f, object.dg.typedefs.unmanaged); - try f.all_buffers.ensureUnusedCapacity(gpa, 1); - f.appendBufAssumeCapacity(object.code.items); + try self.flushTypedefs(f, typedefs.*); + try f.all_buffers.ensureUnusedCapacity(self.base.allocator, 1); + f.appendBufAssumeCapacity(fwd_decl.items); + f.appendBufAssumeCapacity(code.items); } /// Assumes `decl` was in the `remaining_decls` set, and has already been removed. diff --git a/test/behavior/align.zig b/test/behavior/align.zig index 3f7b7184c2..3bed9cbbb6 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -476,7 +476,6 @@ test "read 128-bit field from default aligned struct in global memory" { } test "struct field explicit alignment" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; diff --git a/test/behavior/atomics.zig b/test/behavior/atomics.zig index 1495ac75a4..50bf65a8a4 100644 --- a/test/behavior/atomics.zig +++ b/test/behavior/atomics.zig @@ -33,7 +33,6 @@ fn testCmpxchg() !void { } test "fence" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) 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 diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index e2df3d6aed..78cc683310 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -590,7 +590,6 @@ test "equality compare fn ptrs" { test "self reference through fn ptr field" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const S = struct { const A = struct { diff --git a/test/behavior/bugs/1310.zig b/test/behavior/bugs/1310.zig index 0f574942d3..9d93dacca2 100644 --- a/test/behavior/bugs/1310.zig +++ b/test/behavior/bugs/1310.zig @@ -24,6 +24,5 @@ fn agent_callback(_vm: [*]VM, options: [*]u8) callconv(.C) i32 { test "fixed" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try expect(agent_callback(undefined, undefined) == 11); } diff --git a/test/behavior/bugs/1500.zig b/test/behavior/bugs/1500.zig index 6a41617d2b..cc12c5d0be 100644 --- a/test/behavior/bugs/1500.zig +++ b/test/behavior/bugs/1500.zig @@ -6,7 +6,6 @@ const A = struct { const B = *const fn (A) void; test "allow these dependencies" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; var a: A = undefined; var b: B = undefined; if (false) { diff --git a/test/behavior/bugs/2006.zig b/test/behavior/bugs/2006.zig index 4d76230c88..ff759f2846 100644 --- a/test/behavior/bugs/2006.zig +++ b/test/behavior/bugs/2006.zig @@ -6,7 +6,6 @@ const S = struct { p: *S, }; test "bug 2006" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; var a: S = undefined; a = S{ .p = undefined }; try expect(@sizeOf(S) != 0); diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index cf086328a4..6445bbf3e3 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -410,7 +410,6 @@ fn testCastIntToErr(err: anyerror) !void { test "peer resolve array and const slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO @@ -546,7 +545,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 { test "single-item pointer of array to slice to unknown length pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try testCastPtrOfArrayToSliceAndPtr(); comptime try testCastPtrOfArrayToSliceAndPtr(); @@ -575,7 +573,6 @@ fn testCastPtrOfArrayToSliceAndPtr() !void { test "cast *[1][*]const u8 to [*]const ?[*]const u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO const window_name = [1][*]const u8{"window name"}; @@ -1235,7 +1232,6 @@ test "cast from array reference to fn: runtime fn ptr" { test "*const [N]null u8 to ?[]const u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO const S = struct { diff --git a/test/behavior/floatop.zig b/test/behavior/floatop.zig index a5eb25d4f5..3bb4ba9d0a 100644 --- a/test/behavior/floatop.zig +++ b/test/behavior/floatop.zig @@ -21,7 +21,6 @@ fn epsForType(comptime T: type) T { test "floating point comparisons" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO try testFloatComparisons(); @@ -91,7 +90,6 @@ fn testDifferentSizedFloatComparisons() !void { test "negative f128 floatToInt at compile-time" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - 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_arm) return error.SkipZigTest; // TODO diff --git a/test/behavior/generics.zig b/test/behavior/generics.zig index a0c21a75d8..b7904fb7f9 100644 --- a/test/behavior/generics.zig +++ b/test/behavior/generics.zig @@ -204,7 +204,6 @@ fn foo2(arg: anytype) bool { } test "generic struct" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; var a1 = GenNode(i32){ .value = 13, .next = null, diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 744f4adb9e..193efd3e7a 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -603,7 +603,6 @@ fn should_not_be_zero(x: f128) !void { } test "128-bit multiplication" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) 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 @@ -650,8 +649,6 @@ test "@addWithOverflow" { } test "small int addition" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - var x: u2 = 0; try expect(x == 0); diff --git a/test/behavior/maximum_minimum.zig b/test/behavior/maximum_minimum.zig index 685f65b2b9..977d06204e 100644 --- a/test/behavior/maximum_minimum.zig +++ b/test/behavior/maximum_minimum.zig @@ -6,7 +6,6 @@ const expectEqual = std.testing.expectEqual; test "@max" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -55,7 +54,6 @@ test "@min" { 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 S = struct { fn doTheTest() !void { diff --git a/test/behavior/muladd.zig b/test/behavior/muladd.zig index 1ce5ffb1e7..814e007950 100644 --- a/test/behavior/muladd.zig +++ b/test/behavior/muladd.zig @@ -2,7 +2,6 @@ const builtin = @import("builtin"); const expect = @import("std").testing.expect; test "@mulAdd" { - 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig index 5a878112b5..f9571e9590 100644 --- a/test/behavior/packed-struct.zig +++ b/test/behavior/packed-struct.zig @@ -293,7 +293,6 @@ test "regular in irregular packed struct" { test "byte-aligned field pointer offsets" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; diff --git a/test/behavior/saturating_arithmetic.zig b/test/behavior/saturating_arithmetic.zig index 1790fe4505..16bc32a5f1 100644 --- a/test/behavior/saturating_arithmetic.zig +++ b/test/behavior/saturating_arithmetic.zig @@ -239,7 +239,6 @@ test "saturating shl uses the LHS type" { 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 lhs_const: u8 = 1; var lhs_var: u8 = 1; diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index acd28426ab..cd9572ae3a 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -284,7 +284,6 @@ const Val = struct { test "struct point to self" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var root: Node = undefined; @@ -393,7 +392,6 @@ const APackedStruct = packed struct { test "packed struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO diff --git a/test/behavior/struct_contains_null_ptr_itself.zig b/test/behavior/struct_contains_null_ptr_itself.zig index 7a2e32b2c2..0e015aaf58 100644 --- a/test/behavior/struct_contains_null_ptr_itself.zig +++ b/test/behavior/struct_contains_null_ptr_itself.zig @@ -5,7 +5,6 @@ const builtin = @import("builtin"); test "struct contains null pointer which contains original struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; var x: ?*NodeLineComment = null; try expect(x == null); } diff --git a/test/behavior/switch_prong_implicit_cast.zig b/test/behavior/switch_prong_implicit_cast.zig index 716afc3ace..f58853adb1 100644 --- a/test/behavior/switch_prong_implicit_cast.zig +++ b/test/behavior/switch_prong_implicit_cast.zig @@ -18,7 +18,6 @@ test "switch prong implicit cast" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const result = switch (foo(2) catch unreachable) { FormValue.One => false, FormValue.Two => |x| x, diff --git a/test/behavior/union.zig b/test/behavior/union.zig index cfb522b74e..0160c21761 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1186,7 +1186,6 @@ test "comptime equality of extern unions with same tag" { } test "union tag is set when initiated as a temporary value at runtime" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -1350,7 +1349,6 @@ test "@unionInit uses tag value instead of field index" { } test "union field ptr - zero sized payload" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO @@ -1364,7 +1362,6 @@ test "union field ptr - zero sized payload" { } test "union field ptr - zero sized field" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index 80fa2021d8..581d68dcb6 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -811,7 +811,6 @@ test "vector reduce operation" { test "vector @reduce comptime" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - 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_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO