mirror of
https://github.com/ziglang/zig.git
synced 2024-11-27 07:32:44 +00:00
C backend: errors and optionals
* bitcast treats all pointers as pointers * correctly unwrapping error unions with pointers * equality operators for primitive optional types
This commit is contained in:
parent
8f1e417757
commit
2e15a404e2
@ -1162,12 +1162,12 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
|
||||
|
||||
.slice => try airSlice(f, inst),
|
||||
|
||||
.cmp_eq => try airBinOp(f, inst, " == "),
|
||||
.cmp_eq => try airEquality(f, inst, .cmp_eq),
|
||||
.cmp_gt => try airBinOp(f, inst, " > "),
|
||||
.cmp_gte => try airBinOp(f, inst, " >= "),
|
||||
.cmp_lt => try airBinOp(f, inst, " < "),
|
||||
.cmp_lte => try airBinOp(f, inst, " <= "),
|
||||
.cmp_neq => try airBinOp(f, inst, " != "),
|
||||
.cmp_neq => try airEquality(f, inst, .cmp_neq),
|
||||
|
||||
// bool_and and bool_or are non-short-circuit operations
|
||||
.bool_and => try airBinOp(f, inst, " & "),
|
||||
@ -1257,9 +1257,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
|
||||
.slice_elem_ptr => try airSliceElemPtr(f, inst),
|
||||
.array_elem_val => try airArrayElemVal(f, inst),
|
||||
|
||||
.unwrap_errunion_payload => try airUnwrapErrUnionPay(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_payload_ptr => try airUnwrapErrUnionPay(f, inst, "&"),
|
||||
.unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst),
|
||||
.wrap_errunion_payload => try airWrapErrUnionPay(f, inst),
|
||||
.wrap_errunion_err => try airWrapErrUnionErr(f, inst),
|
||||
@ -1908,6 +1908,51 @@ fn airBinOp(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue
|
||||
return local;
|
||||
}
|
||||
|
||||
fn airEquality(f: *Function, inst: Air.Inst.Index, op: Air.Inst.Tag) !CValue {
|
||||
if (f.liveness.isUnused(inst))
|
||||
return CValue.none;
|
||||
|
||||
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
|
||||
const lhs = try f.resolveInst(bin_op.lhs);
|
||||
const rhs = try f.resolveInst(bin_op.rhs);
|
||||
|
||||
const writer = f.object.writer();
|
||||
const inst_ty = f.air.typeOfIndex(inst);
|
||||
const local = try f.allocLocal(inst_ty, .Const);
|
||||
|
||||
try writer.writeAll(" = ");
|
||||
|
||||
const lhs_ty = f.air.typeOf(bin_op.lhs);
|
||||
if (lhs_ty.tag() == .optional) {
|
||||
// (A && B) || (C && (A == B))
|
||||
// A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload
|
||||
|
||||
try writer.writeAll(if (op == .cmp_eq) "((" else "!((");
|
||||
try f.writeCValue(writer, lhs);
|
||||
try writer.writeAll(".is_null && ");
|
||||
try f.writeCValue(writer, rhs);
|
||||
try writer.writeAll(".is_null) || (");
|
||||
try f.writeCValue(writer, lhs);
|
||||
try writer.writeAll(".payload == ");
|
||||
try f.writeCValue(writer, rhs);
|
||||
try writer.writeAll(".payload && ");
|
||||
try f.writeCValue(writer, lhs);
|
||||
try writer.writeAll(".is_null == ");
|
||||
try f.writeCValue(writer, rhs);
|
||||
try writer.writeAll(".is_null));\n");
|
||||
|
||||
return local;
|
||||
}
|
||||
|
||||
const operator = if (op == .cmp_eq) "==" else "!=";
|
||||
try f.writeCValue(writer, lhs);
|
||||
try writer.print("{s}", .{operator});
|
||||
try f.writeCValue(writer, rhs);
|
||||
try writer.writeAll(";\n");
|
||||
|
||||
return local;
|
||||
}
|
||||
|
||||
fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue {
|
||||
if (f.liveness.isUnused(inst))
|
||||
return CValue.none;
|
||||
@ -2104,8 +2149,8 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
|
||||
const writer = f.object.writer();
|
||||
const inst_ty = f.air.typeOfIndex(inst);
|
||||
if (inst_ty.zigTypeTag() == .Pointer and
|
||||
f.air.typeOf(ty_op.operand).zigTypeTag() == .Pointer)
|
||||
if (inst_ty.isPtrAtRuntime() and
|
||||
f.air.typeOf(ty_op.operand).isPtrAtRuntime())
|
||||
{
|
||||
const local = try f.allocLocal(inst_ty, .Const);
|
||||
try writer.writeAll(" = (");
|
||||
@ -2503,7 +2548,7 @@ fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
return local;
|
||||
}
|
||||
|
||||
fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: []const u8) !CValue {
|
||||
if (f.liveness.isUnused(inst))
|
||||
return CValue.none;
|
||||
|
||||
@ -2519,7 +2564,6 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
|
||||
const inst_ty = f.air.typeOfIndex(inst);
|
||||
const maybe_deref = if (operand_ty.zigTypeTag() == .Pointer) "->" else ".";
|
||||
const maybe_addrof = if (inst_ty.zigTypeTag() == .Pointer) "&" else "";
|
||||
|
||||
const local = try f.allocLocal(inst_ty, .Const);
|
||||
try writer.print(" = {s}(", .{maybe_addrof});
|
||||
|
@ -41,6 +41,8 @@ test {
|
||||
_ = @import("behavior/member_func.zig");
|
||||
_ = @import("behavior/translate_c_macros.zig");
|
||||
_ = @import("behavior/generics.zig");
|
||||
_ = @import("behavior/error.zig");
|
||||
_ = @import("behavior/optional.zig");
|
||||
|
||||
if (builtin.object_format != .c) {
|
||||
// Tests that pass for stage1 and stage2 but not the C backend.
|
||||
@ -55,6 +57,7 @@ test {
|
||||
_ = @import("behavior/bugs/2006.zig");
|
||||
_ = @import("behavior/bugs/3112.zig");
|
||||
_ = @import("behavior/cast_llvm.zig");
|
||||
_ = @import("behavior/error.zig");
|
||||
_ = @import("behavior/eval.zig");
|
||||
_ = @import("behavior/floatop.zig");
|
||||
_ = @import("behavior/fn.zig");
|
||||
@ -63,7 +66,7 @@ test {
|
||||
_ = @import("behavior/math.zig");
|
||||
_ = @import("behavior/maximum_minimum.zig");
|
||||
_ = @import("behavior/null_llvm.zig");
|
||||
_ = @import("behavior/optional.zig");
|
||||
_ = @import("behavior/optional_llvm.zig");
|
||||
_ = @import("behavior/popcount.zig");
|
||||
_ = @import("behavior/saturating_arithmetic.zig");
|
||||
_ = @import("behavior/sizeof_and_typeof.zig");
|
||||
|
@ -18,25 +18,6 @@ test "passing an optional integer as a parameter" {
|
||||
comptime try expect(S.entry());
|
||||
}
|
||||
|
||||
test "self-referential struct through a slice of optional" {
|
||||
const S = struct {
|
||||
const Node = struct {
|
||||
children: []?Node,
|
||||
data: ?u8,
|
||||
|
||||
fn new() Node {
|
||||
return Node{
|
||||
.children = undefined,
|
||||
.data = null,
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var n = S.Node.new();
|
||||
try expect(n.data == null);
|
||||
}
|
||||
|
||||
pub const EmptyStruct = struct {};
|
||||
|
||||
test "optional pointer to size zero struct" {
|
||||
|
23
test/behavior/optional_llvm.zig
Normal file
23
test/behavior/optional_llvm.zig
Normal file
@ -0,0 +1,23 @@
|
||||
const std = @import("std");
|
||||
const testing = std.testing;
|
||||
const expect = testing.expect;
|
||||
const expectEqual = testing.expectEqual;
|
||||
|
||||
test "self-referential struct through a slice of optional" {
|
||||
const S = struct {
|
||||
const Node = struct {
|
||||
children: []?Node,
|
||||
data: ?u8,
|
||||
|
||||
fn new() Node {
|
||||
return Node{
|
||||
.children = undefined,
|
||||
.data = null,
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var n = S.Node.new();
|
||||
try expect(n.data == null);
|
||||
}
|
Loading…
Reference in New Issue
Block a user