aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/check_expr.cpp52
-rw-r--r--src/main.cpp1
-rw-r--r--src/parser.cpp31
-rw-r--r--src/types.cpp70
4 files changed, 104 insertions, 50 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 18cd3026d..1ee250ed2 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -1250,12 +1250,12 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node, Array<Opera
if (!struct_type->failure && !st->is_packed && !st->is_ordered) {
struct_type->failure = false;
struct_type->Struct.are_offsets_set = false;
- struct_type->Struct.offsets = nullptr;
+ gb_zero_item(&struct_type->Struct.offsets);
// NOTE(bill): Reorder fields for reduced size/performance
Array<Entity *> reordered_fields = {};
array_init_count(&reordered_fields, c->allocator, fields.count);
- for_array(i, fields) {
+ for_array(i, reordered_fields) {
reordered_fields[i] = struct_type->Struct.fields_in_src_order[i];
}
@@ -1338,10 +1338,10 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
if (t != nullptr && t != t_invalid) {
bool ok = true;
t = default_type(t);
- if (is_type_untyped(t)) {
+ if (is_type_untyped(t) || is_type_empty_union(t)) {
ok = false;
gbString str = type_to_string(t);
- error(node, "Invalid type in union `%s`", str);
+ error(node, "Invalid variant type in union `%s`", str);
gb_string_free(str);
} else {
for_array(j, variants) {
@@ -1362,6 +1362,44 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
}
union_type->Union.variants = variants;
+
+ if (ut->align != nullptr) {
+ Operand o = {};
+ check_expr(c, &o, ut->align);
+ if (o.mode != Addressing_Constant) {
+ if (o.mode != Addressing_Invalid) {
+ error(ut->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 = i128_to_i64(o.value.value_integer);
+ if (align < 1 || !gb_is_power_of_two(align)) {
+ error(ut->align, "#align must be a power of 2, got %lld", align);
+ return;
+ }
+
+ // NOTE(bill): Success!!!
+ i64 custom_align = gb_clamp(align, 1, build_context.max_align);
+ if (custom_align < align) {
+ warning(ut->align, "Custom alignment has been clamped to %lld from %lld", align, custom_align);
+ }
+ if (variants.count == 0) {
+ error(ut->align, "An empty union cannot have a custom alignment");
+ } else {
+ union_type->Union.custom_align = custom_align;
+ }
+ return;
+ }
+ }
+
+ error(ut->align, "#align must be an integer");
+ return;
+ }
+
}
// void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
@@ -1653,9 +1691,9 @@ bool check_type_specialization_to(Checker *c, Type *specialization, Type *type,
return true;
}
- if (t->Struct.polymorphic_parent == s->Struct.polymorphic_parent) {
- GB_ASSERT(s->Struct.polymorphic_params != nullptr);
- GB_ASSERT(t->Struct.polymorphic_params != nullptr);
+ if (t->Struct.polymorphic_parent == s->Struct.polymorphic_parent &&
+ s->Struct.polymorphic_params != nullptr &&
+ t->Struct.polymorphic_params != nullptr) {
TypeTuple *s_tuple = &s->Struct.polymorphic_params->Tuple;
TypeTuple *t_tuple = &t->Struct.polymorphic_params->Tuple;
diff --git a/src/main.cpp b/src/main.cpp
index a6590956d..abee3e4b0 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,4 +1,5 @@
#define USE_CUSTOM_BACKEND 0
+// #define NO_ARRAY_BOUNDS_CHECK
#include "common.cpp"
#include "timings.cpp"
diff --git a/src/parser.cpp b/src/parser.cpp
index 9b848ca7e..4e764d2a6 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -427,8 +427,9 @@ AST_NODE_KIND(_TypeBegin, "", i32) \
AstNode * align; \
}) \
AST_NODE_KIND(UnionType, "union type", struct { \
- Token token; \
- Array<AstNode *> variants; \
+ Token token; \
+ Array<AstNode *> variants; \
+ AstNode * align; \
}) \
AST_NODE_KIND(EnumType, "enum type", struct { \
Token token; \
@@ -1460,10 +1461,11 @@ AstNode *ast_struct_type(AstFile *f, Token token, Array<AstNode *> fields, isize
}
-AstNode *ast_union_type(AstFile *f, Token token, Array<AstNode *> variants) {
+AstNode *ast_union_type(AstFile *f, Token token, Array<AstNode *> variants, AstNode *align) {
AstNode *result = make_ast_node(f, AstNode_UnionType);
- result->UnionType.token = token;
- result->UnionType.variants = variants;
+ result->UnionType.token = token;
+ result->UnionType.variants = variants;
+ result->UnionType.align = align;
return result;
}
@@ -2496,10 +2498,23 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
Token open = expect_token_after(f, Token_OpenBrace, "union");
Array<AstNode *> variants = make_ast_node_array(f);
isize total_decl_name_count = 0;
+ AstNode *align = nullptr;
CommentGroup docs = f->lead_comment;
Token start_token = f->curr_token;
+ while (allow_token(f, Token_Hash)) {
+ Token tag = expect_token_after(f, Token_Ident, "#");
+ if (tag.string == "align") {
+ if (align) {
+ syntax_error(tag, "Duplicate union tag `#%.*s`", LIT(tag.string));
+ }
+ align = parse_expr(f, true);
+ } else {
+ syntax_error(tag, "Invalid union tag `#%.*s`", LIT(tag.string));
+ }
+ }
+
while (f->curr_token.kind != Token_CloseBrace &&
f->curr_token.kind != Token_EOF) {
@@ -2514,7 +2529,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
Token close = expect_token(f, Token_CloseBrace);
- return ast_union_type(f, token, variants);
+ return ast_union_type(f, token, variants, align);
} break;
case Token_enum: {
@@ -3009,15 +3024,13 @@ AstNode *parse_gen_decl(AstFile *f, Token token, ParseSpecFunc *func) {
if (f->curr_token.kind == Token_OpenParen) {
specs = make_ast_node_array(f);
open = expect_token(f, Token_OpenParen);
- bool require_semicolon_after_paren = false;
while (f->curr_token.kind != Token_CloseParen &&
f->curr_token.kind != Token_EOF) {
AstNode *spec = func(f, docs, token);
array_add(&specs, spec);
}
close = expect_token(f, Token_CloseParen);
- if (require_semicolon_after_paren ||
- f->curr_token.pos.line == close.pos.line ||
+ if (f->curr_token.pos.line == close.pos.line ||
open.pos.line == close.pos.line) {
expect_semicolon(f, nullptr);
}
diff --git a/src/types.cpp b/src/types.cpp
index e7f183e79..ab215fde4 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -74,16 +74,16 @@ struct TypeStruct {
AstNode *node;
Scope * scope;
- i64 * offsets; // == fields.count
- bool are_offsets_set;
- bool are_offsets_being_processed;
- bool is_packed;
- bool is_ordered;
- bool is_raw_union;
- bool is_polymorphic;
- bool is_poly_specialized;
- Type * polymorphic_params; // Type_Tuple
- Type * polymorphic_parent;
+ Array<i64> offsets;
+ bool are_offsets_set;
+ bool are_offsets_being_processed;
+ bool is_packed;
+ bool is_ordered;
+ bool is_raw_union;
+ bool is_polymorphic;
+ bool is_poly_specialized;
+ Type * polymorphic_params; // Type_Tuple
+ Type * polymorphic_parent;
i64 custom_align; // NOTE(bill): Only used in structs at the moment
Entity * names;
@@ -128,8 +128,8 @@ struct TypeStruct {
}) \
TYPE_KIND(Tuple, struct { \
Array<Entity *> variables; /* Entity_Variable */ \
- bool are_offsets_set; \
- i64 * offsets; \
+ Array<i64> offsets; \
+ bool are_offsets_set; \
}) \
TYPE_KIND(Proc, struct { \
AstNode *node; \
@@ -1831,6 +1831,9 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
if (t->Union.variants.count == 0) {
return 1;
}
+ if (t->Union.custom_align > 0) {
+ return gb_clamp(t->Union.custom_align, 1, build_context.max_align);
+ }
i64 max = build_context.word_size;
for_array(i, t->Union.variants) {
Type *variant = t->Union.variants[i];
@@ -1848,6 +1851,9 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
} break;
case Type_Struct: {
+ if (t->Struct.custom_align > 0) {
+ return gb_clamp(t->Struct.custom_align, 1, build_context.max_align);
+ }
if (t->Struct.is_raw_union) {
i64 max = 1;
for_array(i, t->Struct.fields) {
@@ -1863,29 +1869,24 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
}
}
return max;
- } else {
- if (t->Struct.custom_align > 0) {
- return gb_clamp(t->Struct.custom_align, 1, build_context.max_align);
+ } else if (t->Struct.fields.count > 0) {
+ i64 max = 1;
+ if (t->Struct.is_packed) {
+ max = build_context.word_size;
}
- if (t->Struct.fields.count > 0) {
- i64 max = 1;
- if (t->Struct.is_packed) {
- max = build_context.word_size;
+ for_array(i, t->Struct.fields) {
+ Type *field_type = t->Struct.fields[i]->type;
+ type_path_push(path, field_type);
+ if (path->failure) {
+ return FAILURE_ALIGNMENT;
}
- for_array(i, t->Struct.fields) {
- Type *field_type = t->Struct.fields[i]->type;
- type_path_push(path, field_type);
- if (path->failure) {
- return FAILURE_ALIGNMENT;
- }
- i64 align = type_align_of_internal(allocator, field_type, path);
- type_path_pop(path);
- if (max < align) {
- max = align;
- }
+ i64 align = type_align_of_internal(allocator, field_type, path);
+ type_path_pop(path);
+ if (max < align) {
+ max = align;
}
- return max;
}
+ return max;
}
} break;
@@ -1904,8 +1905,9 @@ i64 type_align_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
return gb_clamp(next_pow2(type_size_of_internal(allocator, t, path)), 1, build_context.word_size);
}
-i64 *type_set_offsets_of(gbAllocator allocator, Array<Entity *> fields, bool is_packed, bool is_raw_union) {
- i64 *offsets = gb_alloc_array(allocator, i64, fields.count);
+Array<i64> type_set_offsets_of(gbAllocator allocator, Array<Entity *> fields, bool is_packed, bool is_raw_union) {
+ Array<i64> offsets = {};
+ array_init_count(&offsets, allocator, fields.count);
i64 curr_offset = 0;
if (is_raw_union) {
for_array(i, fields) {
@@ -2120,7 +2122,7 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
if (path->failure) {
return FAILURE_SIZE;
}
- if (t->Struct.are_offsets_being_processed && t->Struct.offsets == nullptr) {
+ if (t->Struct.are_offsets_being_processed && t->Struct.offsets.data == nullptr) {
type_path_print_illegal_cycle(path, path->path.count-1);
return FAILURE_SIZE;
}