From 372b3c33c1c529c1be6284ede5b704f940a69bdb Mon Sep 17 00:00:00 2001 From: Matthew Lugg Date: Sun, 25 Jan 2026 11:12:26 +0000 Subject: [PATCH] std: work around language changes --- lib/std/elf.zig | 4 ++-- lib/std/meta.zig | 2 +- lib/std/multi_array_list.zig | 22 ++++++++++++++-------- lib/std/os/linux.zig | 2 +- lib/std/testing.zig | 5 ++--- lib/std/zon/Serializer.zig | 4 +++- 6 files changed, 23 insertions(+), 16 deletions(-) diff --git a/lib/std/elf.zig b/lib/std/elf.zig index 962e0ceb9e..b9ddf88123 100644 --- a/lib/std/elf.zig +++ b/lib/std/elf.zig @@ -1071,7 +1071,7 @@ pub const Elf32 = struct { pub const Shdr = extern struct { name: Word, type: SHT, - flags: packed struct { shf: SHF }, + flags: packed struct(Word) { shf: SHF }, addr: Elf32.Addr, offset: Elf32.Off, size: Word, @@ -1161,7 +1161,7 @@ pub const Elf64 = struct { pub const Shdr = extern struct { name: Word, type: SHT, - flags: packed struct { shf: SHF, unused: Word = 0 }, + flags: packed struct(Xword) { shf: SHF, unused: Word = 0 }, addr: Elf64.Addr, offset: Elf64.Off, size: Xword, diff --git a/lib/std/meta.zig b/lib/std/meta.zig index f1afa9bc7a..6236f1a56b 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -315,7 +315,7 @@ test declarationInfo { try testing.expect(comptime mem.eql(u8, info.name, "a")); } } -pub fn fields(comptime T: type) switch (@typeInfo(T)) { +pub inline fn fields(comptime T: type) switch (@typeInfo(T)) { .@"struct" => []const Type.StructField, .@"union" => []const Type.UnionField, .@"enum" => []const Type.EnumField, diff --git a/lib/std/multi_array_list.zig b/lib/std/multi_array_list.zig index 990b85a238..92d094f0cc 100644 --- a/lib/std/multi_array_list.zig +++ b/lib/std/multi_array_list.zig @@ -19,7 +19,11 @@ const testing = std.testing; /// For unions you can call `.items(.tags)` or `.items(.data)`. pub fn MultiArrayList(comptime T: type) type { return struct { - bytes: [*]align(@alignOf(T)) u8 = undefined, + /// This pointer is always aligned to the boundary `sizes.big_align`; this is not specified + /// in the type to avoid `MultiArrayList(T)` depending on the alignment of `T` because this + /// can lead to dependency loops. See `allocatedBytes` which `@alignCast`s this pointer to + /// the correct type. + bytes: [*]u8 = undefined, len: usize = 0, capacity: usize = 0, @@ -133,10 +137,8 @@ pub fn MultiArrayList(comptime T: type) type { if (self.ptrs.len == 0 or self.capacity == 0) { return .{}; } - const unaligned_ptr = self.ptrs[sizes.fields[0]]; - const aligned_ptr: [*]align(@alignOf(Elem)) u8 = @alignCast(unaligned_ptr); return .{ - .bytes = aligned_ptr, + .bytes = self.ptrs[sizes.fields[0]], .len = self.len, .capacity = self.capacity, }; @@ -179,6 +181,7 @@ pub fn MultiArrayList(comptime T: type) type { const fields = meta.fields(Elem); /// `sizes.bytes` is an array of @sizeOf each T field. Sorted by alignment, descending. /// `sizes.fields` is an array mapping from `sizes.bytes` array index to field index. + /// `sizes.big_align` is the overall alignment of the allocation, which equals the maximum field alignment. const sizes = blk: { const Data = struct { size: usize, @@ -186,12 +189,14 @@ pub fn MultiArrayList(comptime T: type) type { alignment: usize, }; var data: [fields.len]Data = undefined; + var big_align: usize = 1; for (fields, 0..) |field_info, i| { data[i] = .{ .size = @sizeOf(field_info.type), .size_index = i, .alignment = if (@sizeOf(field_info.type) == 0) 1 else field_info.alignment, }; + big_align = @max(big_align, @alignOf(field_info.type)); } const Sort = struct { fn lessThan(context: void, lhs: Data, rhs: Data) bool { @@ -210,6 +215,7 @@ pub fn MultiArrayList(comptime T: type) type { break :blk .{ .bytes = sizes_bytes, .fields = field_indexes, + .big_align = mem.Alignment.fromByteUnits(big_align), }; }; @@ -452,7 +458,7 @@ pub fn MultiArrayList(comptime T: type) type { assert(new_len <= self.capacity); assert(new_len <= self.len); - const other_bytes = gpa.alignedAlloc(u8, .of(Elem), capacityInBytes(new_len)) catch { + const other_bytes = gpa.alignedAlloc(u8, sizes.big_align, capacityInBytes(new_len)) catch { const self_slice = self.slice(); inline for (fields, 0..) |field_info, i| { if (@sizeOf(field_info.type) != 0) { @@ -533,7 +539,7 @@ pub fn MultiArrayList(comptime T: type) type { /// `new_capacity` must be greater or equal to `len`. pub fn setCapacity(self: *Self, gpa: Allocator, new_capacity: usize) Allocator.Error!void { assert(new_capacity >= self.len); - const new_bytes = try gpa.alignedAlloc(u8, .of(Elem), capacityInBytes(new_capacity)); + const new_bytes = try gpa.alignedAlloc(u8, sizes.big_align, capacityInBytes(new_capacity)); if (self.len == 0) { gpa.free(self.allocatedBytes()); self.bytes = new_bytes.ptr; @@ -650,8 +656,8 @@ pub fn MultiArrayList(comptime T: type) type { return elem_bytes * capacity; } - fn allocatedBytes(self: Self) []align(@alignOf(Elem)) u8 { - return self.bytes[0..capacityInBytes(self.capacity)]; + fn allocatedBytes(self: Self) []align(sizes.big_align.toByteUnits()) u8 { + return @alignCast(self.bytes[0..capacityInBytes(self.capacity)]); } fn FieldType(comptime field: Field) type { diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index cbe085a3af..b884e8ea79 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -7113,7 +7113,7 @@ pub const io_uring_buf_reg = extern struct { flags: Flags, resv: [3]u64, - pub const Flags = packed struct { + pub const Flags = packed struct(u16) { _0: u1 = 0, /// Incremental buffer consumption. inc: bool, diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 09919f8b69..bfb50039ea 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -950,9 +950,8 @@ test "expectEqualDeep primitive type" { } test "expectEqualDeep pointer" { - const a = 1; - const b = 1; - try expectEqualDeep(&a, &b); + try comptime expectEqualDeep(&1, &1); + try expectEqualDeep(&@as(u32, 1), &@as(u32, 1)); } test "expectEqualDeep composite type" { diff --git a/lib/std/zon/Serializer.zig b/lib/std/zon/Serializer.zig index 6f92a64dbd..c30c0e09d8 100644 --- a/lib/std/zon/Serializer.zig +++ b/lib/std/zon/Serializer.zig @@ -793,9 +793,11 @@ test checkValueDepth { try expectValueDepthEquals(2, @as(?u32, 1)); try expectValueDepthEquals(1, @as(?u32, null)); try expectValueDepthEquals(1, null); - try expectValueDepthEquals(2, &1); try expectValueDepthEquals(3, &@as(?u32, 1)); + // The pointer drops the implicit comptime-ness, so we need to specify 'comptime' here + try comptime expectValueDepthEquals(2, &1); + const Union = union(enum) { x: u32, y: struct { x: u32 },