std: update for language changes

Now that zig1.wasm is updated, apply the matching standard library
changes.

The main one is in `std.builtin.Type`, where `alignment` fields now have
type `?usize` rather than `comptime_int`.

Additionally, we need to add explicit backing integers to some packed
unions, because (due to https://github.com/ziglang/zig/issues/24714)
they need explicit backing integers to be used in `extern` contexts.
This change could not happen before now, because prior to this branch,
packed unions did not allow explicit backing integer types (that is,
this branch implemented https://github.com/ziglang/zig/issues/25350).
This commit is contained in:
Matthew Lugg 2026-03-04 16:33:51 +00:00
parent 7b7eee6f4b
commit b69bfe0c08
No known key found for this signature in database
GPG key ID: 3F5B7DCCBF4AF02E
10 changed files with 81 additions and 64 deletions

View file

@ -410,7 +410,7 @@ pub const ResourceDirectoryTable = extern struct {
};
pub const ResourceDirectoryEntry = extern struct {
entry: packed union {
entry: packed union(u32) {
name_offset: packed struct(u32) {
address: u31,
/// This is undocumented in the PE/COFF spec, but the high bit

View file

@ -592,8 +592,8 @@ pub const Type = union(enum) {
size: Size,
is_const: bool,
is_volatile: bool,
/// TODO make this u16 instead of comptime_int
alignment: comptime_int,
/// `null` means implicit alignment, which is equivalent to `@alignOf(child)`.
alignment: ?usize,
address_space: AddressSpace,
child: type,
is_allowzero: bool,
@ -670,7 +670,9 @@ pub const Type = union(enum) {
/// See also: `defaultValue`.
default_value_ptr: ?*const anyopaque,
is_comptime: bool,
alignment: comptime_int,
/// `null` means the field alignment was not explicitly specified. The
/// field will still be aligned to at least `@alignOf` its `type`.
alignment: ?usize,
/// Loads the field's default value from `default_value_ptr`.
/// Returns `null` if the field has no default value.
@ -747,7 +749,9 @@ pub const Type = union(enum) {
pub const UnionField = struct {
name: [:0]const u8,
type: type,
alignment: comptime_int,
/// `null` means the field alignment was not explicitly specified. The
/// field will still be aligned to at least `@alignOf` its `type`.
alignment: ?usize,
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.

View file

@ -436,7 +436,7 @@ pub const thread_state_flavor_t = c_int;
pub const ipc_space_t = mach_port_t;
pub const ipc_space_port_t = ipc_space_t;
pub const mach_msg_option_t = packed union {
pub const mach_msg_option_t = packed union(integer_t) {
RCV: MACH.RCV,
SEND: MACH.SEND,

View file

@ -210,7 +210,7 @@ pub const source_timer_flags_t = packed struct(usize) {
STRICT: bool = false,
unused1: @Int(.unsigned, @bitSizeOf(usize) - 1) = 0,
};
pub const source_flags_t = packed union {
pub const source_flags_t = packed union(usize) {
raw: usize,
MACH_SEND: source_mach_send_flags_t,
MACH_RECV: source_mach_recv_flags_t,

View file

@ -851,7 +851,7 @@ pub const nlist = extern struct {
pub const nlist_64 = extern struct {
n_strx: u32,
n_type: packed union {
n_type: packed union(u8) {
bits: packed struct(u8) {
ext: bool,
type: enum(u3) {

View file

@ -38,6 +38,10 @@ pub const Alignment = enum(math.Log2Int(usize)) {
return @enumFromInt(@ctz(n));
}
pub fn fromByteUnitsOptional(maybe_n: ?usize) ?Alignment {
return if (maybe_n) |n| .fromByteUnits(n) else null;
}
pub inline fn of(comptime T: type) Alignment {
return comptime fromByteUnits(@alignOf(T));
}
@ -2287,8 +2291,8 @@ pub fn byteSwapAllFieldsAligned(comptime S: type, comptime a: Alignment, ptr: *a
ptr.* = @bitCast(@byteSwap(@as(Int, @bitCast(ptr.*))));
} else inline for (std.meta.fields(S)) |f| {
switch (@typeInfo(f.type)) {
.@"struct" => byteSwapAllFieldsAligned(f.type, .fromByteUnits(f.alignment), &@field(ptr, f.name)),
.@"union", .array => byteSwapAllFieldsAligned(f.type, .fromByteUnits(f.alignment), &@field(ptr, f.name)),
.@"struct" => byteSwapAllFieldsAligned(f.type, .fromByteUnits(f.alignment orelse @alignOf(f.type)), &@field(ptr, f.name)),
.@"union", .array => byteSwapAllFieldsAligned(f.type, .fromByteUnits(f.alignment orelse @alignOf(f.type)), &@field(ptr, f.name)),
.@"enum" => {
@field(ptr, f.name) = @enumFromInt(@byteSwap(@intFromEnum(@field(ptr, f.name))));
},
@ -4330,7 +4334,7 @@ pub fn alignPointerOffset(ptr: anytype, align_to: usize) ?usize {
@compileError("expected many item pointer, got " ++ @typeName(T));
// Do nothing if the pointer is already well-aligned.
if (align_to <= info.pointer.alignment)
if (align_to <= info.pointer.alignment orelse @alignOf(info.pointer.child))
return 0;
// Calculate the aligned base address with an eye out for overflow.
@ -4388,7 +4392,11 @@ fn CopyPtrAttrs(
.@"const" = ptr.is_const,
.@"volatile" = ptr.is_volatile,
.@"allowzero" = ptr.is_allowzero,
.@"align" = ptr.alignment,
.@"align" = ptr.alignment orelse a: {
// If the new child is aligned differently than the old one, explicitly align the type.
const want = @alignOf(ptr.child);
break :a if (@alignOf(child) == want) null else want;
},
.@"addrspace" = ptr.address_space,
}, child, null);
}

View file

@ -179,7 +179,11 @@ pub fn destroy(self: Allocator, ptr: anytype) void {
const T = info.child;
if (@sizeOf(T) == 0) return;
const non_const_ptr = @as([*]u8, @ptrCast(@constCast(ptr)));
self.rawFree(non_const_ptr[0..@sizeOf(T)], .fromByteUnits(info.alignment), @returnAddress());
self.rawFree(
non_const_ptr[0..@sizeOf(T)],
.fromByteUnits(info.alignment orelse @alignOf(T)),
@returnAddress(),
);
}
/// Allocates an array of `n` items of type `T` and sets all the
@ -266,7 +270,7 @@ pub inline fn allocAdvancedWithRetAddr(
n: usize,
return_address: usize,
) Error![]align(if (alignment) |a| a.toByteUnits() else @alignOf(T)) T {
const a = comptime (alignment orelse Alignment.of(T));
const a: Alignment = alignment orelse comptime .of(T);
const ptr: [*]align(a.toByteUnits()) T = @ptrCast(try self.allocWithSizeAndAlignment(@sizeOf(T), a, n, return_address));
return ptr[0..n];
}
@ -278,7 +282,7 @@ fn allocWithSizeAndAlignment(
n: usize,
return_address: usize,
) Error![*]align(alignment.toByteUnits()) u8 {
const byte_count = math.mul(usize, size, n) catch return Error.OutOfMemory;
const byte_count = math.mul(usize, size, n) catch return error.OutOfMemory;
return self.allocBytesWithAlignment(alignment, byte_count, return_address);
}
@ -293,7 +297,7 @@ fn allocBytesWithAlignment(
return @as([*]align(alignment.toByteUnits()) u8, @ptrFromInt(ptr));
}
const byte_ptr = self.rawAlloc(byte_count, alignment, return_address) orelse return Error.OutOfMemory;
const byte_ptr = self.rawAlloc(byte_count, alignment, return_address) orelse return error.OutOfMemory;
@memset(byte_ptr[0..byte_count], undefined);
return @alignCast(byte_ptr);
}
@ -308,9 +312,9 @@ fn allocBytesWithAlignment(
///
/// `new_len` may be zero, in which case the allocation is freed.
pub fn resize(self: Allocator, allocation: anytype, new_len: usize) bool {
const Slice = @typeInfo(@TypeOf(allocation)).pointer;
const T = Slice.child;
const alignment = Slice.alignment;
const slice_info = @typeInfo(@TypeOf(allocation)).pointer;
comptime assert(slice_info.size == .slice);
const T = slice_info.child;
if (new_len == 0) {
self.free(allocation);
return true;
@ -323,7 +327,12 @@ pub fn resize(self: Allocator, allocation: anytype, new_len: usize) bool {
// on WebAssembly: https://github.com/ziglang/zig/issues/9660
//const new_len_bytes = new_len *| @sizeOf(T);
const new_len_bytes = math.mul(usize, @sizeOf(T), new_len) catch return false;
return self.rawResize(old_memory, .fromByteUnits(alignment), new_len_bytes, @returnAddress());
return self.rawResize(
old_memory,
.fromByteUnits(slice_info.alignment orelse @alignOf(T)),
new_len_bytes,
@returnAddress(),
);
}
/// Request to modify the size of an allocation, allowing relocation.
@ -342,14 +351,11 @@ pub fn resize(self: Allocator, allocation: anytype, new_len: usize) bool {
/// `new_len` may be zero, in which case the allocation is freed.
///
/// If the allocation's elements' type is zero bytes sized, `allocation.len` is set to `new_len`.
pub fn remap(self: Allocator, allocation: anytype, new_len: usize) t: {
const Slice = @typeInfo(@TypeOf(allocation)).pointer;
break :t ?[]align(Slice.alignment) Slice.child;
} {
const Slice = @typeInfo(@TypeOf(allocation)).pointer;
const T = Slice.child;
pub fn remap(self: Allocator, allocation: anytype, new_len: usize) ?@TypeOf(allocation) {
const slice_info = @typeInfo(@TypeOf(allocation)).pointer;
comptime assert(slice_info.size == .slice);
const T = slice_info.child;
const alignment = Slice.alignment;
if (new_len == 0) {
self.free(allocation);
return allocation[0..0];
@ -367,9 +373,13 @@ pub fn remap(self: Allocator, allocation: anytype, new_len: usize) t: {
// on WebAssembly: https://github.com/ziglang/zig/issues/9660
//const new_len_bytes = new_len *| @sizeOf(T);
const new_len_bytes = math.mul(usize, @sizeOf(T), new_len) catch return null;
const new_ptr = self.rawRemap(old_memory, .fromByteUnits(alignment), new_len_bytes, @returnAddress()) orelse return null;
const new_memory: []align(alignment) u8 = @alignCast(new_ptr[0..new_len_bytes]);
return mem.bytesAsSlice(T, new_memory);
const new_ptr = self.rawRemap(
old_memory,
.fromByteUnits(slice_info.alignment orelse @alignOf(T)),
new_len_bytes,
@returnAddress(),
) orelse return null;
return @ptrCast(@alignCast(new_ptr[0..new_len_bytes]));
}
/// This function requests a new size for an existing allocation, which
@ -386,10 +396,7 @@ pub fn remap(self: Allocator, allocation: anytype, new_len: usize) t: {
/// do the realloc more efficiently than the caller
/// * `resize` which returns `false` when the `Allocator` implementation cannot
/// change the size without relocating the allocation.
pub fn realloc(self: Allocator, old_mem: anytype, new_n: usize) t: {
const Slice = @typeInfo(@TypeOf(old_mem)).pointer;
break :t Error![]align(Slice.alignment) Slice.child;
} {
pub fn realloc(self: Allocator, old_mem: anytype, new_n: usize) Error!@TypeOf(old_mem) {
return self.reallocAdvanced(old_mem, new_n, @returnAddress());
}
@ -398,51 +405,49 @@ pub fn reallocAdvanced(
old_mem: anytype,
new_n: usize,
return_address: usize,
) t: {
const Slice = @typeInfo(@TypeOf(old_mem)).pointer;
break :t Error![]align(Slice.alignment) Slice.child;
} {
const Slice = @typeInfo(@TypeOf(old_mem)).pointer;
const T = Slice.child;
) Error!@TypeOf(old_mem) {
const slice_info = @typeInfo(@TypeOf(old_mem)).pointer;
comptime assert(slice_info.size == .slice);
const T = slice_info.child;
if (old_mem.len == 0) {
return self.allocAdvancedWithRetAddr(T, .fromByteUnits(Slice.alignment), new_n, return_address);
return self.allocAdvancedWithRetAddr(T, .fromByteUnitsOptional(slice_info.alignment), new_n, return_address);
}
if (new_n == 0) {
self.free(old_mem);
const ptr = comptime std.mem.alignBackward(usize, math.maxInt(usize), Slice.alignment);
return @as([*]align(Slice.alignment) T, @ptrFromInt(ptr))[0..0];
const alignment = slice_info.alignment orelse @alignOf(T);
const addr = comptime std.mem.alignBackward(usize, math.maxInt(usize), alignment);
const ptr: *align(alignment) [0]T = @ptrFromInt(addr);
return ptr;
}
const old_byte_slice = mem.sliceAsBytes(old_mem);
const byte_count = math.mul(usize, @sizeOf(T), new_n) catch return Error.OutOfMemory;
const byte_count = math.mul(usize, @sizeOf(T), new_n) catch return error.OutOfMemory;
// Note: can't set shrunk memory to undefined as memory shouldn't be modified on realloc failure
if (self.rawRemap(old_byte_slice, .fromByteUnits(Slice.alignment), byte_count, return_address)) |p| {
const new_bytes: []align(Slice.alignment) u8 = @alignCast(p[0..byte_count]);
return mem.bytesAsSlice(T, new_bytes);
if (self.rawRemap(old_byte_slice, .fromByteUnits(slice_info.alignment orelse @alignOf(T)), byte_count, return_address)) |p| {
return @ptrCast(@alignCast(p[0..byte_count]));
}
const new_mem = self.rawAlloc(byte_count, .fromByteUnits(Slice.alignment), return_address) orelse
const new_mem = self.rawAlloc(byte_count, .fromByteUnits(slice_info.alignment orelse @alignOf(T)), return_address) orelse
return error.OutOfMemory;
const copy_len = @min(byte_count, old_byte_slice.len);
@memcpy(new_mem[0..copy_len], old_byte_slice[0..copy_len]);
@memset(old_byte_slice, undefined);
self.rawFree(old_byte_slice, .fromByteUnits(Slice.alignment), return_address);
self.rawFree(old_byte_slice, .fromByteUnits(slice_info.alignment orelse @alignOf(T)), return_address);
const new_bytes: []align(Slice.alignment) u8 = @alignCast(new_mem[0..byte_count]);
return mem.bytesAsSlice(T, new_bytes);
return @ptrCast(@alignCast(new_mem[0..byte_count]));
}
/// Free an array allocated with `alloc`.
/// If memory has length 0, free is a no-op.
/// To free a single item, see `destroy`.
pub fn free(self: Allocator, memory: anytype) void {
const Slice = @typeInfo(@TypeOf(memory)).pointer;
const bytes = mem.sliceAsBytes(memory);
const bytes_len = bytes.len + if (Slice.sentinel() != null) @sizeOf(Slice.child) else 0;
if (bytes_len == 0) return;
const non_const_ptr = @constCast(bytes.ptr);
@memset(non_const_ptr[0..bytes_len], undefined);
self.rawFree(non_const_ptr[0..bytes_len], .fromByteUnits(Slice.alignment), @returnAddress());
const slice_info = @typeInfo(@TypeOf(memory)).pointer;
comptime assert(slice_info.size == .slice);
const mem_with_sent = memory[0 .. memory.len + @intFromBool(slice_info.sentinel() != null)];
const bytes: []u8 = @ptrCast(@constCast(mem_with_sent));
if (bytes.len == 0) return;
@memset(bytes, undefined);
self.rawFree(bytes, .fromByteUnits(slice_info.alignment orelse @alignOf(slice_info.child)), @returnAddress());
}
/// Copies `m` to newly allocated memory. Caller owns the memory.

View file

@ -63,7 +63,7 @@ pub fn alignment(comptime T: type) comptime_int {
.pointer, .@"fn" => alignment(info.child),
else => @alignOf(T),
},
.pointer => |info| info.alignment,
.pointer => |info| info.alignment orelse @alignOf(info.child),
else => @alignOf(T),
};
}

View file

@ -194,9 +194,9 @@ pub fn MultiArrayList(comptime T: type) type {
data[i] = .{
.size = @sizeOf(field_info.type),
.size_index = i,
.alignment = if (@sizeOf(field_info.type) == 0) 1 else field_info.alignment,
.alignment = field_info.alignment orelse @alignOf(field_info.type),
};
big_align = @max(big_align, @alignOf(field_info.type));
big_align = @max(big_align, data[i].alignment);
}
const Sort = struct {
fn lessThan(context: void, lhs: Data, rhs: Data) bool {

View file

@ -591,7 +591,7 @@ const Parser = struct {
if (pointer.child == u8 and
pointer.is_const and
(pointer.sentinel() == null or pointer.sentinel() == 0) and
pointer.alignment == 1)
(pointer.alignment == null or pointer.alignment == 1))
{
if (opt) {
return self.failNode(node, "expected optional string");
@ -717,7 +717,7 @@ const Parser = struct {
pointer.size != .slice or
!pointer.is_const or
(pointer.sentinel() != null and pointer.sentinel() != 0) or
pointer.alignment != 1)
(pointer.alignment != null and pointer.alignment != 1))
{
return error.WrongType;
}
@ -742,7 +742,7 @@ const Parser = struct {
const slice = try self.gpa.allocWithOptions(
pointer.child,
nodes.len,
.fromByteUnits(pointer.alignment),
.fromByteUnitsOptional(pointer.alignment),
pointer.sentinel(),
);
errdefer self.gpa.free(slice);