mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
LLVM: fix returning extern union with C callconv
This commit is contained in:
parent
6a4df2778e
commit
3ba7098a17
@ -4491,17 +4491,29 @@ pub const FuncGen = struct {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const abi_ret_ty = try lowerFnRetTy(self.dg, fn_info);
|
||||
const ptr_abi_ty = abi_ret_ty.pointerType(0);
|
||||
const operand = try self.resolveInst(un_op);
|
||||
const target = self.dg.module.getTarget();
|
||||
const alignment = ret_ty.abiAlignment(target);
|
||||
|
||||
if (isByRef(ret_ty)) {
|
||||
// operand is a pointer however self.ret_ptr is null so that means
|
||||
// we need to return a value.
|
||||
const casted_ptr = self.builder.buildBitCast(operand, ptr_abi_ty, "");
|
||||
const load_inst = self.builder.buildLoad(casted_ptr, "");
|
||||
load_inst.setAlignment(alignment);
|
||||
_ = self.builder.buildRet(load_inst);
|
||||
return null;
|
||||
}
|
||||
|
||||
const llvm_ret_ty = operand.typeOf();
|
||||
if (abi_ret_ty == llvm_ret_ty) {
|
||||
_ = self.builder.buildRet(operand);
|
||||
return null;
|
||||
}
|
||||
|
||||
const target = self.dg.module.getTarget();
|
||||
const alignment = ret_ty.abiAlignment(target);
|
||||
const ptr_abi_ty = abi_ret_ty.pointerType(0);
|
||||
const rp = self.buildAlloca(llvm_ret_ty);
|
||||
rp.setAlignment(alignment);
|
||||
const store_inst = self.builder.buildStore(operand, rp);
|
||||
|
||||
@ -1226,3 +1226,33 @@ test "extern union most-aligned field is smaller" {
|
||||
var a: ?U = .{ .un = [_]u8{0} ** 110 };
|
||||
try expect(a != null);
|
||||
}
|
||||
|
||||
test "return an extern union from C calling convention" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
|
||||
const namespace = struct {
|
||||
const S = extern struct {
|
||||
x: c_int,
|
||||
};
|
||||
const U = extern union {
|
||||
l: c_long,
|
||||
d: f64,
|
||||
s: S,
|
||||
};
|
||||
|
||||
fn bar(arg_u: U) callconv(.C) U {
|
||||
var u = arg_u;
|
||||
return u;
|
||||
}
|
||||
};
|
||||
|
||||
var u: namespace.U = namespace.U{
|
||||
.l = @as(c_long, 42),
|
||||
};
|
||||
u = namespace.bar(namespace.U{
|
||||
.d = 4.0,
|
||||
});
|
||||
try expect(u.d == 4.0);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user