diff --git a/src/Module.zig b/src/Module.zig index 2c5c01bb7a..a1f804c282 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1104,9 +1104,6 @@ pub const Union = struct { pub fn getLayout(u: Union, target: Target, have_tag: bool) Layout { assert(u.status == .have_layout); - const is_packed = u.layout == .Packed; - if (is_packed) @panic("TODO packed unions"); - var most_aligned_field: usize = undefined; var most_aligned_field_size: u64 = undefined; var biggest_field: usize = undefined; diff --git a/src/Sema.zig b/src/Sema.zig index 2c2ba8bcb5..eca73a88e2 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -12152,34 +12152,16 @@ fn fieldCallBind( const field_index = @intCast(u32, field_index_usize); const field = struct_obj.fields.values()[field_index]; - const ptr_field_ty = try Type.ptr(arena, .{ - .pointee_type = field.ty, - .mutable = ptr_ty.ptrIsMutable(), - .@"addrspace" = ptr_ty.ptrAddressSpace(), - }); - - if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| { - const pointer = try sema.addConstant( - ptr_field_ty, - try Value.Tag.field_ptr.create(arena, .{ - .container_ptr = struct_ptr_val, - .field_index = field_index, - }), - ); - return sema.analyzeLoad(block, src, pointer, src); - } - - try sema.requireRuntimeBlock(block, src); - const ptr_inst = try block.addStructFieldPtr(object_ptr, field_index, ptr_field_ty); - return sema.analyzeLoad(block, src, ptr_inst, src); + return finishFieldCallBind(sema, block, src, ptr_ty, field.ty, field_index, object_ptr); }, .Union => { const union_ty = try sema.resolveTypeFields(block, src, concrete_ty); const fields = union_ty.unionFields(); const field_index_usize = fields.getIndex(field_name) orelse break :find_field; + const field_index = @intCast(u32, field_index_usize); + const field = fields.values()[field_index]; - _ = field_index_usize; - return sema.fail(block, src, "TODO implement field calls on unions", .{}); + return finishFieldCallBind(sema, block, src, ptr_ty, field.ty, field_index, object_ptr); }, .Type => { const namespace = try sema.analyzeLoad(block, src, object_ptr, src); @@ -12236,6 +12218,38 @@ fn fieldCallBind( return sema.fail(block, src, "type '{}' has no field or member function named '{s}'", .{ concrete_ty, field_name }); } +fn finishFieldCallBind( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + ptr_ty: Type, + field_ty: Type, + field_index: u32, + object_ptr: Air.Inst.Ref, +) CompileError!Air.Inst.Ref { + const arena = sema.arena; + const ptr_field_ty = try Type.ptr(arena, .{ + .pointee_type = field_ty, + .mutable = ptr_ty.ptrIsMutable(), + .@"addrspace" = ptr_ty.ptrAddressSpace(), + }); + + if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| { + const pointer = try sema.addConstant( + ptr_field_ty, + try Value.Tag.field_ptr.create(arena, .{ + .container_ptr = struct_ptr_val, + .field_index = field_index, + }), + ); + return sema.analyzeLoad(block, src, pointer, src); + } + + try sema.requireRuntimeBlock(block, src); + const ptr_inst = try block.addStructFieldPtr(object_ptr, field_index, ptr_field_ty); + return sema.analyzeLoad(block, src, ptr_inst, src); +} + fn namespaceLookup( sema: *Sema, block: *Block, diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 626d3758d0..05bd8070a2 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -165,6 +165,18 @@ test "union with specified enum tag" { comptime try doTest(); } +test "packed union generates correctly aligned LLVM type" { + const U = packed union { + f1: fn () error{TestUnexpectedResult}!void, + f2: u32, + }; + var foo = [_]U{ + U{ .f1 = doTest }, + U{ .f2 = 0 }, + }; + try foo[0].f1(); +} + fn doTest() error{TestUnexpectedResult}!void { try expect((try bar(Payload{ .A = 1234 })) == -10); } diff --git a/test/behavior/union_stage1.zig b/test/behavior/union_stage1.zig index 1d8f1a3f17..f5de087ce8 100644 --- a/test/behavior/union_stage1.zig +++ b/test/behavior/union_stage1.zig @@ -3,38 +3,6 @@ const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; const Tag = std.meta.Tag; -const Letter = enum { A, B, C }; -const Payload = union(Letter) { - A: i32, - B: f64, - C: bool, -}; - -fn doTest() error{TestUnexpectedResult}!void { - try expect((try bar(Payload{ .A = 1234 })) == -10); -} - -fn bar(value: Payload) error{TestUnexpectedResult}!i32 { - try expect(@as(Letter, value) == Letter.A); - return switch (value) { - Payload.A => |x| return x - 1244, - Payload.B => |x| if (x == 12.34) @as(i32, 20) else 21, - Payload.C => |x| if (x) @as(i32, 30) else 31, - }; -} - -test "packed union generates correctly aligned LLVM type" { - const U = packed union { - f1: fn () error{TestUnexpectedResult}!void, - f2: u32, - }; - var foo = [_]U{ - U{ .f1 = doTest }, - U{ .f2 = 0 }, - }; - try foo[0].f1(); -} - const MultipleChoice = union(enum(u32)) { A = 20, B = 40,