aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/c.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-05-23 14:36:21 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-05-24 15:34:52 -0700
commitc97c7f9e3bade44136f2bdf8ec4015f1b1b8303f (patch)
tree0495f407107f7ca88b19162da381c7f602ccbb03 /src/codegen/c.zig
parent3a059ebe4c84a1e541bb3b2ccee2e7cc25686a4d (diff)
downloadzig-c97c7f9e3bade44136f2bdf8ec4015f1b1b8303f.tar.gz
zig-c97c7f9e3bade44136f2bdf8ec4015f1b1b8303f.zip
C backend: update to new error union semantics
Diffstat (limited to 'src/codegen/c.zig')
-rw-r--r--src/codegen/c.zig169
1 files changed, 117 insertions, 52 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 5f61f8586e..63082d46be 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -749,6 +749,12 @@ pub const DeclGen = struct {
const error_type = ty.errorUnionSet();
const payload_type = ty.errorUnionPayload();
+ if (error_type.errorSetCardinality() == .zero) {
+ // We use the payload directly as the type.
+ const payload_val = val.castTag(.eu_payload).?.data;
+ return dg.renderValue(writer, payload_type, payload_val, location);
+ }
+
if (!payload_type.hasRuntimeBits()) {
// We use the error type directly as the type.
const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val;
@@ -894,10 +900,12 @@ pub const DeclGen = struct {
try w.writeAll("ZIG_COLD ");
}
}
- const return_ty = dg.decl.ty.fnReturnType();
- if (return_ty.hasRuntimeBits()) {
- try dg.renderType(w, return_ty);
- } else if (return_ty.zigTypeTag() == .NoReturn) {
+ const fn_info = dg.decl.ty.fnInfo();
+ if (fn_info.return_type.hasRuntimeBits()) {
+ try dg.renderType(w, fn_info.return_type);
+ } else if (fn_info.return_type.isError()) {
+ try dg.renderType(w, Type.anyerror);
+ } else if (fn_info.return_type.zigTypeTag() == .NoReturn) {
try w.writeAll("zig_noreturn void");
} else {
try w.writeAll("void");
@@ -905,22 +913,19 @@ pub const DeclGen = struct {
try w.writeAll(" ");
try dg.renderDeclName(w, dg.decl_index);
try w.writeAll("(");
- const param_len = dg.decl.ty.fnParamLen();
- var index: usize = 0;
var params_written: usize = 0;
- while (index < param_len) : (index += 1) {
- const param_type = dg.decl.ty.fnParamType(index);
+ for (fn_info.param_types) |param_type, index| {
if (!param_type.hasRuntimeBitsIgnoreComptime()) continue;
if (params_written > 0) {
try w.writeAll(", ");
}
const name = CValue{ .arg = index };
- try dg.renderTypeAndName(w, dg.decl.ty.fnParamType(index), name, .Mut, 0);
+ try dg.renderTypeAndName(w, param_type, name, .Mut, 0);
params_written += 1;
}
- if (dg.decl.ty.fnIsVarArgs()) {
+ if (fn_info.is_var_args) {
if (params_written != 0) try w.writeAll(", ");
try w.writeAll("...");
} else if (params_written == 0) {
@@ -1156,26 +1161,36 @@ pub const DeclGen = struct {
}
fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 {
- const child_type = t.errorUnionPayload();
- const err_set_type = t.errorUnionSet();
+ const payload_ty = t.errorUnionPayload();
+ const error_ty = t.errorUnionSet();
var buffer = std.ArrayList(u8).init(dg.typedefs.allocator);
defer buffer.deinit();
const bw = buffer.writer();
- try bw.writeAll("typedef struct { ");
const payload_name = CValue{ .bytes = "payload" };
- try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0);
- try bw.writeAll("; uint16_t error; } ");
+ const target = dg.module.getTarget();
+ const payload_align = payload_ty.abiAlignment(target);
+ const error_align = Type.anyerror.abiAlignment(target);
+ if (error_align > payload_align) {
+ try bw.writeAll("typedef struct { ");
+ try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0);
+ try bw.writeAll("; uint16_t error; } ");
+ } else {
+ try bw.writeAll("typedef struct { uint16_t error; ");
+ try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0);
+ try bw.writeAll("; } ");
+ }
+
const name_index = buffer.items.len;
- if (err_set_type.castTag(.error_set_inferred)) |inf_err_set_payload| {
+ 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_{s}_{s};\n", .{
- typeToCIdentifier(err_set_type, dg.module), typeToCIdentifier(child_type, dg.module),
+ typeToCIdentifier(error_ty, dg.module), typeToCIdentifier(payload_ty, dg.module),
});
}
@@ -1359,12 +1374,19 @@ pub const DeclGen = struct {
return w.writeAll(name);
},
.ErrorSet => {
- comptime assert(Type.initTag(.anyerror).abiSize(builtin.target) == 2);
+ comptime assert(Type.anyerror.abiSize(builtin.target) == 2);
return w.writeAll("uint16_t");
},
.ErrorUnion => {
- if (t.errorUnionPayload().abiSize(target) == 0) {
- return dg.renderType(w, t.errorUnionSet());
+ const error_ty = t.errorUnionSet();
+ const payload_ty = t.errorUnionPayload();
+
+ if (error_ty.errorSetCardinality() == .zero) {
+ return dg.renderType(w, payload_ty);
+ }
+
+ if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
+ return dg.renderType(w, Type.anyerror);
}
const name = dg.getTypedefName(t) orelse
@@ -1901,8 +1923,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.array_elem_val => try airArrayElemVal(f, inst),
.unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst, ""),
- .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst),
.unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst, "&"),
+ .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst),
.unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst),
.wrap_errunion_payload => try airWrapErrUnionPay(f, inst),
.wrap_errunion_err => try airWrapErrUnionErr(f, inst),
@@ -2120,11 +2142,14 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue {
fn airRet(f: *Function, inst: Air.Inst.Index) !CValue {
const un_op = f.air.instructions.items(.data)[inst].un_op;
const writer = f.object.writer();
- if (f.air.typeOf(un_op).isFnOrHasRuntimeBitsIgnoreComptime()) {
+ const ret_ty = f.air.typeOf(un_op);
+ if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
const operand = try f.resolveInst(un_op);
try writer.writeAll("return ");
try f.writeCValue(writer, operand);
try writer.writeAll(";\n");
+ } else if (ret_ty.isError()) {
+ try writer.writeAll("return 0;");
} else {
try writer.writeAll("return;\n");
}
@@ -2136,13 +2161,16 @@ fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue {
const writer = f.object.writer();
const ptr_ty = f.air.typeOf(un_op);
const ret_ty = ptr_ty.childType();
- if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
+ if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) {
+ const ptr = try f.resolveInst(un_op);
+ try writer.writeAll("return *");
+ try f.writeCValue(writer, ptr);
+ try writer.writeAll(";\n");
+ } else if (ret_ty.isError()) {
+ try writer.writeAll("return 0;\n");
+ } else {
try writer.writeAll("return;\n");
}
- const ptr = try f.resolveInst(un_op);
- try writer.writeAll("return *");
- try f.writeCValue(writer, ptr);
- try writer.writeAll(";\n");
return CValue.none;
}
@@ -2713,19 +2741,20 @@ fn airCall(
.Pointer => callee_ty.childType(),
else => unreachable,
};
- const ret_ty = fn_ty.fnReturnType();
- const unused_result = f.liveness.isUnused(inst);
const writer = f.object.writer();
- var result_local: CValue = .none;
- if (unused_result) {
- if (ret_ty.hasRuntimeBits()) {
- try writer.print("(void)", .{});
+ const result_local: CValue = r: {
+ if (f.liveness.isUnused(inst)) {
+ if (loweredFnRetTyHasBits(fn_ty)) {
+ try writer.print("(void)", .{});
+ }
+ break :r .none;
+ } else {
+ const local = try f.allocLocal(fn_ty.fnReturnType(), .Const);
+ try writer.writeAll(" = ");
+ break :r local;
}
- } else {
- result_local = try f.allocLocal(ret_ty, .Const);
- try writer.writeAll(" = ");
- }
+ };
callee: {
known: {
@@ -3307,7 +3336,8 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
return local;
}
-// *(E!T) -> E NOT *E
+/// *(E!T) -> E
+/// Note that the result is never a pointer.
fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
if (f.liveness.isUnused(inst))
return CValue.none;
@@ -3319,7 +3349,11 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
const operand_ty = f.air.typeOf(ty_op.operand);
if (operand_ty.zigTypeTag() == .Pointer) {
- if (!operand_ty.childType().errorUnionPayload().hasRuntimeBits()) {
+ const err_union_ty = operand_ty.childType();
+ if (err_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
+ return CValue{ .bytes = "0" };
+ }
+ if (!err_union_ty.errorUnionPayload().hasRuntimeBits()) {
return operand;
}
const local = try f.allocLocal(inst_ty, .Const);
@@ -3328,6 +3362,9 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
try writer.writeAll(";\n");
return local;
}
+ if (operand_ty.errorUnionSet().errorSetCardinality() == .zero) {
+ return CValue{ .bytes = "0" };
+ }
if (!operand_ty.errorUnionPayload().hasRuntimeBits()) {
return operand;
}
@@ -3343,7 +3380,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
return local;
}
-fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []const u8) !CValue {
+fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: [*:0]const u8) !CValue {
if (f.liveness.isUnused(inst))
return CValue.none;
@@ -3351,17 +3388,19 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []cons
const writer = f.object.writer();
const operand = try f.resolveInst(ty_op.operand);
const operand_ty = f.air.typeOf(ty_op.operand);
+ const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer;
+ const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty;
+
+ if (error_union_ty.errorUnionSet().errorSetCardinality() == .zero) {
+ return operand;
+ }
- const error_union_ty = if (operand_ty.zigTypeTag() == .Pointer)
- operand_ty.childType()
- else
- operand_ty;
if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) {
return CValue.none;
}
const inst_ty = f.air.typeOfIndex(inst);
- const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";
+ const maybe_deref = if (operand_is_ptr) "->" else ".";
const local = try f.allocLocal(inst_ty, .Const);
try writer.print(" = {s}(", .{maybe_addrof});
@@ -3421,6 +3460,11 @@ fn airErrUnionPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue {
const error_ty = error_union_ty.errorUnionSet();
const payload_ty = error_union_ty.errorUnionPayload();
+ if (error_ty.errorSetCardinality() == .zero) {
+ // TODO: write undefined bytes through the pointer here
+ return operand;
+ }
+
// First, set the non-error value.
if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
try f.writeCValueDeref(writer, operand);
@@ -3464,6 +3508,9 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
const operand = try f.resolveInst(ty_op.operand);
const inst_ty = f.air.typeOfIndex(inst);
+ if (inst_ty.errorUnionSet().errorSetCardinality() == .zero) {
+ return operand;
+ }
const local = try f.allocLocal(inst_ty, .Const);
try writer.writeAll(" = { .error = 0, .payload = ");
try f.writeCValue(writer, operand);
@@ -3486,16 +3533,23 @@ fn airIsErr(
const operand_ty = f.air.typeOf(un_op);
const local = try f.allocLocal(Type.initTag(.bool), .Const);
const payload_ty = operand_ty.errorUnionPayload();
+ const error_ty = operand_ty.errorUnionSet();
+
try writer.writeAll(" = ");
- if (is_ptr) {
- try f.writeCValueDeref(writer, operand);
+
+ if (error_ty.errorSetCardinality() == .zero) {
+ try writer.print("0 {s} 0;\n", .{op_str});
} else {
- try f.writeCValue(writer, operand);
- }
- if (payload_ty.hasRuntimeBits()) {
- try writer.writeAll(".error");
+ if (is_ptr) {
+ try f.writeCValueDeref(writer, operand);
+ } else {
+ try f.writeCValue(writer, operand);
+ }
+ if (payload_ty.hasRuntimeBits()) {
+ try writer.writeAll(".error");
+ }
+ try writer.print(" {s} 0;\n", .{op_str});
}
- try writer.print(" {s} 0;\n", .{op_str});
return local;
}
@@ -4129,3 +4183,14 @@ fn intMin(ty: Type, target: std.Target, buf: []u8) []const u8 {
},
}
}
+
+fn loweredFnRetTyHasBits(fn_ty: Type) bool {
+ const ret_ty = fn_ty.fnReturnType();
+ if (ret_ty.hasRuntimeBitsIgnoreComptime()) {
+ return true;
+ }
+ if (ret_ty.isError()) {
+ return true;
+ }
+ return false;
+}