Skip to content

Commit c80aa9f

Browse files
authored
Merge pull request #22997 from Rexicon226/align-0-reify
sema: compile error on reifying align(0) fields and pointers
2 parents 616e69c + e82d672 commit c80aa9f

15 files changed

+147
-129
lines changed

lib/compiler/aro/aro/Attribute.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,7 @@ pub const Arguments = blk: {
708708
field.* = .{
709709
.name = decl.name,
710710
.type = @field(attributes, decl.name),
711-
.alignment = 0,
711+
.alignment = @alignOf(@field(attributes, decl.name)),
712712
};
713713
}
714714

lib/std/meta.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -939,7 +939,7 @@ fn CreateUniqueTuple(comptime N: comptime_int, comptime types: [N]type) type {
939939
.type = T,
940940
.default_value_ptr = null,
941941
.is_comptime = false,
942-
.alignment = 0,
942+
.alignment = @alignOf(T),
943943
};
944944
}
945945

lib/std/zig/AstGen.zig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5386,6 +5386,9 @@ fn unionDeclInner(
53865386
return astgen.failNode(member_node, "union field missing type", .{});
53875387
}
53885388
if (member.ast.align_expr.unwrap()) |align_expr| {
5389+
if (layout == .@"packed") {
5390+
return astgen.failNode(align_expr, "unable to override alignment of packed union fields", .{});
5391+
}
53895392
const align_inst = try expr(&block_scope, &block_scope.base, coerced_align_ri, align_expr);
53905393
wip_members.appendToField(@intFromEnum(align_inst));
53915394
any_aligned_fields = true;

lib/std/zig/llvm/Builder.zig

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8533,18 +8533,19 @@ pub const Metadata = enum(u32) {
85338533
.type = []const u8,
85348534
.default_value_ptr = null,
85358535
.is_comptime = false,
8536-
.alignment = 0,
8536+
.alignment = @alignOf([]const u8),
85378537
};
85388538
}
85398539
fmt_str = fmt_str ++ "(";
85408540
inline for (fields[2..], names) |*field, name| {
85418541
fmt_str = fmt_str ++ "{[" ++ name ++ "]f}";
8542+
const T = std.fmt.Formatter(FormatData, format);
85428543
field.* = .{
85438544
.name = name,
8544-
.type = std.fmt.Formatter(FormatData, format),
8545+
.type = T,
85458546
.default_value_ptr = null,
85468547
.is_comptime = false,
8547-
.alignment = 0,
8548+
.alignment = @alignOf(T),
85488549
};
85498550
}
85508551
fmt_str = fmt_str ++ ")\n";

