aboutsummaryrefslogtreecommitdiff
path: root/src/checker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/checker.cpp')
-rw-r--r--src/checker.cpp167
1 files changed, 123 insertions, 44 deletions
diff --git a/src/checker.cpp b/src/checker.cpp
index 396a04d7a..7fa7a9c36 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -521,6 +521,28 @@ GB_COMPARE_PROC(entity_variable_pos_cmp) {
}
+
+gb_internal u64 check_vet_flags(CheckerContext *c) {
+ AstFile *file = c->file;
+ if (file == nullptr &&
+ c->curr_proc_decl &&
+ c->curr_proc_decl->proc_lit) {
+ file = c->curr_proc_decl->proc_lit->file();
+ }
+ if (file && file->vet_flags_set) {
+ return file->vet_flags;
+ }
+ return build_context.vet_flags;
+}
+
+gb_internal u64 check_vet_flags(Ast *node) {
+ AstFile *file = node->file();
+ if (file && file->vet_flags_set) {
+ return file->vet_flags;
+ }
+ return build_context.vet_flags;
+}
+
enum VettedEntityKind {
VettedEntity_Invalid,
@@ -655,9 +677,9 @@ gb_internal bool check_vet_unused(Checker *c, Entity *e, VettedEntity *ve) {
return false;
}
-gb_internal void check_scope_usage(Checker *c, Scope *scope) {
- bool vet_unused = true;
- bool vet_shadowing = true;
+gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) {
+ bool vet_unused = (vet_flags & VetFlag_Unused) != 0;
+ bool vet_shadowing = (vet_flags & (VetFlag_Shadowing|VetFlag_Using)) != 0;
Array<VettedEntity> vetted_entities = {};
array_init(&vetted_entities, heap_allocator());
@@ -691,15 +713,17 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope) {
if (ve.kind == VettedEntity_Shadowed_And_Unused) {
error(e->token, "'%.*s' declared but not used, possibly shadows declaration at line %d", LIT(name), other->token.pos.line);
- } else if (build_context.vet) {
+ } else if (vet_flags) {
switch (ve.kind) {
case VettedEntity_Unused:
- error(e->token, "'%.*s' declared but not used", LIT(name));
+ if (vet_flags & VetFlag_Unused) {
+ error(e->token, "'%.*s' declared but not used", LIT(name));
+ }
break;
case VettedEntity_Shadowed:
- if (e->flags&EntityFlag_Using) {
+ if ((vet_flags & (VetFlag_Shadowing|VetFlag_Using)) != 0 && e->flags&EntityFlag_Using) {
error(e->token, "Declaration of '%.*s' from 'using' shadows declaration at line %d", LIT(name), other->token.pos.line);
- } else {
+ } else if ((vet_flags & (VetFlag_Shadowing)) != 0) {
error(e->token, "Declaration of '%.*s' shadows declaration at line %d", LIT(name), other->token.pos.line);
}
break;
@@ -726,7 +750,7 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope) {
if (child->flags & (ScopeFlag_Proc|ScopeFlag_Type|ScopeFlag_File)) {
// Ignore these
} else {
- check_scope_usage(c, child);
+ check_scope_usage(c, child, vet_flags);
}
}
}
@@ -943,7 +967,6 @@ gb_internal void init_universal(void) {
add_global_bool_constant("true", true);
add_global_bool_constant("false", false);
- // TODO(bill): Set through flags in the compiler
add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR);
add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION);
add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT);
@@ -1046,6 +1069,7 @@ gb_internal void init_universal(void) {
add_global_bool_constant("ODIN_NO_RTTI", bc->no_rtti);
add_global_bool_constant("ODIN_VALGRIND_SUPPORT", bc->ODIN_VALGRIND_SUPPORT);
+ add_global_bool_constant("ODIN_TILDE", bc->tilde_backend);
add_global_constant("ODIN_COMPILE_TIMESTAMP", t_untyped_integer, exact_value_i64(odin_compile_timestamp()));
@@ -1114,6 +1138,7 @@ gb_internal void init_universal(void) {
t_u8_ptr = alloc_type_pointer(t_u8);
+ t_u8_multi_ptr = alloc_type_multi_pointer(t_u8);
t_int_ptr = alloc_type_pointer(t_int);
t_i64_ptr = alloc_type_pointer(t_i64);
t_f64_ptr = alloc_type_pointer(t_f64);
@@ -1453,7 +1478,6 @@ gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMo
if (ctx->decl) {
mutex = &ctx->decl->type_and_value_mutex;
} else if (ctx->pkg) {
- // TODO(bill): is a per package mutex is a good idea here?
mutex = &ctx->pkg->type_and_value_mutex;
}
@@ -1581,30 +1605,28 @@ gb_internal void add_entity_use(CheckerContext *c, Ast *identifier, Entity *enti
if (entity == nullptr) {
return;
}
- if (identifier != nullptr) {
- if (identifier->kind != Ast_Ident) {
- return;
- }
- Ast *empty_ident = nullptr;
- entity->identifier.compare_exchange_strong(empty_ident, identifier);
-
- identifier->Ident.entity = entity;
-
- String dmsg = entity->deprecated_message;
- if (dmsg.len > 0) {
- warning(identifier, "%.*s is deprecated: %.*s", LIT(entity->token.string), LIT(dmsg));
- }
- String wmsg = entity->warning_message;
- if (wmsg.len > 0) {
- warning(identifier, "%.*s: %.*s", LIT(entity->token.string), LIT(wmsg));
- }
- }
- entity->flags |= EntityFlag_Used;
add_declaration_dependency(c, entity);
+ entity->flags |= EntityFlag_Used;
if (entity_has_deferred_procedure(entity)) {
Entity *deferred = entity->Procedure.deferred_procedure.entity;
add_entity_use(c, nullptr, deferred);
}
+ if (identifier == nullptr || identifier->kind != Ast_Ident) {
+ return;
+ }
+ Ast *empty_ident = nullptr;
+ entity->identifier.compare_exchange_strong(empty_ident, identifier);
+
+ identifier->Ident.entity = entity;
+
+ String dmsg = entity->deprecated_message;
+ if (dmsg.len > 0) {
+ warning(identifier, "%.*s is deprecated: %.*s", LIT(entity->token.string), LIT(dmsg));
+ }
+ String wmsg = entity->warning_message;
+ if (wmsg.len > 0) {
+ warning(identifier, "%.*s: %.*s", LIT(entity->token.string), LIT(wmsg));
+ }
}
@@ -1947,9 +1969,9 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
add_type_info_type_internal(c, bt->RelativePointer.base_integer);
break;
- case Type_RelativeSlice:
- add_type_info_type_internal(c, bt->RelativeSlice.slice_type);
- add_type_info_type_internal(c, bt->RelativeSlice.base_integer);
+ case Type_RelativeMultiPointer:
+ add_type_info_type_internal(c, bt->RelativeMultiPointer.pointer_type);
+ add_type_info_type_internal(c, bt->RelativeMultiPointer.base_integer);
break;
case Type_Matrix:
@@ -2188,9 +2210,9 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) {
add_min_dep_type_info(c, bt->RelativePointer.base_integer);
break;
- case Type_RelativeSlice:
- add_min_dep_type_info(c, bt->RelativeSlice.slice_type);
- add_min_dep_type_info(c, bt->RelativeSlice.base_integer);
+ case Type_RelativeMultiPointer:
+ add_min_dep_type_info(c, bt->RelativeMultiPointer.pointer_type);
+ add_min_dep_type_info(c, bt->RelativeMultiPointer.base_integer);
break;
case Type_Matrix:
@@ -2310,7 +2332,9 @@ gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) {
str_lit("memory_equal"),
str_lit("memory_compare"),
str_lit("memory_compare_zero"),
+ );
+ FORCE_ADD_RUNTIME_ENTITIES(!build_context.tilde_backend,
// Extended data type internal procedures
str_lit("umodti3"),
str_lit("udivti3"),
@@ -2556,9 +2580,6 @@ gb_internal Array<EntityGraphNode *> generate_entity_dependency_graph(CheckerInf
}
}
- // TODO(bill): This could be multithreaded to improve performance
- // This means that the entity graph node set will have to be thread safe
-
TIME_SECTION("generate_entity_dependency_graph: Calculate edges for graph M - Part 2");
auto G = array_make<EntityGraphNode *>(allocator, 0, M.count);
@@ -2779,7 +2800,7 @@ gb_internal void init_core_type_info(Checker *c) {
t_type_info_bit_set = find_core_type(c, str_lit("Type_Info_Bit_Set"));
t_type_info_simd_vector = find_core_type(c, str_lit("Type_Info_Simd_Vector"));
t_type_info_relative_pointer = find_core_type(c, str_lit("Type_Info_Relative_Pointer"));
- t_type_info_relative_slice = find_core_type(c, str_lit("Type_Info_Relative_Slice"));
+ t_type_info_relative_multi_pointer = find_core_type(c, str_lit("Type_Info_Relative_Multi_Pointer"));
t_type_info_matrix = find_core_type(c, str_lit("Type_Info_Matrix"));
t_type_info_soa_pointer = find_core_type(c, str_lit("Type_Info_Soa_Pointer"));
@@ -2808,7 +2829,7 @@ gb_internal void init_core_type_info(Checker *c) {
t_type_info_bit_set_ptr = alloc_type_pointer(t_type_info_bit_set);
t_type_info_simd_vector_ptr = alloc_type_pointer(t_type_info_simd_vector);
t_type_info_relative_pointer_ptr = alloc_type_pointer(t_type_info_relative_pointer);
- t_type_info_relative_slice_ptr = alloc_type_pointer(t_type_info_relative_slice);
+ t_type_info_relative_multi_pointer_ptr = alloc_type_pointer(t_type_info_relative_multi_pointer);
t_type_info_matrix_ptr = alloc_type_pointer(t_type_info_matrix);
t_type_info_soa_pointer_ptr = alloc_type_pointer(t_type_info_soa_pointer);
}
@@ -2935,6 +2956,60 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) {
return false;
}
+gb_internal DECL_ATTRIBUTE_PROC(proc_group_attribute) {
+ if (name == ATTRIBUTE_USER_TAG_NAME) {
+ ExactValue ev = check_decl_attribute_value(c, value);
+ if (ev.kind != ExactValue_String) {
+ error(elem, "Expected a string value for '%.*s'", LIT(name));
+ }
+ return true;
+ } else if (name == "objc_name") {
+ ExactValue ev = check_decl_attribute_value(c, value);
+ if (ev.kind == ExactValue_String) {
+ if (string_is_valid_identifier(ev.value_string)) {
+ ac->objc_name = ev.value_string;
+ } else {
+ error(elem, "Invalid identifier for '%.*s', got '%.*s'", LIT(name), LIT(ev.value_string));
+ }
+ } else {
+ error(elem, "Expected a string value for '%.*s'", LIT(name));
+ }
+ return true;
+ } else if (name == "objc_is_class_method") {
+ ExactValue ev = check_decl_attribute_value(c, value);
+ if (ev.kind == ExactValue_Bool) {
+ ac->objc_is_class_method = ev.value_bool;
+ } else {
+ error(elem, "Expected a boolean value for '%.*s'", LIT(name));
+ }
+ return true;
+ } else if (name == "objc_type") {
+ if (value == nullptr) {
+ error(elem, "Expected a type for '%.*s'", LIT(name));
+ } else {
+ Type *objc_type = check_type(c, value);
+ if (objc_type != nullptr) {
+ if (!has_type_got_objc_class_attribute(objc_type)) {
+ gbString t = type_to_string(objc_type);
+ error(value, "'%.*s' expected a named type with the attribute @(obj_class=<string>), got type %s", LIT(name), t);
+ gb_string_free(t);
+ } else {
+ ac->objc_type = objc_type;
+ }
+ }
+ }
+ return true;
+ } else if (name == "require_results") {
+ if (value != nullptr) {
+ error(elem, "Expected no value for '%.*s'", LIT(name));
+ }
+ ac->require_results = true;
+ return true;
+ }
+ return false;
+}
+
+
gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
if (name == ATTRIBUTE_USER_TAG_NAME) {
ExactValue ev = check_decl_attribute_value(c, value);
@@ -3007,7 +3082,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
check_expr(c, &o, value);
Entity *e = entity_of_node(o.expr);
if (e != nullptr && e->kind == Entity_Procedure) {
- warning(elem, "'%.*s' is deprecated, please use one of the following instead: 'deferred_none', 'deferred_in', 'deferred_out'", LIT(name));
+ error(elem, "'%.*s' is not allowed any more, please use one of the following instead: 'deferred_none', 'deferred_in', 'deferred_out'", LIT(name));
if (ac->deferred_procedure.entity != nullptr) {
error(elem, "Previous usage of a 'deferred_*' attribute");
}
@@ -4506,7 +4581,7 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) {
if (value != nullptr) {
error(elem, "Expected no parameter for '%.*s'", LIT(name));
} else if (name == "force") {
- warning(elem, "'force' is deprecated and is identical to 'require'");
+ error(elem, "'force' was replaced with 'require'");
}
ac->require_declaration = true;
return true;
@@ -5904,7 +5979,11 @@ gb_internal void check_parsed_files(Checker *c) {
TIME_SECTION("check scope usage");
for (auto const &entry : c->info.files) {
AstFile *f = entry.value;
- check_scope_usage(c, f->scope);
+ u64 vet_flags = build_context.vet_flags;
+ if (f->vet_flags_set) {
+ vet_flags = f->vet_flags;
+ }
+ check_scope_usage(c, f->scope, vet_flags);
}
TIME_SECTION("add basic type information");
@@ -6022,7 +6101,7 @@ gb_internal void check_parsed_files(Checker *c) {
while (mpsc_dequeue(&c->info.intrinsics_entry_point_usage, &node)) {
if (c->info.entry_point == nullptr && node != nullptr) {
if (node->file()->pkg->kind != Package_Runtime) {
- warning(node, "usage of intrinsics.__entry_point will be a no-op");
+ error(node, "usage of intrinsics.__entry_point will be a no-op");
}
}
}