diff --git a/src/Sema.zig b/src/Sema.zig index d30b46ffba..c08cc09c68 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -300,7 +300,7 @@ pub const Block = struct { .ty = ty, .payload = try block.sema.addExtra(Air.StructField{ .struct_operand = struct_ptr, - .field_index = @intCast(u32, field_index), + .field_index = field_index, }), } }, }); @@ -315,6 +315,24 @@ pub const Block = struct { }); } + pub fn addStructFieldVal( + block: *Block, + struct_val: Air.Inst.Ref, + field_index: u32, + field_ty: Type, + ) !Air.Inst.Ref { + return block.addInst(.{ + .tag = .struct_field_val, + .data = .{ .ty_pl = .{ + .ty = try block.sema.addType(field_ty), + .payload = try block.sema.addExtra(Air.StructField{ + .struct_operand = struct_val, + .field_index = field_index, + }), + } }, + }); + } + pub fn addInst(block: *Block, inst: Air.Inst) error{OutOfMemory}!Air.Inst.Ref { return Air.indexToRef(try block.addInstAsIndex(inst)); } @@ -11261,8 +11279,10 @@ fn structFieldVal( const struct_ty = try sema.resolveTypeFields(block, src, unresolved_struct_ty); const struct_obj = struct_ty.castTag(.@"struct").?.data; - const field_index = struct_obj.fields.getIndex(field_name) orelse + const field_index_big = struct_obj.fields.getIndex(field_name) orelse return sema.failWithBadFieldAccess(block, struct_obj, field_name_src, field_name); + const field_index = @intCast(u32, field_index_big); + const field = struct_obj.fields.values()[field_index]; if (try sema.resolveMaybeUndefVal(block, src, struct_byval)) |struct_val| { @@ -11273,16 +11293,7 @@ fn structFieldVal( } try sema.requireRuntimeBlock(block, src); - return block.addInst(.{ - .tag = .struct_field_val, - .data = .{ .ty_pl = .{ - .ty = try sema.addType(field.ty), - .payload = try sema.addExtra(Air.StructField{ - .struct_operand = struct_byval, - .field_index = @intCast(u32, field_index), - }), - } }, - }); + return block.addStructFieldVal(struct_byval, field_index, field.ty); } fn unionFieldPtr( @@ -11341,8 +11352,9 @@ fn unionFieldVal( const union_ty = try sema.resolveTypeFields(block, src, unresolved_union_ty); const union_obj = union_ty.cast(Type.Payload.Union).?.data; - const field_index = union_obj.fields.getIndex(field_name) orelse + const field_index_big = union_obj.fields.getIndex(field_name) orelse return sema.failWithBadUnionFieldAccess(block, union_obj, field_name_src, field_name); + const field_index = @intCast(u32, field_index_big); const field = union_obj.fields.values()[field_index]; @@ -11355,7 +11367,7 @@ fn unionFieldVal( } try sema.requireRuntimeBlock(block, src); - return sema.fail(block, src, "TODO implement runtime union field access", .{}); + return block.addStructFieldVal(union_byval, field_index, field.ty); } fn elemPtr( diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 8ec5075f84..361bedd577 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -2236,17 +2236,34 @@ pub const FuncGen = struct { const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data; const struct_ty = self.air.typeOf(struct_field.struct_operand); const struct_llvm_val = try self.resolveInst(struct_field.struct_operand); - const field_index = llvmFieldIndex(struct_ty, struct_field.field_index); - if (isByRef(struct_ty)) { - const field_ptr = self.builder.buildStructGEP(struct_llvm_val, field_index, ""); - const field_ty = struct_ty.structFieldType(struct_field.field_index); - if (isByRef(field_ty)) { - return field_ptr; - } else { - return self.builder.buildLoad(field_ptr, ""); - } + const field_index = struct_field.field_index; + const field_ty = struct_ty.structFieldType(field_index); + if (!field_ty.hasCodeGenBits()) { + return null; + } + + assert(isByRef(struct_ty)); + + const field_ptr = switch (struct_ty.zigTypeTag()) { + .Struct => blk: { + const llvm_field_index = llvmFieldIndex(struct_ty, field_index); + break :blk self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, ""); + }, + .Union => blk: { + const llvm_field_ty = try self.dg.llvmType(field_ty); + const target = self.dg.module.getTarget(); + const layout = struct_ty.unionGetLayout(target); + const payload_index = @boolToInt(layout.tag_align >= layout.payload_align); + const union_field_ptr = self.builder.buildStructGEP(struct_llvm_val, payload_index, ""); + break :blk self.builder.buildBitCast(union_field_ptr, llvm_field_ty.pointerType(0), ""); + }, + else => unreachable, + }; + + if (isByRef(field_ty)) { + return field_ptr; } else { - return self.builder.buildExtractValue(struct_llvm_val, field_index, ""); + return self.builder.buildLoad(field_ptr, ""); } }