diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/check_expr.cpp | 52 | ||||
| -rw-r--r-- | src/main.cpp | 1 | ||||
| -rw-r--r-- | src/parser.cpp | 31 | ||||
| -rw-r--r-- | src/types.cpp | 70 |
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; } |