src/InternPool.zig

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,13 +1137,16 @@ const Local = struct {
11371137
const elem_info = @typeInfo(Elem).@"struct";
11381138
const elem_fields = elem_info.fields;
11391139
var new_fields: [elem_fields.len]std.builtin.Type.StructField = undefined;
1140-
for (&new_fields, elem_fields) |*new_field, elem_field| new_field.* = .{
1141-
.name = elem_field.name,
1142-
.type = *[len]elem_field.type,
1143-
.default_value_ptr = null,
1144-
.is_comptime = false,
1145-
.alignment = 0,
1146-
};
1140+
for (&new_fields, elem_fields) |*new_field, elem_field| {
1141+
const T = *[len]elem_field.type;
1142+
new_field.* = .{
1143+
.name = elem_field.name,
1144+
.type = T,
1145+
.default_value_ptr = null,
1146+
.is_comptime = false,
1147+
.alignment = @alignOf(T),
1148+
};
1149+
}
11471150
return @Type(.{ .@"struct" = .{
11481151
.layout = .auto,
11491152
.fields = &new_fields,
@@ -1158,22 +1161,25 @@ const Local = struct {
11581161
const elem_info = @typeInfo(Elem).@"struct";
11591162
const elem_fields = elem_info.fields;
11601163
var new_fields: [elem_fields.len]std.builtin.Type.StructField = undefined;
1161-
for (&new_fields, elem_fields) |*new_field, elem_field| new_field.* = .{
1162-
.name = elem_field.name,
1163-
.type = @Type(.{ .pointer = .{
1164+
for (&new_fields, elem_fields) |*new_field, elem_field| {
1165+
const T = @Type(.{ .pointer = .{
11641166
.size = opts.size,
11651167
.is_const = opts.is_const,
11661168
.is_volatile = false,
1167-
.alignment = 0,
1169+
.alignment = @alignOf(elem_field.type),
11681170
.address_space = .generic,
11691171
.child = elem_field.type,
11701172
.is_allowzero = false,
11711173
.sentinel_ptr = null,
1172-
} }),
1173-
.default_value_ptr = null,
1174-
.is_comptime = false,
1175-
.alignment = 0,
1176-
};
1174+
} });
1175+
new_field.* = .{
1176+
.name = elem_field.name,
1177+
.type = T,
1178+
.default_value_ptr = null,
1179+
.is_comptime = false,
1180+
.alignment = @alignOf(T),
1181+
};
1182+
}
11771183
return @Type(.{ .@"struct" = .{
11781184
.layout = .auto,
11791185
.fields = &new_fields,

src/Sema.zig

Lines changed: 39 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2649,7 +2649,13 @@ pub fn analyzeAsAlign(
26492649
src: LazySrcLoc,
26502650
air_ref: Air.Inst.Ref,
26512651
) !Alignment {
2652-
const alignment_big = try sema.analyzeAsInt(block, src, air_ref, align_ty, .{ .simple = .@"align" });
2652+
const alignment_big = try sema.analyzeAsInt(
2653+
block,
2654+
src,
2655+
air_ref,
2656+
align_ty,
2657+
.{ .simple = .@"align" },
2658+
);
26532659
return sema.validateAlign(block, src, alignment_big);
26542660
}
26552661

@@ -18817,7 +18823,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1881718823
const abi_align: Alignment = if (inst_data.flags.has_align) blk: {
1881818824
const ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_i]);
1881918825
extra_i += 1;
18820-
const coerced = try sema.coerce(block, .u32, try sema.resolveInst(ref), align_src);
18826+
const coerced = try sema.coerce(block, align_ty, try sema.resolveInst(ref), align_src);
1882118827
const val = try sema.resolveConstDefinedValue(block, align_src, coerced, .{ .simple = .@"align" });
1882218828
// Check if this happens to be the lazy alignment of our element type, in
1882318829
// which case we can make this 0 without resolving it.
@@ -20335,15 +20341,11 @@ fn zirReify(
2033520341
try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls),
2033620342
).?);
2033720343

20338-
if (!try sema.intFitsInType(alignment_val, .u32, null)) {
20339-
return sema.fail(block, src, "alignment must fit in 'u32'", .{});
20344+
if (!try sema.intFitsInType(alignment_val, align_ty, null)) {
20345+
return sema.fail(block, src, "alignment must fit in '{f}'", .{align_ty.fmt(pt)});
2034020346
}
20341-
2034220347
const alignment_val_int = try alignment_val.toUnsignedIntSema(pt);
20343-
if (alignment_val_int > 0 and !math.isPowerOfTwo(alignment_val_int)) {
20344-
return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{alignment_val_int});
20345-
}
20346-
const abi_align = Alignment.fromByteUnits(alignment_val_int);
20348+
const abi_align = try sema.validateAlign(block, src, alignment_val_int);
2034720349

2034820350
const elem_ty = child_val.toType();
2034920351
if (abi_align != .none) {
@@ -20920,8 +20922,6 @@ fn reifyUnion(
2092020922
std.hash.autoHash(&hasher, opt_tag_type_val.toIntern());
2092120923
std.hash.autoHash(&hasher, fields_len);
2092220924

20923-
var any_aligns = false;
20924-
2092520925
for (0..fields_len) |field_idx| {
2092620926
const field_info = try fields_val.elemValue(pt, field_idx);
2092720927

@@ -20930,16 +20930,11 @@ fn reifyUnion(
2093020930
const field_align_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 2));
2093120931

2093220932
const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .union_field_name });
20933-
2093420933
std.hash.autoHash(&hasher, .{
2093520934
field_name,
2093620935
field_type_val.toIntern(),
2093720936
field_align_val.toIntern(),
2093820937
});
20939-
20940-
if (field_align_val.toUnsignedInt(zcu) != 0) {
20941-
any_aligns = true;
20942-
}
2094320938
}
2094420939

2094520940
const tracked_inst = try block.trackZir(inst);
@@ -20956,7 +20951,7 @@ fn reifyUnion(
2095620951
true => .safety,
2095720952
false => .none,
2095820953
},
20959-
.any_aligned_fields = any_aligns,
20954+
.any_aligned_fields = layout != .@"packed",
2096020955
.requires_comptime = .unknown,
2096120956
.assumed_runtime_bits = false,
2096220957
.assumed_pointer_aligned = false,
@@ -20989,8 +20984,7 @@ fn reifyUnion(
2098920984
);
2099020985
wip_ty.setName(ip, type_name.name, type_name.nav);
2099120986

20992-
const field_types = try sema.arena.alloc(InternPool.Index, fields_len);
20993-
const field_aligns = if (any_aligns) try sema.arena.alloc(InternPool.Alignment, fields_len) else undefined;
20987+
const loaded_union = ip.loadUnionType(wip_ty.index);
2099420988

2099520989
const enum_tag_ty, const has_explicit_tag = if (opt_tag_type_val.optionalValue(zcu)) |tag_type_val| tag_ty: {
2099620990
switch (ip.indexToKey(tag_type_val.toIntern())) {
@@ -21003,11 +20997,12 @@ fn reifyUnion(
2100320997
const tag_ty_fields_len = enum_tag_ty.enumFieldCount(zcu);
2100420998
var seen_tags = try std.DynamicBitSetUnmanaged.initEmpty(sema.arena, tag_ty_fields_len);
2100520999

21006-
for (field_types, 0..) |*field_ty, field_idx| {
21000+
for (0..fields_len) |field_idx| {
2100721001
const field_info = try fields_val.elemValue(pt, field_idx);
2100821002

2100921003
const field_name_val = try field_info.fieldValue(pt, 0);
2101021004
const field_type_val = try field_info.fieldValue(pt, 1);
21005+
const field_alignment_val = try field_info.fieldValue(pt, 2);
2101121006

2101221007
// Don't pass a reason; first loop acts as an assertion that this is valid.
2101321008
const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined);
@@ -21024,14 +21019,12 @@ fn reifyUnion(
2102421019
}
2102521020
seen_tags.set(enum_index);
2102621021

21027-
field_ty.* = field_type_val.toIntern();
21028-
if (any_aligns) {
21029-
const byte_align = try (try field_info.fieldValue(pt, 2)).toUnsignedIntSema(pt);
21030-
if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) {
21031-
// TODO: better source location
21032-
return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});
21033-
}
21034-
field_aligns[field_idx] = Alignment.fromByteUnits(byte_align);
21022+
loaded_union.field_types.get(ip)[field_idx] = field_type_val.toIntern();
21023+
const byte_align = try field_alignment_val.toUnsignedIntSema(pt);
21024+
if (layout == .@"packed") {
21025+
if (byte_align != 0) return sema.fail(block, src, "alignment of a packed union field must be set to 0", .{});
21026+
} else {
21027+
loaded_union.field_aligns.get(ip)[field_idx] = try sema.validateAlign(block, src, byte_align);
2103521028
}
2103621029
}
2103721030

@@ -21055,11 +21048,12 @@ fn reifyUnion(
2105521048
var field_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .empty;
2105621049
try field_names.ensureTotalCapacity(sema.arena, fields_len);
2105721050

21058-
for (field_types, 0..) |*field_ty, field_idx| {
21051+
for (0..fields_len) |field_idx| {
2105921052
const field_info = try fields_val.elemValue(pt, field_idx);
2106021053

2106121054
const field_name_val = try field_info.fieldValue(pt, 0);
2106221055
const field_type_val = try field_info.fieldValue(pt, 1);
21056+
const field_alignment_val = try field_info.fieldValue(pt, 2);
2106321057

2106421058
// Don't pass a reason; first loop acts as an assertion that this is valid.
2106521059
const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined);
@@ -21069,14 +21063,12 @@ fn reifyUnion(
2106921063
return sema.fail(block, src, "duplicate union field {f}", .{field_name.fmt(ip)});
2107021064
}
2107121065

21072-
field_ty.* = field_type_val.toIntern();
21073-
if (any_aligns) {
21074-
const byte_align = try (try field_info.fieldValue(pt, 2)).toUnsignedIntSema(pt);
21075-
if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) {
21076-
// TODO: better source location
21077-
return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});
21078-
}
21079-
field_aligns[field_idx] = Alignment.fromByteUnits(byte_align);
21066+
loaded_union.field_types.get(ip)[field_idx] = field_type_val.toIntern();
21067+
const byte_align = try field_alignment_val.toUnsignedIntSema(pt);
21068+
if (layout == .@"packed") {
21069+
if (byte_align != 0) return sema.fail(block, src, "alignment of a packed union field must be set to 0", .{});
21070+
} else {
21071+
loaded_union.field_aligns.get(ip)[field_idx] = try sema.validateAlign(block, src, byte_align);
2108021072
}
2108121073
}
2108221074

@@ -21085,7 +21077,7 @@ fn reifyUnion(
2108521077
};
2108621078
errdefer if (!has_explicit_tag) ip.remove(pt.tid, enum_tag_ty); // remove generated tag type on error
2108721079

21088-
for (field_types) |field_ty_ip| {
21080+
for (loaded_union.field_types.get(ip)) |field_ty_ip| {
2108921081
const field_ty: Type = .fromInterned(field_ty_ip);
2109021082
if (field_ty.zigTypeTag(zcu) == .@"opaque") {
2109121083
return sema.failWithOwnedErrorMsg(block, msg: {
@@ -21119,11 +21111,6 @@ fn reifyUnion(
2111921111
}
2112021112
}
2112121113

21122-
const loaded_union = ip.loadUnionType(wip_ty.index);
21123-
loaded_union.setFieldTypes(ip, field_types);
21124-
if (any_aligns) {
21125-
loaded_union.setFieldAligns(ip, field_aligns);
21126-
}
2112721114
loaded_union.setTagType(ip, enum_tag_ty);
2112821115
loaded_union.setStatus(ip, .have_field_types);
2112921116

@@ -21276,7 +21263,6 @@ fn reifyStruct(
2127621263

2127721264
var any_comptime_fields = false;
2127821265
var any_default_inits = false;
21279-
var any_aligned_fields = false;
2128021266

2128121267
for (0..fields_len) |field_idx| {
2128221268
const field_info = try fields_val.elemValue(pt, field_idx);
@@ -21311,11 +21297,6 @@ fn reifyStruct(
2131121297

2131221298
if (field_is_comptime) any_comptime_fields = true;
2131321299
if (field_default_value != .none) any_default_inits = true;
21314-
switch (try field_alignment_val.orderAgainstZeroSema(pt)) {
21315-
.eq => {},
21316-
.gt => any_aligned_fields = true,
21317-
.lt => unreachable,
21318-
}
2131921300
}
2132021301

2132121302
const tracked_inst = try block.trackZir(inst);
@@ -21327,7 +21308,7 @@ fn reifyStruct(
2132721308
.requires_comptime = .unknown,
2132821309
.any_comptime_fields = any_comptime_fields,
2132921310
.any_default_inits = any_default_inits,
21330-
.any_aligned_fields = any_aligned_fields,
21311+
.any_aligned_fields = layout != .@"packed",
2133121312
.inits_resolved = true,
2133221313
.key = .{ .reified = .{
2133321314
.zir_index = tracked_inst,
@@ -21371,21 +21352,14 @@ fn reifyStruct(
2137121352
return sema.fail(block, src, "duplicate struct field name {f}", .{field_name.fmt(ip)});
2137221353
}
2137321354

21374-
if (any_aligned_fields) {
21375-
if (!try sema.intFitsInType(field_alignment_val, .u32, null)) {
21376-
return sema.fail(block, src, "alignment must fit in 'u32'", .{});
21377-
}
21378-
21379-
const byte_align = try field_alignment_val.toUnsignedIntSema(pt);
21380-
if (byte_align == 0) {
21381-
if (layout != .@"packed") {
21382-
struct_type.field_aligns.get(ip)[field_idx] = .none;
21383-
}
21384-
} else {
21385-
if (layout == .@"packed") return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{});
21386-
if (!math.isPowerOfTwo(byte_align)) return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});
21387-
struct_type.field_aligns.get(ip)[field_idx] = Alignment.fromNonzeroByteUnits(byte_align);
21388-
}
21355+
if (!try sema.intFitsInType(field_alignment_val, align_ty, null)) {
21356+
return sema.fail(block, src, "alignment must fit in '{f}'", .{align_ty.fmt(pt)});
21357+
}
21358+
const byte_align = try field_alignment_val.toUnsignedIntSema(pt);
21359+
if (layout == .@"packed") {
21360+
if (byte_align != 0) return sema.fail(block, src, "alignment of a packed struct field must be set to 0", .{});
21361+
} else {
21362+
struct_type.field_aligns.get(ip)[field_idx] = try sema.validateAlign(block, src, byte_align);
2138921363
}
2139021364

2139121365
const field_is_comptime = field_is_comptime_val.toBool();

src/codegen/aarch64/Assemble.zig

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,16 @@ pub fn nextInstruction(as: *Assemble) !?Instruction {
3333
var symbols: Symbols: {
3434
const symbols = @typeInfo(@TypeOf(instruction.symbols)).@"struct".fields;
3535
var symbol_fields: [symbols.len]std.builtin.Type.StructField = undefined;
36-
for (&symbol_fields, symbols) |*symbol_field, symbol| symbol_field.* = .{
37-
.name = symbol.name,
38-
.type = zonCast(SymbolSpec, @field(instruction.symbols, symbol.name), .{}).Storage(),
39-
.default_value_ptr = null,
40-
.is_comptime = false,
41-
.alignment = 0,
42-
};
36+
for (&symbol_fields, symbols) |*symbol_field, symbol| {
37+
const Storage = zonCast(SymbolSpec, @field(instruction.symbols, symbol.name), .{}).Storage();
38+
symbol_field.* = .{
39+
.name = symbol.name,
40+
.type = Storage,
41+
.default_value_ptr = null,
42+
.is_comptime = false,
43+
.alignment = @alignOf(Storage),
44+
};
45+
}
4346
break :Symbols @Type(.{ .@"struct" = .{
4447
.layout = .auto,
4548
.fields = &symbol_fields,

test/behavior/tuple.zig

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,17 +318,19 @@ test "tuple type with void field" {
318318
test "zero sized struct in tuple handled correctly" {
319319
const State = struct {
320320
const Self = @This();
321+
const Inner = struct {};
322+
321323
data: @Type(.{
322324
.@"struct" = .{
323325
.is_tuple = true,
324326
.layout = .auto,
325327
.decls = &.{},
326328
.fields = &.{.{
327329
.name = "0",
328-
.type = struct {},
330+
.type = Inner,
329331
.default_value_ptr = null,
330332
.is_comptime = false,
331-
.alignment = 0,
333+
.alignment = @alignOf(Inner),
332334
}},
333335
},
334336
}),

0 commit comments

Comments
 (0)