authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2025-02-19 09:46:30-08:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2025-08-01 14:57:16-07:00
log17330867eb8f9e24ec8aadf23592e36f90f9dcb3
treef06ea4d62a910509d5407ea142b50e58480d9499
parenta00edbd52d03645366c165e860d9e0ab89caa2fc
signaturelock-open Commit is signed but in an unrecognized format.

Sema: compile error on reifying align(0) struct fields


4 files changed, 87 insertions(+), 60 deletions(-)

src/Sema.zig+22-41
......@@ -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
......@@ -18807,7 +18813,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1880718813 const abi_align: Alignment = if (inst_data.flags.has_align) blk: {
1880818814 const ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_i]);
1880918815 extra_i += 1;
18810 const coerced = try sema.coerce(block, .u32, try sema.resolveInst(ref), align_src);
18816 const coerced = try sema.coerce(block, align_ty, try sema.resolveInst(ref), align_src);
1881118817 const val = try sema.resolveConstDefinedValue(block, align_src, coerced, .{ .simple = .@"align" });
1881218818 // Check if this happens to be the lazy alignment of our element type, in
1881318819 // which case we can make this 0 without resolving it.
......@@ -20325,15 +20331,11 @@ fn zirReify(
2032520331 try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls),
2032620332 ).?);
2032720333
20328 if (!try sema.intFitsInType(alignment_val, .u32, null)) {
20329 return sema.fail(block, src, "alignment must fit in 'u32'", .{});
20334 if (!try sema.intFitsInType(alignment_val, align_ty, null)) {
20335 return sema.fail(block, src, "alignment must fit in '{}'", .{align_ty.fmt(pt)});
2033020336 }
20331
2033220337 const alignment_val_int = try alignment_val.toUnsignedIntSema(pt);
20333 if (alignment_val_int > 0 and !math.isPowerOfTwo(alignment_val_int)) {
20334 return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{alignment_val_int});
20335 }
20336 const abi_align = Alignment.fromByteUnits(alignment_val_int);
20338 const abi_align = try sema.validateAlign(block, src, alignment_val_int);
2033720339
2033820340 const elem_ty = child_val.toType();
2033920341 if (abi_align != .none) {
......@@ -21017,11 +21019,7 @@ fn reifyUnion(
2101721019 field_ty.* = field_type_val.toIntern();
2101821020 if (any_aligns) {
2101921021 const byte_align = try (try field_info.fieldValue(pt, 2)).toUnsignedIntSema(pt);
21020 if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) {
21021 // TODO: better source location
21022 return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});
21023 }
21024 field_aligns[field_idx] = Alignment.fromByteUnits(byte_align);
21022 field_aligns[field_idx] = try sema.validateAlign(block, src, byte_align);
2102521023 }
2102621024 }
2102721025
......@@ -21062,11 +21060,7 @@ fn reifyUnion(
2106221060 field_ty.* = field_type_val.toIntern();
2106321061 if (any_aligns) {
2106421062 const byte_align = try (try field_info.fieldValue(pt, 2)).toUnsignedIntSema(pt);
21065 if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) {
21066 // TODO: better source location
21067 return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});
21068 }
21069 field_aligns[field_idx] = Alignment.fromByteUnits(byte_align);
21063 field_aligns[field_idx] = try sema.validateAlign(block, src, byte_align);
2107021064 }
2107121065 }
2107221066
......@@ -21266,7 +21260,6 @@ fn reifyStruct(
2126621260
2126721261 var any_comptime_fields = false;
2126821262 var any_default_inits = false;
21269 var any_aligned_fields = false;
2127021263
2127121264 for (0..fields_len) |field_idx| {
2127221265 const field_info = try fields_val.elemValue(pt, field_idx);
......@@ -21301,11 +21294,6 @@ fn reifyStruct(
2130121294
2130221295 if (field_is_comptime) any_comptime_fields = true;
2130321296 if (field_default_value != .none) any_default_inits = true;
21304 switch (try field_alignment_val.orderAgainstZeroSema(pt)) {
21305 .eq => {},
21306 .gt => any_aligned_fields = true,
21307 .lt => unreachable,
21308 }
2130921297 }
2131021298
2131121299 const tracked_inst = try block.trackZir(inst);
......@@ -21317,7 +21305,7 @@ fn reifyStruct(
2131721305 .requires_comptime = .unknown,
2131821306 .any_comptime_fields = any_comptime_fields,
2131921307 .any_default_inits = any_default_inits,
21320 .any_aligned_fields = any_aligned_fields,
21308 .any_aligned_fields = true,
2132121309 .inits_resolved = true,
2132221310 .key = .{ .reified = .{
2132321311 .zir_index = tracked_inst,
......@@ -21361,21 +21349,14 @@ fn reifyStruct(
2136121349 return sema.fail(block, src, "duplicate struct field name {f}", .{field_name.fmt(ip)});
2136221350 }
2136321351
21364 if (any_aligned_fields) {
21365 if (!try sema.intFitsInType(field_alignment_val, .u32, null)) {
21366 return sema.fail(block, src, "alignment must fit in 'u32'", .{});
21367 }
21368
21369 const byte_align = try field_alignment_val.toUnsignedIntSema(pt);
21370 if (byte_align == 0) {
21371 if (layout != .@"packed") {
21372 struct_type.field_aligns.get(ip)[field_idx] = .none;
21373 }
21374 } else {
21375 if (layout == .@"packed") return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{});
21376 if (!math.isPowerOfTwo(byte_align)) return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});
21377 struct_type.field_aligns.get(ip)[field_idx] = Alignment.fromNonzeroByteUnits(byte_align);
21378 }
21352 if (!try sema.intFitsInType(field_alignment_val, align_ty, null)) {
21353 return sema.fail(block, src, "alignment must fit in '{f}'", .{align_ty.fmt(pt)});
21354 }
21355 const byte_align = try field_alignment_val.toUnsignedIntSema(pt);
21356 if (layout == .@"packed") {
21357 if (byte_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{});
21358 } else {
21359 struct_type.field_aligns.get(ip)[field_idx] = try sema.validateAlign(block, src, byte_align);
2137921360 }
2138021361
2138121362 const field_is_comptime = field_is_comptime_val.toBool();
test/cases/compile_errors/align_zero.zig+60-14
......@@ -1,52 +1,98 @@
1pub var global_var: i32 align(0) = undefined;
1var global_var: i32 align(0) = undefined;
22
3pub export fn a() void {
3export fn a() void {
44 _ = &global_var;
55}
66
7pub extern var extern_var: i32 align(0);
7extern var extern_var: i32 align(0);
88
9pub export fn b() void {
9export fn b() void {
1010 _ = &extern_var;
1111}
1212
13pub export fn c() align(0) void {}
13export fn c() align(0) void {}
1414
15pub export fn d() void {
15export fn d() void {
1616 _ = *align(0) fn () i32;
1717}
1818
19pub export fn e() void {
19export fn e() void {
2020 var local_var: i32 align(0) = undefined;
2121 _ = &local_var;
2222}
2323
24pub export fn f() void {
24export fn f() void {
2525 _ = *align(0) i32;
2626}
2727
28pub export fn g() void {
28export fn g() void {
2929 _ = []align(0) i32;
3030}
3131
32pub export fn h() void {
32export fn h() void {
3333 _ = struct { field: i32 align(0) };
3434}
3535
36pub export fn i() void {
36export fn i() void {
3737 _ = union { field: i32 align(0) };
3838}
3939
40export fn j() void {
41 _ = @Type(.{ .@"struct" = .{
42 .layout = .auto,
43 .fields = &.{.{
44 .name = "test",
45 .type = u32,
46 .default_value_ptr = null,
47 .is_comptime = false,
48 .alignment = 0,
49 }},
50 .decls = &.{},
51 .is_tuple = false,
52 } });
53}
54
55export fn k() void {
56 _ = @Type(.{ .pointer = .{
57 .size = .one,
58 .is_const = false,
59 .is_volatile = false,
60 .alignment = 0,
61 .address_space = .generic,
62 .child = u32,
63 .is_allowzero = false,
64 .sentinel_ptr = null,
65 } });
66}
67
68export fn l() void {
69 _ = @Type(.{ .@"struct" = .{
70 .layout = .@"packed",
71 .fields = &.{.{
72 .name = "test",
73 .type = u32,
74 .default_value_ptr = null,
75 .is_comptime = false,
76 .alignment = 8,
77 }},
78 .decls = &.{},
79 .is_tuple = false,
80 } });
81}
82
4083// error
4184// backend=stage2
4285// target=native
4386//
44// :1:31: error: alignment must be >= 1
45// :7:38: error: alignment must be >= 1
46// :13:25: error: alignment must be >= 1
87// :1:27: error: alignment must be >= 1
88// :7:34: error: alignment must be >= 1
89// :13:21: error: alignment must be >= 1
4790// :16:16: error: alignment must be >= 1
4891// :20:30: error: alignment must be >= 1
4992// :25:16: error: alignment must be >= 1
5093// :29:17: error: alignment must be >= 1
5194// :33:35: error: alignment must be >= 1
5295// :37:34: error: alignment must be >= 1
96// :41:9: error: alignment can only be 0 on packed struct fields
97// :56:9: error: alignment must be >= 1
98// :69:9: error: alignment in a packed struct field must be set to 0
test/cases/compile_errors/bad_alignment_type.zig+2-2
......@@ -11,5 +11,5 @@ export fn entry2() void {
1111// backend=stage2
1212// target=native
1313//
14// :2:22: error: expected type 'u32', found 'bool'
15// :6:21: error: fractional component prevents float value '12.34' from coercion to type 'u32'
14// :2:22: error: expected type 'u29', found 'bool'
15// :6:21: error: fractional component prevents float value '12.34' from coercion to type 'u29'
test/cases/compile_errors/reify_type_with_invalid_field_alignment.zig+3-3
......@@ -43,6 +43,6 @@ comptime {
4343
4444// error
4545//
46// :2:9: error: alignment value '3' is not a power of two or zero
47// :14:9: error: alignment value '5' is not a power of two or zero
48// :30:9: error: alignment value '7' is not a power of two or zero
46// :2:9: error: alignment value '3' is not a power of two
47// :14:9: error: alignment value '5' is not a power of two
48// :30:9: error: alignment value '7' is not a power of two