mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-24 14:45:00 -07:00
Add #field_align(N)
It sets the minimum alignment for the fields within a struct. This cannot be used with `#packed`, but can be used with `#align(N)`. If `#align(N)` is less than `#field_align(N)`, then a warning will be printed.
This commit is contained in:
+25
-15
@@ -219,13 +219,13 @@ gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entit
|
||||
}
|
||||
|
||||
|
||||
gb_internal bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) {
|
||||
gb_internal bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_, char const *msg) {
|
||||
GB_ASSERT(align_ != nullptr);
|
||||
Operand o = {};
|
||||
check_expr(ctx, &o, node);
|
||||
if (o.mode != Addressing_Constant) {
|
||||
if (o.mode != Addressing_Invalid) {
|
||||
error(node, "#align must be a constant");
|
||||
error(node, "#%s must be a constant", msg);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -237,13 +237,13 @@ gb_internal bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_)
|
||||
if (v.used > 1) {
|
||||
gbAllocator a = heap_allocator();
|
||||
String str = big_int_to_string(a, &v);
|
||||
error(node, "#align too large, %.*s", LIT(str));
|
||||
error(node, "#%s too large, %.*s", msg, LIT(str));
|
||||
gb_free(a, str.text);
|
||||
return false;
|
||||
}
|
||||
i64 align = big_int_to_i64(&v);
|
||||
if (align < 1 || !gb_is_power_of_two(cast(isize)align)) {
|
||||
error(node, "#align must be a power of 2, got %lld", align);
|
||||
error(node, "#%s must be a power of 2, got %lld", msg, align);
|
||||
return false;
|
||||
}
|
||||
*align_ = align;
|
||||
@@ -251,7 +251,7 @@ gb_internal bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_)
|
||||
}
|
||||
}
|
||||
|
||||
error(node, "#align must be an integer");
|
||||
error(node, "#%s must be an integer", msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -645,16 +645,26 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *
|
||||
check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context);
|
||||
}
|
||||
|
||||
if (st->align != nullptr) {
|
||||
if (st->is_packed) {
|
||||
syntax_error(st->align, "'#align' cannot be applied with '#packed'");
|
||||
return;
|
||||
}
|
||||
i64 custom_align = 1;
|
||||
if (check_custom_align(ctx, st->align, &custom_align)) {
|
||||
struct_type->Struct.custom_align = custom_align;
|
||||
}
|
||||
#define ST_ALIGN(_name) if (st->_name != nullptr) { \
|
||||
if (st->is_packed) { \
|
||||
syntax_error(st->_name, "'#%s' cannot be applied with '#packed'", #_name); \
|
||||
return; \
|
||||
} \
|
||||
i64 align = 1; \
|
||||
if (check_custom_align(ctx, st->_name, &align, #_name)) { \
|
||||
struct_type->Struct.custom_##_name = align; \
|
||||
} \
|
||||
}
|
||||
|
||||
ST_ALIGN(field_align);
|
||||
ST_ALIGN(align);
|
||||
if (struct_type->Struct.custom_align < struct_type->Struct.custom_field_align) {
|
||||
warning(st->align, "#align(%lld) is defined to be less than #field_name(%lld)",
|
||||
cast(long long)struct_type->Struct.custom_align,
|
||||
cast(long long)struct_type->Struct.custom_field_align);
|
||||
}
|
||||
|
||||
#undef ST_ALIGN
|
||||
}
|
||||
gb_internal void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Operand> *poly_operands, Type *named_type, Type *original_type_for_poly) {
|
||||
GB_ASSERT(is_type_union(union_type));
|
||||
@@ -746,7 +756,7 @@ gb_internal void check_union_type(CheckerContext *ctx, Type *union_type, Ast *no
|
||||
|
||||
if (ut->align != nullptr) {
|
||||
i64 custom_align = 1;
|
||||
if (check_custom_align(ctx, ut->align, &custom_align)) {
|
||||
if (check_custom_align(ctx, ut->align, &custom_align, "align")) {
|
||||
if (variants.count == 0) {
|
||||
error(ut->align, "An empty union cannot have a custom alignment");
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user