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 {...@@ -1488,29 +1488,42 @@ pub const DeclGen = struct {
1488 // The forward declaration for T is stored with a key of *const T.1488 // The forward declaration for T is stored with a key of *const T.
1489 const child_ty = t.childType();1489 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
1498 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);1491 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1499 defer buffer.deinit();1492 defer buffer.deinit();
1493 const bw = buffer.writer();
15001494
1501 const tag = switch (child_ty.zigTypeTag()) {1495 const tag = switch (child_ty.zigTypeTag()) {
1502 .Struct => "struct ",1496 .Struct, .ErrorUnion, .Optional => "struct",
1503 .Union => if (child_ty.unionTagTypeSafety()) |_| "struct " else "union ",1497 .Union => if (child_ty.unionTagTypeSafety()) |_| "struct" else "union",
1504 else => unreachable,1498 else => unreachable,
1505 };1499 };
1506 const name_begin = buffer.items.len + "typedef ".len + tag.len;1500 try bw.writeAll("typedef ");
1507 try buffer.writer().print("typedef {s}zig_S_{}__{d} ", .{1501 try bw.writeAll(tag);
1508 tag,1502 const name_begin = buffer.items.len + " ".len;
1509 fmtIdent(fqn_buf.items),1503 try bw.writeAll(" zig_");
1510 @enumToInt(owner_decl_index),1504 switch (child_ty.zigTypeTag()) {
1511 });1505 .Struct, .Union => {
1512 const name_end = buffer.items.len - " ".len;1506 var fqn_buf = std.ArrayList(u8).init(dg.typedefs.allocator);
1513 try buffer.ensureUnusedCapacity((name_end - name_begin) + ";\n".len);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(' ');
1514 buffer.appendSliceAssumeCapacity(buffer.items[name_begin..name_end]);1527 buffer.appendSliceAssumeCapacity(buffer.items[name_begin..name_end]);
1515 buffer.appendSliceAssumeCapacity(";\n");1528 buffer.appendSliceAssumeCapacity(";\n");
15161529
...@@ -1570,7 +1583,11 @@ pub const DeclGen = struct {...@@ -1570,7 +1583,11 @@ pub const DeclGen = struct {
1570 return name;1583 return name;
1571 }1584 }
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 {
1574 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);1591 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1575 defer buffer.deinit();1592 defer buffer.deinit();
15761593
...@@ -1582,7 +1599,7 @@ pub const DeclGen = struct {...@@ -1582,7 +1599,7 @@ pub const DeclGen = struct {
1582 if (!field_ty.hasRuntimeBits() or fields.values[i].tag() != .unreachable_value) continue;1599 if (!field_ty.hasRuntimeBits() or fields.values[i].tag() != .unreachable_value) continue;
15831600
1584 try buffer.append(' ');1601 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);
1586 try buffer.appendSlice(";\n");1603 try buffer.appendSlice(";\n");
15871604
1588 field_id += 1;1605 field_id += 1;
...@@ -1670,6 +1687,11 @@ pub const DeclGen = struct {...@@ -1670,6 +1687,11 @@ pub const DeclGen = struct {
1670 fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {1687 fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
1671 assert(t.errorUnionSet().tag() == .anyerror);1688 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
1673 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);1695 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1674 defer buffer.deinit();1696 defer buffer.deinit();
1675 const bw = buffer.writer();1697 const bw = buffer.writer();
...@@ -1682,7 +1704,9 @@ pub const DeclGen = struct {...@@ -1682,7 +1704,9 @@ pub const DeclGen = struct {
1682 const target = dg.module.getTarget();1704 const target = dg.module.getTarget();
1683 const payload_align = payload_ty.abiAlignment(target);1705 const payload_align = payload_ty.abiAlignment(target);
1684 const error_align = error_ty.abiAlignment(target);1706 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 ");
1686 if (error_align > payload_align) {1710 if (error_align > payload_align) {
1687 try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete);1711 try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete);
1688 try bw.writeAll(";\n ");1712 try bw.writeAll(";\n ");
...@@ -1692,15 +1716,10 @@ pub const DeclGen = struct {...@@ -1692,15 +1716,10 @@ pub const DeclGen = struct {
1692 try bw.writeAll(";\n ");1716 try bw.writeAll(";\n ");
1693 try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete);1717 try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete);
1694 }1718 }
1695 try bw.writeAll(";\n} ");1719 try bw.writeAll(";\n};\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");
17001720
1701 const rendered = try buffer.toOwnedSlice();1721 const rendered = try buffer.toOwnedSlice();
1702 errdefer dg.typedefs.allocator.free(rendered);1722 errdefer dg.typedefs.allocator.free(rendered);
1703 const name = rendered[name_begin..name_end];
17041723
1705 try dg.typedefs.ensureUnusedCapacity(1);1724 try dg.typedefs.ensureUnusedCapacity(1);
1706 dg.typedefs.putAssumeCapacityNoClobber(1725 dg.typedefs.putAssumeCapacityNoClobber(
...@@ -1744,24 +1763,29 @@ pub const DeclGen = struct {...@@ -1744,24 +1763,29 @@ pub const DeclGen = struct {
1744 return name;1763 return name;
1745 }1764 }
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
1748 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);1772 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
1749 defer buffer.deinit();1773 defer buffer.deinit();
1750 const bw = buffer.writer();1774 const bw = buffer.writer();
17511775
1752 try bw.writeAll("typedef struct {\n ");1776 var opt_buf: Type.Payload.ElemType = undefined;
1753 try dg.renderTypeAndName(bw, child_type, .{ .identifier = "payload" }, .Mut, 0, .Complete);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);
1754 try bw.writeAll(";\n ");1783 try bw.writeAll(";\n ");
1755 try dg.renderTypeAndName(bw, Type.bool, .{ .identifier = "is_null" }, .Mut, 0, .Complete);1784 try dg.renderTypeAndName(bw, Type.bool, .{ .identifier = "is_null" }, .Mut, 0, .Complete);
1756 try bw.writeAll(";\n} ");1785 try bw.writeAll(";\n};\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");
17611786
1762 const rendered = try buffer.toOwnedSlice();1787 const rendered = try buffer.toOwnedSlice();
1763 errdefer dg.typedefs.allocator.free(rendered);1788 errdefer dg.typedefs.allocator.free(rendered);
1764 const name = rendered[name_begin..name_end];
17651789
1766 try dg.typedefs.ensureUnusedCapacity(1);1790 try dg.typedefs.ensureUnusedCapacity(1);
1767 dg.typedefs.putAssumeCapacityNoClobber(1791 dg.typedefs.putAssumeCapacityNoClobber(
...@@ -1900,18 +1924,34 @@ pub const DeclGen = struct {...@@ -1900,18 +1924,34 @@ pub const DeclGen = struct {
1900 },1924 },
1901 .Optional => {1925 .Optional => {
1902 var opt_buf: Type.Payload.ElemType = undefined;1926 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())
1906 return dg.renderType(w, Type.bool, kind);1930 return dg.renderType(w, Type.bool, kind);
19071931
1908 if (t.optionalReprIsPayload())1932 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) orelse1935 switch (kind) {
1912 try dg.renderOptionalTypedef(t, child_type);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 }
1915 },1955 },
1916 .ErrorUnion => {1956 .ErrorUnion => {
1917 const payload_ty = t.errorUnionPayload();1957 const payload_ty = t.errorUnionPayload();
...@@ -1924,10 +1964,26 @@ pub const DeclGen = struct {...@@ -1924,10 +1964,26 @@ pub const DeclGen = struct {
1924 };1964 };
1925 const error_union_ty = Type.initPayload(&error_union_pl.base);1965 const error_union_ty = Type.initPayload(&error_union_pl.base);
19261966
1927 const name = dg.getTypedefName(error_union_ty) orelse1967 switch (kind) {
1928 try dg.renderErrorUnionTypedef(error_union_ty);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 }
1931 },1987 },
1932 .Struct, .Union => |tag| if (t.containerLayout() == .Packed) {1988 .Struct, .Union => |tag| if (t.containerLayout() == .Packed) {
1933 if (t.castTag(.@"struct")) |struct_obj| {1989 if (t.castTag(.@"struct")) |struct_obj| {
...@@ -1965,28 +2021,31 @@ pub const DeclGen = struct {...@@ -1965,28 +2021,31 @@ pub const DeclGen = struct {
1965 const tuple_ty = Type.initPayload(&tuple_pl.base);2021 const tuple_ty = Type.initPayload(&tuple_pl.base);
19662022
1967 const name = dg.getTypedefName(tuple_ty) orelse2023 const name = dg.getTypedefName(tuple_ty) orelse
1968 try dg.renderTupleTypedef(tuple_ty);2024 try dg.renderTupleTypedef(tuple_ty, kind);
19692025
1970 try w.writeAll(name);2026 try w.writeAll(name);
1971 } else if (kind == .Complete) {2027 } else switch (kind) {
1972 const name = dg.getTypedefName(t) orelse switch (tag) {2028 .Complete => {
1973 .Struct => try dg.renderStructTypedef(t),2029 const name = dg.getTypedefName(t) orelse switch (tag) {
1974 .Union => try dg.renderUnionTypedef(t),2030 .Struct => try dg.renderStructTypedef(t),
1975 else => unreachable,2031 .Union => try dg.renderUnionTypedef(t),
1976 };2032 else => unreachable,
2033 };
19772034
1978 try w.writeAll(name);2035 try w.writeAll(name);
1979 } else {2036 },
1980 var ptr_pl = Type.Payload.ElemType{2037 .Forward => {
1981 .base = .{ .tag = .single_const_pointer },2038 var ptr_pl = Type.Payload.ElemType{
1982 .data = t,2039 .base = .{ .tag = .single_const_pointer },
1983 };2040 .data = t,
1984 const ptr_ty = Type.initPayload(&ptr_pl.base);2041 };
2042 const ptr_ty = Type.initPayload(&ptr_pl.base);
19852043
1986 const name = dg.getTypedefName(ptr_ty) orelse2044 const name = dg.getTypedefName(ptr_ty) orelse
1987 try dg.renderFwdTypedef(ptr_ty);2045 try dg.renderFwdTypedef(ptr_ty);
19882046
1989 try w.writeAll(name);2047 try w.writeAll(name);
2048 },
1990 },2049 },
1991 .Enum => {2050 .Enum => {
1992 // For enums, we simply use the integer tag type.2051 // For enums, we simply use the integer tag type.
test/behavior/bugs/3112.zig-1
...@@ -14,7 +14,6 @@ fn prev(p: ?State) void {...@@ -14,7 +14,6 @@ fn prev(p: ?State) void {
14test "zig test crash" {14test "zig test crash" {
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
16 if (builtin.zig_backend == .stage1) return error.SkipZigTest;16 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
17 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
18 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;17 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
19 var global: State = undefined;18 var global: State = undefined;
20 global.enter = prev;19 global.enter = prev;
test/behavior/optional.zig-1
...@@ -184,7 +184,6 @@ test "nested orelse" {...@@ -184,7 +184,6 @@ test "nested orelse" {
184}184}
185185
186test "self-referential struct through a slice of optional" {186test "self-referential struct through a slice of optional" {
187 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
188 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO187 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
189188
190 const S = struct {189 const S = struct {