diff --git a/src/codegen/loongarch/abi.zig b/src/codegen/loongarch/abi.zig index 09e42a7cb96731dbf0ee44b37ad74f0548a08c93..ba9b79d39d5be3d10e20176bc5574c9205df5ad7 100644 --- a/src/codegen/loongarch/abi.zig +++ b/src/codegen/loongarch/abi.zig @@ -95,7 +95,7 @@ const Classifier = struct { var class: Class = .ignored; const elem_ty = ty.childType(c.zcu); const elem_class = c.classifyType(elem_ty); - for (0..std.math.lossyCast(usize, ty.arrayLen(c.zcu))) |_| { + for (0..std.math.lossyCast(usize, ty.arrayLenIncludingSentinel(c.zcu))) |_| { class = class.combineMember(elem_class, elem_ty); if (class == .address) break; } diff --git a/src/codegen/s390x/abi.zig b/src/codegen/s390x/abi.zig index 7b35245fdad37be5e062bbcc873c116a78a99152..2c3051ffc3139a314cedadf9ec98027d846a7dd3 100644 --- a/src/codegen/s390x/abi.zig +++ b/src/codegen/s390x/abi.zig @@ -45,14 +45,7 @@ pub fn classifyType(ty: Type, context: Context, zcu: *Zcu) Class { 128 => return .pointer, }, .pointer, .optional => return .simple, - .array => switch (ty.arrayLen(zcu)) { - 0 => return .none, - 1 => switch (context) { - .ret => {}, - .arg => return classifyType(ty.childType(zcu), context, zcu), - }, - else => {}, - }, + .array => {}, .@"struct", .@"union" => |tag| switch (ty.containerLayout(zcu)) { .auto => unreachable, .@"extern" => switch (context) { diff --git a/src/codegen/wasm/abi.zig b/src/codegen/wasm/abi.zig index 0c6afdcc500202b4b4dd4b794d28b9fdb813af70..1952c65227e8d57b0c164a62286814265bae0e3c 100644 --- a/src/codegen/wasm/abi.zig +++ b/src/codegen/wasm/abi.zig @@ -71,20 +71,35 @@ pub fn classifyTypeForLlvm(ty: Type, zcu: *const Zcu) LlvmClass { }, .@"struct" => { const struct_type = zcu.typeToStruct(ty).?; - if (struct_type.layout == .@"packed") { - return .{ .direct = ty }; + switch (struct_type.layout) { + .auto => unreachable, + .@"packed" => return .{ .direct = ty }, + .@"extern" => {}, } - if (struct_type.field_types.len > 1) { - // The struct type is non-scalar. - return .indirect; - } - const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[0]); - const explicit_align = struct_type.field_aligns.getOrNone(ip, 0); - if (explicit_align != .none) { - if (explicit_align.compareStrict(.gt, field_ty.abiAlignment(zcu))) + var opt_single_field_ty: ?Type = null; + for (struct_type.field_types.get(ip), 0..) |field_ty_index, field_index| { + const field_ty: Type = .fromInterned(field_ty_index); + if (!field_ty.hasRuntimeBits(zcu)) continue; + + if (opt_single_field_ty != null) { + return .indirect; + } + + const field_align = struct_type.field_aligns.getOrNone(ip, field_index); + if (field_align != .none and field_align.compareStrict(.gt, field_ty.abiAlignment(zcu))) { return .indirect; + } + opt_single_field_ty = field_ty; + } + const single_field_ty = opt_single_field_ty.?; + if (single_field_ty.zigTypeTag(zcu) == .array) { + switch (single_field_ty.arrayLenIncludingSentinel(zcu)) { + 0 => unreachable, + 1 => return classifyTypeForLlvm(single_field_ty.childType(zcu), zcu), + else => {}, + } } - return classifyTypeForLlvm(field_ty, zcu); + return classifyTypeForLlvm(single_field_ty, zcu); }, .@"union" => { const union_obj = zcu.typeToUnion(ty).?; @@ -95,6 +110,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/src/codegen/x86_64/abi.zig b/src/codegen/x86_64/abi.zig index 3ebad4dee2a9235f641e12be27684d247bfd2de1..471c09974d6bd29a29fb0fd37bd1b7e7612088b7 100644 --- a/src/codegen/x86_64/abi.zig +++ b/src/codegen/x86_64/abi.zig @@ -443,7 +443,7 @@ fn classifySystemVArray( const field_classes = std.mem.sliceTo(&classifySystemV(array_ty.childType(zcu), zcu, target, .other), .none); var byte_offset = starting_byte_offset; const elem_size = array_ty.childType(zcu).abiSize(zcu); - for (0..@intCast(array_ty.arrayLen(zcu))) |_| { + for (0..@intCast(array_ty.arrayLenIncludingSentinel(zcu))) |_| { for (result[@intCast(byte_offset / 8)..][0..field_classes.len], field_classes) |*result_class, field_class| result_class.* = result_class.combineSystemV(field_class); byte_offset += elem_size; diff --git a/test/c_abi/cfuncs.c b/test/c_abi/cfuncs.c index b74ea9ffef180944eb00c919dd5a6513fa6d32ad..327bc04ceb34148541b994bb894f04bea85bf210 100644 --- a/test/c_abi/cfuncs.c +++ b/test/c_abi/cfuncs.c @@ -15194,6 +15194,22 @@ void c_test_struct_f32_f32_f32_f32_f32(void) { 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); } +struct Struct_f32 zig_ret_struct_void_f32(void); +void zig_struct_void_f32(struct Struct_f32, size_t); + +struct Struct_f32 c_ret_struct_void_f32(void) { + return (struct Struct_f32){ .a = 4 }; +} +void c_struct_void_f32(struct Struct_f32 s, size_t i) { + assert_or_panic(s.a == 5); + assert_or_panic(i == 6); +} +void c_test_struct_void_f32(void) { + struct Struct_f32 s = zig_ret_struct_void_f32(); + assert_or_panic(s.a == 1); + zig_struct_void_f32((struct Struct_f32){ .a = 2 }, 3); +} + struct Struct_array_1_f32 { float a[1]; }; @@ -15314,6 +15330,106 @@ void c_test_struct_array_5_f32(void) { zig_struct_array_5_f32((struct Struct_array_5_f32){ .a = { 6, 7, 8, 9, 10 } }, 11); } +struct Struct_array_1_f32 zig_ret_struct_array_0_sentinel_f32(void); +void zig_struct_array_0_sentinel_f32(struct Struct_array_1_f32, size_t); + +struct Struct_array_1_f32 c_ret_struct_array_0_sentinel_f32(void) { + return (struct Struct_array_1_f32){ .a = { 0x1e1 } }; +} +void c_struct_array_0_sentinel_f32(struct Struct_array_1_f32 s, size_t i) { + assert_or_panic(s.a[0] == 0x1e1); + assert_or_panic(i == 2); +} +void c_test_struct_array_0_sentinel_f32(void) { + struct Struct_array_1_f32 s = zig_ret_struct_array_0_sentinel_f32(); + assert_or_panic(s.a[0] == 0x1e1); + zig_struct_array_0_sentinel_f32((struct Struct_array_1_f32){ .a = { 0x1e1 } }, 1); +} + +struct Struct_array_2_f32 zig_ret_struct_array_1_sentinel_f32(void); +void zig_struct_array_1_sentinel_f32(struct Struct_array_2_f32, size_t); + +struct Struct_array_2_f32 c_ret_struct_array_1_sentinel_f32(void) { + return (struct Struct_array_2_f32){ .a = { 4, 0x1e1 } }; +} +void c_struct_array_1_sentinel_f32(struct Struct_array_2_f32 s, size_t i) { + assert_or_panic(s.a[0] == 5); + assert_or_panic(s.a[1] == 0x1e1); + assert_or_panic(i == 6); +} +void c_test_struct_array_1_sentinel_f32(void) { + struct Struct_array_2_f32 s = zig_ret_struct_array_1_sentinel_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 0x1e1); + zig_struct_array_1_sentinel_f32((struct Struct_array_2_f32){ .a = { 2, 0x1e1 } }, 3); +} + +struct Struct_array_3_f32 zig_ret_struct_array_2_sentinel_f32(void); +void zig_struct_array_2_sentinel_f32(struct Struct_array_3_f32, size_t); + +struct Struct_array_3_f32 c_ret_struct_array_2_sentinel_f32(void) { + return (struct Struct_array_3_f32){ .a = { 6, 7, 0x1e1 } }; +} +void c_struct_array_2_sentinel_f32(struct Struct_array_3_f32 s, size_t i) { + assert_or_panic(s.a[0] == 8); + assert_or_panic(s.a[1] == 9); + assert_or_panic(s.a[2] == 0x1e1); + assert_or_panic(i == 10); +} +void c_test_struct_array_2_sentinel_f32(void) { + struct Struct_array_3_f32 s = zig_ret_struct_array_2_sentinel_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 0x1e1); + zig_struct_array_2_sentinel_f32((struct Struct_array_3_f32){ .a = { 3, 4, 0x1e1 } }, 5); +} + +struct Struct_array_4_f32 zig_ret_struct_array_3_sentinel_f32(void); +void zig_struct_array_3_sentinel_f32(struct Struct_array_4_f32, size_t); + +struct Struct_array_4_f32 c_ret_struct_array_3_sentinel_f32(void) { + return (struct Struct_array_4_f32){ .a = { 8, 9, 10, 0x1e1 } }; +} +void c_struct_array_3_sentinel_f32(struct Struct_array_4_f32 s, size_t i) { + assert_or_panic(s.a[0] == 11); + assert_or_panic(s.a[1] == 12); + assert_or_panic(s.a[2] == 13); + assert_or_panic(s.a[3] == 0x1e1); + assert_or_panic(i == 14); +} +void c_test_struct_array_3_sentinel_f32(void) { + struct Struct_array_4_f32 s = zig_ret_struct_array_3_sentinel_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + assert_or_panic(s.a[3] == 0x1e1); + zig_struct_array_3_sentinel_f32((struct Struct_array_4_f32){ .a = { 4, 5, 6, 0x1e1 } }, 7); +} + +struct Struct_array_5_f32 zig_ret_struct_array_4_sentinel_f32(void); +void zig_struct_array_4_sentinel_f32(struct Struct_array_5_f32, size_t); + +struct Struct_array_5_f32 c_ret_struct_array_4_sentinel_f32(void) { + return (struct Struct_array_5_f32){ .a = { 10, 11, 12, 13, 0x1e1 } }; +} +void c_struct_array_4_sentinel_f32(struct Struct_array_5_f32 s, size_t i) { + assert_or_panic(s.a[0] == 14); + assert_or_panic(s.a[1] == 15); + assert_or_panic(s.a[2] == 16); + assert_or_panic(s.a[3] == 17); + assert_or_panic(s.a[4] == 0x1e1); + assert_or_panic(i == 18); +} +void c_test_struct_array_4_sentinel_f32(void) { + struct Struct_array_5_f32 s = zig_ret_struct_array_4_sentinel_f32(); + assert_or_panic(s.a[0] == 1); + assert_or_panic(s.a[1] == 2); + assert_or_panic(s.a[2] == 3); + assert_or_panic(s.a[3] == 4); + assert_or_panic(s.a[4] == 0x1e1); + zig_struct_array_4_sentinel_f32((struct Struct_array_5_f32){ .a = { 5, 6, 7, 8, 0x1e1 } }, 9); +} + struct Struct_f32a8 { alignas(8) float a; }; @@ -15649,6 +15765,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 1fd267402d74dbb38e524c8e232240ff97ef5217..a481a015117276e8abf7c4393f6d85cf60dd20fb 100644 --- a/test/c_abi/main.zig +++ b/test/c_abi/main.zig @@ -16103,24 +16103,44 @@ test "struct f32, f32, f32, f32, f32" { c_test_struct_f32_f32_f32_f32_f32(); } +const Struct_void_f32 = extern struct { + _: void = {}, + a: f32, +}; + +export fn zig_ret_struct_void_f32() Struct_void_f32 { + return .{ .a = 1 }; +} +export fn zig_struct_void_f32(s: Struct_void_f32, i: usize) void { + expect(s.a == 2) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_struct_void_f32() Struct_void_f32; +extern fn c_struct_void_f32(Struct_void_f32, usize) void; +extern fn c_test_struct_void_f32() void; + +test "struct void, f32" { + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch == .x86 and builtin.os.tag == .windows) return error.SkipZigTest; + + const s = c_ret_struct_void_f32(); + try expect(s.a == 4); + c_struct_void_f32(.{ .a = 5 }, 6); + c_test_struct_void_f32(); +} + const Struct_array_1_f32 = extern struct { a: [1]f32, }; -comptime { - skip: { - if (builtin.cpu.arch.isWasm()) break :skip; - - _ = struct { - export fn zig_ret_struct_array_1_f32() Struct_array_1_f32 { - return .{ .a = .{1} }; - } - export fn zig_struct_array_1_f32(s: Struct_array_1_f32, i: usize) void { - expect(s.a[0] == 2) catch @panic("test failure"); - expect(i == 3) catch @panic("test failure"); - } - }; - } +export fn zig_ret_struct_array_1_f32() Struct_array_1_f32 { + return .{ .a = .{1} }; +} +export fn zig_struct_array_1_f32(s: Struct_array_1_f32, i: usize) void { + expect(s.a[0] == 2) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); } extern fn c_ret_struct_array_1_f32() Struct_array_1_f32; @@ -16133,8 +16153,6 @@ test "struct [1]f32" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; - if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; const s = c_ret_struct_array_1_f32(); try expect(s.a[0] == 4); @@ -16278,6 +16296,191 @@ test "struct [5]f32" { c_test_struct_array_5_f32(); } +const Struct_array_0_sentinel_f32 = extern struct { + a: [0:0x1e1]f32, +}; + +export fn zig_ret_struct_array_0_sentinel_f32() Struct_array_0_sentinel_f32 { + return .{ .a = .{} }; +} +export fn zig_struct_array_0_sentinel_f32(s: Struct_array_0_sentinel_f32, i: usize) void { + var sentinel_index: usize = 0; + _ = &sentinel_index; + expect(s.a[sentinel_index] == 0x1e1) catch @panic("test failure"); + expect(i == 1) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_0_sentinel_f32() Struct_array_0_sentinel_f32; +extern fn c_struct_array_0_sentinel_f32(Struct_array_0_sentinel_f32, usize) void; +extern fn c_test_struct_array_0_sentinel_f32() void; + +test "struct [0:sentinel]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; + + var sentinel_index: usize = 0; + _ = &sentinel_index; + const s = c_ret_struct_array_0_sentinel_f32(); + try expect(s.a[sentinel_index] == 0x1e1); + c_struct_array_0_sentinel_f32(.{ .a = .{} }, 2); + c_test_struct_array_0_sentinel_f32(); +} + +const Struct_array_1_sentinel_f32 = extern struct { + a: [1:0x1e1]f32, +}; + +export fn zig_ret_struct_array_1_sentinel_f32() Struct_array_1_sentinel_f32 { + return .{ .a = .{1} }; +} +export fn zig_struct_array_1_sentinel_f32(s: Struct_array_1_sentinel_f32, i: usize) void { + var sentinel_index: usize = 1; + _ = &sentinel_index; + expect(s.a[0] == 2) catch @panic("test failure"); + expect(s.a[sentinel_index] == 0x1e1) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_1_sentinel_f32() Struct_array_1_sentinel_f32; +extern fn c_struct_array_1_sentinel_f32(Struct_array_1_sentinel_f32, usize) void; +extern fn c_test_struct_array_1_sentinel_f32() void; + +test "struct [1:sentinel]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .loongarch64 and builtin.abi.float() == .hard) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; + + var sentinel_index: usize = 1; + _ = &sentinel_index; + const s = c_ret_struct_array_1_sentinel_f32(); + try expect(s.a[0] == 4); + try expect(s.a[sentinel_index] == 0x1e1); + c_struct_array_1_sentinel_f32(.{ .a = .{5} }, 6); + c_test_struct_array_1_sentinel_f32(); +} + +const Struct_array_2_sentinel_f32 = extern struct { + a: [2:0x1e1]f32, +}; + +export fn zig_ret_struct_array_2_sentinel_f32() Struct_array_2_sentinel_f32 { + return .{ .a = .{ 1, 2 } }; +} +export fn zig_struct_array_2_sentinel_f32(s: Struct_array_2_sentinel_f32, i: usize) void { + var sentinel_index: usize = 2; + _ = &sentinel_index; + expect(s.a[0] == 3) catch @panic("test failure"); + expect(s.a[1] == 4) catch @panic("test failure"); + expect(s.a[sentinel_index] == 0x1e1) catch @panic("test failure"); + expect(i == 5) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_2_sentinel_f32() Struct_array_2_sentinel_f32; +extern fn c_struct_array_2_sentinel_f32(Struct_array_2_sentinel_f32, usize) void; +extern fn c_test_struct_array_2_sentinel_f32() void; + +test "struct [2:sentinel]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + var sentinel_index: usize = 2; + _ = &sentinel_index; + const s = c_ret_struct_array_2_sentinel_f32(); + try expect(s.a[0] == 6); + try expect(s.a[1] == 7); + try expect(s.a[sentinel_index] == 0x1e1); + c_struct_array_2_sentinel_f32(.{ .a = .{ 8, 9 } }, 10); + c_test_struct_array_2_sentinel_f32(); +} + +const Struct_array_3_sentinel_f32 = extern struct { + a: [3:0x1e1]f32, +}; + +export fn zig_ret_struct_array_3_sentinel_f32() Struct_array_3_sentinel_f32 { + return .{ .a = .{ 1, 2, 3 } }; +} +export fn zig_struct_array_3_sentinel_f32(s: Struct_array_3_sentinel_f32, i: usize) void { + var sentinel_index: usize = 3; + _ = &sentinel_index; + expect(s.a[0] == 4) catch @panic("test failure"); + expect(s.a[1] == 5) catch @panic("test failure"); + expect(s.a[2] == 6) catch @panic("test failure"); + expect(s.a[sentinel_index] == 0x1e1) catch @panic("test failure"); + expect(i == 7) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_3_sentinel_f32() Struct_array_3_sentinel_f32; +extern fn c_struct_array_3_sentinel_f32(Struct_array_3_sentinel_f32, usize) void; +extern fn c_test_struct_array_3_sentinel_f32() void; + +test "struct [3:sentinel]f32" { + if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest; + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + var sentinel_index: usize = 3; + _ = &sentinel_index; + const s = c_ret_struct_array_3_sentinel_f32(); + try expect(s.a[0] == 8); + try expect(s.a[1] == 9); + try expect(s.a[2] == 10); + try expect(s.a[sentinel_index] == 0x1e1); + c_struct_array_3_sentinel_f32(.{ .a = .{ 11, 12, 13 } }, 14); + c_test_struct_array_3_sentinel_f32(); +} + +const Struct_array_4_sentinel_f32 = extern struct { + a: [4:0x1e1]f32, +}; + +export fn zig_ret_struct_array_4_sentinel_f32() Struct_array_4_sentinel_f32 { + return .{ .a = .{ 1, 2, 3, 4 } }; +} +export fn zig_struct_array_4_sentinel_f32(s: Struct_array_4_sentinel_f32, i: usize) void { + var sentinel_index: usize = 4; + _ = &sentinel_index; + expect(s.a[0] == 5) catch @panic("test failure"); + expect(s.a[1] == 6) catch @panic("test failure"); + expect(s.a[2] == 7) catch @panic("test failure"); + expect(s.a[3] == 8) catch @panic("test failure"); + expect(s.a[sentinel_index] == 0x1e1) catch @panic("test failure"); + expect(i == 9) catch @panic("test failure"); +} + +extern fn c_ret_struct_array_4_sentinel_f32() Struct_array_4_sentinel_f32; +extern fn c_struct_array_4_sentinel_f32(Struct_array_4_sentinel_f32, usize) void; +extern fn c_test_struct_array_4_sentinel_f32() void; + +test "struct [4:sentinel]f32" { + if (builtin.cpu.arch.isArm()) return error.SkipZigTest; + if (builtin.cpu.arch == .hexagon) return error.SkipZigTest; + if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; + if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; + + var sentinel_index: usize = 4; + _ = &sentinel_index; + const s = c_ret_struct_array_4_sentinel_f32(); + try expect(s.a[0] == 10); + try expect(s.a[1] == 11); + try expect(s.a[2] == 12); + try expect(s.a[3] == 13); + try expect(s.a[sentinel_index] == 0x1e1); + c_struct_array_4_sentinel_f32(.{ .a = .{ 14, 15, 16, 17 } }, 18); + c_test_struct_array_4_sentinel_f32(); +} + const Struct_f32a8 = extern struct { a: f32 align(8), }; @@ -16579,20 +16782,12 @@ const Struct_array_1_f64 = extern struct { a: [1]f64, }; -comptime { - skip: { - if (builtin.cpu.arch.isWasm()) break :skip; - - _ = struct { - export fn zig_ret_struct_array_1_f64() Struct_array_1_f64 { - return .{ .a = .{1} }; - } - export fn zig_struct_array_1_f64(s: Struct_array_1_f64, i: usize) void { - expect(s.a[0] == 2) catch @panic("test failure"); - expect(i == 3) catch @panic("test failure"); - } - }; - } +export fn zig_ret_struct_array_1_f64() Struct_array_1_f64 { + return .{ .a = .{1} }; +} +export fn zig_struct_array_1_f64(s: Struct_array_1_f64, i: usize) void { + expect(s.a[0] == 2) catch @panic("test failure"); + expect(i == 3) catch @panic("test failure"); } extern fn c_ret_struct_array_1_f64() Struct_array_1_f64; @@ -16605,8 +16800,6 @@ test "struct [1]f64" { if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest; if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest; if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest; - if (builtin.cpu.arch == .s390x) return error.SkipZigTest; - if (builtin.cpu.arch.isWasm()) return error.SkipZigTest; const s = c_ret_struct_array_1_f64(); try expect(s.a[0] == 4); @@ -16750,6 +16943,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 {