authorgravatar for emily.a.bellows@hey.comEmily Bellows <emily.a.bellows@hey.com> 2021-10-31 14:21:02-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-11-02 12:45:29-04:00
log674932e503e5b3a929f5a17eb4aa2fd2866219c3
tree996ee589e424fde8f61fe6edd1a02001c49001e2
parent325bae7fc0025f7153bd1de1c28e642e896190b1

C backend: implement ?void, and other zero sized types


5 files changed, 75 insertions(+), 29 deletions(-)

src/codegen/c.zig+16-1
......@@ -308,6 +308,11 @@ pub const DeclGen = struct {
308308 if (ty.isPtrLikeOptional()) {
309309 return dg.renderValue(writer, payload_type, val);
310310 }
311 const target = dg.module.getTarget();
312 if (payload_type.abiSize(target) == 0) {
313 const is_null = val.castTag(.opt_payload) == null;
314 return writer.print("{}", .{is_null});
315 }
311316 try writer.writeByte('(');
312317 try dg.renderType(writer, ty);
313318 try writer.writeAll("){");
......@@ -588,10 +593,13 @@ pub const DeclGen = struct {
588593 .Optional => {
589594 var opt_buf: Type.Payload.ElemType = undefined;
590595 const child_type = t.optionalChild(&opt_buf);
596 const target = dg.module.getTarget();
591597 if (t.isPtrLikeOptional()) {
592598 return dg.renderType(w, child_type);
593599 } else if (dg.typedefs.get(t)) |some| {
594600 return w.writeAll(some.name);
601 } else if (child_type.abiSize(target) == 0) {
602 return w.writeAll("bool");
595603 }
596604
597605 var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
......@@ -2100,14 +2108,21 @@ fn airIsNull(
21002108 const un_op = f.air.instructions.items(.data)[inst].un_op;
21012109 const writer = f.object.writer();
21022110 const operand = try f.resolveInst(un_op);
2111 const target = f.object.dg.module.getTarget();
21032112
21042113 const local = try f.allocLocal(Type.initTag(.bool), .Const);
21052114 try writer.writeAll(" = (");
21062115 try f.writeCValue(writer, operand);
21072116
2108 if (f.air.typeOf(un_op).isPtrLikeOptional()) {
2117 const ty = f.air.typeOf(un_op);
2118 var opt_buf: Type.Payload.ElemType = undefined;
2119 const payload_type = ty.optionalChild(&opt_buf);
2120
2121 if (ty.isPtrLikeOptional()) {
21092122 // operand is a regular pointer, test `operand !=/== NULL`
21102123 try writer.print("){s} {s} NULL;\n", .{ deref_suffix, operator });
2124 } else if (payload_type.abiSize(target) == 0) {
2125 try writer.print("){s} {s} true;\n", .{ deref_suffix, operator });
21112126 } else {
21122127 try writer.print("){s}.is_null {s} true;\n", .{ deref_suffix, operator });
21132128 }
src/type.zig+7-1
......@@ -1805,7 +1805,13 @@ pub const Type = extern union {
18051805 .void,
18061806 => 0,
18071807
1808 .@"struct" => return self.structFieldOffset(self.structFieldCount(), target),
1808 .@"struct" => {
1809 const field_count = self.structFieldCount();
1810 if (field_count == 0) {
1811 return 0;
1812 }
1813 return self.structFieldOffset(field_count, target);
1814 },
18091815 .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => {
18101816 var buffer: Payload.Bits = undefined;
18111817 const int_tag_ty = self.intTagType(&buffer);
test/behavior.zig+2-1
......@@ -6,6 +6,7 @@ test {
66 _ = @import("behavior/bool.zig");
77 _ = @import("behavior/if.zig");
88 _ = @import("behavior/truncate.zig");
9 _ = @import("behavior/null.zig");
910
1011 if (builtin.object_format != .c) {
1112 // Tests that pass for stage1 and stage2 but not the C backend.
......@@ -48,7 +49,7 @@ test {
4849 _ = @import("behavior/math.zig");
4950 _ = @import("behavior/maximum_minimum.zig");
5051 _ = @import("behavior/member_func.zig");
51 _ = @import("behavior/null.zig");
52 _ = @import("behavior/null_llvm.zig");
5253 _ = @import("behavior/optional.zig");
5354 _ = @import("behavior/pointers.zig");
5455 _ = @import("behavior/popcount.zig");
test/behavior/null.zig+14-26
......@@ -59,18 +59,6 @@ fn foo(x: ?i32) ?bool {
5959 return value > 1234;
6060}
6161
62test "null literal outside function" {
63 const is_null = here_is_a_null_literal.context == null;
64 try expect(is_null);
65
66 const is_non_null = here_is_a_null_literal.context != null;
67 try expect(!is_non_null);
68}
69const SillyStruct = struct {
70 context: ?i32,
71};
72const here_is_a_null_literal = SillyStruct{ .context = null };
73
7462test "test null runtime" {
7563 try testTestNullRuntime(null);
7664}
......@@ -97,23 +85,23 @@ fn bar(x: ?void) ?void {
9785 }
9886}
9987
100const StructWithOptional = struct {
101 field: ?i32,
102};
88const Empty = struct {};
10389
104var struct_with_optional: StructWithOptional = undefined;
90test "optional struct{}" {
91 _ = try optionalEmptyStructImpl();
92 _ = comptime try optionalEmptyStructImpl();
93}
10594
106test "unwrap optional which is field of global var" {
107 struct_with_optional.field = null;
108 if (struct_with_optional.field) |payload| {
109 _ = payload;
110 unreachable;
111 }
112 struct_with_optional.field = 1234;
113 if (struct_with_optional.field) |payload| {
114 try expect(payload == 1234);
95fn optionalEmptyStructImpl() !void {
96 try expect(baz(null) == null);
97 try expect(baz(Empty{}) != null);
98}
99
100fn baz(x: ?Empty) ?Empty {
101 if (x) |_| {
102 return Empty{};
115103 } else {
116 unreachable;
104 return null;
117105 }
118106}
119107
test/behavior/null_llvm.zig created+36
......@@ -0,0 +1,36 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4test "null literal outside function" {
5 const is_null = here_is_a_null_literal.context == null;
6 try expect(is_null);
7
8 const is_non_null = here_is_a_null_literal.context != null;
9 try expect(!is_non_null);
10}
11
12const SillyStruct = struct {
13 context: ?i32,
14};
15
16const here_is_a_null_literal = SillyStruct{ .context = null };
17
18const StructWithOptional = struct {
19 field: ?i32,
20};
21
22var struct_with_optional: StructWithOptional = undefined;
23
24test "unwrap optional which is field of global var" {
25 struct_with_optional.field = null;
26 if (struct_with_optional.field) |payload| {
27 _ = payload;
28 unreachable;
29 }
30 struct_with_optional.field = 1234;
31 if (struct_with_optional.field) |payload| {
32 try expect(payload == 1234);
33 } else {
34 unreachable;
35 }
36}