diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin index 309d2c147..52845ea4e 100644 --- a/core/odin/ast/ast.odin +++ b/core/odin/ast/ast.odin @@ -410,6 +410,7 @@ Foreign_Import_Decl :: struct { name: ^Ident, collection_name: string, fullpaths: []string, + attributes: [dynamic]^Attribute, // dynamic as parsing will add to them lazily comment: ^Comment_Group, } diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index fb3a87e8b..7da4a0b44 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -827,6 +827,9 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind: case ast.Foreign_Block_Decl: if d.docs == nil do d.docs = docs; append(&d.attributes, attribute); + case ast.Foreign_Import_Decl: + if d.docs == nil do d.docs = docs; + append(&d.attributes, attribute); case: error(p, decl.pos, "expected a value or foreign declaration after an attribute"); free(attribute); diff --git a/src/checker.cpp b/src/checker.cpp index e7b347f1a..4490caa69 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -803,6 +803,7 @@ void init_checker_info(CheckerInfo *i) { map_init(&i->files, a); map_init(&i->packages, a); array_init(&i->variable_init_order, a); + array_init(&i->required_foreign_imports_through_force, a); i->allow_identifier_uses = build_context.query_data_set_settings.kind == QueryDataSet_GoToDefinitions; if (i->allow_identifier_uses) { @@ -823,6 +824,8 @@ void destroy_checker_info(CheckerInfo *i) { map_destroy(&i->packages); array_free(&i->variable_init_order); array_free(&i->identifier_uses); + array_free(&i->required_foreign_imports_through_force); + } CheckerContext make_checker_context(Checker *c) { @@ -1696,6 +1699,11 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { } } + for_array(i, c->info.required_foreign_imports_through_force) { + Entity *e = c->info.required_foreign_imports_through_force[i]; + add_dependency_to_set(c, e); + } + add_dependency_to_set(c, start); } @@ -3172,6 +3180,16 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) { scope->flags |= ScopeFlag_HasBeenImported; } +DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) { + if (name == "force") { + if (value != nullptr) { + error(elem, "Expected no parameter for '%.*s'", LIT(name)); + } + ac->force_foreign_import = true; + return true; + } + return false; +} void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { if (decl->been_handled) return; @@ -3216,6 +3234,14 @@ void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) { Entity *e = alloc_entity_library_name(parent_scope, fl->library_name, t_invalid, fl->fullpaths, library_name); add_entity(ctx->checker, parent_scope, nullptr, e); + + + AttributeContext ac = {}; + check_decl_attributes(ctx, fl->attributes, foreign_import_decl_attribute, &ac); + if (ac.force_foreign_import) { + array_add(&ctx->info->required_foreign_imports_through_force, e); + add_entity_use(ctx, nullptr, e); + } } bool collect_checked_packages_from_decl_list(Checker *c, Array const &decls) { diff --git a/src/checker.hpp b/src/checker.hpp index c33514511..c5d6f71cd 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -98,6 +98,7 @@ struct AttributeContext { bool is_export; bool is_static; bool require_results; + bool force_foreign_import; String link_name; String link_prefix; isize init_expr_list_count; @@ -249,6 +250,8 @@ struct CheckerInfo { PtrSet minimum_dependency_set; PtrSet minimum_dependency_type_info_set; + Array required_foreign_imports_through_force; + bool allow_identifier_uses; Array identifier_uses; // only used by 'odin query' diff --git a/src/ir.cpp b/src/ir.cpp index e7317a960..8d5587341 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -11335,6 +11335,11 @@ void ir_gen_tree(irGen *s) { } } + for_array(i, m->info->required_foreign_imports_through_force) { + Entity *e = m->info->required_foreign_imports_through_force[i]; + ir_add_foreign_library_path(m, e); + } + #endif { // Startup Runtime // Cleanup(bill): probably better way of doing code insertion diff --git a/src/parser.cpp b/src/parser.cpp index 10aa10119..cb04ca1f5 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1049,6 +1049,8 @@ Ast *ast_foreign_import_decl(AstFile *f, Token token, Array filepaths, To result->ForeignImportDecl.library_name = library_name; result->ForeignImportDecl.docs = docs; result->ForeignImportDecl.comment = comment; + result->ForeignImportDecl.attributes.allocator = heap_allocator(); + return result; } @@ -3865,7 +3867,9 @@ Ast *parse_attribute(AstFile *f, Token token, TokenKind open_kind, TokenKind clo array_add(&decl->ValueDecl.attributes, attribute); } else if (decl->kind == Ast_ForeignBlockDecl) { array_add(&decl->ForeignBlockDecl.attributes, attribute); - } else { + } else if (decl->kind == Ast_ForeignImportDecl) { + array_add(&decl->ForeignImportDecl.attributes, attribute); + }else { syntax_error(decl, "Expected a value or foreign declaration after an attribute, got %.*s", LIT(ast_strings[decl->kind])); return ast_bad_stmt(f, token, f->curr_token); } diff --git a/src/parser.hpp b/src/parser.hpp index f07f3ce0d..b9e53dbe8 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -426,6 +426,7 @@ AST_KIND(_DeclBegin, "", bool) \ Token library_name; \ String collection_name; \ Array fullpaths; \ + Array attributes; \ CommentGroup *docs; \ CommentGroup *comment; \ }) \