From cfe5c649c5886f16e2413f80b038151a4cd5e4af Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Tue, 5 Sep 2023 17:29:54 +0200 Subject: [PATCH] Prevent ordering issues with "builtin" by resolving it early. --- src/compiler/ast.c | 13 ++++++++ src/compiler/compiler_internal.h | 1 + src/compiler/parse_expr.c | 2 +- src/compiler/parse_global.c | 34 +++++++++++++------- src/compiler/parser_internal.h | 2 +- src/compiler/sema_decls.c | 4 +-- src/compiler/sema_expr.c | 4 +-- src/compiler/sema_name_resolution.c | 5 +++ src/compiler/sema_passes.c | 4 +++ src/version.h | 2 +- test/test_suite/visibility/ambiguous_var.c3t | 2 +- 11 files changed, 53 insertions(+), 20 deletions(-) diff --git a/src/compiler/ast.c b/src/compiler/ast.c index e43d05a73..f7d3361c5 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -383,6 +383,19 @@ bool decl_is_local(Decl *decl) return !decl->is_external_visible && decl->visibility != VISIBLE_PUBLIC && !decl->is_export; } +bool decl_needs_prefix(Decl *decl) +{ + switch (decl->decl_kind) + { + case DECL_VAR: + case DECL_FUNC: + case DECL_MACRO: + return !decl->is_autoimport; + default: + return false; + } +} + Decl *decl_find_enum_constant(Decl *decl, const char *name) { VECEACH(decl->enums.values, i) diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 721958bd0..a4803d425 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2158,6 +2158,7 @@ static inline DeclKind decl_from_token(TokenType type); static inline bool decl_is_var_local(Decl *decl); bool decl_is_ct_var(Decl *decl); Decl *decl_find_enum_constant(Decl *decl, const char *name); +bool decl_needs_prefix(Decl *decl); AlignSize decl_find_member_offset(Decl *decl, Decl *member); bool decl_is_externally_visible(Decl *decl); bool decl_is_local(Decl *decl); diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index f9577dd67..d68731151 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -412,7 +412,7 @@ static Expr *parse_lambda(ParseContext *c, Expr *left) sig->params = decls; sig->rtype = return_type ? type_infoid(return_type) : 0; sig->variadic = variadic; - if (!parse_attributes(c, &func->attributes, NULL, NULL)) return poisoned_expr; + if (!parse_attributes(c, &func->attributes, NULL, NULL, NULL)) return poisoned_expr; if (tok_is(c, TOKEN_IMPLIES)) { diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index a57de1e86..9e3d86d99 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -264,7 +264,7 @@ bool parse_module(ParseContext *c, AstId contracts) Visibility visibility = VISIBLE_PUBLIC; Attr** attrs = NULL; bool is_cond; - if (!parse_attributes(c, &attrs, &visibility, &is_cond)) return false; + if (!parse_attributes(c, &attrs, &visibility, NULL, &is_cond)) return false; FOREACH_BEGIN(Attr *attr, attrs) if (attr->is_custom) RETURN_SEMA_ERROR(attr, "Custom attributes cannot be used with 'module'."); switch (attr->attr_kind) @@ -732,7 +732,7 @@ Decl *parse_local_decl_after_type(ParseContext *c, TypeInfo *type) Decl *decl = decl_new_var_current(c, type, VARDECL_LOCAL); advance(c); - if (!parse_attributes(c, &decl->attributes, NULL, NULL)) return poisoned_decl; + if (!parse_attributes(c, &decl->attributes, NULL, NULL, NULL)) return poisoned_decl; if (tok_is(c, TOKEN_EQ)) { if (!decl) @@ -796,7 +796,7 @@ Decl *parse_const_declaration(ParseContext *c, bool is_global) } else { - if (!parse_attributes(c, &decl->attributes, NULL, NULL)) return poisoned_decl; + if (!parse_attributes(c, &decl->attributes, NULL, NULL, NULL)) return poisoned_decl; } // Required initializer @@ -966,9 +966,11 @@ static bool parse_attributes_for_global(ParseContext *c, Decl *decl) if (decl->decl_kind == DECL_FUNC) decl->func_decl.attr_test = c->unit->test_by_default; if (decl->decl_kind == DECL_FUNC) decl->func_decl.attr_benchmark = c->unit->benchmark_by_default; decl->is_export = c->unit->export_by_default; + bool is_builtin = false; bool is_cond; - if (!parse_attributes(c, &decl->attributes, &visibility, &is_cond)) return false; + if (!parse_attributes(c, &decl->attributes, &visibility, decl_needs_prefix(decl) ? &is_builtin : NULL, &is_cond)) return false; decl->is_cond = is_cond; + decl->is_autoimport = is_builtin; decl->visibility = visibility; return true; } @@ -976,11 +978,11 @@ static bool parse_attributes_for_global(ParseContext *c, Decl *decl) /** * attribute_list ::= attribute* * - * Patch visibility attributes immediately. + * Patch visibility and builtin attributes immediately. * * @return true if parsing succeeded, false if recovery is needed */ -bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *cond_ref) +bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref) { Visibility visibility = -1; if (cond_ref) *cond_ref = false; @@ -989,6 +991,7 @@ bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visib Attr *attr; if (!parse_attribute(c, &attr, false)) return false; if (!attr) return true; + bool parsed_builtin = false; Visibility parsed_visibility = -1; if (!attr->is_custom) { @@ -1006,6 +1009,9 @@ bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visib case ATTRIBUTE_LOCAL: parsed_visibility = VISIBLE_LOCAL; break; + case ATTRIBUTE_BUILTIN: + parsed_builtin = true; + break; case ATTRIBUTE_IF: if (!cond_ref) RETURN_SEMA_ERROR(attr, "'%s' cannot be used here.", attr->name); *cond_ref = true; @@ -1013,6 +1019,12 @@ bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visib default: break; } + if (parsed_builtin) + { + if (!builtin_ref) RETURN_SEMA_ERROR(attr, "'@builtin' cannot be used here."); + *builtin_ref = true; + continue; + } if (parsed_visibility != -1) { if (!visibility_ref) RETURN_SEMA_ERROR(attr, "'%s' cannot be used here.", attr->name); @@ -1358,7 +1370,7 @@ bool parse_parameters(ParseContext *c, Decl ***params_ref, Decl **body_params, } Decl *param = decl_new_var(name, span, type, param_kind); param->var.type_info = type; - if (!parse_attributes(c, ¶m->attributes, NULL, NULL)) return false; + if (!parse_attributes(c, ¶m->attributes, NULL, NULL, NULL)) return false; if (!no_name) { if (try_consume(c, TOKEN_EQ)) @@ -1457,7 +1469,7 @@ bool parse_struct_body(ParseContext *c, Decl *parent) else { bool is_cond; - if (!parse_attributes(c, &member->attributes, NULL, &is_cond)) return false; + if (!parse_attributes(c, &member->attributes, NULL, NULL, &is_cond)) return false; member->is_cond = true; if (!parse_struct_body(c, member)) return decl_poison(parent); } @@ -1499,7 +1511,7 @@ bool parse_struct_body(ParseContext *c, Decl *parent) } advance(c); bool is_cond; - if (!parse_attributes(c, &member->attributes, NULL, &is_cond)) return false; + if (!parse_attributes(c, &member->attributes, NULL, NULL, &is_cond)) return false; member->is_cond = true; if (!try_consume(c, TOKEN_COMMA)) break; if (was_inline) @@ -1930,7 +1942,7 @@ static inline Decl *parse_def_attribute(ParseContext *c) CONSUME_OR_RET(TOKEN_LBRACE, poisoned_decl); bool is_cond; - if (!parse_attributes(c, &attributes, NULL, &is_cond)) return poisoned_decl; + if (!parse_attributes(c, &attributes, NULL, NULL, &is_cond)) return poisoned_decl; CONSUME_OR_RET(TOKEN_RBRACE, poisoned_decl); decl->attr_decl.attrs = attributes; decl->is_cond = is_cond; @@ -2311,7 +2323,7 @@ static inline Decl *parse_static_top_level(ParseContext *c) advance(c); Attr *attr = NULL; bool is_cond; - if (!parse_attributes(c, &init->attributes, NULL, &is_cond)) return poisoned_decl; + if (!parse_attributes(c, &init->attributes, NULL, NULL, &is_cond)) return poisoned_decl; init->is_cond = is_cond; ASSIGN_ASTID_OR_RET(init->xxlizer.init, parse_compound_stmt(c), poisoned_decl); RANGE_EXTEND_PREV(init); diff --git a/src/compiler/parser_internal.h b/src/compiler/parser_internal.h index 29ab9393c..12fcbd538 100644 --- a/src/compiler/parser_internal.h +++ b/src/compiler/parser_internal.h @@ -46,7 +46,7 @@ Ast *parse_short_body(ParseContext *c, TypeInfoId return_type, bool require_eos) bool parse_attribute(ParseContext *c, Attr **attribute_ref, bool expect_eos); -bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *cond_ref); +bool parse_attributes(ParseContext *c, Attr ***attributes_ref, Visibility *visibility_ref, bool *builtin_ref, bool *cond_ref); bool parse_switch_body(ParseContext *c, Ast ***cases, TokenType case_type, TokenType default_type); Expr *parse_ct_expression_list(ParseContext *c, bool allow_decl); diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index d502cb5a0..264629aab 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -1732,6 +1732,7 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, case ATTRIBUTE_PRIVATE: case ATTRIBUTE_PUBLIC: case ATTRIBUTE_LOCAL: + case ATTRIBUTE_BUILTIN: // These are pseudo-attributes. UNREACHABLE; case ATTRIBUTE_DEPRECATED: @@ -1929,9 +1930,6 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, assert(domain == ATTR_FUNC); decl->func_decl.attr_naked = true; break; - case ATTRIBUTE_BUILTIN: - decl->is_autoimport = true; - break; case ATTRIBUTE_OVERLAP: decl->bitstruct.overlap = true; break; diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 6b03367df..6932e8a97 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -908,10 +908,10 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to, return false; } - if (decl->decl_kind == DECL_VAR || decl->decl_kind == DECL_FUNC || decl->decl_kind == DECL_MACRO) + if (decl_needs_prefix(decl)) { if (!sema_analyse_decl(context, decl)) return false; - if (decl->unit->module != context->unit->module && !decl->is_autoimport && !expr->identifier_expr.path) + if (decl->unit->module != context->unit->module && !expr->identifier_expr.path) { const char *message; switch (decl->decl_kind) diff --git a/src/compiler/sema_name_resolution.c b/src/compiler/sema_name_resolution.c index 797858994..451a8ac4a 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -510,6 +510,11 @@ static void sema_report_error_on_decl(Decl *found, NameResolve *name_resolve) } else { + if (decl_needs_prefix(found)) + { + sema_error_at(span, "The %s needs a path prefix (e.g. '%s::%s').", symbol_type, found_path, symbol); + return; + } sema_error_at(span, "The %s '%s' is defined in both '%s' and '%s', please use either " "%s::%s or %s::%s to resolve the ambiguity.", diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index 99c71d8fc..fd14fd2e4 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -317,6 +317,10 @@ void sema_process_includes(CompilationUnit *unit) void sema_analysis_pass_register_global_declarations(Module *module) { DEBUG_LOG("Pass: Register globals for module '%s'.", module->name->module); + if (str_eq("std::core::env", module->name->module)) + { + printf(""); + } VECEACH(module->units, index) { CompilationUnit *unit = module->units[index]; diff --git a/src/version.h b/src/version.h index 9821039c7..0f61eb8af 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.632" \ No newline at end of file +#define COMPILER_VERSION "0.4.633" \ No newline at end of file diff --git a/test/test_suite/visibility/ambiguous_var.c3t b/test/test_suite/visibility/ambiguous_var.c3t index 1220ae9c5..9e27bb0c0 100644 --- a/test/test_suite/visibility/ambiguous_var.c3t +++ b/test/test_suite/visibility/ambiguous_var.c3t @@ -23,5 +23,5 @@ fn void test2() c = foo::b; c = bar::b; c = foo::a; - c = b; // #error: global variable 'b' is defined in both 'foo' and 'bar', please use either foo::b or bar::b to resolve the ambiguity + c = b; // #error: global variable needs a path prefix (e.g. 'foo::b') }