diff --git a/src/InternPool.zig b/src/InternPool.zig index 03eb5994d5..b7d79d6c29 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -536,6 +536,19 @@ pub const Key = union(enum) { s.flagsPtr(ip).layout_wip = false; } + pub fn setAlignmentWip(s: @This(), ip: *InternPool) bool { + if (s.layout == .Packed) return false; + const flags_ptr = s.flagsPtr(ip); + if (flags_ptr.alignment_wip) return true; + flags_ptr.alignment_wip = true; + return false; + } + + pub fn clearAlignmentWip(s: @This(), ip: *InternPool) void { + if (s.layout == .Packed) return; + s.flagsPtr(ip).alignment_wip = false; + } + pub fn setFullyResolved(s: @This(), ip: *InternPool) bool { if (s.layout == .Packed) return true; const flags_ptr = s.flagsPtr(ip); @@ -2971,6 +2984,8 @@ pub const Tag = enum(u8) { any_aligned_fields: bool, /// `undefined` until the layout_resolved alignment: Alignment, + /// Dependency loop detection when resolving struct alignment. + alignment_wip: bool, /// Dependency loop detection when resolving field types. field_types_wip: bool, /// Dependency loop detection when resolving struct layout. @@ -2982,7 +2997,7 @@ pub const Tag = enum(u8) { // which `layout_resolved` does not ensure. fully_resolved: bool, - _: u12 = 0, + _: u11 = 0, }; }; }; @@ -5300,6 +5315,7 @@ pub fn getStructType( .any_default_inits = ini.any_default_inits, .any_aligned_fields = ini.any_aligned_fields, .alignment = .none, + .alignment_wip = false, .field_types_wip = false, .layout_wip = false, .layout_resolved = false, diff --git a/src/Sema.zig b/src/Sema.zig index 93f9c0db63..827b145417 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -26698,21 +26698,25 @@ fn structFieldPtrByIndex( } } } else if (struct_type.layout == .Extern) { - // For extern structs, field aligment might be bigger than type's natural alignment. Eg, in - // `extern struct { x: u32, y: u16 }` the second field is aligned as u32. + // For extern structs, field alignment might be bigger than type's + // natural alignment. Eg, in `extern struct { x: u32, y: u16 }` the + // second field is aligned as u32. const field_offset = struct_ty.structFieldOffset(field_index, mod); ptr_ty_data.flags.alignment = if (parent_align == .none) .none else @enumFromInt(@min(@intFromEnum(parent_align), @ctz(field_offset))); } else { - // Our alignment is capped at the field alignment + // Our alignment is capped at the field alignment. const field_align = try sema.structFieldAlignment( struct_type.fieldAlign(ip, field_index), field_ty.toType(), struct_type.layout, ); - ptr_ty_data.flags.alignment = field_align.min(parent_align); + ptr_ty_data.flags.alignment = if (struct_ptr_ty_info.flags.alignment == .none) + field_align + else + field_align.min(parent_align); } const ptr_field_ty = try sema.ptrType(ptr_ty_data); @@ -28635,8 +28639,8 @@ const InMemoryCoercionResult = union(enum) { break; }, .ptr_alignment => |pair| { - try sema.errNote(block, src, msg, "pointer alignment '{}' cannot cast into pointer alignment '{}'", .{ - pair.actual, pair.wanted, + try sema.errNote(block, src, msg, "pointer alignment '{d}' cannot cast into pointer alignment '{d}'", .{ + pair.actual.toByteUnits(0), pair.wanted.toByteUnits(0), }); break; }, @@ -34307,20 +34311,29 @@ pub fn resolveStructAlignment( try sema.resolveTypeFieldsStruct(ty, struct_type); + if (struct_type.setAlignmentWip(ip)) { + // We'll guess "pointer-aligned", if the struct has an + // underaligned pointer field then some allocations + // might require explicit alignment. + //TODO write this bit and emit an error later if incorrect + //struct_type.flagsPtr(ip).assumed_pointer_aligned = true; + const result = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)); + struct_type.flagsPtr(ip).alignment = result; + return result; + } + var result: Alignment = .@"1"; for (0..struct_type.field_types.len) |i| { - if (struct_type.fieldIsComptime(ip, i)) continue; const field_ty = struct_type.field_types.get(ip)[i].toType(); - if (try sema.typeRequiresComptime(field_ty)) continue; - if (try sema.typeHasRuntimeBits(field_ty)) { - const field_align = try sema.structFieldAlignment( - struct_type.fieldAlign(ip, i), - field_ty, - struct_type.layout, - ); - result = result.max(field_align); - } + if (struct_type.fieldIsComptime(ip, i) or try sema.typeRequiresComptime(field_ty)) + continue; + const field_align = try sema.structFieldAlignment( + struct_type.fieldAlign(ip, i), + field_ty, + struct_type.layout, + ); + result = result.max(field_align); } struct_type.flagsPtr(ip).alignment = result; @@ -34358,7 +34371,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { for (aligns, sizes, 0..) |*field_align, *field_size, i| { const field_ty = struct_type.field_types.get(ip)[i].toType(); - if (struct_type.fieldIsComptime(ip, i) or !(try sema.typeHasRuntimeBits(field_ty))) { + if (struct_type.fieldIsComptime(ip, i) or try sema.typeRequiresComptime(field_ty)) { struct_type.offsets.get(ip)[i] = 0; field_size.* = 0; field_align.* = .none; @@ -34439,10 +34452,8 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { var offset: u64 = 0; var big_align: Alignment = .@"1"; while (it.next()) |i| { - const field_ty = struct_type.field_types.get(ip)[i].toType(); - // Type query definitely valid as we performed it earlier - if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; - big_align = big_align.max(aligns[i]); + if (aligns[i] == .none) continue; + big_align = big_align.maxStrict(aligns[i]); offsets[i] = @intCast(aligns[i].forward(offset)); offset = offsets[i] + sizes[i]; } @@ -36870,7 +36881,7 @@ fn structFieldAlignment( // extern const ty_abi_align = try sema.typeAbiAlignment(field_ty); if (field_ty.isAbiInt(mod) and field_ty.intInfo(mod).bits >= 128) { - return ty_abi_align.max(.@"16"); + return ty_abi_align.maxStrict(.@"16"); } return ty_abi_align; }