authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2022-12-03 21:48:19-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2022-12-03 21:58:18-05:00
loge3b8658e657118054fd57aa18aff281747f63ee8
tree31b74583e93ce827d36b0149e20e1c1331c1ec71
parent6d1292552e14a5678f069c1880adf04022951138

cbe: add forward declarations for optionals and error unions

Arrays will have to wait for type rewrite.

3 files changed, 120 insertions(+), 63 deletions(-)

src/codegen/c.zig+120-61
......@@ -1488,29 +1488,42 @@ pub const DeclGen = struct {
14881488 // The forward declaration for T is stored with a key of *const T.
14891489 const child_ty = t.childType();
14901490
1491 var fqn_buf = std.ArrayList(u8).init(dg.typedefs.allocator);
1492 defer fqn_buf.deinit();
1493
1494 const owner_decl_index = child_ty.getOwnerDecl();
1495 const owner_decl = dg.module.declPtr(owner_decl_index);
1496 try owner_decl.renderFullyQualifiedName(dg.module, fqn_buf.writer());
1497
14981491 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
14991492 defer buffer.deinit();
1493 const bw = buffer.writer();
15001494
15011495 const tag = switch (child_ty.zigTypeTag()) {
1502 .Struct => "struct ",
1503 .Union => if (child_ty.unionTagTypeSafety()) |_| "struct " else "union ",
1496 .Struct, .ErrorUnion, .Optional => "struct",
1497 .Union => if (child_ty.unionTagTypeSafety()) |_| "struct" else "union",
15041498 else => unreachable,
15051499 };
1506 const name_begin = buffer.items.len + "typedef ".len + tag.len;
1507 try buffer.writer().print("typedef {s}zig_S_{}__{d} ", .{
1508 tag,
1509 fmtIdent(fqn_buf.items),
1510 @enumToInt(owner_decl_index),
1511 });
1512 const name_end = buffer.items.len - " ".len;
1513 try buffer.ensureUnusedCapacity((name_end - name_begin) + ";\n".len);
1500 try bw.writeAll("typedef ");
1501 try bw.writeAll(tag);
1502 const name_begin = buffer.items.len + " ".len;
1503 try bw.writeAll(" zig_");
1504 switch (child_ty.zigTypeTag()) {
1505 .Struct, .Union => {
1506 var fqn_buf = std.ArrayList(u8).init(dg.typedefs.allocator);
1507 defer fqn_buf.deinit();
1508
1509 const owner_decl_index = child_ty.getOwnerDecl();
1510 const owner_decl = dg.module.declPtr(owner_decl_index);
1511 try owner_decl.renderFullyQualifiedName(dg.module, fqn_buf.writer());
1512
1513 try bw.print("S_{}__{d}", .{ fmtIdent(fqn_buf.items), @enumToInt(owner_decl_index) });
1514 },
1515 .ErrorUnion => {
1516 try bw.print("E_{}", .{typeToCIdentifier(child_ty.errorUnionPayload(), dg.module)});
1517 },
1518 .Optional => {
1519 var opt_buf: Type.Payload.ElemType = undefined;
1520 try bw.print("Q_{}", .{typeToCIdentifier(child_ty.optionalChild(&opt_buf), dg.module)});
1521 },
1522 else => unreachable,
1523 }
1524 const name_end = buffer.items.len;
1525 try buffer.ensureUnusedCapacity(" ".len + (name_end - name_begin) + ";\n".len);
1526 buffer.appendAssumeCapacity(' ');
15141527 buffer.appendSliceAssumeCapacity(buffer.items[name_begin..name_end]);
15151528 buffer.appendSliceAssumeCapacity(";\n");
15161529
......@@ -1570,7 +1583,11 @@ pub const DeclGen = struct {
15701583 return name;
15711584 }
15721585
1573 fn renderTupleTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1586 fn renderTupleTypedef(
1587 dg: *DeclGen,
1588 t: Type,
1589 kind: TypedefKind,
1590 ) error{ OutOfMemory, AnalysisFail }![]const u8 {
15741591 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
15751592 defer buffer.deinit();
15761593
......@@ -1582,7 +1599,7 @@ pub const DeclGen = struct {
15821599 if (!field_ty.hasRuntimeBits() or fields.values[i].tag() != .unreachable_value) continue;
15831600
15841601 try buffer.append(' ');
1585 try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .field = field_id }, .Mut, 0, .Complete);
1602 try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .field = field_id }, .Mut, 0, kind);
15861603 try buffer.appendSlice(";\n");
15871604
15881605 field_id += 1;
......@@ -1670,6 +1687,11 @@ pub const DeclGen = struct {
16701687 fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
16711688 assert(t.errorUnionSet().tag() == .anyerror);
16721689
1690 var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t };
1691 const ptr_ty = Type.initPayload(&ptr_pl.base);
1692 const name = dg.getTypedefName(ptr_ty) orelse
1693 try dg.renderFwdTypedef(ptr_ty);
1694
16731695 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
16741696 defer buffer.deinit();
16751697 const bw = buffer.writer();
......@@ -1682,7 +1704,9 @@ pub const DeclGen = struct {
16821704 const target = dg.module.getTarget();
16831705 const payload_align = payload_ty.abiAlignment(target);
16841706 const error_align = error_ty.abiAlignment(target);
1685 try bw.writeAll("typedef struct {\n ");
1707 try bw.writeAll("struct ");
1708 try bw.writeAll(name);
1709 try bw.writeAll(" {\n ");
16861710 if (error_align > payload_align) {
16871711 try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete);
16881712 try bw.writeAll(";\n ");
......@@ -1692,15 +1716,10 @@ pub const DeclGen = struct {
16921716 try bw.writeAll(";\n ");
16931717 try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete);
16941718 }
1695 try bw.writeAll(";\n} ");
1696 const name_begin = buffer.items.len;
1697 try bw.print("zig_E_{}", .{typeToCIdentifier(payload_ty, dg.module)});
1698 const name_end = buffer.items.len;
1699 try bw.writeAll(";\n");
1719 try bw.writeAll(";\n};\n");
17001720
17011721 const rendered = try buffer.toOwnedSlice();
17021722 errdefer dg.typedefs.allocator.free(rendered);
1703 const name = rendered[name_begin..name_end];
17041723
17051724 try dg.typedefs.ensureUnusedCapacity(1);
17061725 dg.typedefs.putAssumeCapacityNoClobber(
......@@ -1744,24 +1763,29 @@ pub const DeclGen = struct {
17441763 return name;
17451764 }
17461765
1747 fn renderOptionalTypedef(dg: *DeclGen, t: Type, child_type: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1766 fn renderOptionalTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1767 var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t };
1768 const ptr_ty = Type.initPayload(&ptr_pl.base);
1769 const name = dg.getTypedefName(ptr_ty) orelse
1770 try dg.renderFwdTypedef(ptr_ty);
1771
17481772 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
17491773 defer buffer.deinit();
17501774 const bw = buffer.writer();
17511775
1752 try bw.writeAll("typedef struct {\n ");
1753 try dg.renderTypeAndName(bw, child_type, .{ .identifier = "payload" }, .Mut, 0, .Complete);
1776 var opt_buf: Type.Payload.ElemType = undefined;
1777 const child_ty = t.optionalChild(&opt_buf);
1778
1779 try bw.writeAll("struct ");
1780 try bw.writeAll(name);
1781 try bw.writeAll(" {\n");
1782 try dg.renderTypeAndName(bw, child_ty, .{ .identifier = "payload" }, .Mut, 0, .Complete);
17541783 try bw.writeAll(";\n ");
17551784 try dg.renderTypeAndName(bw, Type.bool, .{ .identifier = "is_null" }, .Mut, 0, .Complete);
1756 try bw.writeAll(";\n} ");
1757 const name_begin = buffer.items.len;
1758 try bw.print("zig_Q_{}", .{typeToCIdentifier(child_type, dg.module)});
1759 const name_end = buffer.items.len;
1760 try bw.writeAll(";\n");
1785 try bw.writeAll(";\n};\n");
17611786
17621787 const rendered = try buffer.toOwnedSlice();
17631788 errdefer dg.typedefs.allocator.free(rendered);
1764 const name = rendered[name_begin..name_end];
17651789
17661790 try dg.typedefs.ensureUnusedCapacity(1);
17671791 dg.typedefs.putAssumeCapacityNoClobber(
......@@ -1900,18 +1924,34 @@ pub const DeclGen = struct {
19001924 },
19011925 .Optional => {
19021926 var opt_buf: Type.Payload.ElemType = undefined;
1903 const child_type = t.optionalChild(&opt_buf);
1927 const child_ty = t.optionalChild(&opt_buf);
19041928
1905 if (!child_type.hasRuntimeBitsIgnoreComptime())
1929 if (!child_ty.hasRuntimeBitsIgnoreComptime())
19061930 return dg.renderType(w, Type.bool, kind);
19071931
19081932 if (t.optionalReprIsPayload())
1909 return dg.renderType(w, child_type, kind);
1933 return dg.renderType(w, child_ty, kind);
19101934
1911 const name = dg.getTypedefName(t) orelse
1912 try dg.renderOptionalTypedef(t, child_type);
1935 switch (kind) {
1936 .Complete => {
1937 const name = dg.getTypedefName(t) orelse
1938 try dg.renderOptionalTypedef(t);
19131939
1914 return w.writeAll(name);
1940 try w.writeAll(name);
1941 },
1942 .Forward => {
1943 var ptr_pl = Type.Payload.ElemType{
1944 .base = .{ .tag = .single_const_pointer },
1945 .data = t,
1946 };
1947 const ptr_ty = Type.initPayload(&ptr_pl.base);
1948
1949 const name = dg.getTypedefName(ptr_ty) orelse
1950 try dg.renderFwdTypedef(ptr_ty);
1951
1952 try w.writeAll(name);
1953 },
1954 }
19151955 },
19161956 .ErrorUnion => {
19171957 const payload_ty = t.errorUnionPayload();
......@@ -1924,10 +1964,26 @@ pub const DeclGen = struct {
19241964 };
19251965 const error_union_ty = Type.initPayload(&error_union_pl.base);
19261966
1927 const name = dg.getTypedefName(error_union_ty) orelse
1928 try dg.renderErrorUnionTypedef(error_union_ty);
1967 switch (kind) {
1968 .Complete => {
1969 const name = dg.getTypedefName(error_union_ty) orelse
1970 try dg.renderErrorUnionTypedef(error_union_ty);
19291971
1930 return w.writeAll(name);
1972 try w.writeAll(name);
1973 },
1974 .Forward => {
1975 var ptr_pl = Type.Payload.ElemType{
1976 .base = .{ .tag = .single_const_pointer },
1977 .data = error_union_ty,
1978 };
1979 const ptr_ty = Type.initPayload(&ptr_pl.base);
1980
1981 const name = dg.getTypedefName(ptr_ty) orelse
1982 try dg.renderFwdTypedef(ptr_ty);
1983
1984 try w.writeAll(name);
1985 },
1986 }
19311987 },
19321988 .Struct, .Union => |tag| if (t.containerLayout() == .Packed) {
19331989 if (t.castTag(.@"struct")) |struct_obj| {
......@@ -1965,28 +2021,31 @@ pub const DeclGen = struct {
19652021 const tuple_ty = Type.initPayload(&tuple_pl.base);
19662022
19672023 const name = dg.getTypedefName(tuple_ty) orelse
1968 try dg.renderTupleTypedef(tuple_ty);
2024 try dg.renderTupleTypedef(tuple_ty, kind);
19692025
19702026 try w.writeAll(name);
1971 } else if (kind == .Complete) {
1972 const name = dg.getTypedefName(t) orelse switch (tag) {
1973 .Struct => try dg.renderStructTypedef(t),
1974 .Union => try dg.renderUnionTypedef(t),
1975 else => unreachable,
1976 };
2027 } else switch (kind) {
2028 .Complete => {
2029 const name = dg.getTypedefName(t) orelse switch (tag) {
2030 .Struct => try dg.renderStructTypedef(t),
2031 .Union => try dg.renderUnionTypedef(t),
2032 else => unreachable,
2033 };
19772034
1978 try w.writeAll(name);
1979 } else {
1980 var ptr_pl = Type.Payload.ElemType{
1981 .base = .{ .tag = .single_const_pointer },
1982 .data = t,
1983 };
1984 const ptr_ty = Type.initPayload(&ptr_pl.base);
2035 try w.writeAll(name);
2036 },
2037 .Forward => {
2038 var ptr_pl = Type.Payload.ElemType{
2039 .base = .{ .tag = .single_const_pointer },
2040 .data = t,
2041 };
2042 const ptr_ty = Type.initPayload(&ptr_pl.base);
19852043
1986 const name = dg.getTypedefName(ptr_ty) orelse
1987 try dg.renderFwdTypedef(ptr_ty);
2044 const name = dg.getTypedefName(ptr_ty) orelse
2045 try dg.renderFwdTypedef(ptr_ty);
19882046
1989 try w.writeAll(name);
2047 try w.writeAll(name);
2048 },
19902049 },
19912050 .Enum => {
19922051 // For enums, we simply use the integer tag type.
test/behavior/bugs/3112.zig-1
......@@ -14,7 +14,6 @@ fn prev(p: ?State) void {
1414test "zig test crash" {
1515 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1616 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
17 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
1817 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1918 var global: State = undefined;
2019 global.enter = prev;
test/behavior/optional.zig-1
......@@ -184,7 +184,6 @@ test "nested orelse" {
184184}
185185
186186test "self-referential struct through a slice of optional" {
187 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
188187 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
189188
190189 const S = struct {