authorgravatar for techatrix@mailbox.orgTechatrix <techatrix@mailbox.org> 2026-08-03 21:52:28+02:00
committergravatar for techatrix@mailbox.orgTechatrix <techatrix@mailbox.org> 2026-08-05 15:27:02+02:00
logfd13c819264007e8731fdb5ae9af211d18c70e9a
tree17ae59f36e0cc54435a81f185cf33f2a0eabcc7f
parent0bebd6108e586c5b6e216b4e69c1a06aa07d411d
signaturebadge-check Signed by SSH key SHA256:HYC3SjXQcAt6uwv9pu/6OoVQ2rUH8rb5zKiUHSe9uxk

c_abi: fix struct with OPV fields on wasm


3 files changed, 66 insertions(+), 14 deletions(-)

src/codegen/wasm/abi.zig+22-14
......@@ -71,27 +71,35 @@ pub fn classifyTypeForLlvm(ty: Type, zcu: *const Zcu) LlvmClass {
7171 },
7272 .@"struct" => {
7373 const struct_type = zcu.typeToStruct(ty).?;
74 if (struct_type.layout == .@"packed") {
75 return .{ .direct = ty };
76 }
77 if (struct_type.field_types.len > 1) {
78 // The struct type is non-scalar.
79 return .indirect;
74 switch (struct_type.layout) {
75 .auto => unreachable,
76 .@"packed" => return .{ .direct = ty },
77 .@"extern" => {},
8078 }
81 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[0]);
82 const explicit_align = struct_type.field_aligns.getOrNone(ip, 0);
83 if (explicit_align != .none) {
84 if (explicit_align.compareStrict(.gt, field_ty.abiAlignment(zcu)))
79 var opt_single_field_ty: ?Type = null;
80 for (struct_type.field_types.get(ip), 0..) |field_ty_index, field_index| {
81 const field_ty: Type = .fromInterned(field_ty_index);
82 if (!field_ty.hasRuntimeBits(zcu)) continue;
83
84 if (opt_single_field_ty != null) {
8585 return .indirect;
86 }
87
88 const field_align = struct_type.field_aligns.getOrNone(ip, field_index);
89 if (field_align != .none and field_align.compareStrict(.gt, field_ty.abiAlignment(zcu))) {
90 return .indirect;
91 }
92 opt_single_field_ty = field_ty;
8693 }
87 if (field_ty.zigTypeTag(zcu) == .array) {
88 switch (field_ty.arrayLenIncludingSentinel(zcu)) {
94 const single_field_ty = opt_single_field_ty.?;
95 if (single_field_ty.zigTypeTag(zcu) == .array) {
96 switch (single_field_ty.arrayLenIncludingSentinel(zcu)) {
8997 0 => unreachable,
90 1 => return classifyTypeForLlvm(field_ty.childType(zcu), zcu),
98 1 => return classifyTypeForLlvm(single_field_ty.childType(zcu), zcu),
9199 else => {},
92100 }
93101 }
94 return classifyTypeForLlvm(field_ty, zcu);
102 return classifyTypeForLlvm(single_field_ty, zcu);
95103 },
96104 .@"union" => {
97105 const union_obj = zcu.typeToUnion(ty).?;
test/c_abi/cfuncs.c+16
......@@ -15194,6 +15194,22 @@ void c_test_struct_f32_f32_f32_f32_f32(void) {
1519415194 zig_struct_f32_f32_f32_f32_f32((struct Struct_f32_f32_f32_f32_f32){ .a = 6, .b = 7, .c = 8, .d = 9, .e = 10 }, 11);
1519515195}
1519615196
15197struct Struct_f32 zig_ret_struct_void_f32(void);
15198void zig_struct_void_f32(struct Struct_f32, size_t);
15199
15200struct Struct_f32 c_ret_struct_void_f32(void) {
15201 return (struct Struct_f32){ .a = 4 };
15202}
15203void c_struct_void_f32(struct Struct_f32 s, size_t i) {
15204 assert_or_panic(s.a == 5);
15205 assert_or_panic(i == 6);
15206}
15207void c_test_struct_void_f32(void) {
15208 struct Struct_f32 s = zig_ret_struct_void_f32();
15209 assert_or_panic(s.a == 1);
15210 zig_struct_void_f32((struct Struct_f32){ .a = 2 }, 3);
15211}
15212
1519715213struct Struct_array_1_f32 {
1519815214 float a[1];
1519915215};
test/c_abi/main.zig+28
......@@ -16103,6 +16103,34 @@ test "struct f32, f32, f32, f32, f32" {
1610316103 c_test_struct_f32_f32_f32_f32_f32();
1610416104}
1610516105
16106const Struct_void_f32 = extern struct {
16107 _: void = {},
16108 a: f32,
16109};
16110
16111export fn zig_ret_struct_void_f32() Struct_void_f32 {
16112 return .{ .a = 1 };
16113}
16114export fn zig_struct_void_f32(s: Struct_void_f32, i: usize) void {
16115 expect(s.a == 2) catch @panic("test failure");
16116 expect(i == 3) catch @panic("test failure");
16117}
16118
16119extern fn c_ret_struct_void_f32() Struct_void_f32;
16120extern fn c_struct_void_f32(Struct_void_f32, usize) void;
16121extern fn c_test_struct_void_f32() void;
16122
16123test "struct void, f32" {
16124 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
16125 if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
16126 if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest;
16127
16128 const s = c_ret_struct_void_f32();
16129 try expect(s.a == 4);
16130 c_struct_void_f32(.{ .a = 5 }, 6);
16131 c_test_struct_void_f32();
16132}
16133
1610616134const Struct_array_1_f32 = extern struct {
1610716135 a: [1]f32,
1610816136};