aboutsummaryrefslogtreecommitdiff
path: root/src/checker.cpp
diff options
context:
space:
mode:
authorkorvahkh <92224397+korvahkh@users.noreply.github.com>2024-06-13 01:27:44 +0000
committerGitHub <noreply@github.com>2024-06-13 01:27:44 +0000
commit104ca2ce22c269b71df08edb00cb26bee4daf59d (patch)
treeee0a3275d3b42ae9aa85d09bf01f278d3965cc31 /src/checker.cpp
parenta7a6ff8c693be92929327660fd446dfc0af62e01 (diff)
parenta67df0739245d85e7aa773e7271a64121ca534c5 (diff)
Merge branch 'odin-lang:master' into fix-omitempty-comma
Diffstat (limited to 'src/checker.cpp')
-rw-r--r--src/checker.cpp252
1 files changed, 176 insertions, 76 deletions
diff --git a/src/checker.cpp b/src/checker.cpp
index 9d44c34dc..852fb89bb 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -3,6 +3,8 @@
#include "entity.cpp"
#include "types.cpp"
+String get_final_microarchitecture();
+
gb_internal void check_expr(CheckerContext *c, Operand *operand, Ast *expression);
gb_internal void check_expr_or_type(CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint=nullptr);
gb_internal void add_comparison_procedures_for_fields(CheckerContext *c, Type *t);
@@ -1016,6 +1018,7 @@ gb_internal void init_universal(void) {
{"NetBSD", TargetOs_netbsd},
{"WASI", TargetOs_wasi},
{"JS", TargetOs_js},
+ {"Orca", TargetOs_orca},
{"Freestanding", TargetOs_freestanding},
};
@@ -1039,6 +1042,8 @@ gb_internal void init_universal(void) {
add_global_enum_constant(fields, "ODIN_ARCH", bc->metrics.arch);
add_global_string_constant("ODIN_ARCH_STRING", target_arch_names[bc->metrics.arch]);
}
+
+ add_global_string_constant("ODIN_MICROARCH_STRING", get_final_microarchitecture());
{
GlobalEnumValue values[BuildMode_COUNT] = {
@@ -1130,6 +1135,17 @@ gb_internal void init_universal(void) {
add_global_constant("ODIN_COMPILE_TIMESTAMP", t_untyped_integer, exact_value_i64(odin_compile_timestamp()));
{
+ String version = {};
+
+ #ifdef GIT_SHA
+ version.text = cast(u8 *)GIT_SHA;
+ version.len = gb_strlen(GIT_SHA);
+ #endif
+
+ add_global_string_constant("ODIN_VERSION_HASH", version);
+ }
+
+ {
bool f16_supported = lb_use_new_pass_system();
if (is_arch_wasm()) {
f16_supported = false;
@@ -1166,6 +1182,18 @@ gb_internal void init_universal(void) {
add_global_constant("ODIN_SANITIZER_FLAGS", named_type, exact_value_u64(bc->sanitizer_flags));
}
+ {
+ GlobalEnumValue values[5] = {
+ {"None", -1},
+ {"Minimal", 0},
+ {"Size", 1},
+ {"Speed", 2},
+ {"Aggressive", 3},
+ };
+
+ auto fields = add_global_enum_type(str_lit("Odin_Optimization_Mode"), values, gb_count_of(values));
+ add_global_enum_constant(fields, "ODIN_OPTIMIZATION_MODE", bc->optimization_level);
+ }
// Builtin Procedures
@@ -1283,6 +1311,7 @@ gb_internal void init_checker_info(CheckerInfo *i) {
mpsc_init(&i->definition_queue, a); //); // 1<<20);
mpsc_init(&i->required_global_variable_queue, a); // 1<<10);
mpsc_init(&i->required_foreign_imports_through_force_queue, a); // 1<<10);
+ mpsc_init(&i->foreign_imports_to_check_fullpaths, a); // 1<<10);
mpsc_init(&i->intrinsics_entry_point_usage, a); // 1<<10); // just waste some memory here, even if it probably never used
string_map_init(&i->load_directory_cache);
@@ -1307,6 +1336,7 @@ gb_internal void destroy_checker_info(CheckerInfo *i) {
mpsc_destroy(&i->definition_queue);
mpsc_destroy(&i->required_global_variable_queue);
mpsc_destroy(&i->required_foreign_imports_through_force_queue);
+ mpsc_destroy(&i->foreign_imports_to_check_fullpaths);
map_destroy(&i->objc_msgSend_types);
string_map_destroy(&i->load_file_cache);
@@ -1449,6 +1479,10 @@ gb_internal Entity *entity_of_node(Ast *expr) {
case_ast_node(cc, CaseClause, expr);
return cc->implicit_entity;
case_end;
+
+ case_ast_node(ce, CallExpr, expr);
+ return ce->entity_procedure_of;
+ case_end;
}
return nullptr;
}
@@ -3125,6 +3159,18 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) {
error(elem, "Expected a string value for '%.*s'", LIT(name));
}
return true;
+ } else if (name == "link_suffix") {
+ if (ev.kind == ExactValue_String) {
+ String link_suffix = ev.value_string;
+ if (!is_foreign_name_valid(link_suffix)) {
+ error(elem, "Invalid link suffix: '%.*s'", LIT(link_suffix));
+ } else {
+ c->foreign_context.link_suffix = link_suffix;
+ }
+ } else {
+ error(elem, "Expected a string value for '%.*s'", LIT(name));
+ }
+ return true;
} else if (name == "private") {
EntityVisiblityKind kind = EntityVisiblity_PrivateToPackage;
if (ev.kind == ExactValue_Invalid) {
@@ -3419,6 +3465,18 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
error(elem, "Expected a string value for '%.*s'", LIT(name));
}
return true;
+ } else if (name == "link_suffix") {
+ ExactValue ev = check_decl_attribute_value(c, value);
+
+ if (ev.kind == ExactValue_String) {
+ ac->link_suffix = ev.value_string;
+ if (!is_foreign_name_valid(ac->link_suffix)) {
+ error(elem, "Invalid link suffix: %.*s", LIT(ac->link_suffix));
+ }
+ } else {
+ error(elem, "Expected a string value for '%.*s'", LIT(name));
+ }
+ return true;
} else if (name == "deprecated") {
ExactValue ev = check_decl_attribute_value(c, value);
@@ -3601,6 +3659,12 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) {
}
ac->is_static = true;
return true;
+ } else if (name == "rodata") {
+ if (value != nullptr) {
+ error(elem, "'rodata' does not have any parameters");
+ }
+ ac->rodata = true;
+ return true;
} else if (name == "thread_local") {
ExactValue ev = check_decl_attribute_value(c, value);
if (ac->init_expr_list_count > 0) {
@@ -3700,6 +3764,17 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) {
error(elem, "Expected a string value for '%.*s'", LIT(name));
}
return true;
+ } else if (name == "link_suffix") {
+ ExactValue ev = check_decl_attribute_value(c, value);
+ if (ev.kind == ExactValue_String) {
+ ac->link_suffix = ev.value_string;
+ if (!is_foreign_name_valid(ac->link_suffix)) {
+ error(elem, "Invalid link suffix: %.*s", LIT(ac->link_suffix));
+ }
+ } else {
+ error(elem, "Expected a string value for '%.*s'", LIT(name));
+ }
+ return true;
} else if (name == "link_section") {
ExactValue ev = check_decl_attribute_value(c, value);
if (ev.kind == ExactValue_String) {
@@ -3731,6 +3806,7 @@ gb_internal DECL_ATTRIBUTE_PROC(const_decl_attribute) {
name == "linkage" ||
name == "link_name" ||
name == "link_prefix" ||
+ name == "link_suffix" ||
false) {
error(elem, "@(%.*s) is not supported for compile time constant value declarations", LIT(name));
return true;
@@ -3773,8 +3849,10 @@ gb_internal void check_decl_attributes(CheckerContext *c, Array<Ast *> const &at
if (attributes.count == 0) return;
String original_link_prefix = {};
+ String original_link_suffix = {};
if (ac) {
original_link_prefix = ac->link_prefix;
+ original_link_suffix = ac->link_suffix;
}
StringSet set = {};
@@ -3849,6 +3927,12 @@ gb_internal void check_decl_attributes(CheckerContext *c, Array<Ast *> const &at
ac->link_prefix.len = 0;
}
}
+ if (ac->link_suffix.text == original_link_suffix.text) {
+ if (ac->link_name.len > 0) {
+ ac->link_suffix.text = nullptr;
+ ac->link_suffix.len = 0;
+ }
+ }
}
}
@@ -4143,6 +4227,7 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) {
e->Variable.foreign_library_ident = fl;
e->Variable.link_prefix = c->foreign_context.link_prefix;
+ e->Variable.link_suffix = c->foreign_context.link_suffix;
}
Ast *init_expr = value;
@@ -4217,6 +4302,7 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) {
}
}
e->Procedure.link_prefix = c->foreign_context.link_prefix;
+ e->Procedure.link_suffix = c->foreign_context.link_suffix;
GB_ASSERT(cc != ProcCC_Invalid);
pl->type->ProcType.calling_convention = cc;
@@ -4874,6 +4960,83 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) {
return false;
}
+gb_internal void check_foreign_import_fullpaths(Checker *c) {
+ CheckerContext ctx = make_checker_context(c);
+
+ UntypedExprInfoMap untyped = {};
+ defer (map_destroy(&untyped));
+
+ for (Entity *e = nullptr; mpsc_dequeue(&c->info.foreign_imports_to_check_fullpaths, &e); /**/) {
+ GB_ASSERT(e != nullptr);
+ GB_ASSERT(e->kind == Entity_LibraryName);
+ Ast *decl = e->LibraryName.decl;
+ ast_node(fl, ForeignImportDecl, decl);
+
+ AstFile *f = decl->file();
+
+ reset_checker_context(&ctx, f, &untyped);
+ ctx.collect_delayed_decls = false;
+
+ GB_ASSERT(ctx.scope == e->scope);
+
+ if (fl->fullpaths.count == 0) {
+ String base_dir = dir_from_path(decl->file()->fullpath);
+
+ auto fullpaths = array_make<String>(permanent_allocator(), 0, fl->filepaths.count);
+
+ for (Ast *fp_node : fl->filepaths) {
+ Operand op = {};
+ check_expr(&ctx, &op, fp_node);
+ if (op.mode != Addressing_Constant && op.value.kind != ExactValue_String) {
+ gbString s = expr_to_string(op.expr);
+ error(fp_node, "Expected a constant string value, got '%s'", s);
+ gb_string_free(s);
+ continue;
+ }
+ if (!is_type_string(op.type)) {
+ gbString s = type_to_string(op.type);
+ error(fp_node, "Expected a constant string value, got value of type '%s'", s);
+ gb_string_free(s);
+ continue;
+ }
+
+ String file_str = op.value.value_string;
+ file_str = string_trim_whitespace(file_str);
+
+ String fullpath = file_str;
+ if (allow_check_foreign_filepath()) {
+ String foreign_path = {};
+ bool ok = determine_path_from_string(nullptr, decl, base_dir, file_str, &foreign_path, /*use error not syntax_error*/true);
+ if (ok) {
+ fullpath = foreign_path;
+ }
+ }
+ array_add(&fullpaths, fullpath);
+ }
+ fl->fullpaths = slice_from_array(fullpaths);
+ }
+
+ for (String const &path : fl->fullpaths) {
+ String ext = path_extension(path);
+ if (str_eq_ignore_case(ext, ".c") ||
+ str_eq_ignore_case(ext, ".cpp") ||
+ str_eq_ignore_case(ext, ".cxx") ||
+ str_eq_ignore_case(ext, ".h") ||
+ str_eq_ignore_case(ext, ".hpp") ||
+ str_eq_ignore_case(ext, ".hxx") ||
+ false
+ ) {
+ error(fl->token, "With 'foreign import', you cannot import a %.*s file/directory, you must precompile the library and link against that", LIT(ext));
+ break;
+ }
+ }
+
+ add_untyped_expressions(ctx.info, &untyped);
+
+ e->LibraryName.paths = fl->fullpaths;
+ }
+}
+
gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
if (decl->state_flags & StateFlag_BeenHandled) return;
decl->state_flags |= StateFlag_BeenHandled;
@@ -4883,59 +5046,26 @@ gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
Scope *parent_scope = ctx->scope;
GB_ASSERT(parent_scope->flags&ScopeFlag_File);
- GB_ASSERT(fl->fullpaths.count > 0);
- String fullpath = fl->fullpaths[0];
- String library_name = path_to_entity_name(fl->library_name.string, fullpath);
- if (is_blank_ident(library_name)) {
- error(fl->token, "File name, %.*s, cannot be as a library name as it is not a valid identifier", LIT(fl->library_name.string));
- return;
+ String library_name = fl->library_name.string;
+ if (library_name.len == 0 && fl->fullpaths.count != 0) {
+ String fullpath = fl->fullpaths[0];
+ library_name = path_to_entity_name(fl->library_name.string, fullpath);
}
-
- for (String const &path : fl->fullpaths) {
- String ext = path_extension(path);
- if (str_eq_ignore_case(ext, ".c") ||
- str_eq_ignore_case(ext, ".cpp") ||
- str_eq_ignore_case(ext, ".cxx") ||
- str_eq_ignore_case(ext, ".h") ||
- str_eq_ignore_case(ext, ".hpp") ||
- str_eq_ignore_case(ext, ".hxx") ||
- false
- ) {
- error(fl->token, "With 'foreign import', you cannot import a %.*s file directory, you must precompile the library and link against that", LIT(ext));
- break;
- }
+ if (library_name.len == 0 || is_blank_ident(library_name)) {
+ error(fl->token, "File name, '%.*s', cannot be as a library name as it is not a valid identifier", LIT(library_name));
+ return;
}
- // if (fl->collection_name != "system") {
- // char *c_str = gb_alloc_array(heap_allocator(), char, fullpath.len+1);
- // defer (gb_free(heap_allocator(), c_str));
- // gb_memmove(c_str, fullpath.text, fullpath.len);
- // c_str[fullpath.len] = '\0';
-
- // gbFile f = {};
- // gbFileError file_err = gb_file_open(&f, c_str);
- // defer (gb_file_close(&f));
-
- // switch (file_err) {
- // case gbFileError_Invalid:
- // error(decl, "Invalid file or cannot be found ('%.*s')", LIT(fullpath));
- // return;
- // case gbFileError_NotExists:
- // error(decl, "File cannot be found ('%.*s')", LIT(fullpath));
- // return;
- // }
- // }
-
GB_ASSERT(fl->library_name.pos.line != 0);
fl->library_name.string = library_name;
Entity *e = alloc_entity_library_name(parent_scope, fl->library_name, t_invalid,
fl->fullpaths, library_name);
+ e->LibraryName.decl = decl;
add_entity_flags_from_file(ctx, e, parent_scope);
add_entity(ctx, parent_scope, nullptr, e);
-
AttributeContext ac = {};
check_decl_attributes(ctx, fl->attributes, foreign_import_decl_attribute, &ac);
if (ac.require_declaration) {
@@ -4950,12 +5080,8 @@ gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
e->LibraryName.extra_linker_flags = extra_linker_flags;
}
- if (has_asm_extension(fullpath)) {
- if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.os != TargetOs_darwin) {
- error(decl, "Assembly files are not yet supported on this platform: %.*s_%.*s",
- LIT(target_os_names[build_context.metrics.os]), LIT(target_arch_names[build_context.metrics.arch]));
- }
- }
+ mpsc_enqueue(&ctx->info->foreign_imports_to_check_fullpaths, e);
+
}
// Returns true if a new package is present
@@ -5763,35 +5889,6 @@ gb_internal void remove_neighbouring_duplicate_entires_from_sorted_array(Array<E
gb_internal void check_test_procedures(Checker *c) {
array_sort(c->info.testing_procedures, init_procedures_cmp);
remove_neighbouring_duplicate_entires_from_sorted_array(&c->info.testing_procedures);
-
- if (build_context.test_names.entries.count == 0) {
- return;
- }
-
- AstPackage *pkg = c->info.init_package;
- Scope *s = pkg->scope;
-
- for (String const &name : build_context.test_names) {
- Entity *e = scope_lookup(s, name);
- if (e == nullptr) {
- Token tok = {};
- if (pkg->files.count != 0) {
- tok = pkg->files[0]->tokens[0];
- }
- error(tok, "Unable to find the test '%.*s' in 'package %.*s' ", LIT(name), LIT(pkg->name));
- }
- }
-
- for (isize i = 0; i < c->info.testing_procedures.count; /**/) {
- Entity *e = c->info.testing_procedures[i];
- String name = e->token.string;
- if (!string_set_exists(&build_context.test_names, name)) {
- array_ordered_remove(&c->info.testing_procedures, i);
- } else {
- i += 1;
- }
- }
-
}
@@ -6317,6 +6414,9 @@ gb_internal void check_parsed_files(Checker *c) {
TIME_SECTION("check procedure bodies");
check_procedure_bodies(c);
+ TIME_SECTION("check foreign import fullpaths");
+ check_foreign_import_fullpaths(c);
+
TIME_SECTION("add entities from procedure bodies");
check_merge_queues_into_arrays(c);