aboutsummaryrefslogtreecommitdiff
path: root/src/check_expr.c
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2017-02-05 15:19:30 +0000
committerGinger Bill <bill@gingerbill.org>2017-02-05 15:19:30 +0000
commit2a5b674d33e4f483964da119f76038457cd9f1f2 (patch)
tree1e094b9e6ed3fa435dc5c76cdf7f4a7e740781f7 /src/check_expr.c
parent7944b7714f5478b9a89e3fc1e331e8090652e49e (diff)
Custom struct alignment
Diffstat (limited to 'src/check_expr.c')
-rw-r--r--src/check_expr.c39
1 files changed, 39 insertions, 0 deletions
diff --git a/src/check_expr.c b/src/check_expr.c
index 21e357c9d..c001a903f 100644
--- a/src/check_expr.c
+++ b/src/check_expr.c
@@ -553,6 +553,45 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) {
}
type_set_offsets(c->sizes, c->allocator, struct_type);
+
+ if (st->align != NULL) {
+ if (st->is_packed) {
+ syntax_error_node(st->align, "`#align` cannot be applied with `#packed`");
+ return;
+ }
+
+ Operand o = {0};
+ check_expr(c, &o, st->align);
+ if (o.mode != Addressing_Constant) {
+ if (o.mode != Addressing_Invalid) {
+ error_node(st->align, "#align must be a constant");
+ }
+ return;
+ }
+
+ Type *type = base_type(o.type);
+ if (is_type_untyped(type) || is_type_integer(type)) {
+ if (o.value.kind == ExactValue_Integer) {
+ i64 align = o.value.value_integer;
+ if (align < 1 || !gb_is_power_of_two(align)) {
+ error_node(st->align, "#align must be a power of 2, got %lld", align);
+ return;
+ }
+
+ // NOTE(bill): Success!!!
+ i64 custom_align = gb_clamp(align, 1, c->sizes.max_align);
+ if (custom_align < align) {
+ warning_node(st->align, "Custom alignment has been clamped to %lld from %lld", align, custom_align);
+ }
+ struct_type->Record.custom_align = custom_align;
+ return;
+ }
+ }
+
+ error_node(st->align, "#align must be an integer");
+ return;
+ }
+
}
void check_union_type(Checker *c, Type *union_type, AstNode *node) {