Commit baea62a8ad
Changed files (5)
src
src/codegen/c.zig
@@ -1310,21 +1310,21 @@ pub const DeclGen = struct {
try writer.writeByte('{');
var empty = true;
- const field_types = struct_type.field_types.get(ip);
- for (struct_type.runtime_order.get(ip)) |runtime_order| {
- const field_i = runtime_order.toInt() orelse break;
- const field_ty = field_types[field_i];
+ for (0..struct_type.field_types.len) |field_i| {
+ const field_ty = struct_type.field_types.get(ip)[field_i].toType();
+ if (struct_type.fieldIsComptime(ip, field_i)) continue;
+ if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
if (!empty) try writer.writeByte(',');
const field_val = switch (ip.indexToKey(val.ip_index).aggregate.storage) {
.bytes => |bytes| try ip.get(mod.gpa, .{ .int = .{
- .ty = field_ty,
+ .ty = field_ty.toIntern(),
.storage = .{ .u64 = bytes[field_i] },
} }),
.elems => |elems| elems[field_i],
.repeated_elem => |elem| elem,
};
- try dg.renderValue(writer, field_ty.toType(), field_val.toValue(), initializer_type);
+ try dg.renderValue(writer, field_ty, field_val.toValue(), initializer_type);
empty = false;
}
src/codegen/llvm.zig
@@ -2493,7 +2493,6 @@ pub const Object = struct {
const struct_type = mod.typeToStruct(ty).?;
const field_types = struct_type.field_types.get(ip);
- const field_names = struct_type.field_names.get(ip);
var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
defer di_fields.deinit(gpa);
@@ -2514,18 +2513,21 @@ pub const Object = struct {
const field_offset = field_align.forward(offset);
offset = field_offset + field_size;
- const field_name = ip.stringToSlice(field_names[field_index]);
+ const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse
+ try ip.getOrPutStringFmt(gpa, "{d}", .{field_index});
+
+ const field_di_ty = try o.lowerDebugType(field_ty, .full);
try di_fields.append(gpa, dib.createMemberType(
fwd_decl.toScope(),
- field_name,
+ ip.stringToSlice(field_name),
null, // file
0, // line
field_size * 8, // size in bits
field_align.toByteUnits(0) * 8, // align in bits
field_offset * 8, // offset in bits
0, // flags
- try o.lowerDebugType(field_ty, .full),
+ field_di_ty,
));
}
@@ -3301,13 +3303,11 @@ pub const Object = struct {
var offset: u64 = 0;
var big_align: InternPool.Alignment = .@"1";
var struct_kind: Builder.Type.Structure.Kind = .normal;
-
- for (struct_type.runtime_order.get(ip)) |runtime_index| {
- const field_index = runtime_index.toInt() orelse break;
+ var it = struct_type.iterateRuntimeOrder(ip);
+ while (it.next()) |field_index| {
const field_ty = struct_type.field_types.get(ip)[field_index].toType();
- const field_aligns = struct_type.field_aligns.get(ip);
const field_align = mod.structFieldAlignment(
- if (field_aligns.len == 0) .none else field_aligns[field_index],
+ struct_type.fieldAlign(ip, field_index),
field_ty,
struct_type.layout,
);
@@ -4012,7 +4012,7 @@ pub const Object = struct {
comptime assert(struct_layout_version == 2);
var llvm_index: usize = 0;
var offset: u64 = 0;
- var big_align: InternPool.Alignment = .none;
+ var big_align: InternPool.Alignment = .@"1";
var need_unnamed = false;
var field_it = struct_type.iterateRuntimeOrder(ip);
while (field_it.next()) |field_index| {
src/InternPool.zig
@@ -382,6 +382,7 @@ pub const Key = union(enum) {
pub const ComptimeBits = struct {
start: u32,
+ /// This is the number of u32 elements, not the number of struct fields.
len: u32,
pub fn get(this: @This(), ip: *const InternPool) []u32 {
@@ -505,12 +506,23 @@ pub const Key = union(enum) {
return false;
}
+ pub fn setTypesWip(s: @This(), ip: *InternPool) bool {
+ if (s.layout == .Packed) return false;
+ const flags_ptr = s.flagsPtr(ip);
+ if (flags_ptr.field_types_wip) return true;
+ flags_ptr.field_types_wip = true;
+ return false;
+ }
+
+ pub fn clearTypesWip(s: @This(), ip: *InternPool) void {
+ if (s.layout == .Packed) return;
+ s.flagsPtr(ip).field_types_wip = false;
+ }
+
pub fn setLayoutWip(s: @This(), ip: *InternPool) bool {
if (s.layout == .Packed) return false;
const flags_ptr = s.flagsPtr(ip);
- if (flags_ptr.field_types_wip or flags_ptr.layout_wip) {
- return true;
- }
+ if (flags_ptr.layout_wip) return true;
flags_ptr.layout_wip = true;
return false;
}
@@ -527,14 +539,6 @@ pub const Key = union(enum) {
s.flagsPtr(ip).fully_resolved = false;
}
- pub fn setRequiresComptime(s: @This(), ip: *InternPool) void {
- assert(s.layout != .Packed);
- const flags_ptr = s.flagsPtr(ip);
- // Layout is resolved (and non-existent) in the case of a comptime-known struct.
- flags_ptr.layout_resolved = true;
- flags_ptr.requires_comptime = .yes;
- }
-
/// The returned pointer expires with any addition to the `InternPool`.
/// Asserts the struct is not packed.
pub fn size(self: @This(), ip: *InternPool) *u32 {
@@ -567,7 +571,7 @@ pub const Key = union(enum) {
pub fn haveLayout(s: @This(), ip: *InternPool) bool {
return switch (s.layout) {
- .Packed => s.haveFieldTypes(ip),
+ .Packed => s.backingIntType(ip).* != .none,
.Auto, .Extern => s.flagsPtr(ip).layout_resolved,
};
}
@@ -3149,7 +3153,15 @@ pub const Alignment = enum(u6) {
return std.math.order(@intFromEnum(lhs), @intFromEnum(rhs));
}
+ /// Relaxed comparison. We have this as default because a lot of callsites
+ /// were upgraded from directly using comparison operators on byte units,
+ /// with the `none` value represented by zero.
+ /// Prefer `compareStrict` if possible.
pub fn compare(lhs: Alignment, op: std.math.CompareOperator, rhs: Alignment) bool {
+ return std.math.compare(lhs.toRelaxedCompareUnits(), op, rhs.toRelaxedCompareUnits());
+ }
+
+ pub fn compareStrict(lhs: Alignment, op: std.math.CompareOperator, rhs: Alignment) bool {
assert(lhs != .none);
assert(rhs != .none);
return std.math.compare(@intFromEnum(lhs), op, @intFromEnum(rhs));
@@ -3194,6 +3206,7 @@ pub const Alignment = enum(u6) {
/// not invalidated when items are added to the `InternPool`.
pub const Slice = struct {
start: u32,
+ /// This is the number of alignment values, not the number of u32 elements.
len: u32,
pub fn get(slice: Slice, ip: *const InternPool) []Alignment {
@@ -3204,6 +3217,13 @@ pub const Alignment = enum(u6) {
}
};
+ pub fn toRelaxedCompareUnits(a: Alignment) u8 {
+ const n: u8 = @intFromEnum(a);
+ assert(n <= @intFromEnum(Alignment.none));
+ if (n == @intFromEnum(Alignment.none)) return 0;
+ return n + 1;
+ }
+
const LlvmBuilderAlignment = @import("codegen/llvm/Builder.zig").Alignment;
pub fn toLlvm(this: @This()) LlvmBuilderAlignment {
@@ -4067,16 +4087,14 @@ fn extraStructType(ip: *const InternPool, extra_index: u32) Key.StructType {
};
const field_aligns: Alignment.Slice = t: {
if (!s.data.flags.any_aligned_fields) break :t .{ .start = 0, .len = 0 };
- const len = (fields_len + 3) / 4;
- const aligns: Alignment.Slice = .{ .start = index, .len = len };
- index += len;
+ const aligns: Alignment.Slice = .{ .start = index, .len = fields_len };
+ index += (fields_len + 3) / 4;
break :t aligns;
};
const comptime_bits: Key.StructType.ComptimeBits = t: {
if (!s.data.flags.any_comptime_fields) break :t .{ .start = 0, .len = 0 };
- const len = (fields_len + 31) / 32;
- const comptime_bits: Key.StructType.ComptimeBits = .{ .start = index, .len = len };
- index += len;
+ const comptime_bits: Key.StructType.ComptimeBits = .{ .start = index, .len = fields_len };
+ index += (fields_len + 31) / 32;
break :t comptime_bits;
};
const runtime_order: Key.StructType.RuntimeOrder.Slice = t: {
src/Sema.zig
@@ -17646,12 +17646,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len);
for (struct_field_vals, 0..) |*field_val, i| {
- const name_nts = struct_type.fieldName(ip, i).unwrap().?;
+ // TODO: write something like getCoercedInts to avoid needing to dupe
+ const name = if (struct_type.fieldName(ip, i).unwrap()) |name_nts|
+ try sema.arena.dupe(u8, ip.stringToSlice(name_nts))
+ else
+ try std.fmt.allocPrintZ(gpa, "{d}", .{i});
const field_ty = struct_type.field_types.get(ip)[i].toType();
const field_init = struct_type.fieldInit(ip, i);
const field_is_comptime = struct_type.fieldIsComptime(ip, i);
- // TODO: write something like getCoercedInts to avoid needing to dupe
- const name = try sema.arena.dupe(u8, ip.stringToSlice(name_nts));
const name_val = v: {
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
@@ -17676,11 +17678,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const opt_default_val = if (field_init == .none) null else field_init.toValue();
const default_val_ptr = try sema.optRefValue(block, field_ty, opt_default_val);
- const alignment = mod.structFieldAlignment(
- struct_type.field_aligns.get(ip)[i],
- field_ty,
- struct_type.layout,
- );
+ const alignment = switch (struct_type.layout) {
+ .Packed => .none,
+ else => try sema.structFieldAlignment(
+ struct_type.fieldAlign(ip, i),
+ field_ty,
+ struct_type.layout,
+ ),
+ };
const struct_field_fields = .{
// name: []const u8,
@@ -19291,7 +19296,7 @@ fn finishStructInit(
for (0..struct_type.field_types.len) |i| {
if (field_inits[i] != .none) continue;
- const field_init = struct_type.field_inits.get(ip)[i];
+ const field_init = struct_type.fieldInit(ip, i);
if (field_init == .none) {
const field_name = struct_type.field_names.get(ip)[i];
const template = "missing struct field: {}";
@@ -20995,9 +21000,10 @@ fn reifyStruct(
.fields_len = fields_len,
.requires_comptime = .unknown,
.is_tuple = is_tuple,
- // So that we don't have to scan ahead, we allocate space in the struct for
- // alignments, comptime fields, and default inits. This might result in wasted
- // space, however, this is a permitted encoding of struct types.
+ // So that we don't have to scan ahead, we allocate space in the struct
+ // type for alignments, comptime fields, and default inits. This might
+ // result in wasted space, however, this is a permitted encoding of
+ // struct types.
.any_comptime_fields = true,
.any_default_inits = true,
.any_aligned_fields = true,
@@ -21042,6 +21048,8 @@ fn reifyStruct(
if (layout == .Packed) {
if (abi_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{});
if (is_comptime_val.toBool()) return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{});
+ } else {
+ struct_type.field_aligns.get(ip)[i] = Alignment.fromByteUnits(abi_align);
}
if (layout == .Extern and is_comptime_val.toBool()) {
return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{});
@@ -21065,8 +21073,7 @@ fn reifyStruct(
.{field_index},
);
}
- }
- if (struct_type.addFieldName(ip, field_name)) |prev_index| {
+ } else if (struct_type.addFieldName(ip, field_name)) |prev_index| {
_ = prev_index; // TODO: better source location
return sema.fail(block, src, "duplicate struct field {}", .{field_name.fmt(ip)});
}
@@ -21084,7 +21091,6 @@ fn reifyStruct(
}
struct_type.field_types.get(ip)[i] = field_ty.toIntern();
- struct_type.field_aligns.get(ip)[i] = Alignment.fromByteUnits(abi_align);
struct_type.field_inits.get(ip)[i] = default_val;
if (is_comptime_val.toBool())
struct_type.setFieldComptime(ip, i);
@@ -23772,7 +23778,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
} else {
ptr_ty_data.flags.alignment = blk: {
if (mod.typeToStruct(parent_ty)) |struct_type| {
- break :blk struct_type.field_aligns.get(ip)[field_index];
+ break :blk struct_type.fieldAlign(ip, field_index);
} else if (mod.typeToUnion(parent_ty)) |union_obj| {
break :blk union_obj.fieldAlign(ip, field_index);
} else {
@@ -26670,7 +26676,7 @@ fn structFieldPtrByIndex(
if (parent_align != .none and ptr_ty_data.packed_offset.bit_offset % 8 == 0 and
target.cpu.arch.endian() == .Little)
{
- const elem_size_bytes = ptr_ty_data.child.toType().abiSize(mod);
+ const elem_size_bytes = try sema.typeAbiSize(ptr_ty_data.child.toType());
const elem_size_bits = ptr_ty_data.child.toType().bitSize(mod);
if (elem_size_bytes * 8 == elem_size_bits) {
const byte_offset = ptr_ty_data.packed_offset.bit_offset / 8;
@@ -26691,7 +26697,7 @@ fn structFieldPtrByIndex(
} else {
// Our alignment is capped at the field alignment
const field_align = try sema.structFieldAlignment(
- struct_type.field_aligns.get(ip)[field_index],
+ struct_type.fieldAlign(ip, field_index),
field_ty.toType(),
struct_type.layout,
);
@@ -26700,7 +26706,7 @@ fn structFieldPtrByIndex(
const ptr_field_ty = try mod.ptrType(ptr_ty_data);
- if (struct_type.comptime_bits.getBit(ip, field_index)) {
+ if (struct_type.fieldIsComptime(ip, field_index)) {
const val = try mod.intern(.{ .ptr = .{
.ty = ptr_field_ty.toIntern(),
.addr = .{ .comptime_field = struct_type.field_inits.get(ip)[field_index] },
@@ -26744,7 +26750,7 @@ fn structFieldVal(
const field_index = struct_type.nameIndex(ip, field_name) orelse
return sema.failWithBadStructFieldAccess(block, struct_type, field_name_src, field_name);
- if (struct_type.comptime_bits.getBit(ip, field_index)) {
+ if (struct_type.fieldIsComptime(ip, field_index)) {
return Air.internedToRef(struct_type.field_inits.get(ip)[field_index]);
}
@@ -29199,12 +29205,12 @@ fn coerceInMemoryAllowedPtrs(
const src_align = if (src_info.flags.alignment != .none)
src_info.flags.alignment
else
- src_info.child.toType().abiAlignment(mod);
+ try sema.typeAbiAlignment(src_info.child.toType());
const dest_align = if (dest_info.flags.alignment != .none)
dest_info.flags.alignment
else
- dest_info.child.toType().abiAlignment(mod);
+ try sema.typeAbiAlignment(dest_info.child.toType());
if (dest_align.compare(.gt, src_align)) {
return InMemoryCoercionResult{ .ptr_alignment = .{
@@ -30969,7 +30975,7 @@ fn coerceTupleToStruct(
const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i);
const coerced = try sema.coerce(block, field_ty, elem_ref, field_src);
field_refs[field_index] = coerced;
- if (struct_type.comptime_bits.getBit(ip, field_index)) {
+ if (struct_type.fieldIsComptime(ip, field_index)) {
const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {
return sema.failWithNeededComptime(block, field_src, .{
.needed_comptime_reason = "value stored in comptime field must be comptime-known",
@@ -30998,7 +31004,7 @@ fn coerceTupleToStruct(
if (field_ref.* != .none) continue;
const field_name = struct_type.field_names.get(ip)[i];
- const field_default_val = struct_type.field_inits.get(ip)[i];
+ const field_default_val = struct_type.fieldInit(ip, i);
const field_src = inst_src; // TODO better source location
if (field_default_val == .none) {
const template = "missing struct field: {}";
@@ -31088,7 +31094,7 @@ fn coerceTupleToTuple(
};
const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
.anon_struct_type => |anon_struct_type| anon_struct_type.values.get(ip)[field_index_usize],
- .struct_type => |struct_type| struct_type.field_inits.get(ip)[field_index_usize],
+ .struct_type => |struct_type| struct_type.fieldInit(ip, field_index_usize),
else => unreachable,
};
@@ -31126,7 +31132,7 @@ fn coerceTupleToTuple(
const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
.anon_struct_type => |anon_struct_type| anon_struct_type.values.get(ip)[i],
- .struct_type => |struct_type| struct_type.field_inits.get(ip)[i],
+ .struct_type => |struct_type| struct_type.fieldInit(ip, i),
else => unreachable,
};
@@ -33332,12 +33338,12 @@ fn resolvePeerTypesInner(
if (ptr_info.flags.alignment != .none)
ptr_info.flags.alignment
else
- ptr_info.child.toType().abiAlignment(mod),
+ try sema.typeAbiAlignment(ptr_info.child.toType()),
if (peer_info.flags.alignment != .none)
peer_info.flags.alignment
else
- peer_info.child.toType().abiAlignment(mod),
+ try sema.typeAbiAlignment(peer_info.child.toType()),
);
if (ptr_info.flags.address_space != peer_info.flags.address_space) {
@@ -34288,14 +34294,16 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
return sema.failWithOwnedErrorMsg(null, msg);
}
- if (try sema.typeRequiresComptime(ty))
- return;
-
const aligns = try sema.arena.alloc(Alignment, struct_type.field_types.len);
const sizes = try sema.arena.alloc(u64, struct_type.field_types.len);
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))) {
+ field_size.* = 0;
+ field_align.* = .none;
+ continue;
+ }
field_size.* = sema.typeAbiSize(field_ty) catch |err| switch (err) {
error.AnalysisFail => {
const msg = sema.err orelse return err;
@@ -34322,7 +34330,9 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
}
if (struct_type.hasReorderedFields()) {
- for (sizes, struct_type.runtime_order.get(ip), 0..) |size, *ro, i| {
+ const runtime_order = struct_type.runtime_order.get(ip);
+
+ for (sizes, runtime_order, 0..) |size, *ro, i| {
ro.* = if (size != 0) @enumFromInt(i) else .omitted;
}
@@ -34339,7 +34349,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
return a_align.compare(.gt, b_align);
}
};
- mem.sortUnstable(RuntimeOrder, struct_type.runtime_order.get(ip), AlignSortContext{
+ mem.sortUnstable(RuntimeOrder, runtime_order, AlignSortContext{
.aligns = aligns,
}, AlignSortContext.lessThan);
}
@@ -34348,7 +34358,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
const offsets = struct_type.offsets.get(ip);
var it = struct_type.iterateRuntimeOrder(ip);
var offset: u64 = 0;
- var big_align: Alignment = .none;
+ var big_align: Alignment = .@"1";
while (it.next()) |i| {
big_align = big_align.max(aligns[i]);
offsets[i] = @intCast(aligns[i].forward(offset));
@@ -34358,22 +34368,61 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
const flags = struct_type.flagsPtr(ip);
flags.alignment = big_align;
flags.layout_resolved = true;
+ _ = try sema.typeRequiresComptime(ty);
}
fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) CompileError!void {
const gpa = mod.gpa;
const ip = &mod.intern_pool;
- var fields_bit_sum: u64 = 0;
- for (0..struct_type.field_types.len) |i| {
- const field_ty = struct_type.field_types.get(ip)[i].toType();
- fields_bit_sum += field_ty.bitSize(mod);
- }
-
const decl_index = struct_type.decl.unwrap().?;
const decl = mod.declPtr(decl_index);
const zir = mod.namespacePtr(struct_type.namespace.unwrap().?).file_scope.zir;
+
+ var analysis_arena = std.heap.ArenaAllocator.init(gpa);
+ defer analysis_arena.deinit();
+
+ var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
+ defer comptime_mutable_decls.deinit();
+
+ var sema: Sema = .{
+ .mod = mod,
+ .gpa = gpa,
+ .arena = analysis_arena.allocator(),
+ .code = zir,
+ .owner_decl = decl,
+ .owner_decl_index = decl_index,
+ .func_index = .none,
+ .func_is_naked = false,
+ .fn_ret_ty = Type.void,
+ .fn_ret_ty_ies = null,
+ .owner_func_index = .none,
+ .comptime_mutable_decls = &comptime_mutable_decls,
+ };
+ defer sema.deinit();
+
+ var block: Block = .{
+ .parent = null,
+ .sema = &sema,
+ .src_decl = decl_index,
+ .namespace = struct_type.namespace.unwrap() orelse decl.src_namespace,
+ .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
+ .instructions = .{},
+ .inlining = null,
+ .is_comptime = true,
+ };
+ defer assert(block.instructions.items.len == 0);
+
+ const fields_bit_sum = blk: {
+ var accumulator: u64 = 0;
+ for (0..struct_type.field_types.len) |i| {
+ const field_ty = struct_type.field_types.get(ip)[i].toType();
+ accumulator += try field_ty.bitSizeAdvanced(mod, &sema);
+ }
+ break :blk accumulator;
+ };
+
const extended = zir.instructions.items(.data)[struct_type.zir_index].extended;
assert(extended.opcode == .struct_decl);
const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
@@ -34387,40 +34436,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp
const backing_int_body_len = zir.extra[extra_index];
extra_index += 1;
- var analysis_arena = std.heap.ArenaAllocator.init(gpa);
- defer analysis_arena.deinit();
-
- var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
- defer comptime_mutable_decls.deinit();
-
- var sema: Sema = .{
- .mod = mod,
- .gpa = gpa,
- .arena = analysis_arena.allocator(),
- .code = zir,
- .owner_decl = decl,
- .owner_decl_index = decl_index,
- .func_index = .none,
- .func_is_naked = false,
- .fn_ret_ty = Type.void,
- .fn_ret_ty_ies = null,
- .owner_func_index = .none,
- .comptime_mutable_decls = &comptime_mutable_decls,
- };
- defer sema.deinit();
-
- var block: Block = .{
- .parent = null,
- .sema = &sema,
- .src_decl = decl_index,
- .namespace = struct_type.namespace.unwrap() orelse decl.src_namespace,
- .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
- .instructions = .{},
- .inlining = null,
- .is_comptime = true,
- };
- defer assert(block.instructions.items.len == 0);
-
const backing_int_src: LazySrcLoc = .{ .node_offset_container_tag = 0 };
const backing_int_ty = blk: {
if (backing_int_body_len == 0) {
@@ -34435,44 +34450,18 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp
try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum);
struct_type.backingIntType(ip).* = backing_int_ty.toIntern();
- for (comptime_mutable_decls.items) |ct_decl_index| {
- const ct_decl = mod.declPtr(ct_decl_index);
- _ = try ct_decl.internValue(mod);
- }
} else {
if (fields_bit_sum > std.math.maxInt(u16)) {
- var sema: Sema = .{
- .mod = mod,
- .gpa = gpa,
- .arena = undefined,
- .code = zir,
- .owner_decl = decl,
- .owner_decl_index = decl_index,
- .func_index = .none,
- .func_is_naked = false,
- .fn_ret_ty = Type.void,
- .fn_ret_ty_ies = null,
- .owner_func_index = .none,
- .comptime_mutable_decls = undefined,
- };
- defer sema.deinit();
-
- var block: Block = .{
- .parent = null,
- .sema = &sema,
- .src_decl = decl_index,
- .namespace = struct_type.namespace.unwrap() orelse
- mod.declPtr(struct_type.decl.unwrap().?).src_namespace,
- .wip_capture_scope = undefined,
- .instructions = .{},
- .inlining = null,
- .is_comptime = true,
- };
return sema.fail(&block, LazySrcLoc.nodeOffset(0), "size of packed struct '{d}' exceeds maximum bit width of 65535", .{fields_bit_sum});
}
const backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum));
struct_type.backingIntType(ip).* = backing_int_ty.toIntern();
}
+
+ for (comptime_mutable_decls.items) |ct_decl_index| {
+ const ct_decl = mod.declPtr(ct_decl_index);
+ _ = try ct_decl.internValue(mod);
+ }
}
fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void {
@@ -34813,10 +34802,9 @@ fn resolveTypeFieldsStruct(
else => {},
}
- if (struct_type.haveFieldTypes(ip))
- return;
+ if (struct_type.haveFieldTypes(ip)) return;
- if (struct_type.flagsPtr(ip).field_types_wip) {
+ if (struct_type.setTypesWip(ip)) {
const msg = try Module.ErrorMsg.create(
sema.gpa,
mod.declPtr(owner_decl).srcLoc(mod),
@@ -34825,9 +34813,7 @@ fn resolveTypeFieldsStruct(
);
return sema.failWithOwnedErrorMsg(null, msg);
}
-
- struct_type.flagsPtr(ip).field_types_wip = true;
- errdefer struct_type.flagsPtr(ip).field_types_wip = false;
+ errdefer struct_type.clearTypesWip(ip);
try semaStructFields(mod, sema.arena, struct_type);
}
@@ -36175,7 +36161,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
struct_type.field_types.len,
);
for (field_vals, 0..) |*field_val, i| {
- if (struct_type.comptime_bits.getBit(ip, i)) {
+ if (struct_type.fieldIsComptime(ip, i)) {
field_val.* = struct_type.field_inits.get(ip)[i];
continue;
}
@@ -36679,7 +36665,11 @@ pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
if (struct_type.fieldIsComptime(ip, i)) continue;
const field_ty = struct_type.field_types.get(ip)[i];
if (try sema.typeRequiresComptime(field_ty.toType())) {
- struct_type.setRequiresComptime(ip);
+ // Note that this does not cause the layout to
+ // be considered resolved. Comptime-only types
+ // still maintain a layout of their
+ // runtime-known fields.
+ struct_type.flagsPtr(ip).requires_comptime = .yes;
return true;
}
}
src/type.zig
@@ -843,7 +843,7 @@ pub const Type = struct {
pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value {
switch (try ty.abiAlignmentAdvanced(mod, .lazy)) {
.val => |val| return val,
- .scalar => |x| return mod.intValue(Type.comptime_int, x.toByteUnitsOptional().?),
+ .scalar => |x| return mod.intValue(Type.comptime_int, x.toByteUnits(0)),
}
}
@@ -997,8 +997,7 @@ pub const Type = struct {
}
const flags = struct_type.flagsPtr(ip).*;
- if (flags.layout_resolved)
- return .{ .scalar = flags.alignment };
+ if (flags.layout_resolved) return .{ .scalar = flags.alignment };
switch (strat) {
.eager => unreachable, // struct layout not resolved
@@ -1423,20 +1422,12 @@ pub const Type = struct {
},
.eager => {},
}
- switch (struct_type.layout) {
- .Packed => {
- return .{
- .scalar = struct_type.backingIntType(ip).toType().abiSize(mod),
- };
- },
- .Auto, .Extern => {
- const field_count = ty.structFieldCount(mod);
- if (field_count == 0) {
- return .{ .scalar = 0 };
- }
- return .{ .scalar = ty.structFieldOffset(field_count, mod) };
+ return switch (struct_type.layout) {
+ .Packed => .{
+ .scalar = struct_type.backingIntType(ip).toType().abiSize(mod),
},
- }
+ .Auto, .Extern => .{ .scalar = struct_type.size(ip).* },
+ };
},
.anon_struct_type => |tuple| {
switch (strat) {
@@ -1655,19 +1646,19 @@ pub const Type = struct {
},
.struct_type => |struct_type| {
if (struct_type.layout == .Packed) {
- if (opt_sema) |sema| _ = try sema.resolveTypeLayout(ty);
+ if (opt_sema) |sema| try sema.resolveTypeLayout(ty);
return try struct_type.backingIntType(ip).*.toType().bitSizeAdvanced(mod, opt_sema);
}
return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
},
.anon_struct_type => {
- if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty);
+ if (opt_sema) |sema| try sema.resolveTypeFields(ty);
return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
},
.union_type => |union_type| {
- if (opt_sema) |sema| _ = try sema.resolveTypeFields(ty);
+ if (opt_sema) |sema| try sema.resolveTypeFields(ty);
if (ty.containerLayout(mod) != .Packed) {
return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
}
@@ -2091,6 +2082,7 @@ pub const Type = struct {
return switch (ip.indexToKey(ty.toIntern())) {
.vector_type => |vector_type| vector_type.len,
.array_type => |array_type| array_type.len,
+ .struct_type => |struct_type| struct_type.field_types.len,
.anon_struct_type => |tuple| tuple.types.len,
else => unreachable,
@@ -2964,7 +2956,7 @@ pub const Type = struct {
switch (ip.indexToKey(ty.toIntern())) {
.struct_type => |struct_type| {
assert(struct_type.layout != .Packed);
- const explicit_align = struct_type.field_aligns.get(ip)[index];
+ const explicit_align = struct_type.fieldAlign(ip, index);
const field_ty = struct_type.field_types.get(ip)[index].toType();
return mod.structFieldAlignment(explicit_align, field_ty, struct_type.layout);
},
@@ -2983,7 +2975,7 @@ pub const Type = struct {
const ip = &mod.intern_pool;
switch (ip.indexToKey(ty.toIntern())) {
.struct_type => |struct_type| {
- const val = struct_type.field_inits.get(ip)[index];
+ const val = struct_type.fieldInit(ip, index);
// TODO: avoid using `unreachable` to indicate this.
if (val == .none) return Value.@"unreachable";
return val.toValue();
@@ -3002,7 +2994,7 @@ pub const Type = struct {
const ip = &mod.intern_pool;
switch (ip.indexToKey(ty.toIntern())) {
.struct_type => |struct_type| {
- if (struct_type.comptime_bits.getBit(ip, index)) {
+ if (struct_type.fieldIsComptime(ip, index)) {
return struct_type.field_inits.get(ip)[index].toValue();
} else {
return struct_type.field_types.get(ip)[index].toType().onePossibleValue(mod);