Commit cfc19eace7

Veikka Tuominen <git@vexu.eu>
2021-01-29 17:20:35
stage2 cbe: errors
1 parent c22f010
Changed files (3)
src
codegen
link
src/codegen/c.zig
@@ -217,6 +217,11 @@ pub const DeclGen = struct {
                     try writer.writeAll(" }");
                 }
             },
+            .ErrorSet => {
+                const payload = val.castTag(.@"error").?;
+                // error values will be #defined at the top of the file
+                return writer.print("zig_error_{s}", .{payload.data.name});
+            },
             else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement value {s}", .{
                 @tagName(e),
             }),
@@ -327,6 +332,16 @@ pub const DeclGen = struct {
                 try dg.renderType(w, child_type);
                 try w.writeAll(" payload; bool is_null; }");
             },
+            .ErrorSet => {
+                comptime std.debug.assert(Type.initTag(.anyerror).abiSize(std.Target.current) == 2);
+                try w.writeAll("uint16_t");
+            },
+            .ErrorUnion => {
+                // TODO this needs to be typedeffed since different structs are different types.
+                try w.writeAll("struct { ");
+                try dg.renderType(w, t.errorUnionChild());
+                try w.writeAll(" payload; uint16_t error; }");
+            },
             .Null, .Undefined => unreachable, // must be const or comptime
             else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement type {s}", .{
                 @tagName(e),
@@ -464,6 +479,8 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
             .wrap_optional => try genWrapOptional(o, inst.castTag(.wrap_optional).?),
             .optional_payload => try genOptionalPayload(o, inst.castTag(.optional_payload).?),
             .optional_payload_ptr => try genOptionalPayload(o, inst.castTag(.optional_payload).?),
+            .is_err => try genIsErr(o, inst.castTag(.is_err).?),
+            .is_err_ptr => try genIsErr(o, inst.castTag(.is_err_ptr).?),
             else => |e| return o.dg.fail(o.dg.decl.src(), "TODO: C backend: implement codegen for {}", .{e}),
         };
         switch (result_value) {
@@ -900,6 +917,18 @@ fn genWrapOptional(o: *Object, inst: *Inst.UnOp) !CValue {
     return local;
 }
 
+fn genIsErr(o: *Object, inst: *Inst.UnOp) !CValue {
+    const writer = o.writer();
+    const maybe_deref = if (inst.base.tag == .is_err_ptr) "[0]" else "";
+    const operand = try o.resolveInst(inst.operand);
+
+    const local = try o.allocLocal(Type.initTag(.bool), .Const);
+    try writer.writeAll(" = (");
+    try o.writeCValue(writer, operand);
+    try writer.print("){s}.error != 0;\n", .{maybe_deref});
+    return local;
+}
+
 fn IndentWriter(comptime UnderlyingWriter: type) type {
     return struct {
         const Self = @This();
src/link/C.zig
@@ -150,6 +150,19 @@ pub fn flushModule(self: *C, comp: *Compilation) !void {
         .iov_len = zig_h.len,
     });
 
+    var error_defs_buf = std.ArrayList(u8).init(comp.gpa);
+    defer error_defs_buf.deinit();
+
+    var it = module.global_error_set.iterator();
+    while (it.next()) |entry| {
+        try error_defs_buf.writer().print("#define zig_error_{s} {d}\n", .{ entry.key, entry.value });
+    }
+    try error_defs_buf.writer().writeByte('\n');
+    all_buffers.appendAssumeCapacity(.{
+        .iov_base = error_defs_buf.items.ptr,
+        .iov_len = error_defs_buf.items.len,
+    });
+
     var fn_count: usize = 0;
 
     // Forward decls and non-functions first.
src/type.zig
@@ -1813,6 +1813,18 @@ pub const Type = extern union {
         }
     }
 
+    /// Asserts that the type is an error union.
+    pub fn errorUnionChild(self: Type) Type {
+        return switch (self.tag()) {
+            .anyerror_void_error_union => Type.initTag(.anyerror),
+            .error_union => {
+                const payload = self.castTag(.error_union).?;
+                return payload.data.payload;
+            },
+            else => unreachable,
+        };
+    }
+
     /// Asserts the type is an array or vector.
     pub fn arrayLen(self: Type) u64 {
         return switch (self.tag()) {