diff --git a/src/codegen/wasm/abi.zig b/src/codegen/wasm/abi.zig index 9f0b9b6dc9ebb7715d16839a6f42fd954d7787a2..5c88caddb98a35c6f192c647fb5d53eb032375a5 100644 --- a/src/codegen/wasm/abi.zig +++ b/src/codegen/wasm/abi.zig @@ -102,6 +102,13 @@ pub fn classifyTypeForLlvm(ty: Type, zcu: *const Zcu) LlvmClass { assert(layout.tag_size == 0); if (union_obj.field_types.len > 1) return .indirect; const first_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[0]); + if (first_field_ty.zigTypeTag(zcu) == .array) { + switch (first_field_ty.arrayLenIncludingSentinel(zcu)) { + 0 => unreachable, + 1 => return classifyTypeForLlvm(first_field_ty.childType(zcu), zcu), + else => {}, + } + } return classifyTypeForLlvm(first_field_ty, zcu); }, .error_union, diff --git a/test/c_abi/cfuncs.c b/test/c_abi/cfuncs.c index a259e23413a131b4e73b5f34329e1b2e6093f44d..110e5fd18dd4a5593c7004f439e85eed82c46a1d 100644 --- a/test/c_abi/cfuncs.c +++ b/test/c_abi/cfuncs.c @@ -15749,6 +15749,26 @@ void c_test_struct_array_5_f64(void) { zig_struct_array_5_f64((struct Struct_array_5_f64){ .a = { 6, 7, 8, 9, 10 } }, 11); } +union Union_f64 { + double a; +}; + +union Union_f64 zig_ret_union_f64(void); +void zig_union_f64(union Union_f64, size_t); + +union Union_f64 c_ret_union_f64(void) { + return (union Union_f64){ .a = 4 }; +} +void c_union_f64(union Union_f64 s, size_t i) { + assert_or_panic(s.a == 5); + assert_or_panic(i == 6); +} +void c_test_union_f64(void) { + union Union_f64 s = zig_ret_union_f64(); + assert_or_panic(s.a == 1); + zig_union_f64((union Union_f64){ .a = 2 }, 3); +} + struct Struct_u32_Union_u32_u32u32 { uint32_t a; union { diff --git a/test/c_abi/main.zig b/test/c_abi/main.zig index 4cc383805d755af213f3e84a2cb5447c0a5315f1..2286d838b86402f9e5e03c30e7db3732c2e3c3f4 100644 --- a/test/c_abi/main.zig +++ b/test/c_abi/main.zig @@ -16918,6 +16918,36 @@ test "struct [5]f64" { c_test_struct_array_5_f64(); } +const Union_f64 = extern union { + a: f64, +}; + +export fn zig_ret_union_f64() Union_f64 { + return .{ .a = 1 }; +} +export fn zig_union_f64(s: Union_f64, i: usize) void { + expect(s.a == 2) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_union_f64() Union_f64; +extern fn c_union_f64(Union_f64, usize) void; +extern fn c_test_union_f64() void; + +test "union f64" { + if (builtin.cpu.arch.isArm() and builtin.abi.float() == .soft) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRiscv32()) return error.SkipZigTest; + if (builtin.cpu.arch == .s390x) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; + + const s = c_ret_union_f64(); + try expect(s.a == 4); + c_union_f64(.{ .a = 5 }, 6); + c_test_union_f64(); +} + const Struct_u32_Union_u32_u32u32 = extern struct { a: u32, b: extern union {