diff --git a/lib/compiler/resinator/cvtres.zig b/lib/compiler/resinator/cvtres.zig index 26b6620af2..6973be714c 100644 --- a/lib/compiler/resinator/cvtres.zig +++ b/lib/compiler/resinator/cvtres.zig @@ -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 diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index e10935f0c6..00ae6199d1 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -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. diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index f18b61187c..452411c52e 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -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, diff --git a/lib/std/c/darwin/dispatch.zig b/lib/std/c/darwin/dispatch.zig index 68b0b48782..770eadf717 100644 --- a/lib/std/c/darwin/dispatch.zig +++ b/lib/std/c/darwin/dispatch.zig @@ -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, diff --git a/lib/std/macho.zig b/lib/std/macho.zig index 57f892bdf7..9fdce9dd66 100644 --- a/lib/std/macho.zig +++ b/lib/std/macho.zig @@ -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) { diff --git a/lib/std/mem.zig b/lib/std/mem.zig index cc03e5b2c5..4b34ad1238 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -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); } diff --git a/lib/std/mem/Allocator.zig b/lib/std/mem/Allocator.zig index db1ea978ea..caf049f296 100644 --- a/lib/std/mem/Allocator.zig +++ b/lib/std/mem/Allocator.zig @@ -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. diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 6236f1a56b..632c65678f 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -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), }; } diff --git a/lib/std/multi_array_list.zig b/lib/std/multi_array_list.zig index 92d094f0cc..fde7e93ed6 100644 --- a/lib/std/multi_array_list.zig +++ b/lib/std/multi_array_list.zig @@ -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 { diff --git a/lib/std/zon/parse.zig b/lib/std/zon/parse.zig index aaa6622762..a3b9fe4a56 100644 --- a/lib/std/zon/parse.zig +++ b/lib/std/zon/parse.zig @@ -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);