mirror of
https://github.com/ziglang/zig.git
synced 2026-01-29 02:35:28 +00:00
Merge pull request #11012 from ziglang/x64-union-tag
stage2,x64: basic (un)tagged unions
This commit is contained in:
commit
331cc810de
@ -2098,17 +2098,72 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
|
||||
|
||||
fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
|
||||
_ = bin_op;
|
||||
return self.fail("TODO implement airSetUnionTag for {}", .{self.target.cpu.arch});
|
||||
const ptr_ty = self.air.typeOf(bin_op.lhs);
|
||||
const union_ty = ptr_ty.childType();
|
||||
const tag_ty = self.air.typeOf(bin_op.rhs);
|
||||
const layout = union_ty.unionGetLayout(self.target.*);
|
||||
|
||||
if (layout.tag_size == 0) {
|
||||
return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
|
||||
const ptr = try self.resolveInst(bin_op.lhs);
|
||||
ptr.freezeIfRegister(&self.register_manager);
|
||||
defer ptr.unfreezeIfRegister(&self.register_manager);
|
||||
|
||||
const tag = try self.resolveInst(bin_op.rhs);
|
||||
tag.freezeIfRegister(&self.register_manager);
|
||||
defer tag.unfreezeIfRegister(&self.register_manager);
|
||||
|
||||
const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align < layout.payload_align) blk: {
|
||||
// TODO reusing the operand
|
||||
const reg = try self.copyToTmpRegister(ptr_ty, ptr);
|
||||
try self.genBinMathOpMir(.add, ptr_ty, .{ .register = reg }, .{ .immediate = layout.payload_size });
|
||||
break :blk MCValue{ .register = reg };
|
||||
} else ptr;
|
||||
|
||||
try self.store(adjusted_ptr, tag, ptr_ty, tag_ty);
|
||||
|
||||
return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
|
||||
fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
|
||||
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
|
||||
const result: MCValue = if (self.liveness.isUnused(inst))
|
||||
.dead
|
||||
else
|
||||
return self.fail("TODO implement airGetUnionTag for {}", .{self.target.cpu.arch});
|
||||
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
|
||||
if (self.liveness.isUnused(inst)) {
|
||||
return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
|
||||
}
|
||||
|
||||
const tag_ty = self.air.typeOfIndex(inst);
|
||||
const union_ty = self.air.typeOf(ty_op.operand);
|
||||
const layout = union_ty.unionGetLayout(self.target.*);
|
||||
|
||||
if (layout.tag_size == 0) {
|
||||
return self.finishAir(inst, .none, .{ ty_op.operand, .none, .none });
|
||||
}
|
||||
|
||||
// TODO reusing the operand
|
||||
const operand = try self.resolveInst(ty_op.operand);
|
||||
operand.freezeIfRegister(&self.register_manager);
|
||||
defer operand.unfreezeIfRegister(&self.register_manager);
|
||||
|
||||
const tag_abi_size = tag_ty.abiSize(self.target.*);
|
||||
const offset: i32 = if (layout.tag_align < layout.payload_align) @intCast(i32, layout.payload_size) else 0;
|
||||
const dst_mcv: MCValue = blk: {
|
||||
switch (operand) {
|
||||
.stack_offset => |off| {
|
||||
if (tag_abi_size <= 8) {
|
||||
break :blk try self.copyToRegisterWithInstTracking(inst, tag_ty, .{
|
||||
.stack_offset = off - offset,
|
||||
});
|
||||
}
|
||||
|
||||
return self.fail("TODO implement get_union_tag for ABI larger than 8 bytes and operand {}", .{operand});
|
||||
},
|
||||
else => return self.fail("TODO implement get_union_tag for {}", .{operand}),
|
||||
}
|
||||
};
|
||||
|
||||
return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
|
||||
}
|
||||
|
||||
fn airClz(self: *Self, inst: Air.Inst.Index) !void {
|
||||
@ -2429,8 +2484,15 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
|
||||
});
|
||||
},
|
||||
.stack_offset => {
|
||||
const tmp_reg = try self.copyToTmpRegister(value_ty, value);
|
||||
return self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
|
||||
if (abi_size <= 8) {
|
||||
const tmp_reg = try self.copyToTmpRegister(value_ty, value);
|
||||
return self.store(ptr, .{ .register = tmp_reg }, ptr_ty, value_ty);
|
||||
}
|
||||
|
||||
try self.genInlineMemcpy(0, value_ty, value, .{
|
||||
.source_stack_base = .rbp,
|
||||
.dest_stack_base = reg.to64(),
|
||||
});
|
||||
},
|
||||
else => |other| {
|
||||
return self.fail("TODO implement set pointee with {}", .{other});
|
||||
@ -3905,36 +3967,22 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u
|
||||
.dead, .unreach => unreachable,
|
||||
.immediate => |imm| {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .@"test",
|
||||
.tag = .xor,
|
||||
.ops = (Mir.Ops{
|
||||
.reg1 = registerAlias(cond_reg, abi_size),
|
||||
}).encode(),
|
||||
.data = .{ .imm = @intCast(u32, imm) },
|
||||
});
|
||||
return self.addInst(.{
|
||||
.tag = .cond_jmp_eq_ne,
|
||||
.ops = (Mir.Ops{
|
||||
.flags = 0b00,
|
||||
}).encode(),
|
||||
.data = .{ .inst = undefined },
|
||||
});
|
||||
},
|
||||
.register => |reg| {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .@"test",
|
||||
.tag = .xor,
|
||||
.ops = (Mir.Ops{
|
||||
.reg1 = registerAlias(cond_reg, abi_size),
|
||||
.reg2 = registerAlias(reg, abi_size),
|
||||
}).encode(),
|
||||
.data = undefined,
|
||||
});
|
||||
return self.addInst(.{
|
||||
.tag = .cond_jmp_eq_ne,
|
||||
.ops = (Mir.Ops{
|
||||
.flags = 0b00,
|
||||
}).encode(),
|
||||
.data = .{ .inst = undefined },
|
||||
});
|
||||
},
|
||||
.stack_offset => {
|
||||
if (abi_size <= 8) {
|
||||
@ -3948,6 +3996,22 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u
|
||||
return self.fail("TODO implement switch mir when case is {}", .{case});
|
||||
},
|
||||
}
|
||||
|
||||
_ = try self.addInst(.{
|
||||
.tag = .@"test",
|
||||
.ops = (Mir.Ops{
|
||||
.reg1 = registerAlias(cond_reg, abi_size),
|
||||
.reg2 = registerAlias(cond_reg, abi_size),
|
||||
}).encode(),
|
||||
.data = undefined,
|
||||
});
|
||||
return self.addInst(.{
|
||||
.tag = .cond_jmp_eq_ne,
|
||||
.ops = (Mir.Ops{
|
||||
.flags = 0b00,
|
||||
}).encode(),
|
||||
.data = .{ .inst = undefined },
|
||||
});
|
||||
},
|
||||
.stack_offset => {
|
||||
try self.spillCompareFlagsIfOccupied();
|
||||
@ -5408,24 +5472,14 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
|
||||
}
|
||||
|
||||
switch (typed_value.ty.zigTypeTag()) {
|
||||
.Array => {
|
||||
return self.lowerUnnamedConst(typed_value);
|
||||
},
|
||||
.Pointer => switch (typed_value.ty.ptrSize()) {
|
||||
.Slice => {
|
||||
return self.lowerUnnamedConst(typed_value);
|
||||
},
|
||||
.Slice => {},
|
||||
else => {
|
||||
switch (typed_value.val.tag()) {
|
||||
.int_u64 => {
|
||||
return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
|
||||
},
|
||||
.slice => {
|
||||
return self.lowerUnnamedConst(typed_value);
|
||||
},
|
||||
else => {
|
||||
return self.fail("TODO codegen more kinds of const pointers: {}", .{typed_value.val.tag()});
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
},
|
||||
},
|
||||
@ -5434,10 +5488,9 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
|
||||
if (info.bits <= ptr_bits and info.signedness == .signed) {
|
||||
return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt()) };
|
||||
}
|
||||
if (info.bits > ptr_bits or info.signedness == .signed) {
|
||||
return self.fail("TODO const int bigger than ptr and signed int", .{});
|
||||
if (!(info.bits > ptr_bits or info.signedness == .signed)) {
|
||||
return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
|
||||
}
|
||||
return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
|
||||
},
|
||||
.Bool => {
|
||||
return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) };
|
||||
@ -5457,7 +5510,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
|
||||
} else if (typed_value.ty.abiSize(self.target.*) == 1) {
|
||||
return MCValue{ .immediate = @boolToInt(typed_value.val.isNull()) };
|
||||
}
|
||||
return self.fail("TODO non pointer optionals", .{});
|
||||
},
|
||||
.Enum => {
|
||||
if (typed_value.val.castTag(.enum_field_index)) |field_index| {
|
||||
@ -5504,13 +5556,11 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
|
||||
return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val });
|
||||
}
|
||||
}
|
||||
return self.lowerUnnamedConst(typed_value);
|
||||
},
|
||||
.Struct => {
|
||||
return self.lowerUnnamedConst(typed_value);
|
||||
},
|
||||
else => return self.fail("TODO implement const of type '{}'", .{typed_value.ty}),
|
||||
else => {},
|
||||
}
|
||||
|
||||
return self.lowerUnnamedConst(typed_value);
|
||||
}
|
||||
|
||||
const CallMCValues = struct {
|
||||
|
||||
@ -1859,6 +1859,9 @@ fn lowerToRmEnc(
|
||||
switch (reg_or_mem) {
|
||||
.register => |src_reg| {
|
||||
const encoder = try Encoder.init(code, 4);
|
||||
if (reg.size() == 16) {
|
||||
encoder.prefix16BitMode();
|
||||
}
|
||||
encoder.rex(.{
|
||||
.w = setRexWRegister(reg) or setRexWRegister(src_reg),
|
||||
.r = reg.isExtended(),
|
||||
@ -1902,6 +1905,9 @@ fn lowerToMrEnc(
|
||||
switch (reg_or_mem) {
|
||||
.register => |dst_reg| {
|
||||
const encoder = try Encoder.init(code, 3);
|
||||
if (dst_reg.size() == 16) {
|
||||
encoder.prefix16BitMode();
|
||||
}
|
||||
encoder.rex(.{
|
||||
.w = setRexWRegister(dst_reg) or setRexWRegister(reg),
|
||||
.r = reg.isExtended(),
|
||||
|
||||
@ -466,10 +466,74 @@ pub fn generateSymbol(
|
||||
return Result{ .appended = {} };
|
||||
},
|
||||
.Union => {
|
||||
// TODO generateSymbol for unions
|
||||
// TODO generate debug info for unions
|
||||
const target = bin_file.options.target;
|
||||
const abi_size = try math.cast(usize, typed_value.ty.abiSize(target));
|
||||
try code.writer().writeByteNTimes(0xaa, abi_size);
|
||||
const union_obj = typed_value.val.castTag(.@"union").?.data;
|
||||
const layout = typed_value.ty.unionGetLayout(target);
|
||||
|
||||
if (layout.payload_size == 0) {
|
||||
switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
|
||||
.ty = typed_value.ty.unionTagType().?,
|
||||
.val = union_obj.tag,
|
||||
}, code, debug_output)) {
|
||||
.appended => {},
|
||||
.externally_managed => |external_slice| {
|
||||
code.appendSliceAssumeCapacity(external_slice);
|
||||
},
|
||||
.fail => |em| return Result{ .fail = em },
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we should store the tag first.
|
||||
if (layout.tag_align >= layout.payload_align) {
|
||||
switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
|
||||
.ty = typed_value.ty.unionTagType().?,
|
||||
.val = union_obj.tag,
|
||||
}, code, debug_output)) {
|
||||
.appended => {},
|
||||
.externally_managed => |external_slice| {
|
||||
code.appendSliceAssumeCapacity(external_slice);
|
||||
},
|
||||
.fail => |em| return Result{ .fail = em },
|
||||
}
|
||||
}
|
||||
|
||||
const union_ty = typed_value.ty.cast(Type.Payload.Union).?.data;
|
||||
const field_index = union_ty.tag_ty.enumTagFieldIndex(union_obj.tag).?;
|
||||
assert(union_ty.haveFieldTypes());
|
||||
const field_ty = union_ty.fields.values()[field_index].ty;
|
||||
if (!field_ty.hasRuntimeBits()) {
|
||||
try code.writer().writeByteNTimes(0xaa, try math.cast(usize, layout.payload_size));
|
||||
} else {
|
||||
switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
|
||||
.ty = field_ty,
|
||||
.val = union_obj.val,
|
||||
}, code, debug_output)) {
|
||||
.appended => {},
|
||||
.externally_managed => |external_slice| {
|
||||
code.appendSliceAssumeCapacity(external_slice);
|
||||
},
|
||||
.fail => |em| return Result{ .fail = em },
|
||||
}
|
||||
|
||||
const padding = try math.cast(usize, layout.payload_size - field_ty.abiSize(target));
|
||||
if (padding > 0) {
|
||||
try code.writer().writeByteNTimes(0, padding);
|
||||
}
|
||||
}
|
||||
|
||||
if (layout.tag_size > 0) {
|
||||
switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
|
||||
.ty = union_ty.tag_ty,
|
||||
.val = union_obj.tag,
|
||||
}, code, debug_output)) {
|
||||
.appended => {},
|
||||
.externally_managed => |external_slice| {
|
||||
code.appendSliceAssumeCapacity(external_slice);
|
||||
},
|
||||
.fail => |em| return Result{ .fail = em },
|
||||
}
|
||||
}
|
||||
|
||||
return Result{ .appended = {} };
|
||||
},
|
||||
|
||||
@ -4,68 +4,100 @@ const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
const Tag = std.meta.Tag;
|
||||
|
||||
const Foo = union {
|
||||
const FooWithFloats = union {
|
||||
float: f64,
|
||||
int: i32,
|
||||
};
|
||||
|
||||
test "basic unions" {
|
||||
test "basic unions with floats" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
var foo = FooWithFloats{ .int = 1 };
|
||||
try expect(foo.int == 1);
|
||||
foo = FooWithFloats{ .float = 12.34 };
|
||||
try expect(foo.float == 12.34);
|
||||
}
|
||||
|
||||
fn setFloat(foo: *FooWithFloats, x: f64) void {
|
||||
foo.* = FooWithFloats{ .float = x };
|
||||
}
|
||||
|
||||
test "init union with runtime value - floats" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
var foo: FooWithFloats = undefined;
|
||||
|
||||
setFloat(&foo, 12.34);
|
||||
try expect(foo.float == 12.34);
|
||||
}
|
||||
|
||||
test "basic unions" {
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
var foo = Foo{ .int = 1 };
|
||||
try expect(foo.int == 1);
|
||||
foo = Foo{ .float = 12.34 };
|
||||
try expect(foo.float == 12.34);
|
||||
foo = Foo{ .str = .{ .slice = "Hello!" } };
|
||||
try expect(std.mem.eql(u8, foo.str.slice, "Hello!"));
|
||||
}
|
||||
|
||||
const Foo = union {
|
||||
int: i32,
|
||||
str: struct {
|
||||
slice: []const u8,
|
||||
},
|
||||
};
|
||||
|
||||
test "init union with runtime value" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
var foo: Foo = undefined;
|
||||
|
||||
setFloat(&foo, 12.34);
|
||||
try expect(foo.float == 12.34);
|
||||
|
||||
setInt(&foo, 42);
|
||||
try expect(foo.int == 42);
|
||||
}
|
||||
|
||||
fn setFloat(foo: *Foo, x: f64) void {
|
||||
foo.* = Foo{ .float = x };
|
||||
setStr(&foo, "Hello!");
|
||||
try expect(std.mem.eql(u8, foo.str.slice, "Hello!"));
|
||||
}
|
||||
|
||||
fn setInt(foo: *Foo, x: i32) void {
|
||||
foo.* = Foo{ .int = x };
|
||||
}
|
||||
|
||||
fn setStr(foo: *Foo, slice: []const u8) void {
|
||||
foo.* = Foo{ .str = .{ .slice = slice } };
|
||||
}
|
||||
|
||||
test "comptime union field access" {
|
||||
comptime {
|
||||
var foo = Foo{ .int = 0 };
|
||||
var foo = FooWithFloats{ .int = 0 };
|
||||
try expect(foo.int == 0);
|
||||
|
||||
foo = Foo{ .float = 42.42 };
|
||||
try expect(foo.float == 42.42);
|
||||
foo = FooWithFloats{ .float = 12.34 };
|
||||
try expect(foo.float == 12.34);
|
||||
}
|
||||
}
|
||||
|
||||
const FooExtern = extern union {
|
||||
float: f64,
|
||||
int: i32,
|
||||
str: struct {
|
||||
slice: []const u8,
|
||||
},
|
||||
};
|
||||
|
||||
test "basic extern unions" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
var foo = FooExtern{ .int = 1 };
|
||||
try expect(foo.int == 1);
|
||||
foo.float = 12.34;
|
||||
try expect(foo.float == 12.34);
|
||||
foo.str.slice = "Well";
|
||||
try expect(std.mem.eql(u8, foo.str.slice, "Well"));
|
||||
}
|
||||
|
||||
const ExternPtrOrInt = extern union {
|
||||
@ -129,7 +161,6 @@ test "access a member of tagged union with conflicting enum tag name" {
|
||||
}
|
||||
|
||||
test "constant tagged union with payload" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
@ -227,7 +258,6 @@ fn testComparison() !void {
|
||||
}
|
||||
|
||||
test "comparison between union and enum literal" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
@ -297,7 +327,6 @@ pub const PackThis = union(enum) {
|
||||
};
|
||||
|
||||
test "constant packed union" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
@ -457,7 +486,6 @@ test "update the tag value for zero-sized unions" {
|
||||
}
|
||||
|
||||
test "union initializer generates padding only if needed" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
@ -470,7 +498,6 @@ test "union initializer generates padding only if needed" {
|
||||
}
|
||||
|
||||
test "runtime tag name with single field" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
@ -483,7 +510,6 @@ test "runtime tag name with single field" {
|
||||
}
|
||||
|
||||
test "method call on an empty union" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
@ -547,7 +573,6 @@ test "tagged union type" {
|
||||
}
|
||||
|
||||
test "tagged union as return value" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
@ -628,7 +653,6 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) !void {
|
||||
}
|
||||
|
||||
test "switch on union with only 1 field" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
@ -658,7 +682,6 @@ const PartialInstWithPayload = union(enum) {
|
||||
};
|
||||
|
||||
test "union with only 1 field casted to its enum type which has enum value specified" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
@ -796,7 +819,6 @@ test "@unionInit stored to a const" {
|
||||
}
|
||||
|
||||
test "@unionInit can modify a union type" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
@ -839,7 +861,6 @@ test "@unionInit can modify a pointer value" {
|
||||
}
|
||||
|
||||
test "union no tag with struct member" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user