authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-08-03 09:58:23+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-08-03 09:58:23+01:00
logc80aa9f71960ed90787033293fbc4c6ccfe0fba8
tree84d5df492d5a0f6c3c31370ed97c6e58e1c14c40
parent616e69c80745cdc872b1db5ad63b919d82d9e9cb
parente82d67233b615e04fb5e4f31cd93216a2c1c2899
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #22997 from Rexicon226/align-0-reify

sema: compile error on reifying align(0) fields and pointers

15 files changed, 147 insertions(+), 129 deletions(-)

lib/compiler/aro/aro/Attribute.zig+1-1
...@@ -708,7 +708,7 @@ pub const Arguments = blk: {...@@ -708,7 +708,7 @@ pub const Arguments = blk: {
708 field.* = .{708 field.* = .{
709 .name = decl.name,709 .name = decl.name,
710 .type = @field(attributes, decl.name),710 .type = @field(attributes, decl.name),
711 .alignment = 0,711 .alignment = @alignOf(@field(attributes, decl.name)),
712 };712 };
713 }713 }
714714
lib/std/meta.zig+1-1
...@@ -939,7 +939,7 @@ fn CreateUniqueTuple(comptime N: comptime_int, comptime types: [N]type) type {...@@ -939,7 +939,7 @@ fn CreateUniqueTuple(comptime N: comptime_int, comptime types: [N]type) type {
939 .type = T,939 .type = T,
940 .default_value_ptr = null,940 .default_value_ptr = null,
941 .is_comptime = false,941 .is_comptime = false,
942 .alignment = 0,942 .alignment = @alignOf(T),
943 };943 };
944 }944 }
945945
lib/std/zig/AstGen.zig+3
...@@ -5386,6 +5386,9 @@ fn unionDeclInner(...@@ -5386,6 +5386,9 @@ fn unionDeclInner(
5386 return astgen.failNode(member_node, "union field missing type", .{});5386 return astgen.failNode(member_node, "union field missing type", .{});
5387 }5387 }
5388 if (member.ast.align_expr.unwrap()) |align_expr| {5388 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 }
5389 const align_inst = try expr(&block_scope, &block_scope.base, coerced_align_ri, align_expr);5392 const align_inst = try expr(&block_scope, &block_scope.base, coerced_align_ri, align_expr);
5390 wip_members.appendToField(@intFromEnum(align_inst));5393 wip_members.appendToField(@intFromEnum(align_inst));
5391 any_aligned_fields = true;5394 any_aligned_fields = true;
lib/std/zig/llvm/Builder.zig+4-3
...@@ -8533,18 +8533,19 @@ pub const Metadata = enum(u32) {...@@ -8533,18 +8533,19 @@ pub const Metadata = enum(u32) {
8533 .type = []const u8,8533 .type = []const u8,
8534 .default_value_ptr = null,8534 .default_value_ptr = null,
8535 .is_comptime = false,8535 .is_comptime = false,
8536 .alignment = 0,8536 .alignment = @alignOf([]const u8),
8537 };8537 };
8538 }8538 }
8539 fmt_str = fmt_str ++ "(";8539 fmt_str = fmt_str ++ "(";
8540 inline for (fields[2..], names) |*field, name| {8540 inline for (fields[2..], names) |*field, name| {
8541 fmt_str = fmt_str ++ "{[" ++ name ++ "]f}";8541 fmt_str = fmt_str ++ "{[" ++ name ++ "]f}";
8542 const T = std.fmt.Formatter(FormatData, format);
8542 field.* = .{8543 field.* = .{
8543 .name = name,8544 .name = name,
8544 .type = std.fmt.Formatter(FormatData, format),8545 .type = T,
8545 .default_value_ptr = null,8546 .default_value_ptr = null,
8546 .is_comptime = false,8547 .is_comptime = false,
8547 .alignment = 0,8548 .alignment = @alignOf(T),
8548 };8549 };
8549 }8550 }
8550 fmt_str = fmt_str ++ ")\n";8551 fmt_str = fmt_str ++ ")\n";
src/InternPool.zig+22-16
...@@ -1137,13 +1137,16 @@ const Local = struct {...@@ -1137,13 +1137,16 @@ const Local = struct {
1137 const elem_info = @typeInfo(Elem).@"struct";1137 const elem_info = @typeInfo(Elem).@"struct";
1138 const elem_fields = elem_info.fields;1138 const elem_fields = elem_info.fields;
1139 var new_fields: [elem_fields.len]std.builtin.Type.StructField = undefined;1139 var new_fields: [elem_fields.len]std.builtin.Type.StructField = undefined;
1140 for (&new_fields, elem_fields) |*new_field, elem_field| new_field.* = .{1140 for (&new_fields, elem_fields) |*new_field, elem_field| {
1141 .name = elem_field.name,1141 const T = *[len]elem_field.type;
1142 .type = *[len]elem_field.type,1142 new_field.* = .{
1143 .default_value_ptr = null,1143 .name = elem_field.name,
1144 .is_comptime = false,1144 .type = T,
1145 .alignment = 0,1145 .default_value_ptr = null,
1146 };1146 .is_comptime = false,
1147 .alignment = @alignOf(T),
1148 };
1149 }
1147 return @Type(.{ .@"struct" = .{1150 return @Type(.{ .@"struct" = .{
1148 .layout = .auto,1151 .layout = .auto,
1149 .fields = &new_fields,1152 .fields = &new_fields,
...@@ -1158,22 +1161,25 @@ const Local = struct {...@@ -1158,22 +1161,25 @@ const Local = struct {
1158 const elem_info = @typeInfo(Elem).@"struct";1161 const elem_info = @typeInfo(Elem).@"struct";
1159 const elem_fields = elem_info.fields;1162 const elem_fields = elem_info.fields;
1160 var new_fields: [elem_fields.len]std.builtin.Type.StructField = undefined;1163 var new_fields: [elem_fields.len]std.builtin.Type.StructField = undefined;
1161 for (&new_fields, elem_fields) |*new_field, elem_field| new_field.* = .{1164 for (&new_fields, elem_fields) |*new_field, elem_field| {
1162 .name = elem_field.name,1165 const T = @Type(.{ .pointer = .{
1163 .type = @Type(.{ .pointer = .{
1164 .size = opts.size,1166 .size = opts.size,
1165 .is_const = opts.is_const,1167 .is_const = opts.is_const,
1166 .is_volatile = false,1168 .is_volatile = false,
1167 .alignment = 0,1169 .alignment = @alignOf(elem_field.type),
1168 .address_space = .generic,1170 .address_space = .generic,
1169 .child = elem_field.type,1171 .child = elem_field.type,
1170 .is_allowzero = false,1172 .is_allowzero = false,
1171 .sentinel_ptr = null,1173 .sentinel_ptr = null,
1172 } }),1174 } });
1173 .default_value_ptr = null,1175 new_field.* = .{
1174 .is_comptime = false,1176 .name = elem_field.name,
1175 .alignment = 0,1177 .type = T,
1176 };1178 .default_value_ptr = null,
1179 .is_comptime = false,
1180 .alignment = @alignOf(T),
1181 };
1182 }
1177 return @Type(.{ .@"struct" = .{1183 return @Type(.{ .@"struct" = .{
1178 .layout = .auto,1184 .layout = .auto,
1179 .fields = &new_fields,1185 .fields = &new_fields,
src/Sema.zig+39-65
...@@ -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
...@@ -18817,7 +18823,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -18817,7 +18823,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
18817 const abi_align: Alignment = if (inst_data.flags.has_align) blk: {18823 const abi_align: Alignment = if (inst_data.flags.has_align) blk: {
18818 const ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_i]);18824 const ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_i]);
18819 extra_i += 1;18825 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);
18821 const val = try sema.resolveConstDefinedValue(block, align_src, coerced, .{ .simple = .@"align" });18827 const val = try sema.resolveConstDefinedValue(block, align_src, coerced, .{ .simple = .@"align" });
18822 // Check if this happens to be the lazy alignment of our element type, in18828 // Check if this happens to be the lazy alignment of our element type, in
18823 // which case we can make this 0 without resolving it.18829 // which case we can make this 0 without resolving it.
...@@ -20335,15 +20341,11 @@ fn zirReify(...@@ -20335,15 +20341,11 @@ fn zirReify(
20335 try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls),20341 try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls),
20336 ).?);20342 ).?);
2033720343
20338 if (!try sema.intFitsInType(alignment_val, .u32, null)) {20344 if (!try sema.intFitsInType(alignment_val, align_ty, null)) {
20339 return sema.fail(block, src, "alignment must fit in 'u32'", .{});20345 return sema.fail(block, src, "alignment must fit in '{f}'", .{align_ty.fmt(pt)});
20340 }20346 }
20341
20342 const alignment_val_int = try alignment_val.toUnsignedIntSema(pt);20347 const alignment_val_int = try alignment_val.toUnsignedIntSema(pt);
20343 if (alignment_val_int > 0 and !math.isPowerOfTwo(alignment_val_int)) {20348 const abi_align = try sema.validateAlign(block, src, 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);
2034720349
20348 const elem_ty = child_val.toType();20350 const elem_ty = child_val.toType();
20349 if (abi_align != .none) {20351 if (abi_align != .none) {
...@@ -20920,8 +20922,6 @@ fn reifyUnion(...@@ -20920,8 +20922,6 @@ fn reifyUnion(
20920 std.hash.autoHash(&hasher, opt_tag_type_val.toIntern());20922 std.hash.autoHash(&hasher, opt_tag_type_val.toIntern());
20921 std.hash.autoHash(&hasher, fields_len);20923 std.hash.autoHash(&hasher, fields_len);
2092220924
20923 var any_aligns = false;
20924
20925 for (0..fields_len) |field_idx| {20925 for (0..fields_len) |field_idx| {
20926 const field_info = try fields_val.elemValue(pt, field_idx);20926 const field_info = try fields_val.elemValue(pt, field_idx);
2092720927
...@@ -20930,16 +20930,11 @@ fn reifyUnion(...@@ -20930,16 +20930,11 @@ fn reifyUnion(
20930 const field_align_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 2));20930 const field_align_val = try sema.resolveLazyValue(try field_info.fieldValue(pt, 2));
2093120931
20932 const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .union_field_name });20932 const field_name = try sema.sliceToIpString(block, src, field_name_val, .{ .simple = .union_field_name });
20933
20934 std.hash.autoHash(&hasher, .{20933 std.hash.autoHash(&hasher, .{
20935 field_name,20934 field_name,
20936 field_type_val.toIntern(),20935 field_type_val.toIntern(),
20937 field_align_val.toIntern(),20936 field_align_val.toIntern(),
20938 });20937 });
20939
20940 if (field_align_val.toUnsignedInt(zcu) != 0) {
20941 any_aligns = true;
20942 }
20943 }20938 }
2094420939
20945 const tracked_inst = try block.trackZir(inst);20940 const tracked_inst = try block.trackZir(inst);
...@@ -20956,7 +20951,7 @@ fn reifyUnion(...@@ -20956,7 +20951,7 @@ fn reifyUnion(
20956 true => .safety,20951 true => .safety,
20957 false => .none,20952 false => .none,
20958 },20953 },
20959 .any_aligned_fields = any_aligns,20954 .any_aligned_fields = layout != .@"packed",
20960 .requires_comptime = .unknown,20955 .requires_comptime = .unknown,
20961 .assumed_runtime_bits = false,20956 .assumed_runtime_bits = false,
20962 .assumed_pointer_aligned = false,20957 .assumed_pointer_aligned = false,
...@@ -20989,8 +20984,7 @@ fn reifyUnion(...@@ -20989,8 +20984,7 @@ fn reifyUnion(
20989 );20984 );
20990 wip_ty.setName(ip, type_name.name, type_name.nav);20985 wip_ty.setName(ip, type_name.name, type_name.nav);
2099120986
20992 const field_types = try sema.arena.alloc(InternPool.Index, fields_len);20987 const loaded_union = ip.loadUnionType(wip_ty.index);
20993 const field_aligns = if (any_aligns) try sema.arena.alloc(InternPool.Alignment, fields_len) else undefined;
2099420988
20995 const enum_tag_ty, const has_explicit_tag = if (opt_tag_type_val.optionalValue(zcu)) |tag_type_val| tag_ty: {20989 const enum_tag_ty, const has_explicit_tag = if (opt_tag_type_val.optionalValue(zcu)) |tag_type_val| tag_ty: {
20996 switch (ip.indexToKey(tag_type_val.toIntern())) {20990 switch (ip.indexToKey(tag_type_val.toIntern())) {
...@@ -21003,11 +20997,12 @@ fn reifyUnion(...@@ -21003,11 +20997,12 @@ fn reifyUnion(
21003 const tag_ty_fields_len = enum_tag_ty.enumFieldCount(zcu);20997 const tag_ty_fields_len = enum_tag_ty.enumFieldCount(zcu);
21004 var seen_tags = try std.DynamicBitSetUnmanaged.initEmpty(sema.arena, tag_ty_fields_len);20998 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| {
21007 const field_info = try fields_val.elemValue(pt, field_idx);21001 const field_info = try fields_val.elemValue(pt, field_idx);
2100821002
21009 const field_name_val = try field_info.fieldValue(pt, 0);21003 const field_name_val = try field_info.fieldValue(pt, 0);
21010 const field_type_val = try field_info.fieldValue(pt, 1);21004 const field_type_val = try field_info.fieldValue(pt, 1);
21005 const field_alignment_val = try field_info.fieldValue(pt, 2);
2101121006
21012 // Don't pass a reason; first loop acts as an assertion that this is valid.21007 // Don't pass a reason; first loop acts as an assertion that this is valid.
21013 const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined);21008 const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined);
...@@ -21024,14 +21019,12 @@ fn reifyUnion(...@@ -21024,14 +21019,12 @@ fn reifyUnion(
21024 }21019 }
21025 seen_tags.set(enum_index);21020 seen_tags.set(enum_index);
2102621021
21027 field_ty.* = field_type_val.toIntern();21022 loaded_union.field_types.get(ip)[field_idx] = field_type_val.toIntern();
21028 if (any_aligns) {21023 const byte_align = try field_alignment_val.toUnsignedIntSema(pt);
21029 const byte_align = try (try field_info.fieldValue(pt, 2)).toUnsignedIntSema(pt);21024 if (layout == .@"packed") {
21030 if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) {21025 if (byte_align != 0) return sema.fail(block, src, "alignment of a packed union field must be set to 0", .{});
21031 // TODO: better source location21026 } else {
21032 return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});21027 loaded_union.field_aligns.get(ip)[field_idx] = try sema.validateAlign(block, src, byte_align);
21033 }
21034 field_aligns[field_idx] = Alignment.fromByteUnits(byte_align);
21035 }21028 }
21036 }21029 }
2103721030
...@@ -21055,11 +21048,12 @@ fn reifyUnion(...@@ -21055,11 +21048,12 @@ fn reifyUnion(
21055 var field_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .empty;21048 var field_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .empty;
21056 try field_names.ensureTotalCapacity(sema.arena, fields_len);21049 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| {
21059 const field_info = try fields_val.elemValue(pt, field_idx);21052 const field_info = try fields_val.elemValue(pt, field_idx);
2106021053
21061 const field_name_val = try field_info.fieldValue(pt, 0);21054 const field_name_val = try field_info.fieldValue(pt, 0);
21062 const field_type_val = try field_info.fieldValue(pt, 1);21055 const field_type_val = try field_info.fieldValue(pt, 1);
21056 const field_alignment_val = try field_info.fieldValue(pt, 2);
2106321057
21064 // Don't pass a reason; first loop acts as an assertion that this is valid.21058 // Don't pass a reason; first loop acts as an assertion that this is valid.
21065 const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined);21059 const field_name = try sema.sliceToIpString(block, src, field_name_val, undefined);
...@@ -21069,14 +21063,12 @@ fn reifyUnion(...@@ -21069,14 +21063,12 @@ fn reifyUnion(
21069 return sema.fail(block, src, "duplicate union field {f}", .{field_name.fmt(ip)});21063 return sema.fail(block, src, "duplicate union field {f}", .{field_name.fmt(ip)});
21070 }21064 }
2107121065
21072 field_ty.* = field_type_val.toIntern();21066 loaded_union.field_types.get(ip)[field_idx] = field_type_val.toIntern();
21073 if (any_aligns) {21067 const byte_align = try field_alignment_val.toUnsignedIntSema(pt);
21074 const byte_align = try (try field_info.fieldValue(pt, 2)).toUnsignedIntSema(pt);21068 if (layout == .@"packed") {
21075 if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) {21069 if (byte_align != 0) return sema.fail(block, src, "alignment of a packed union field must be set to 0", .{});
21076 // TODO: better source location21070 } else {
21077 return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});21071 loaded_union.field_aligns.get(ip)[field_idx] = try sema.validateAlign(block, src, byte_align);
21078 }
21079 field_aligns[field_idx] = Alignment.fromByteUnits(byte_align);
21080 }21072 }
21081 }21073 }
2108221074
...@@ -21085,7 +21077,7 @@ fn reifyUnion(...@@ -21085,7 +21077,7 @@ fn reifyUnion(
21085 };21077 };
21086 errdefer if (!has_explicit_tag) ip.remove(pt.tid, enum_tag_ty); // remove generated tag type on error21078 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| {
21089 const field_ty: Type = .fromInterned(field_ty_ip);21081 const field_ty: Type = .fromInterned(field_ty_ip);
21090 if (field_ty.zigTypeTag(zcu) == .@"opaque") {21082 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
21091 return sema.failWithOwnedErrorMsg(block, msg: {21083 return sema.failWithOwnedErrorMsg(block, msg: {
...@@ -21119,11 +21111,6 @@ fn reifyUnion(...@@ -21119,11 +21111,6 @@ fn reifyUnion(
21119 }21111 }
21120 }21112 }
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 }
21127 loaded_union.setTagType(ip, enum_tag_ty);21114 loaded_union.setTagType(ip, enum_tag_ty);
21128 loaded_union.setStatus(ip, .have_field_types);21115 loaded_union.setStatus(ip, .have_field_types);
2112921116
...@@ -21276,7 +21263,6 @@ fn reifyStruct(...@@ -21276,7 +21263,6 @@ fn reifyStruct(
2127621263
21277 var any_comptime_fields = false;21264 var any_comptime_fields = false;
21278 var any_default_inits = false;21265 var any_default_inits = false;
21279 var any_aligned_fields = false;
2128021266
21281 for (0..fields_len) |field_idx| {21267 for (0..fields_len) |field_idx| {
21282 const field_info = try fields_val.elemValue(pt, field_idx);21268 const field_info = try fields_val.elemValue(pt, field_idx);
...@@ -21311,11 +21297,6 @@ fn reifyStruct(...@@ -21311,11 +21297,6 @@ fn reifyStruct(
2131121297
21312 if (field_is_comptime) any_comptime_fields = true;21298 if (field_is_comptime) any_comptime_fields = true;
21313 if (field_default_value != .none) any_default_inits = true;21299 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 }
21319 }21300 }
2132021301
21321 const tracked_inst = try block.trackZir(inst);21302 const tracked_inst = try block.trackZir(inst);
...@@ -21327,7 +21308,7 @@ fn reifyStruct(...@@ -21327,7 +21308,7 @@ fn reifyStruct(
21327 .requires_comptime = .unknown,21308 .requires_comptime = .unknown,
21328 .any_comptime_fields = any_comptime_fields,21309 .any_comptime_fields = any_comptime_fields,
21329 .any_default_inits = any_default_inits,21310 .any_default_inits = any_default_inits,
21330 .any_aligned_fields = any_aligned_fields,21311 .any_aligned_fields = layout != .@"packed",
21331 .inits_resolved = true,21312 .inits_resolved = true,
21332 .key = .{ .reified = .{21313 .key = .{ .reified = .{
21333 .zir_index = tracked_inst,21314 .zir_index = tracked_inst,
...@@ -21371,21 +21352,14 @@ fn reifyStruct(...@@ -21371,21 +21352,14 @@ fn reifyStruct(
21371 return sema.fail(block, src, "duplicate struct field name {f}", .{field_name.fmt(ip)});21352 return sema.fail(block, src, "duplicate struct field name {f}", .{field_name.fmt(ip)});
21372 }21353 }
2137321354
21374 if (any_aligned_fields) {21355 if (!try sema.intFitsInType(field_alignment_val, align_ty, null)) {
21375 if (!try sema.intFitsInType(field_alignment_val, .u32, null)) {21356 return sema.fail(block, src, "alignment must fit in '{f}'", .{align_ty.fmt(pt)});
21376 return sema.fail(block, src, "alignment must fit in 'u32'", .{});21357 }
21377 }21358 const byte_align = try field_alignment_val.toUnsignedIntSema(pt);
2137821359 if (layout == .@"packed") {
21379 const byte_align = try field_alignment_val.toUnsignedIntSema(pt);21360 if (byte_align != 0) return sema.fail(block, src, "alignment of a packed struct field must be set to 0", .{});
21380 if (byte_align == 0) {21361 } else {
21381 if (layout != .@"packed") {21362 struct_type.field_aligns.get(ip)[field_idx] = try sema.validateAlign(block, src, byte_align);
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 }
21389 }21363 }
2139021364
21391 const field_is_comptime = field_is_comptime_val.toBool();21365 const field_is_comptime = field_is_comptime_val.toBool();
src/codegen/aarch64/Assemble.zig+10-7
...@@ -33,13 +33,16 @@ pub fn nextInstruction(as: *Assemble) !?Instruction {...@@ -33,13 +33,16 @@ pub fn nextInstruction(as: *Assemble) !?Instruction {
33 var symbols: Symbols: {33 var symbols: Symbols: {
34 const symbols = @typeInfo(@TypeOf(instruction.symbols)).@"struct".fields;34 const symbols = @typeInfo(@TypeOf(instruction.symbols)).@"struct".fields;
35 var symbol_fields: [symbols.len]std.builtin.Type.StructField = undefined;35 var symbol_fields: [symbols.len]std.builtin.Type.StructField = undefined;
36 for (&symbol_fields, symbols) |*symbol_field, symbol| symbol_field.* = .{36 for (&symbol_fields, symbols) |*symbol_field, symbol| {
37 .name = symbol.name,37 const Storage = zonCast(SymbolSpec, @field(instruction.symbols, symbol.name), .{}).Storage();
38 .type = zonCast(SymbolSpec, @field(instruction.symbols, symbol.name), .{}).Storage(),38 symbol_field.* = .{
39 .default_value_ptr = null,39 .name = symbol.name,
40 .is_comptime = false,40 .type = Storage,
41 .alignment = 0,41 .default_value_ptr = null,
42 };42 .is_comptime = false,
43 .alignment = @alignOf(Storage),
44 };
45 }
43 break :Symbols @Type(.{ .@"struct" = .{46 break :Symbols @Type(.{ .@"struct" = .{
44 .layout = .auto,47 .layout = .auto,
45 .fields = &symbol_fields,48 .fields = &symbol_fields,
test/behavior/tuple.zig+4-2
...@@ -318,6 +318,8 @@ test "tuple type with void field" {...@@ -318,6 +318,8 @@ test "tuple type with void field" {
318test "zero sized struct in tuple handled correctly" {318test "zero sized struct in tuple handled correctly" {
319 const State = struct {319 const State = struct {
320 const Self = @This();320 const Self = @This();
321 const Inner = struct {};
322
321 data: @Type(.{323 data: @Type(.{
322 .@"struct" = .{324 .@"struct" = .{
323 .is_tuple = true,325 .is_tuple = true,
...@@ -325,10 +327,10 @@ test "zero sized struct in tuple handled correctly" {...@@ -325,10 +327,10 @@ test "zero sized struct in tuple handled correctly" {
325 .decls = &.{},327 .decls = &.{},
326 .fields = &.{.{328 .fields = &.{.{
327 .name = "0",329 .name = "0",
328 .type = struct {},330 .type = Inner,
329 .default_value_ptr = null,331 .default_value_ptr = null,
330 .is_comptime = false,332 .is_comptime = false,
331 .alignment = 0,333 .alignment = @alignOf(Inner),
332 }},334 }},
333 },335 },
334 }),336 }),
test/behavior/type.zig+3-3
...@@ -433,8 +433,8 @@ test "Type.Union" {...@@ -433,8 +433,8 @@ test "Type.Union" {
433 .layout = .@"packed",433 .layout = .@"packed",
434 .tag_type = null,434 .tag_type = null,
435 .fields = &.{435 .fields = &.{
436 .{ .name = "signed", .type = i32, .alignment = @alignOf(i32) },436 .{ .name = "signed", .type = i32, .alignment = 0 },
437 .{ .name = "unsigned", .type = u32, .alignment = @alignOf(u32) },437 .{ .name = "unsigned", .type = u32, .alignment = 0 },
438 },438 },
439 .decls = &.{},439 .decls = &.{},
440 },440 },
...@@ -735,7 +735,7 @@ test "struct field names sliced at comptime from larger string" {...@@ -735,7 +735,7 @@ test "struct field names sliced at comptime from larger string" {
735 var it = std.mem.tokenizeScalar(u8, text, '\n');735 var it = std.mem.tokenizeScalar(u8, text, '\n');
736 while (it.next()) |name| {736 while (it.next()) |name| {
737 fields = fields ++ &[_]Type.StructField{.{737 fields = fields ++ &[_]Type.StructField{.{
738 .alignment = 0,738 .alignment = @alignOf(usize),
739 .name = name ++ "",739 .name = name ++ "",
740 .type = usize,740 .type = usize,
741 .default_value_ptr = null,741 .default_value_ptr = null,
test/cases/compile_errors/align_zero.zig+44-16
...@@ -1,52 +1,80 @@...@@ -1,52 +1,80 @@
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
40// error68// error
41// backend=stage2
42// target=native
43//69//
44// :1:31: error: alignment must be >= 170// :1:27: error: alignment must be >= 1
45// :7:38: error: alignment must be >= 171// :7:34: error: alignment must be >= 1
46// :13:25: error: alignment must be >= 172// :13:21: error: alignment must be >= 1
47// :16:16: error: alignment must be >= 173// :16:16: error: alignment must be >= 1
48// :20:30: error: alignment must be >= 174// :20:30: error: alignment must be >= 1
49// :25:16: error: alignment must be >= 175// :25:16: error: alignment must be >= 1
50// :29:17: error: alignment must be >= 176// :29:17: error: alignment must be >= 1
51// :33:35: error: alignment must be >= 177// :33:35: error: alignment must be >= 1
52// :37:34: error: alignment must be >= 178// :37:34: error: alignment must be >= 1
79// :41:9: error: alignment must be >= 1
80// :56:9: error: alignment must be >= 1
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/packed_struct_field_alignment_unavailable_for_reify_type.zig deleted-9
...@@ -1,9 +0,0 @@
1export fn entry() void {
2 _ = @Type(.{ .@"struct" = .{ .layout = .@"packed", .fields = &.{
3 .{ .name = "one", .type = u4, .default_value_ptr = null, .is_comptime = false, .alignment = 2 },
4 }, .decls = &.{}, .is_tuple = false } });
5}
6
7// error
8//
9// :2:9: error: alignment in a packed struct field must be set to 0
test/cases/compile_errors/packed_union_alignment_override.zig created+9
...@@ -0,0 +1,9 @@
1const U = packed union {
2 x: f32,
3 y: u8 align(10),
4 z: u32,
5};
6
7// error
8//
9// :3:17: error: unable to override alignment of packed union fields
test/cases/compile_errors/reify_struct.zig+2-1
...@@ -75,4 +75,5 @@ comptime {...@@ -75,4 +75,5 @@ comptime {
75// :16:5: error: tuple field name '3' does not match field index 075// :16:5: error: tuple field name '3' does not match field index 0
76// :30:5: error: comptime field without default initialization value76// :30:5: error: comptime field without default initialization value
77// :44:5: error: extern struct fields cannot be marked comptime77// :44:5: error: extern struct fields cannot be marked comptime
78// :58:5: error: alignment in a packed struct field must be set to 078// :58:5: error: alignment of a packed struct field must be set to 0
79
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