Commit acf9de376d

Krzysztof Wolicki <der.teufel.mail@gmail.com>
2023-11-16 09:19:54
Sema: Add error for non-power of 2 field alignment when reifying Unions, Structs, Pointers
1 parent 359842f
Changed files (2)
src/Sema.zig
@@ -20431,9 +20431,11 @@ fn zirReify(
                 return sema.fail(block, src, "alignment must fit in 'u32'", .{});
             }
 
-            const abi_align = Alignment.fromByteUnits(
-                (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?,
-            );
+            const alignment_val_int = (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?;
+            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 elem_ty = child_val.toType();
             if (abi_align != .none) {
@@ -20895,7 +20897,14 @@ fn zirReify(
                 }
 
                 const field_ty = type_val.toType();
-                const field_align = Alignment.fromByteUnits((try alignment_val.getUnsignedIntAdvanced(mod, sema)).?);
+                const alignment_val_int = (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?;
+                if (alignment_val_int > 0 and !math.isPowerOfTwo(alignment_val_int)) {
+                    // TODO: better source location
+                    return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{
+                        alignment_val_int,
+                    });
+                }
+                const field_align = Alignment.fromByteUnits(alignment_val_int);
                 any_aligned_fields = any_aligned_fields or field_align != .none;
 
                 try union_fields.append(sema.arena, .{
@@ -21214,6 +21223,7 @@ fn reifyStruct(
             if (abi_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{});
             if (is_comptime_val.toBool()) return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{});
         } else {
+            if (abi_align > 0 and !math.isPowerOfTwo(abi_align)) return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{abi_align});
             struct_type.field_aligns.get(ip)[i] = Alignment.fromByteUnits(abi_align);
         }
         if (layout == .Extern and is_comptime_val.toBool()) {
test/cases/compile_errors/reify_type_with_invalid_field_alignment.zig
@@ -0,0 +1,50 @@
+comptime {
+    _ = @Type(.{
+        .Union = .{
+            .layout = .Auto,
+            .tag_type = null,
+            .fields = &.{
+                .{ .name = "foo", .type = usize, .alignment = 3 },
+            },
+            .decls = &.{},
+        },
+    });
+}
+comptime {
+    _ = @Type(.{
+        .Struct = .{
+            .layout = .Auto,
+            .fields = &.{.{
+                .name = "0",
+                .type = u32,
+                .default_value = null,
+                .is_comptime = true,
+                .alignment = 5,
+            }},
+            .decls = &.{},
+            .is_tuple = false,
+        },
+    });
+}
+comptime {
+    _ = @Type(.{
+        .Pointer = .{
+            .size = .Many,
+            .is_const = true,
+            .is_volatile = false,
+            .alignment = 7,
+            .address_space = .generic,
+            .child = u8,
+            .is_allowzero = false,
+            .sentinel = null,
+        },
+    });
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :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