authorgravatar for techatrix@mailbox.orgTechatrix <techatrix@mailbox.org> 2026-08-03 18:17:09+02:00
committergravatar for techatrix@mailbox.orgTechatrix <techatrix@mailbox.org> 2026-08-05 15:27:02+02:00
logc80045cbe77c9cd044ab07b189003726169e0ace
tree18955fe7f8c0264026ff199b8d134b0aec56ae17
parent01e5c1885684609d84c79135e716b33a1c3fd9a1
signaturebadge-check Signed by SSH key SHA256:HYC3SjXQcAt6uwv9pu/6OoVQ2rUH8rb5zKiUHSe9uxk

c_abi: include array sentinel in length calculation


5 files changed, 290 insertions(+), 3 deletions(-)

src/codegen/loongarch/abi.zig+1-1
......@@ -95,7 +95,7 @@ const Classifier = struct {
9595 var class: Class = .ignored;
9696 const elem_ty = ty.childType(c.zcu);
9797 const elem_class = c.classifyType(elem_ty);
98 for (0..std.math.lossyCast(usize, ty.arrayLen(c.zcu))) |_| {
98 for (0..std.math.lossyCast(usize, ty.arrayLenIncludingSentinel(c.zcu))) |_| {
9999 class = class.combineMember(elem_class, elem_ty);
100100 if (class == .address) break;
101101 }
src/codegen/s390x/abi.zig+1-1
......@@ -45,7 +45,7 @@ pub fn classifyType(ty: Type, context: Context, zcu: *Zcu) Class {
4545 128 => return .pointer,
4646 },
4747 .pointer, .optional => return .simple,
48 .array => switch (ty.arrayLen(zcu)) {
48 .array => switch (ty.arrayLenIncludingSentinel(zcu)) {
4949 0 => return .none,
5050 1 => switch (context) {
5151 .ret => {},
src/codegen/x86_64/abi.zig+1-1
......@@ -443,7 +443,7 @@ fn classifySystemVArray(
443443 const field_classes = std.mem.sliceTo(&classifySystemV(array_ty.childType(zcu), zcu, target, .other), .none);
444444 var byte_offset = starting_byte_offset;
445445 const elem_size = array_ty.childType(zcu).abiSize(zcu);
446 for (0..@intCast(array_ty.arrayLen(zcu))) |_| {
446 for (0..@intCast(array_ty.arrayLenIncludingSentinel(zcu))) |_| {
447447 for (result[@intCast(byte_offset / 8)..][0..field_classes.len], field_classes) |*result_class, field_class|
448448 result_class.* = result_class.combineSystemV(field_class);
449449 byte_offset += elem_size;
test/c_abi/cfuncs.c+100
......@@ -15314,6 +15314,106 @@ void c_test_struct_array_5_f32(void) {
1531415314 zig_struct_array_5_f32((struct Struct_array_5_f32){ .a = { 6, 7, 8, 9, 10 } }, 11);
1531515315}
1531615316
15317struct Struct_array_1_f32 zig_ret_struct_array_0_sentinel_f32(void);
15318void zig_struct_array_0_sentinel_f32(struct Struct_array_1_f32, size_t);
15319
15320struct Struct_array_1_f32 c_ret_struct_array_0_sentinel_f32(void) {
15321 return (struct Struct_array_1_f32){ .a = { 0x1e1 } };
15322}
15323void c_struct_array_0_sentinel_f32(struct Struct_array_1_f32 s, size_t i) {
15324 assert_or_panic(s.a[0] == 0x1e1);
15325 assert_or_panic(i == 2);
15326}
15327void c_test_struct_array_0_sentinel_f32(void) {
15328 struct Struct_array_1_f32 s = zig_ret_struct_array_0_sentinel_f32();
15329 assert_or_panic(s.a[0] == 0x1e1);
15330 zig_struct_array_0_sentinel_f32((struct Struct_array_1_f32){ .a = { 0x1e1 } }, 1);
15331}
15332
15333struct Struct_array_2_f32 zig_ret_struct_array_1_sentinel_f32(void);
15334void zig_struct_array_1_sentinel_f32(struct Struct_array_2_f32, size_t);
15335
15336struct Struct_array_2_f32 c_ret_struct_array_1_sentinel_f32(void) {
15337 return (struct Struct_array_2_f32){ .a = { 4, 0x1e1 } };
15338}
15339void c_struct_array_1_sentinel_f32(struct Struct_array_2_f32 s, size_t i) {
15340 assert_or_panic(s.a[0] == 5);
15341 assert_or_panic(s.a[1] == 0x1e1);
15342 assert_or_panic(i == 6);
15343}
15344void c_test_struct_array_1_sentinel_f32(void) {
15345 struct Struct_array_2_f32 s = zig_ret_struct_array_1_sentinel_f32();
15346 assert_or_panic(s.a[0] == 1);
15347 assert_or_panic(s.a[1] == 0x1e1);
15348 zig_struct_array_1_sentinel_f32((struct Struct_array_2_f32){ .a = { 2, 0x1e1 } }, 3);
15349}
15350
15351struct Struct_array_3_f32 zig_ret_struct_array_2_sentinel_f32(void);
15352void zig_struct_array_2_sentinel_f32(struct Struct_array_3_f32, size_t);
15353
15354struct Struct_array_3_f32 c_ret_struct_array_2_sentinel_f32(void) {
15355 return (struct Struct_array_3_f32){ .a = { 6, 7, 0x1e1 } };
15356}
15357void c_struct_array_2_sentinel_f32(struct Struct_array_3_f32 s, size_t i) {
15358 assert_or_panic(s.a[0] == 8);
15359 assert_or_panic(s.a[1] == 9);
15360 assert_or_panic(s.a[2] == 0x1e1);
15361 assert_or_panic(i == 10);
15362}
15363void c_test_struct_array_2_sentinel_f32(void) {
15364 struct Struct_array_3_f32 s = zig_ret_struct_array_2_sentinel_f32();
15365 assert_or_panic(s.a[0] == 1);
15366 assert_or_panic(s.a[1] == 2);
15367 assert_or_panic(s.a[2] == 0x1e1);
15368 zig_struct_array_2_sentinel_f32((struct Struct_array_3_f32){ .a = { 3, 4, 0x1e1 } }, 5);
15369}
15370
15371struct Struct_array_4_f32 zig_ret_struct_array_3_sentinel_f32(void);
15372void zig_struct_array_3_sentinel_f32(struct Struct_array_4_f32, size_t);
15373
15374struct Struct_array_4_f32 c_ret_struct_array_3_sentinel_f32(void) {
15375 return (struct Struct_array_4_f32){ .a = { 8, 9, 10, 0x1e1 } };
15376}
15377void c_struct_array_3_sentinel_f32(struct Struct_array_4_f32 s, size_t i) {
15378 assert_or_panic(s.a[0] == 11);
15379 assert_or_panic(s.a[1] == 12);
15380 assert_or_panic(s.a[2] == 13);
15381 assert_or_panic(s.a[3] == 0x1e1);
15382 assert_or_panic(i == 14);
15383}
15384void c_test_struct_array_3_sentinel_f32(void) {
15385 struct Struct_array_4_f32 s = zig_ret_struct_array_3_sentinel_f32();
15386 assert_or_panic(s.a[0] == 1);
15387 assert_or_panic(s.a[1] == 2);
15388 assert_or_panic(s.a[2] == 3);
15389 assert_or_panic(s.a[3] == 0x1e1);
15390 zig_struct_array_3_sentinel_f32((struct Struct_array_4_f32){ .a = { 4, 5, 6, 0x1e1 } }, 7);
15391}
15392
15393struct Struct_array_5_f32 zig_ret_struct_array_4_sentinel_f32(void);
15394void zig_struct_array_4_sentinel_f32(struct Struct_array_5_f32, size_t);
15395
15396struct Struct_array_5_f32 c_ret_struct_array_4_sentinel_f32(void) {
15397 return (struct Struct_array_5_f32){ .a = { 10, 11, 12, 13, 0x1e1 } };
15398}
15399void c_struct_array_4_sentinel_f32(struct Struct_array_5_f32 s, size_t i) {
15400 assert_or_panic(s.a[0] == 14);
15401 assert_or_panic(s.a[1] == 15);
15402 assert_or_panic(s.a[2] == 16);
15403 assert_or_panic(s.a[3] == 17);
15404 assert_or_panic(s.a[4] == 0x1e1);
15405 assert_or_panic(i == 18);
15406}
15407void c_test_struct_array_4_sentinel_f32(void) {
15408 struct Struct_array_5_f32 s = zig_ret_struct_array_4_sentinel_f32();
15409 assert_or_panic(s.a[0] == 1);
15410 assert_or_panic(s.a[1] == 2);
15411 assert_or_panic(s.a[2] == 3);
15412 assert_or_panic(s.a[3] == 4);
15413 assert_or_panic(s.a[4] == 0x1e1);
15414 zig_struct_array_4_sentinel_f32((struct Struct_array_5_f32){ .a = { 5, 6, 7, 8, 0x1e1 } }, 9);
15415}
15416
1531715417struct Struct_f32a8 {
1531815418 alignas(8) float a;
1531915419};
test/c_abi/main.zig+187
......@@ -16278,6 +16278,193 @@ test "struct [5]f32" {
1627816278 c_test_struct_array_5_f32();
1627916279}
1628016280
16281const Struct_array_0_sentinel_f32 = extern struct {
16282 a: [0:0x1e1]f32,
16283};
16284
16285export fn zig_ret_struct_array_0_sentinel_f32() Struct_array_0_sentinel_f32 {
16286 return .{ .a = .{} };
16287}
16288export fn zig_struct_array_0_sentinel_f32(s: Struct_array_0_sentinel_f32, i: usize) void {
16289 var sentinel_index: usize = 0;
16290 _ = &sentinel_index;
16291 expect(s.a[sentinel_index] == 0x1e1) catch @panic("test failure");
16292 expect(i == 1) catch @panic("test failure");
16293}
16294
16295extern fn c_ret_struct_array_0_sentinel_f32() Struct_array_0_sentinel_f32;
16296extern fn c_struct_array_0_sentinel_f32(Struct_array_0_sentinel_f32, usize) void;
16297extern fn c_test_struct_array_0_sentinel_f32() void;
16298
16299test "struct [0:sentinel]f32" {
16300 if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest;
16301 if (builtin.cpu.arch.isArm()) return error.SkipZigTest;
16302 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
16303 if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
16304 if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
16305 if (builtin.cpu.arch == .s390x) return error.SkipZigTest;
16306 if (builtin.cpu.arch.isWasm()) return error.SkipZigTest;
16307
16308 var sentinel_index: usize = 0;
16309 _ = &sentinel_index;
16310 const s = c_ret_struct_array_0_sentinel_f32();
16311 try expect(s.a[sentinel_index] == 0x1e1);
16312 c_struct_array_0_sentinel_f32(.{ .a = .{} }, 2);
16313 c_test_struct_array_0_sentinel_f32();
16314}
16315
16316const Struct_array_1_sentinel_f32 = extern struct {
16317 a: [1:0x1e1]f32,
16318};
16319
16320export fn zig_ret_struct_array_1_sentinel_f32() Struct_array_1_sentinel_f32 {
16321 return .{ .a = .{1} };
16322}
16323export fn zig_struct_array_1_sentinel_f32(s: Struct_array_1_sentinel_f32, i: usize) void {
16324 var sentinel_index: usize = 1;
16325 _ = &sentinel_index;
16326 expect(s.a[0] == 2) catch @panic("test failure");
16327 expect(s.a[sentinel_index] == 0x1e1) catch @panic("test failure");
16328 expect(i == 3) catch @panic("test failure");
16329}
16330
16331extern fn c_ret_struct_array_1_sentinel_f32() Struct_array_1_sentinel_f32;
16332extern fn c_struct_array_1_sentinel_f32(Struct_array_1_sentinel_f32, usize) void;
16333extern fn c_test_struct_array_1_sentinel_f32() void;
16334
16335test "struct [1:sentinel]f32" {
16336 if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest;
16337 if (builtin.cpu.arch.isArm()) return error.SkipZigTest;
16338 if (builtin.cpu.arch == .loongarch64 and builtin.abi.float() == .hard) return error.SkipZigTest;
16339 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
16340 if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
16341 if (builtin.cpu.arch.isRISCV()) return error.SkipZigTest;
16342
16343 var sentinel_index: usize = 1;
16344 _ = &sentinel_index;
16345 const s = c_ret_struct_array_1_sentinel_f32();
16346 try expect(s.a[0] == 4);
16347 try expect(s.a[sentinel_index] == 0x1e1);
16348 c_struct_array_1_sentinel_f32(.{ .a = .{5} }, 6);
16349 c_test_struct_array_1_sentinel_f32();
16350}
16351
16352const Struct_array_2_sentinel_f32 = extern struct {
16353 a: [2:0x1e1]f32,
16354};
16355
16356export fn zig_ret_struct_array_2_sentinel_f32() Struct_array_2_sentinel_f32 {
16357 return .{ .a = .{ 1, 2 } };
16358}
16359export fn zig_struct_array_2_sentinel_f32(s: Struct_array_2_sentinel_f32, i: usize) void {
16360 var sentinel_index: usize = 2;
16361 _ = &sentinel_index;
16362 expect(s.a[0] == 3) catch @panic("test failure");
16363 expect(s.a[1] == 4) catch @panic("test failure");
16364 expect(s.a[sentinel_index] == 0x1e1) catch @panic("test failure");
16365 expect(i == 5) catch @panic("test failure");
16366}
16367
16368extern fn c_ret_struct_array_2_sentinel_f32() Struct_array_2_sentinel_f32;
16369extern fn c_struct_array_2_sentinel_f32(Struct_array_2_sentinel_f32, usize) void;
16370extern fn c_test_struct_array_2_sentinel_f32() void;
16371
16372test "struct [2:sentinel]f32" {
16373 if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest;
16374 if (builtin.cpu.arch.isArm()) return error.SkipZigTest;
16375 if (builtin.cpu.arch == .hexagon) return error.SkipZigTest;
16376 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
16377 if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
16378
16379 var sentinel_index: usize = 2;
16380 _ = &sentinel_index;
16381 const s = c_ret_struct_array_2_sentinel_f32();
16382 try expect(s.a[0] == 6);
16383 try expect(s.a[1] == 7);
16384 try expect(s.a[sentinel_index] == 0x1e1);
16385 c_struct_array_2_sentinel_f32(.{ .a = .{ 8, 9 } }, 10);
16386 c_test_struct_array_2_sentinel_f32();
16387}
16388
16389const Struct_array_3_sentinel_f32 = extern struct {
16390 a: [3:0x1e1]f32,
16391};
16392
16393export fn zig_ret_struct_array_3_sentinel_f32() Struct_array_3_sentinel_f32 {
16394 return .{ .a = .{ 1, 2, 3 } };
16395}
16396export fn zig_struct_array_3_sentinel_f32(s: Struct_array_3_sentinel_f32, i: usize) void {
16397 var sentinel_index: usize = 3;
16398 _ = &sentinel_index;
16399 expect(s.a[0] == 4) catch @panic("test failure");
16400 expect(s.a[1] == 5) catch @panic("test failure");
16401 expect(s.a[2] == 6) catch @panic("test failure");
16402 expect(s.a[sentinel_index] == 0x1e1) catch @panic("test failure");
16403 expect(i == 7) catch @panic("test failure");
16404}
16405
16406extern fn c_ret_struct_array_3_sentinel_f32() Struct_array_3_sentinel_f32;
16407extern fn c_struct_array_3_sentinel_f32(Struct_array_3_sentinel_f32, usize) void;
16408extern fn c_test_struct_array_3_sentinel_f32() void;
16409
16410test "struct [3:sentinel]f32" {
16411 if (builtin.cpu.arch.isAARCH64()) return error.SkipZigTest;
16412 if (builtin.cpu.arch.isArm()) return error.SkipZigTest;
16413 if (builtin.cpu.arch == .hexagon) return error.SkipZigTest;
16414 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
16415 if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
16416
16417 var sentinel_index: usize = 3;
16418 _ = &sentinel_index;
16419 const s = c_ret_struct_array_3_sentinel_f32();
16420 try expect(s.a[0] == 8);
16421 try expect(s.a[1] == 9);
16422 try expect(s.a[2] == 10);
16423 try expect(s.a[sentinel_index] == 0x1e1);
16424 c_struct_array_3_sentinel_f32(.{ .a = .{ 11, 12, 13 } }, 14);
16425 c_test_struct_array_3_sentinel_f32();
16426}
16427
16428const Struct_array_4_sentinel_f32 = extern struct {
16429 a: [4:0x1e1]f32,
16430};
16431
16432export fn zig_ret_struct_array_4_sentinel_f32() Struct_array_4_sentinel_f32 {
16433 return .{ .a = .{ 1, 2, 3, 4 } };
16434}
16435export fn zig_struct_array_4_sentinel_f32(s: Struct_array_4_sentinel_f32, i: usize) void {
16436 var sentinel_index: usize = 4;
16437 _ = &sentinel_index;
16438 expect(s.a[0] == 5) catch @panic("test failure");
16439 expect(s.a[1] == 6) catch @panic("test failure");
16440 expect(s.a[2] == 7) catch @panic("test failure");
16441 expect(s.a[3] == 8) catch @panic("test failure");
16442 expect(s.a[sentinel_index] == 0x1e1) catch @panic("test failure");
16443 expect(i == 9) catch @panic("test failure");
16444}
16445
16446extern fn c_ret_struct_array_4_sentinel_f32() Struct_array_4_sentinel_f32;
16447extern fn c_struct_array_4_sentinel_f32(Struct_array_4_sentinel_f32, usize) void;
16448extern fn c_test_struct_array_4_sentinel_f32() void;
16449
16450test "struct [4:sentinel]f32" {
16451 if (builtin.cpu.arch.isArm()) return error.SkipZigTest;
16452 if (builtin.cpu.arch == .hexagon) return error.SkipZigTest;
16453 if (builtin.cpu.arch.isMIPS64()) return error.SkipZigTest;
16454 if (builtin.cpu.arch.isPowerPC()) return error.SkipZigTest;
16455
16456 var sentinel_index: usize = 4;
16457 _ = &sentinel_index;
16458 const s = c_ret_struct_array_4_sentinel_f32();
16459 try expect(s.a[0] == 10);
16460 try expect(s.a[1] == 11);
16461 try expect(s.a[2] == 12);
16462 try expect(s.a[3] == 13);
16463 try expect(s.a[sentinel_index] == 0x1e1);
16464 c_struct_array_4_sentinel_f32(.{ .a = .{ 14, 15, 16, 17 } }, 18);
16465 c_test_struct_array_4_sentinel_f32();
16466}
16467
1628116468const Struct_f32a8 = extern struct {
1628216469 a: f32 align(8),
1628316470};