diff --git a/src/Sema.zig b/src/Sema.zig index d7add0724d..b855e4cc9d 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2649,7 +2649,13 @@ pub fn analyzeAsAlign( src: LazySrcLoc, air_ref: Air.Inst.Ref, ) !Alignment { - const alignment_big = try sema.analyzeAsInt(block, src, air_ref, align_ty, .{ .simple = .@"align" }); + const alignment_big = try sema.analyzeAsInt( + block, + src, + air_ref, + align_ty, + .{ .simple = .@"align" }, + ); return sema.validateAlign(block, src, alignment_big); } @@ -18807,7 +18813,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const abi_align: Alignment = if (inst_data.flags.has_align) blk: { const ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_i]); extra_i += 1; - const coerced = try sema.coerce(block, .u32, try sema.resolveInst(ref), align_src); + const coerced = try sema.coerce(block, align_ty, try sema.resolveInst(ref), align_src); const val = try sema.resolveConstDefinedValue(block, align_src, coerced, .{ .simple = .@"align" }); // Check if this happens to be the lazy alignment of our element type, in // which case we can make this 0 without resolving it. @@ -20325,15 +20331,11 @@ fn zirReify( try ip.getOrPutString(gpa, pt.tid, "sentinel_ptr", .no_embedded_nulls), ).?); - if (!try sema.intFitsInType(alignment_val, .u32, null)) { - return sema.fail(block, src, "alignment must fit in 'u32'", .{}); + if (!try sema.intFitsInType(alignment_val, align_ty, null)) { + return sema.fail(block, src, "alignment must fit in '{}'", .{align_ty.fmt(pt)}); } - const alignment_val_int = try alignment_val.toUnsignedIntSema(pt); - if (alignment_val_int > 0 and !math.isPowerOfTwo(alignment_val_int)) { - return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{alignment_val_int}); - } - const abi_align = Alignment.fromByteUnits(alignment_val_int); + const abi_align = try sema.validateAlign(block, src, alignment_val_int); const elem_ty = child_val.toType(); if (abi_align != .none) { @@ -21017,11 +21019,7 @@ fn reifyUnion( field_ty.* = field_type_val.toIntern(); if (any_aligns) { const byte_align = try (try field_info.fieldValue(pt, 2)).toUnsignedIntSema(pt); - if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) { - // TODO: better source location - return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align}); - } - field_aligns[field_idx] = Alignment.fromByteUnits(byte_align); + field_aligns[field_idx] = try sema.validateAlign(block, src, byte_align); } } @@ -21062,11 +21060,7 @@ fn reifyUnion( field_ty.* = field_type_val.toIntern(); if (any_aligns) { const byte_align = try (try field_info.fieldValue(pt, 2)).toUnsignedIntSema(pt); - if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) { - // TODO: better source location - return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align}); - } - field_aligns[field_idx] = Alignment.fromByteUnits(byte_align); + field_aligns[field_idx] = try sema.validateAlign(block, src, byte_align); } } @@ -21266,7 +21260,6 @@ fn reifyStruct( var any_comptime_fields = false; var any_default_inits = false; - var any_aligned_fields = false; for (0..fields_len) |field_idx| { const field_info = try fields_val.elemValue(pt, field_idx); @@ -21301,11 +21294,6 @@ fn reifyStruct( if (field_is_comptime) any_comptime_fields = true; if (field_default_value != .none) any_default_inits = true; - switch (try field_alignment_val.orderAgainstZeroSema(pt)) { - .eq => {}, - .gt => any_aligned_fields = true, - .lt => unreachable, - } } const tracked_inst = try block.trackZir(inst); @@ -21317,7 +21305,7 @@ fn reifyStruct( .requires_comptime = .unknown, .any_comptime_fields = any_comptime_fields, .any_default_inits = any_default_inits, - .any_aligned_fields = any_aligned_fields, + .any_aligned_fields = true, .inits_resolved = true, .key = .{ .reified = .{ .zir_index = tracked_inst, @@ -21361,21 +21349,14 @@ fn reifyStruct( return sema.fail(block, src, "duplicate struct field name {f}", .{field_name.fmt(ip)}); } - if (any_aligned_fields) { - if (!try sema.intFitsInType(field_alignment_val, .u32, null)) { - return sema.fail(block, src, "alignment must fit in 'u32'", .{}); - } - - const byte_align = try field_alignment_val.toUnsignedIntSema(pt); - if (byte_align == 0) { - if (layout != .@"packed") { - struct_type.field_aligns.get(ip)[field_idx] = .none; - } - } else { - if (layout == .@"packed") return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{}); - if (!math.isPowerOfTwo(byte_align)) return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align}); - struct_type.field_aligns.get(ip)[field_idx] = Alignment.fromNonzeroByteUnits(byte_align); - } + if (!try sema.intFitsInType(field_alignment_val, align_ty, null)) { + return sema.fail(block, src, "alignment must fit in '{f}'", .{align_ty.fmt(pt)}); + } + const byte_align = try field_alignment_val.toUnsignedIntSema(pt); + if (layout == .@"packed") { + if (byte_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{}); + } else { + struct_type.field_aligns.get(ip)[field_idx] = try sema.validateAlign(block, src, byte_align); } const field_is_comptime = field_is_comptime_val.toBool(); diff --git a/test/cases/compile_errors/align_zero.zig b/test/cases/compile_errors/align_zero.zig index a63523b853..e6d1a993d4 100644 --- a/test/cases/compile_errors/align_zero.zig +++ b/test/cases/compile_errors/align_zero.zig @@ -1,52 +1,98 @@ -pub var global_var: i32 align(0) = undefined; +var global_var: i32 align(0) = undefined; -pub export fn a() void { +export fn a() void { _ = &global_var; } -pub extern var extern_var: i32 align(0); +extern var extern_var: i32 align(0); -pub export fn b() void { +export fn b() void { _ = &extern_var; } -pub export fn c() align(0) void {} +export fn c() align(0) void {} -pub export fn d() void { +export fn d() void { _ = *align(0) fn () i32; } -pub export fn e() void { +export fn e() void { var local_var: i32 align(0) = undefined; _ = &local_var; } -pub export fn f() void { +export fn f() void { _ = *align(0) i32; } -pub export fn g() void { +export fn g() void { _ = []align(0) i32; } -pub export fn h() void { +export fn h() void { _ = struct { field: i32 align(0) }; } -pub export fn i() void { +export fn i() void { _ = union { field: i32 align(0) }; } +export fn j() void { + _ = @Type(.{ .@"struct" = .{ + .layout = .auto, + .fields = &.{.{ + .name = "test", + .type = u32, + .default_value_ptr = null, + .is_comptime = false, + .alignment = 0, + }}, + .decls = &.{}, + .is_tuple = false, + } }); +} + +export fn k() void { + _ = @Type(.{ .pointer = .{ + .size = .one, + .is_const = false, + .is_volatile = false, + .alignment = 0, + .address_space = .generic, + .child = u32, + .is_allowzero = false, + .sentinel_ptr = null, + } }); +} + +export fn l() void { + _ = @Type(.{ .@"struct" = .{ + .layout = .@"packed", + .fields = &.{.{ + .name = "test", + .type = u32, + .default_value_ptr = null, + .is_comptime = false, + .alignment = 8, + }}, + .decls = &.{}, + .is_tuple = false, + } }); +} + // error // backend=stage2 // target=native // -// :1:31: error: alignment must be >= 1 -// :7:38: error: alignment must be >= 1 -// :13:25: error: alignment must be >= 1 +// :1:27: error: alignment must be >= 1 +// :7:34: error: alignment must be >= 1 +// :13:21: error: alignment must be >= 1 // :16:16: error: alignment must be >= 1 // :20:30: error: alignment must be >= 1 // :25:16: error: alignment must be >= 1 // :29:17: error: alignment must be >= 1 // :33:35: error: alignment must be >= 1 // :37:34: error: alignment must be >= 1 +// :41:9: error: alignment can only be 0 on packed struct fields +// :56:9: error: alignment must be >= 1 +// :69:9: error: alignment in a packed struct field must be set to 0 diff --git a/test/cases/compile_errors/bad_alignment_type.zig b/test/cases/compile_errors/bad_alignment_type.zig index c85eb8427d..c03f05d0ad 100644 --- a/test/cases/compile_errors/bad_alignment_type.zig +++ b/test/cases/compile_errors/bad_alignment_type.zig @@ -11,5 +11,5 @@ export fn entry2() void { // backend=stage2 // target=native // -// :2:22: error: expected type 'u32', found 'bool' -// :6:21: error: fractional component prevents float value '12.34' from coercion to type 'u32' +// :2:22: error: expected type 'u29', found 'bool' +// :6:21: error: fractional component prevents float value '12.34' from coercion to type 'u29' diff --git a/test/cases/compile_errors/reify_type_with_invalid_field_alignment.zig b/test/cases/compile_errors/reify_type_with_invalid_field_alignment.zig index 0fcb4ba7fc..a04f3e957c 100644 --- a/test/cases/compile_errors/reify_type_with_invalid_field_alignment.zig +++ b/test/cases/compile_errors/reify_type_with_invalid_field_alignment.zig @@ -43,6 +43,6 @@ comptime { // error // -// :2:9: error: alignment value '3' is not a power of two or zero -// :14:9: error: alignment value '5' is not a power of two or zero -// :30:9: error: alignment value '7' is not a power of two or zero +// :2:9: error: alignment value '3' is not a power of two +// :14:9: error: alignment value '5' is not a power of two +// :30:9: error: alignment value '7' is not a power of two