diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 017c0d39e..8bbfde523 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -35,6 +35,10 @@ Decl *decl_new(DeclKind decl_kind, const char *name, SourceSpan span) return decl; } +bool decl_is_deprecated(Decl *decl) +{ + return decl->resolved_attributes && decl->attrs_resolved && decl->attrs_resolved->deprecated; +} // Check if local or parameter $foo/$Foo bool decl_is_ct_var(Decl *decl) @@ -43,12 +47,12 @@ bool decl_is_ct_var(Decl *decl) return decl_var_kind_is_ct(decl->var.kind); } -Decl *decl_new_with_type(const char *name, SourceSpan loc, DeclKind decl_type) +Decl *decl_new_with_type(const char *name, SourceSpan span, DeclKind decl_type) { Decl *decl = decl_calloc(); decl->decl_kind = decl_type; decl->name = name; - decl->span = loc; + decl->span = span; TypeKind kind = TYPE_POISONED; switch (decl_type) { @@ -95,6 +99,7 @@ const char *decl_safe_name(Decl *decl) if (decl->name) return decl->name; return decl_to_name(decl); } + const char *decl_to_name(Decl *decl) { const char *name = decl_to_a_name(decl); @@ -155,9 +160,9 @@ const char *decl_to_a_name(Decl *decl) } -Decl *decl_new_var(const char *name, SourceSpan loc, TypeInfo *type, VarDeclKind kind) +Decl *decl_new_var(const char *name, SourceSpan span, TypeInfo *type, VarDeclKind kind) { - Decl *decl = decl_new(DECL_VAR, name, loc); + Decl *decl = decl_new(DECL_VAR, name, span); decl->var.kind = kind; decl->var.type_info = type ? type_infoid(type) : 0; return decl; @@ -173,7 +178,7 @@ Decl *decl_new_generated_var(Type *type, VarDeclKind kind, SourceSpan span) decl->var.is_temp = true; decl->type = type; decl->alignment = type ? type_alloca_alignment(type) : 0; - ASSERT(!type || !type_is_user_defined(type) || type->decl->resolve_status == RESOLVE_DONE); + ASSERT_AT(span, !type || !type_is_user_defined(type) || type->decl->resolve_status == RESOLVE_DONE); decl->var.type_info = type_info_id_new_base(type, span); decl->resolve_status = RESOLVE_DONE; return decl; @@ -292,8 +297,8 @@ AttributeType attribute_by_name(const char *name) return ATTRIBUTE_NONE; } - -void decl_append_links_to_global(Decl *decl) +// Look for the @link directive, if a decl is codegen then add it to the linking process. +void decl_append_links_to_global_during_codegen(Decl *decl) { CompilationUnit *unit = decl->unit; if (unit && unit->links) @@ -310,16 +315,22 @@ void decl_append_links_to_global(Decl *decl) } } +/* + * Count the expected number of elements needed for an initializer + * by folding any anonymous structs and unions. + */ int decl_count_elements(Decl *structlike) { int elements = 0; Decl **members = structlike->strukt.members; unsigned member_size = vec_size(members); if (member_size == 0) return 0; + // In the case we have a union, we only count the first element. if (structlike->decl_kind == DECL_UNION) member_size = 1; for (unsigned i = 0; i < member_size; i++) { Decl *member = members[i]; + // Recursively count the anonymous struct/unions if (member->decl_kind != DECL_VAR && !member->name) { elements += decl_count_elements(member); @@ -330,6 +341,7 @@ int decl_count_elements(Decl *structlike) return elements; } +// This is used to check if a macro folds to a single compile time value. bool ast_is_compile_time(Ast *ast) { switch (ast->ast_kind) @@ -341,6 +353,7 @@ bool ast_is_compile_time(Ast *ast) if (!ast->return_stmt.expr) return true; return expr_is_runtime_const(ast->return_stmt.expr); case AST_EXPR_STMT: + // $a; is fine return expr_is_runtime_const(ast->expr_stmt); case AST_CT_COMPOUND_STMT: { @@ -365,14 +378,25 @@ bool ast_is_compile_time(Ast *ast) } } +// Should this declaration be linked externally bool decl_is_externally_visible(Decl *decl) { return decl->is_external_visible || decl->visibility == VISIBLE_PUBLIC || decl->is_export; } +/* + * Is this declartion a global of some sort? + * In other words a static, thread local, global constant or a global + */ bool decl_is_global(Decl *ident) { + switch (ident->decl_kind) + { + case DECL_FUNC: return true; + case DECL_VAR: break; + default: return false; + } switch (ident->var.kind) { case VARDECL_LOCAL: @@ -396,11 +420,13 @@ bool decl_is_global(Decl *ident) UNREACHABLE } +// Is is @local or is it @private but never imported in some other compilation unit (module) bool decl_is_local(Decl *decl) { return !decl->is_external_visible && decl->visibility != VISIBLE_PUBLIC && !decl->is_export; } +// Does the decl need to be prefixed, or is it for some reason like a builtin. bool decl_needs_prefix(Decl *decl) { switch (decl->decl_kind) @@ -418,6 +444,7 @@ bool decl_needs_prefix(Decl *decl) } } +// Find a particular enum by name. Decl *decl_find_enum_constant(Decl *decl, const char *name) { FOREACH(Decl *, enum_constant, decl->enums.values) @@ -427,6 +454,7 @@ Decl *decl_find_enum_constant(Decl *decl, const char *name) return NULL; } + AlignSize decl_find_member_offset(Decl *decl, Decl *member) { static const AlignSize NO_MATCH = ~(AlignSize)0; @@ -442,7 +470,7 @@ AlignSize decl_find_member_offset(Decl *decl, Decl *member) default: return NO_MATCH; } - ASSERT(members); + ASSERT_SPAN(decl, members); unsigned list = vec_size(members); for (unsigned i = 0; i < list; i++) { @@ -460,9 +488,12 @@ AlignSize decl_find_member_offset(Decl *decl, Decl *member) return NO_MATCH; } +// Is it a for statement, AST_FOREACH should not reach here. bool ast_supports_continue(Ast *stmt) { + ASSERT_SPAN(stmt, stmt->ast_kind != AST_FOREACH_STMT); if (stmt->ast_kind != AST_FOR_STMT) return false; + // We don't support `continue` in a `do { };` statement. return stmt->for_stmt.cond || !stmt->flow.skip_first; } @@ -511,7 +542,7 @@ void scratch_buffer_set_extern_decl_name(Decl *decl, bool clear) } if (decl->visibility == VISIBLE_LOCAL) { - assert(module); + ASSERT_SPAN(decl, module); scratch_buffer_printf(".%u", (unsigned)declid(decl)); } } diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 84f81ab11..a540ad838 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -19,7 +19,6 @@ typedef int32_t IndexDiff; typedef int64_t ArrayIndex; typedef uint16_t StructIndex; typedef uint32_t AlignSize; -typedef int32_t ScopeId; typedef uint64_t ArraySize; typedef uint64_t BitSize; typedef uint16_t FileId; @@ -1639,7 +1638,6 @@ typedef struct EndJump_ typedef struct DynamicScope_ { - ScopeId scope_id; bool allow_dead_code : 1; bool is_dead : 1; bool is_poisoned : 1; @@ -1789,7 +1787,6 @@ struct SemaContext_ CallEnv call_env; Decl *current_macro; InliningSpan *inlined_at; - ScopeId scope_id; unsigned macro_call_depth; // Jump tracking JumpTarget break_jump; @@ -2308,7 +2305,7 @@ const char *decl_safe_name(Decl *decl); const char *decl_to_name(Decl *decl); const char *decl_to_a_name(Decl *decl); int decl_count_elements(Decl *structlike); -void decl_append_links_to_global(Decl *decl); +void decl_append_links_to_global_during_codegen(Decl *decl); INLINE bool decl_ok(Decl *decl); INLINE bool decl_poison(Decl *decl); @@ -2319,6 +2316,7 @@ static inline Decl *decl_raw(Decl *decl); static inline DeclKind decl_from_token(TokenType type); static inline bool decl_is_var_local(Decl *decl); bool decl_is_ct_var(Decl *decl); +bool decl_is_deprecated(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); diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index 22faa98f3..bcf182b2d 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -541,7 +541,7 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl) // Skip real constants. if (!decl->type) return; - decl_append_links_to_global(decl); + decl_append_links_to_global_during_codegen(decl); LLVMValueRef init_value; diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index 12aae8fde..25848765c 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -673,7 +673,7 @@ void llvm_emit_function_decl(GenContext *c, Decl *decl) { ASSERT_SPAN(decl, decl->decl_kind == DECL_FUNC); // Resolve function backend type for function. - decl_append_links_to_global(decl); + decl_append_links_to_global_during_codegen(decl); LLVMValueRef function = llvm_get_ref(c, decl); decl->backend_ref = function; if (decl->attrs_resolved && decl->attrs_resolved->section) diff --git a/src/compiler/sema_internal.h b/src/compiler/sema_internal.h index 740f3d249..5d0bde043 100644 --- a/src/compiler/sema_internal.h +++ b/src/compiler/sema_internal.h @@ -201,7 +201,7 @@ INLINE Attr* attr_find_kind(Attr **attrs, AttributeType attr_type) INLINE void sema_display_deprecated_warning_on_use(SemaContext *context, Decl *decl, SourceSpan span) { ASSERT(decl->resolve_status == RESOLVE_DONE); - if (!decl->resolved_attributes || !decl->attrs_resolved || !decl->attrs_resolved->deprecated) return; + if (!decl_is_deprecated(decl)) return; if (context->call_env.ignore_deprecation) return; const char *msg = decl->attrs_resolved->deprecated; diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index 929ac9fd3..232a2e3f9 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -659,7 +659,6 @@ void sema_analysis_pass_decls(Module *module) context.active_scope = (DynamicScope) { .depth = 0, - .scope_id = 0, .label_start = 0, .current_local = 0, }; diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 373797f04..8c773d1c6 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -298,7 +298,7 @@ static inline bool sema_analyse_continue_stmt(SemaContext *context, Ast *stateme // Continue can only be used with "for" statements, skipping the "do { };" statement if (!ast_supports_continue(jump_target.target)) { - RETURN_SEMA_ERROR(statement, "'continue' may only be used with 'for', 'while' and 'do-while' statements."); + RETURN_SEMA_ERROR(statement, "'continue' may only be used with 'for', 'foreach', 'while' and 'do-while' statements."); } } else @@ -3338,8 +3338,10 @@ bool sema_analyse_contracts(SemaContext *context, AstId doc, AstId **asserts, So bool sema_analyse_function_body(SemaContext *context, Decl *func) { + // Stop if it's already poisoned. if (!decl_ok(func)) return false; + // Check the signature here we test for variadic raw, since we don't support it. Signature *signature = &func->func_decl.signature; if (signature->variadic == VARIADIC_RAW) { @@ -3347,8 +3349,12 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func) " please use typed vaargs on the form 'int... args' or " "untyped vaargs on the form 'args...' instead."); } + + // Pull out the prototype FunctionPrototype *prototype = func->type->function.prototype; - ASSERT(prototype); + ASSERT_SPAN(func, prototype); + + // Set up the context for analysis context->original_inline_line = 0; context->original_module = NULL; context->call_env = (CallEnv) { @@ -3356,23 +3362,23 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func) .is_naked_fn = func->func_decl.attr_naked, .kind = CALL_ENV_FUNCTION, .pure = func->func_decl.signature.attrs.is_pure, - .ignore_deprecation = func->allow_deprecated || (func->resolved_attributes && func->attrs_resolved && func->attrs_resolved->deprecated && func->resolved_attributes && func->attrs_resolved->deprecated) + .ignore_deprecation = func->allow_deprecated || decl_is_deprecated(func) }; + context->rtype = prototype->rtype; context->macro_call_depth = 0; context->active_scope = (DynamicScope) { - .scope_id = 0, .depth = 0, .label_start = 0, .current_local = 0 }; vec_resize(context->ct_locals, 0); - // Clear returns vec_resize(context->block_returns, 0); - context->scope_id = 0; + // Zero out any jumps context->break_jump = context->continue_jump = context->next_jump = (JumpTarget) { .target = NULL }; - ASSERT(func->func_decl.body); + ASSERT_SPAN(func, func->func_decl.body); + Ast *body = astptr(func->func_decl.body); Decl **lambda_params = NULL; SCOPE_START @@ -3383,6 +3389,8 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func) } if (func->func_decl.is_lambda) { + // If we're a lambda we need to pass on the compile time values that will + // be baked into the function. lambda_params = copy_decl_list_single(func->func_decl.lambda_ct_parameters); FOREACH(Decl *, ct_param, lambda_params) { diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index 7b251d6ef..af50a7469 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -35,7 +35,6 @@ void context_change_scope_with_flags(SemaContext *context, ScopeFlags flags) unsigned label_start = new_label_scope ? last_local : context->active_scope.label_start; context->active_scope = (DynamicScope) { - .scope_id = ++context->scope_id, .allow_dead_code = false, .is_dead = scope_is_dead, .is_poisoned = scope_is_poisoned, @@ -47,10 +46,6 @@ void context_change_scope_with_flags(SemaContext *context, ScopeFlags flags) .defer_start = parent_defer, .flags = flags, }; - if (context->scope_id == 0) - { - FATAL_ERROR("Too many scopes."); - } } const char *context_filename(SemaContext *context) diff --git a/test/test_suite/expressions/grabbing_function_alias.c3t b/test/test_suite/expressions/grabbing_function_alias.c3t new file mode 100644 index 000000000..e0db11abc --- /dev/null +++ b/test/test_suite/expressions/grabbing_function_alias.c3t @@ -0,0 +1,7 @@ +alias c = main; +void* e = &c; + +fn int main() +{ + return 0; +} \ No newline at end of file