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(...@@ -2649,7 +2649,13 @@ pub fn analyzeAsAlign(
2649 src: LazySrcLoc,2649 src: LazySrcLoc,
2650 air_ref: Air.Inst.Ref,2650 air_ref: Air.Inst.Ref,
2651) !Alignment {2651) !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 );
2653 return sema.validateAlign(block, src, alignment_big);2659 return sema.validateAlign(block, src, alignment_big);
2654}2660}
26552661
...@@ -18807,7 +18813,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -18807,7 +18813,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
18807 const abi_align: Alignment = if (inst_data.flags.has_align) blk: {18813 const abi_align: Alignment = if (inst_data.flags.has_align) blk: {
18808 const ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_i]);18814 const ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_i]);
18809 extra_i += 1;18815 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);
18811 const val = try sema.resolveConstDefinedValue(block, align_src, coerced, .{ .simple = .@"align" });18817 const val = try sema.resolveConstDefinedValue(block, align_src, coerced, .{ .simple = .@"align" });
18812 // Check if this happens to be the lazy alignment of our element type, in18818 // Check if this happens to be the lazy alignment of our element type, in
18813 // which case we can make this 0 without resolving it.18819 // which case we can make this 0 without resolving it.
...@@ -20325,15 +20331,11 @@ fn zirReify(...@@ -20325,15 +20331,11 @@ fn zirReify(
20325 try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls),20331 try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls),
20326 ).?);20332 ).?);
2032720333
20328 if (!try sema.intFitsInType(alignment_val, .u32, null)) {20334 if (!try sema.intFitsInType(alignment_val, align_ty, null)) {
20329 return sema.fail(block, src, "alignment must fit in 'u32'", .{});20335 return sema.fail(block, src, "alignment must fit in '{}'", .{align_ty.fmt(pt)});
20330 }20336 }
20331
20332 const alignment_val_int = try alignment_val.toUnsignedIntSema(pt);20337 const alignment_val_int = try alignment_val.toUnsignedIntSema(pt);
20333 if (alignment_val_int > 0 and !math.isPowerOfTwo(alignment_val_int)) {20338 const abi_align = try sema.validateAlign(block, src, 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);
2033720339
20338 const elem_ty = child_val.toType();20340 const elem_ty = child_val.toType();
20339 if (abi_align != .none) {20341 if (abi_align != .none) {
...@@ -21017,11 +21019,7 @@ fn reifyUnion(...@@ -21017,11 +21019,7 @@ fn reifyUnion(
21017 field_ty.* = field_type_val.toIntern();21019 field_ty.* = field_type_val.toIntern();
21018 if (any_aligns) {21020 if (any_aligns) {
21019 const byte_align = try (try field_info.fieldValue(pt, 2)).toUnsignedIntSema(pt);21021 const byte_align = try (try field_info.fieldValue(pt, 2)).toUnsignedIntSema(pt);
21020 if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) {21022 field_aligns[field_idx] = try sema.validateAlign(block, src, 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);
21025 }21023 }
21026 }21024 }
2102721025
...@@ -21062,11 +21060,7 @@ fn reifyUnion(...@@ -21062,11 +21060,7 @@ fn reifyUnion(
21062 field_ty.* = field_type_val.toIntern();21060 field_ty.* = field_type_val.toIntern();
21063 if (any_aligns) {21061 if (any_aligns) {
21064 const byte_align = try (try field_info.fieldValue(pt, 2)).toUnsignedIntSema(pt);21062 const byte_align = try (try field_info.fieldValue(pt, 2)).toUnsignedIntSema(pt);
21065 if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) {21063 field_aligns[field_idx] = try sema.validateAlign(block, src, 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);
21070 }21064 }
21071 }21065 }
2107221066
...@@ -21266,7 +21260,6 @@ fn reifyStruct(...@@ -21266,7 +21260,6 @@ fn reifyStruct(
2126621260
21267 var any_comptime_fields = false;21261 var any_comptime_fields = false;
21268 var any_default_inits = false;21262 var any_default_inits = false;
21269 var any_aligned_fields = false;
2127021263
21271 for (0..fields_len) |field_idx| {21264 for (0..fields_len) |field_idx| {
21272 const field_info = try fields_val.elemValue(pt, field_idx);21265 const field_info = try fields_val.elemValue(pt, field_idx);
...@@ -21301,11 +21294,6 @@ fn reifyStruct(...@@ -21301,11 +21294,6 @@ fn reifyStruct(
2130121294
21302 if (field_is_comptime) any_comptime_fields = true;21295 if (field_is_comptime) any_comptime_fields = true;
21303 if (field_default_value != .none) any_default_inits = true;21296 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 }
21309 }21297 }
2131021298
21311 const tracked_inst = try block.trackZir(inst);21299 const tracked_inst = try block.trackZir(inst);
...@@ -21317,7 +21305,7 @@ fn reifyStruct(...@@ -21317,7 +21305,7 @@ fn reifyStruct(
21317 .requires_comptime = .unknown,21305 .requires_comptime = .unknown,
21318 .any_comptime_fields = any_comptime_fields,21306 .any_comptime_fields = any_comptime_fields,
21319 .any_default_inits = any_default_inits,21307 .any_default_inits = any_default_inits,
21320 .any_aligned_fields = any_aligned_fields,21308 .any_aligned_fields = true,
21321 .inits_resolved = true,21309 .inits_resolved = true,
21322 .key = .{ .reified = .{21310 .key = .{ .reified = .{
21323 .zir_index = tracked_inst,21311 .zir_index = tracked_inst,
...@@ -21361,21 +21349,14 @@ fn reifyStruct(...@@ -21361,21 +21349,14 @@ fn reifyStruct(
21361 return sema.fail(block, src, "duplicate struct field name {f}", .{field_name.fmt(ip)});21349 return sema.fail(block, src, "duplicate struct field name {f}", .{field_name.fmt(ip)});
21362 }21350 }
2136321351
21364 if (any_aligned_fields) {21352 if (!try sema.intFitsInType(field_alignment_val, align_ty, null)) {
21365 if (!try sema.intFitsInType(field_alignment_val, .u32, null)) {21353 return sema.fail(block, src, "alignment must fit in '{f}'", .{align_ty.fmt(pt)});
21366 return sema.fail(block, src, "alignment must fit in 'u32'", .{});21354 }
21367 }21355 const byte_align = try field_alignment_val.toUnsignedIntSema(pt);
2136821356 if (layout == .@"packed") {
21369 const byte_align = try field_alignment_val.toUnsignedIntSema(pt);21357 if (byte_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{});
21370 if (byte_align == 0) {21358 } else {
21371 if (layout != .@"packed") {21359 struct_type.field_aligns.get(ip)[field_idx] = try sema.validateAlign(block, src, byte_align);
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 }
21379 }21360 }
2138021361
21381 const field_is_comptime = field_is_comptime_val.toBool();21362 const field_is_comptime = field_is_comptime_val.toBool();
test/cases/compile_errors/align_zero.zig+60-14
...@@ -1,52 +1,98 @@...@@ -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 {
4 _ = &global_var;4 _ = &global_var;
5}5}
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 {
10 _ = &extern_var;10 _ = &extern_var;
11}11}
1212
13pub export fn c() align(0) void {}13export fn c() align(0) void {}
1414
15pub export fn d() void {15export fn d() void {
16 _ = *align(0) fn () i32;16 _ = *align(0) fn () i32;
17}17}
1818
19pub export fn e() void {19export fn e() void {
20 var local_var: i32 align(0) = undefined;20 var local_var: i32 align(0) = undefined;
21 _ = &local_var;21 _ = &local_var;
22}22}
2323
24pub export fn f() void {24export fn f() void {
25 _ = *align(0) i32;25 _ = *align(0) i32;
26}26}
2727
28pub export fn g() void {28export fn g() void {
29 _ = []align(0) i32;29 _ = []align(0) i32;
30}30}
3131
32pub export fn h() void {32export fn h() void {
33 _ = struct { field: i32 align(0) };33 _ = struct { field: i32 align(0) };
34}34}
3535
36pub export fn i() void {36export fn i() void {
37 _ = union { field: i32 align(0) };37 _ = union { field: i32 align(0) };
38}38}
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
40// error83// error
41// backend=stage284// backend=stage2
42// target=native85// target=native
43//86//
44// :1:31: error: alignment must be >= 187// :1:27: error: alignment must be >= 1
45// :7:38: error: alignment must be >= 188// :7:34: error: alignment must be >= 1
46// :13:25: error: alignment must be >= 189// :13:21: error: alignment must be >= 1
47// :16:16: error: alignment must be >= 190// :16:16: error: alignment must be >= 1
48// :20:30: error: alignment must be >= 191// :20:30: error: alignment must be >= 1
49// :25:16: error: alignment must be >= 192// :25:16: error: alignment must be >= 1
50// :29:17: error: alignment must be >= 193// :29:17: error: alignment must be >= 1
51// :33:35: error: alignment must be >= 194// :33:35: error: alignment must be >= 1
52// :37:34: error: alignment must be >= 195// :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 {...@@ -11,5 +11,5 @@ export fn entry2() void {
11// backend=stage211// backend=stage2
12// target=native12// target=native
13//13//
14// :2:22: error: expected type 'u32', found 'bool'14// :2:22: error: expected type 'u29', found 'bool'
15// :6:21: error: fractional component prevents float value '12.34' from coercion to type 'u32'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 {...@@ -43,6 +43,6 @@ comptime {
4343
44// error44// error
45//45//
46// :2:9: error: alignment value '3' is not a power of two or zero46// :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 or zero47// :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 or zero48// :30:9: error: alignment value '7' is not a power of two