mirror of
https://github.com/ziglang/zig.git
synced 2026-01-12 02:15:12 +00:00
Now it checks that the code is correctly compiled rather than only checking that it does not crash the compiler.
438 lines
14 KiB
Zig
438 lines
14 KiB
Zig
const std = @import("std");
|
|
const builtin = @import("builtin");
|
|
const assert = std.debug.assert;
|
|
const expect = std.testing.expect;
|
|
const expectEqual = std.testing.expectEqual;
|
|
const native_endian = builtin.cpu.arch.endian();
|
|
|
|
test "correct size of packed structs" {
|
|
const T1 = packed struct { one: u8, three: [3]u8 };
|
|
|
|
try expectEqual(4, @sizeOf(T1));
|
|
try expectEqual(4 * 8, @bitSizeOf(T1));
|
|
|
|
const T2 = packed struct { three: [3]u8, one: u8 };
|
|
|
|
try expectEqual(4, @sizeOf(T2));
|
|
try expectEqual(4 * 8, @bitSizeOf(T2));
|
|
|
|
const T3 = packed struct { _1: u1, x: u7, _: u24 };
|
|
|
|
try expectEqual(4, @sizeOf(T3));
|
|
try expectEqual(4 * 8, @bitSizeOf(T3));
|
|
|
|
const T4 = packed struct { _1: u1, x: u7, _2: u8, _3: u16 };
|
|
|
|
try expectEqual(4, @sizeOf(T4));
|
|
try expectEqual(4 * 8, @bitSizeOf(T4));
|
|
|
|
const T5 = packed struct { _1: u1, x: u7, _2: u16, _3: u8 };
|
|
|
|
try expectEqual(4, @sizeOf(T5));
|
|
try expectEqual(4 * 8, @bitSizeOf(T5));
|
|
}
|
|
|
|
test "flags in packed structs" {
|
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
|
|
|
const Flags1 = packed struct {
|
|
// first 8 bits
|
|
b0_0: u1,
|
|
b0_1: u1,
|
|
b0_2: u1,
|
|
b0_3: u1,
|
|
b0_4: u1,
|
|
b0_5: u1,
|
|
b0_6: u1,
|
|
b0_7: u1,
|
|
|
|
// 7 more bits
|
|
b1_0: u1,
|
|
b1_1: u1,
|
|
b1_2: u1,
|
|
b1_3: u1,
|
|
b1_4: u1,
|
|
b1_5: u1,
|
|
b1_6: u1,
|
|
|
|
// some padding to fill to 24 bits
|
|
_: u9,
|
|
};
|
|
|
|
try expectEqual(@sizeOf(u24), @sizeOf(Flags1));
|
|
try expectEqual(24, @bitSizeOf(Flags1));
|
|
|
|
const Flags2 = packed struct {
|
|
// byte 0
|
|
b0_0: u1,
|
|
b0_1: u1,
|
|
b0_2: u1,
|
|
b0_3: u1,
|
|
b0_4: u1,
|
|
b0_5: u1,
|
|
b0_6: u1,
|
|
b0_7: u1,
|
|
|
|
// partial byte 1 (but not 8 bits)
|
|
b1_0: u1,
|
|
b1_1: u1,
|
|
b1_2: u1,
|
|
b1_3: u1,
|
|
b1_4: u1,
|
|
b1_5: u1,
|
|
b1_6: u1,
|
|
|
|
// some padding that should yield @sizeOf(Flags2) == 4
|
|
_: u10,
|
|
};
|
|
|
|
try expectEqual(@sizeOf(u25), @sizeOf(Flags2));
|
|
try expectEqual(25, @bitSizeOf(Flags2));
|
|
|
|
const Flags3 = packed struct {
|
|
// byte 0
|
|
b0_0: u1,
|
|
b0_1: u1,
|
|
b0_2: u1,
|
|
b0_3: u1,
|
|
b0_4: u1,
|
|
b0_5: u1,
|
|
b0_6: u1,
|
|
b0_7: u1,
|
|
|
|
// byte 1
|
|
b1_0: u1,
|
|
b1_1: u1,
|
|
b1_2: u1,
|
|
b1_3: u1,
|
|
b1_4: u1,
|
|
b1_5: u1,
|
|
b1_6: u1,
|
|
b1_7: u1,
|
|
|
|
// some padding that should yield @sizeOf(Flags2) == 4
|
|
_: u16, // it works, if the padding is 8-based
|
|
};
|
|
|
|
try expectEqual(@sizeOf(u32), @sizeOf(Flags3));
|
|
try expectEqual(32, @bitSizeOf(Flags3));
|
|
}
|
|
|
|
test "arrays in packed structs" {
|
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
|
|
|
const T1 = packed struct { array: [3][3]u8 };
|
|
const T2 = packed struct { array: [9]u8 };
|
|
|
|
try expectEqual(@sizeOf(u72), @sizeOf(T1));
|
|
try expectEqual(72, @bitSizeOf(T1));
|
|
try expectEqual(@sizeOf(u72), @sizeOf(T2));
|
|
try expectEqual(72, @bitSizeOf(T2));
|
|
}
|
|
|
|
test "consistent size of packed structs" {
|
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
|
|
|
const TxData1 = packed struct { data: u8, _23: u23, full: bool = false };
|
|
const TxData2 = packed struct { data: u9, _22: u22, full: bool = false };
|
|
|
|
const register_size_bits = 32;
|
|
const register_size_bytes = @sizeOf(u32);
|
|
|
|
try expectEqual(register_size_bits, @bitSizeOf(TxData1));
|
|
try expectEqual(register_size_bytes, @sizeOf(TxData1));
|
|
|
|
try expectEqual(register_size_bits, @bitSizeOf(TxData2));
|
|
try expectEqual(register_size_bytes, @sizeOf(TxData2));
|
|
|
|
const TxData3 = packed struct { a: u32, b: [3]u8 };
|
|
const TxData4 = packed struct { a: u32, b: u24 };
|
|
const TxData5 = packed struct { a: [3]u8, b: u32 };
|
|
const TxData6 = packed struct { a: u24, b: u32 };
|
|
|
|
const expectedBitSize = 56;
|
|
const expectedByteSize = @sizeOf(u56);
|
|
|
|
try expectEqual(expectedBitSize, @bitSizeOf(TxData3));
|
|
try expectEqual(expectedByteSize, @sizeOf(TxData3));
|
|
|
|
try expectEqual(expectedBitSize, @bitSizeOf(TxData4));
|
|
try expectEqual(expectedByteSize, @sizeOf(TxData4));
|
|
|
|
try expectEqual(expectedBitSize, @bitSizeOf(TxData5));
|
|
try expectEqual(expectedByteSize, @sizeOf(TxData5));
|
|
|
|
try expectEqual(expectedBitSize, @bitSizeOf(TxData6));
|
|
try expectEqual(expectedByteSize, @sizeOf(TxData6));
|
|
}
|
|
|
|
test "correct sizeOf and offsets in packed structs" {
|
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
|
|
|
const PStruct = packed struct {
|
|
bool_a: bool,
|
|
bool_b: bool,
|
|
bool_c: bool,
|
|
bool_d: bool,
|
|
bool_e: bool,
|
|
bool_f: bool,
|
|
u1_a: u1,
|
|
bool_g: bool,
|
|
u1_b: u1,
|
|
u3_a: u3,
|
|
u10_a: u10,
|
|
u10_b: u10,
|
|
};
|
|
try expectEqual(0, @offsetOf(PStruct, "bool_a"));
|
|
try expectEqual(0, @bitOffsetOf(PStruct, "bool_a"));
|
|
try expectEqual(0, @offsetOf(PStruct, "bool_b"));
|
|
try expectEqual(1, @bitOffsetOf(PStruct, "bool_b"));
|
|
try expectEqual(0, @offsetOf(PStruct, "bool_c"));
|
|
try expectEqual(2, @bitOffsetOf(PStruct, "bool_c"));
|
|
try expectEqual(0, @offsetOf(PStruct, "bool_d"));
|
|
try expectEqual(3, @bitOffsetOf(PStruct, "bool_d"));
|
|
try expectEqual(0, @offsetOf(PStruct, "bool_e"));
|
|
try expectEqual(4, @bitOffsetOf(PStruct, "bool_e"));
|
|
try expectEqual(0, @offsetOf(PStruct, "bool_f"));
|
|
try expectEqual(5, @bitOffsetOf(PStruct, "bool_f"));
|
|
try expectEqual(0, @offsetOf(PStruct, "u1_a"));
|
|
try expectEqual(6, @bitOffsetOf(PStruct, "u1_a"));
|
|
try expectEqual(0, @offsetOf(PStruct, "bool_g"));
|
|
try expectEqual(7, @bitOffsetOf(PStruct, "bool_g"));
|
|
try expectEqual(1, @offsetOf(PStruct, "u1_b"));
|
|
try expectEqual(8, @bitOffsetOf(PStruct, "u1_b"));
|
|
try expectEqual(1, @offsetOf(PStruct, "u3_a"));
|
|
try expectEqual(9, @bitOffsetOf(PStruct, "u3_a"));
|
|
try expectEqual(1, @offsetOf(PStruct, "u10_a"));
|
|
try expectEqual(12, @bitOffsetOf(PStruct, "u10_a"));
|
|
try expectEqual(2, @offsetOf(PStruct, "u10_b"));
|
|
try expectEqual(22, @bitOffsetOf(PStruct, "u10_b"));
|
|
try expectEqual(4, @sizeOf(PStruct));
|
|
|
|
if (native_endian == .Little) {
|
|
const s1 = @bitCast(PStruct, @as(u32, 0x12345678));
|
|
try expectEqual(false, s1.bool_a);
|
|
try expectEqual(false, s1.bool_b);
|
|
try expectEqual(false, s1.bool_c);
|
|
try expectEqual(true, s1.bool_d);
|
|
try expectEqual(true, s1.bool_e);
|
|
try expectEqual(true, s1.bool_f);
|
|
try expectEqual(@as(u1, 1), s1.u1_a);
|
|
try expectEqual(false, s1.bool_g);
|
|
try expectEqual(@as(u1, 0), s1.u1_b);
|
|
try expectEqual(@as(u3, 3), s1.u3_a);
|
|
try expectEqual(@as(u10, 0b1101000101), s1.u10_a);
|
|
try expectEqual(@as(u10, 0b0001001000), s1.u10_b);
|
|
|
|
const s2 = @bitCast(packed struct { x: u1, y: u7, z: u24 }, @as(u32, 0xd5c71ff4));
|
|
try expectEqual(@as(u1, 0), s2.x);
|
|
try expectEqual(@as(u7, 0b1111010), s2.y);
|
|
try expectEqual(@as(u24, 0xd5c71f), s2.z);
|
|
}
|
|
|
|
const S = packed struct { a: u32, pad: [3]u32, b: u32 };
|
|
|
|
try expectEqual(16, @offsetOf(S, "b"));
|
|
try expectEqual(128, @bitOffsetOf(S, "b"));
|
|
try expectEqual(@sizeOf(u160), @sizeOf(S));
|
|
}
|
|
|
|
test "nested packed structs" {
|
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
|
|
|
const S1 = packed struct { a: u8, b: u8, c: u8 };
|
|
|
|
const S2 = packed struct { d: u8, e: u8, f: u8 };
|
|
|
|
const S3 = packed struct { x: S1, y: S2 };
|
|
const S3Padded = packed struct { s3: S3, pad: u16 };
|
|
|
|
try expectEqual(48, @bitSizeOf(S3));
|
|
try expectEqual(@sizeOf(u48), @sizeOf(S3));
|
|
|
|
try expectEqual(3, @offsetOf(S3, "y"));
|
|
try expectEqual(24, @bitOffsetOf(S3, "y"));
|
|
|
|
if (native_endian == .Little) {
|
|
const s3 = @bitCast(S3Padded, @as(u64, 0xe952d5c71ff4)).s3;
|
|
try expectEqual(@as(u8, 0xf4), s3.x.a);
|
|
try expectEqual(@as(u8, 0x1f), s3.x.b);
|
|
try expectEqual(@as(u8, 0xc7), s3.x.c);
|
|
try expectEqual(@as(u8, 0xd5), s3.y.d);
|
|
try expectEqual(@as(u8, 0x52), s3.y.e);
|
|
try expectEqual(@as(u8, 0xe9), s3.y.f);
|
|
}
|
|
|
|
const S4 = packed struct { a: i32, b: i8 };
|
|
const S5 = packed struct { a: i32, b: i8, c: S4 };
|
|
const S6 = packed struct { a: i32, b: S4, c: i8 };
|
|
|
|
const expectedBitSize = 80;
|
|
const expectedByteSize = @sizeOf(u80);
|
|
try expectEqual(expectedBitSize, @bitSizeOf(S5));
|
|
try expectEqual(expectedByteSize, @sizeOf(S5));
|
|
try expectEqual(expectedBitSize, @bitSizeOf(S6));
|
|
try expectEqual(expectedByteSize, @sizeOf(S6));
|
|
|
|
try expectEqual(5, @offsetOf(S5, "c"));
|
|
try expectEqual(40, @bitOffsetOf(S5, "c"));
|
|
try expectEqual(9, @offsetOf(S6, "c"));
|
|
try expectEqual(72, @bitOffsetOf(S6, "c"));
|
|
}
|
|
|
|
test "regular in irregular packed struct" {
|
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
|
|
const Irregular = packed struct {
|
|
bar: Regular = Regular{},
|
|
_: u24 = 0,
|
|
pub const Regular = packed struct { a: u16 = 0, b: u8 = 0 };
|
|
};
|
|
|
|
var foo = Irregular{};
|
|
foo.bar.a = 235;
|
|
foo.bar.b = 42;
|
|
|
|
try expectEqual(@as(u16, 235), foo.bar.a);
|
|
try expectEqual(@as(u8, 42), foo.bar.b);
|
|
}
|
|
|
|
test "byte-aligned field pointer offsets" {
|
|
if (builtin.zig_backend == .stage1) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
|
|
const S = struct {
|
|
const A = packed struct {
|
|
a: u8,
|
|
b: u8,
|
|
c: u8,
|
|
d: u8,
|
|
};
|
|
|
|
const B = packed struct {
|
|
a: u16,
|
|
b: u16,
|
|
};
|
|
|
|
fn doTheTest() !void {
|
|
var a: A = .{
|
|
.a = 1,
|
|
.b = 2,
|
|
.c = 3,
|
|
.d = 4,
|
|
};
|
|
switch (comptime builtin.cpu.arch.endian()) {
|
|
.Little => {
|
|
comptime assert(@TypeOf(&a.a) == *align(4) u8);
|
|
comptime assert(@TypeOf(&a.b) == *u8);
|
|
comptime assert(@TypeOf(&a.c) == *align(2) u8);
|
|
comptime assert(@TypeOf(&a.d) == *u8);
|
|
},
|
|
.Big => {
|
|
// TODO re-evaluate packed struct endianness
|
|
comptime assert(@TypeOf(&a.a) == *align(4:0:4) u8);
|
|
comptime assert(@TypeOf(&a.b) == *align(4:8:4) u8);
|
|
comptime assert(@TypeOf(&a.c) == *align(4:16:4) u8);
|
|
comptime assert(@TypeOf(&a.d) == *align(4:24:4) u8);
|
|
},
|
|
}
|
|
try expect(a.a == 1);
|
|
try expect(a.b == 2);
|
|
try expect(a.c == 3);
|
|
try expect(a.d == 4);
|
|
|
|
a.a += 1;
|
|
try expect(a.a == 2);
|
|
try expect(a.b == 2);
|
|
try expect(a.c == 3);
|
|
try expect(a.d == 4);
|
|
|
|
a.b += 1;
|
|
try expect(a.a == 2);
|
|
try expect(a.b == 3);
|
|
try expect(a.c == 3);
|
|
try expect(a.d == 4);
|
|
|
|
a.c += 1;
|
|
try expect(a.a == 2);
|
|
try expect(a.b == 3);
|
|
try expect(a.c == 4);
|
|
try expect(a.d == 4);
|
|
|
|
a.d += 1;
|
|
try expect(a.a == 2);
|
|
try expect(a.b == 3);
|
|
try expect(a.c == 4);
|
|
try expect(a.d == 5);
|
|
|
|
var b: B = .{
|
|
.a = 1,
|
|
.b = 2,
|
|
};
|
|
switch (comptime builtin.cpu.arch.endian()) {
|
|
.Little => {
|
|
comptime assert(@TypeOf(&b.a) == *align(4) u16);
|
|
comptime assert(@TypeOf(&b.b) == *u16);
|
|
},
|
|
.Big => {
|
|
comptime assert(@TypeOf(&b.a) == *align(4:0:4) u16);
|
|
comptime assert(@TypeOf(&b.b) == *align(4:16:4) u16);
|
|
},
|
|
}
|
|
try expect(b.a == 1);
|
|
try expect(b.b == 2);
|
|
|
|
b.a += 1;
|
|
try expect(b.a == 2);
|
|
try expect(b.b == 2);
|
|
|
|
b.b += 1;
|
|
try expect(b.a == 2);
|
|
try expect(b.b == 3);
|
|
}
|
|
};
|
|
|
|
try S.doTheTest();
|
|
comptime try S.doTheTest();
|
|
}
|
|
|
|
test "load pointer from packed struct" {
|
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
|
|
|
const A = struct {
|
|
index: u16,
|
|
};
|
|
const B = packed struct {
|
|
x: *A,
|
|
y: u32,
|
|
};
|
|
var a: A = .{ .index = 123 };
|
|
var b_list: []B = &.{.{ .x = &a, .y = 99 }};
|
|
for (b_list) |b| {
|
|
var i = b.x.index;
|
|
try expect(i == 123);
|
|
}
|
|
}
|