diff --git a/lib/std/core/builtin.c3 b/lib/std/core/builtin.c3 index ef9469e15..a6373b64a 100644 --- a/lib/std/core/builtin.c3 +++ b/lib/std/core/builtin.c3 @@ -76,8 +76,6 @@ enum CallLocation : int(String name) MACRO("macro"), LAMBDA("lambda"), TEST("test"), - INITIALIZER("initializer"), - FINALIZER("finalizer") } struct CallstackElement @@ -427,7 +425,7 @@ fn void install_signal_handler(CInt signal, SignalFunction func) @local } // Clean this up -static initialize @priority(101) +fn void install_signal_handlers() @init(101) @local { install_signal_handler(libc::SIGBUS, &sig_bus_error); install_signal_handler(libc::SIGSEGV, &sig_segmentation_fault); diff --git a/lib/std/core/mem.c3 b/lib/std/core/mem.c3 index 3cc4fb9ab..9b540e732 100644 --- a/lib/std/core/mem.c3 +++ b/lib/std/core/mem.c3 @@ -656,7 +656,7 @@ module std::core::mem @if(WASM_NOLIBC); SimpleHeapAllocator wasm_allocator @private; extern int __heap_base; -static initialize @priority(1) +fn void initialize_wasm_mem() @init(1) @private { allocator::wasm_memory.allocate_block(mem::DEFAULT_MEM_ALIGNMENT)!!; // Give us a valid null. // Check if we need to move the heap. diff --git a/src/compiler/ast.c b/src/compiler/ast.c index ff032f410..78f79c426 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -112,12 +112,10 @@ const char *decl_to_a_name(Decl *decl) case DECL_ERASED: return "an erased declaration"; case DECL_FAULT: return "a fault"; case DECL_FAULTVALUE: return "a fault value"; - case DECL_FINALIZE: return "a static finalizer"; case DECL_FNTYPE: return "a function type"; case DECL_FUNC: return "a function"; case DECL_GLOBALS: return "globals"; case DECL_IMPORT: return "an import"; - case DECL_INITIALIZE: return "a static initializer"; case DECL_LABEL: return "a label"; case DECL_MACRO: return "a macro"; case DECL_POISONED: return "a poisoned decl"; diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 57ba97c33..5b638e727 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -551,9 +551,12 @@ typedef struct bool attr_winmain : 1; bool attr_dynamic : 1; bool attr_interface : 1; + bool attr_init : 1; + bool attr_finalizer : 1; bool is_lambda : 1; union { + uint32_t priority; DeclId any_prototype; Decl **generated_lambda; Decl **lambda_ct_parameters; @@ -640,13 +643,6 @@ typedef struct AstId parent; } LabelDecl; -typedef struct -{ - unsigned priority; - AstId init; -} InitializerDecl; - - typedef struct Decl_ { const char *name; @@ -696,7 +692,6 @@ typedef struct Decl_ Type *type; union { - InitializerDecl xxlizer; Decl** decl_list; struct { @@ -1607,7 +1602,6 @@ struct CompilationUnit_ Decl **ct_asserts; Decl **ct_echos; Decl **ct_includes; - Decl **xxlizers; Decl **vars; Decl **macros; Decl **methods; @@ -1901,10 +1895,8 @@ extern const char *kw_at_require; extern const char *kw_at_return; extern const char *kw_check_assign; extern const char *kw_deprecated; -extern const char *kw_finalize; extern const char *kw_in; extern const char *kw_incr; -extern const char *kw_initialize; extern const char *kw_inout; extern const char *kw_kind; extern const char *kw_len; diff --git a/src/compiler/context.c b/src/compiler/context.c index 65d155762..f2abf5392 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -122,8 +122,6 @@ void decl_register(Decl *decl) { case DECL_ERASED: return; - case DECL_INITIALIZE: - case DECL_FINALIZE: case DECL_POISONED: case DECL_CT_ASSERT: case DECL_CT_ECHO: @@ -246,10 +244,6 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl) case DECL_CT_ASSERT: vec_add(unit->ct_asserts, decl); return; - case DECL_INITIALIZE: - case DECL_FINALIZE: - vec_add(unit->xxlizers, decl); - return; } DEBUG_LOG("Registering symbol '%s' in %s.", decl->name, unit->module->name->module); diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 815a08341..f4f0426c4 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -890,10 +890,6 @@ Decl *copy_decl(CopyStruct *c, Decl *decl) case DECL_CT_INCLUDE: MACRO_COPY_EXPR(copy->include.filename); break; - case DECL_INITIALIZE: - case DECL_FINALIZE: - MACRO_COPY_ASTID(copy->xxlizer.init); - break; case DECL_BODYPARAM: MACRO_COPY_DECL_LIST(copy->body_params); break; diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 96a2081a7..0fab610d4 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -139,12 +139,10 @@ typedef enum DECL_ERASED, DECL_FAULT, DECL_FAULTVALUE, - DECL_FINALIZE, DECL_FNTYPE, DECL_FUNC, DECL_GLOBALS, DECL_IMPORT, - DECL_INITIALIZE, DECL_LABEL, DECL_MACRO, DECL_STRUCT, @@ -155,8 +153,8 @@ typedef enum #define NON_TYPE_DECLS DECL_IMPORT: case DECL_MACRO: \ case DECL_DECLARRAY: case DECL_ATTRIBUTE: case DECL_LABEL: \ - case DECL_DEFINE: case DECL_CT_ASSERT: case DECL_INITIALIZE: case DECL_CT_EXEC: \ - case DECL_FINALIZE: case DECL_CT_ECHO: case DECL_CT_INCLUDE: case DECL_GLOBALS: \ + case DECL_DEFINE: case DECL_CT_ASSERT: case DECL_CT_EXEC: \ + case DECL_CT_ECHO: case DECL_CT_INCLUDE: case DECL_GLOBALS: \ case DECL_BODYPARAM: case DECL_VAR: case DECL_ENUM_CONSTANT: case DECL_FAULTVALUE: \ case DECL_POISONED @@ -751,11 +749,8 @@ typedef enum ATTR_CALL = 1 << 12, ATTR_BITSTRUCT = 1 << 13, ATTR_MACRO = 1 << 14, - ATTR_INITIALIZER = 1 << 15, - ATTR_FINALIZER = 1 << 16, - ATTR_DEFINE = 1 << 17, - ATTR_ENUM_VALUE = 1 << 18, - ATTR_XXLIZER = ATTR_INITIALIZER | ATTR_FINALIZER + ATTR_DEFINE = 1 << 15, + ATTR_ENUM_VALUE = 1 << 16, } AttributeDomain; typedef enum @@ -777,8 +772,10 @@ typedef enum ATTRIBUTE_DYNAMIC, ATTRIBUTE_EXPORT, ATTRIBUTE_EXTERN, + ATTRIBUTE_FINALIZER, ATTRIBUTE_IF, ATTRIBUTE_INLINE, + ATTRIBUTE_INIT, ATTRIBUTE_INTERFACE, ATTRIBUTE_LITTLEENDIAN, ATTRIBUTE_LOCAL, @@ -793,7 +790,6 @@ typedef enum ATTRIBUTE_OPERATOR, ATTRIBUTE_OVERLAP, ATTRIBUTE_PACKED, - ATTRIBUTE_PRIORITY, ATTRIBUTE_PRIVATE, ATTRIBUTE_PUBLIC, ATTRIBUTE_PURE, diff --git a/src/compiler/json_output.c b/src/compiler/json_output.c index 6a3984f88..8f2af292a 100644 --- a/src/compiler/json_output.c +++ b/src/compiler/json_output.c @@ -47,12 +47,10 @@ static inline const char *decl_type_to_string(Decl *type) case DECL_ENUM_CONSTANT: return "enum_const"; case DECL_FAULT: return "fault"; case DECL_FAULTVALUE: return "fault_val"; - case DECL_FINALIZE: return "finalizer"; case DECL_FNTYPE: return "fntype"; case DECL_FUNC: return "function"; case DECL_GLOBALS: return "global"; case DECL_IMPORT: return "import"; - case DECL_INITIALIZE: return "initializer"; case DECL_MACRO: return "macro"; case DECL_STRUCT: return "struct"; case DECL_UNION: return "union"; diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index eb010b726..d3fc2cfb3 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -1125,8 +1125,6 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl) case DECL_TYPEDEF: case DECL_UNION: case DECL_DECLARRAY: - case DECL_INITIALIZE: - case DECL_FINALIZE: case DECL_BODYPARAM: case DECL_CT_ECHO: case DECL_CT_EXEC: @@ -1436,11 +1434,6 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context .debug_file = unit->llvm.debug_file, .file_id = unit->file->file_id }; - FOREACH_BEGIN(Decl *initializer, unit->xxlizers) - has_elements = true; - llvm_emit_xxlizer(gen_context, initializer); - FOREACH_END(); - FOREACH_BEGIN(Decl *method, unit->methods) if (only_used && !method->is_live) continue; llvm_emit_function_decl(gen_context, method); diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index 825c578e6..d4f06180e 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -6,6 +6,7 @@ #include "llvm_codegen_internal.h" static LLVMValueRef llvm_add_xxlizer(GenContext *c, unsigned priority, bool is_finalizer); +static void llvm_append_xxlizer(GenContext *c, unsigned priority, bool is_initializer, LLVMValueRef function); static void llvm_emit_param_attributes(GenContext *c, LLVMValueRef function, ABIArgInfo *info, bool is_return, int index, int last_index); static inline void llvm_emit_return_value(GenContext *context, LLVMValueRef value); static void llvm_expand_from_args(GenContext *c, Type *type, LLVMValueRef ref, unsigned *index, AlignSize alignment); @@ -412,6 +413,10 @@ void llvm_emit_function_body(GenContext *c, Decl *decl, StacktraceType type) DEBUG_LOG("Generating function %s.", decl->extname); if (decl->func_decl.attr_dynamic) vec_add(c->dynamic_functions, decl); assert(decl->backend_ref); + if (decl->func_decl.attr_init || decl->func_decl.attr_finalizer) + { + llvm_append_xxlizer(c, decl->func_decl.priority, decl->func_decl.attr_init, decl->backend_ref); + } llvm_emit_body(c, decl->backend_ref, type_get_resolved_prototype(decl->type), @@ -549,12 +554,6 @@ void llvm_emit_body(GenContext *c, LLVMValueRef function, FunctionPrototype *pro case ST_MACRO: function_name = decl->name; break; - case ST_INITIALIZER: - function_name = "[static initializer]"; - break; - case ST_FINALIZER: - function_name = "[static finalizer]"; - break; default: UNREACHABLE } @@ -658,6 +657,13 @@ void llvm_emit_body(GenContext *c, LLVMValueRef function, FunctionPrototype *pro c->function = prev_function; } +static void llvm_append_xxlizer(GenContext *c, unsigned priority, bool is_initializer, LLVMValueRef function) +{ + LLVMValueRef **array_ref = is_initializer ? &c->constructors : &c->destructors; + LLVMValueRef vals[3] = { llvm_const_int(c, type_int, priority), function, llvm_get_zero(c, type_voidptr) }; + vec_add(*array_ref, LLVMConstStructInContext(c->context, vals, 3, false)); +} + static LLVMValueRef llvm_add_xxlizer(GenContext *c, unsigned priority, bool is_initializer) { LLVMTypeRef initializer_type = LLVMFunctionType(LLVMVoidTypeInContext(c->context), NULL, 0, false); @@ -671,43 +677,6 @@ static LLVMValueRef llvm_add_xxlizer(GenContext *c, unsigned priority, bool is_i return function; } -void llvm_emit_xxlizer(GenContext *c, Decl *decl) -{ - Ast *body = astptrzero(decl->xxlizer.init); - if (!body) - { - // Skip if it doesn't have a body. - return; - } - bool is_initializer = decl->decl_kind == DECL_INITIALIZE; - LLVMValueRef function = llvm_add_xxlizer(c, decl->xxlizer.priority, is_initializer); - if (llvm_use_debug(c)) - { - uint32_t row = decl->span.row; - if (!row) row = 1; - LLVMMetadataRef type = LLVMDIBuilderCreateSubroutineType(c->debug.builder, c->debug.file.debug_file, NULL, 0, 0); - - c->debug.function = LLVMDIBuilderCreateFunction(c->debug.builder, - c->debug.file.debug_file, - scratch_buffer.str, scratch_buffer.len, - scratch_buffer.str, scratch_buffer.len, - c->debug.file.debug_file, - row, - type, - true, - true, - row, - LLVMDIFlagZero, - active_target.optlevel != OPTIMIZATION_NONE); - LLVMSetSubprogram(function, c->debug.function); - } - llvm_emit_body(c, - function, - NULL, - NULL, - body, decl, is_initializer ? ST_INITIALIZER : ST_FINALIZER); -} - void llvm_emit_dynamic_functions(GenContext *c, Decl **funcs) { diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index d74f7125a..eb51a4966 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -58,8 +58,6 @@ typedef enum ST_LAMBDA, ST_BENCHMARK, ST_TEST, - ST_INITIALIZER, - ST_FINALIZER } StacktraceType; typedef struct @@ -345,7 +343,6 @@ LLVMMetadataRef llvm_get_debug_type(GenContext *c, Type *type); LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type); LLVMTypeRef llvm_get_pointee_type(GenContext *c, Type *any_type); void llvm_emit_function_decl(GenContext *c, Decl *decl); -void llvm_emit_xxlizer(GenContext *c, Decl *decl); bool llvm_types_are_similar(LLVMTypeRef original, LLVMTypeRef coerce); // -- Attributes --- diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index cbc8ac0fb..fb6284ae8 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -9,7 +9,6 @@ static bool context_next_is_path_prefix_start(ParseContext *c); static inline Decl *parse_func_definition(ParseContext *c, AstId contracts, bool is_interface); static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl); static inline bool parse_enum_param_list(ParseContext *c, Decl*** parameters_ref); -static inline Decl *parse_static_top_level(ParseContext *c); static Decl *parse_include(ParseContext *c); static Decl *parse_exec(ParseContext *c); static bool parse_attributes_for_global(ParseContext *c, Decl *decl); @@ -2297,39 +2296,6 @@ static inline Decl *parse_func_definition(ParseContext *c, AstId contracts, bool return func; } -static inline Decl *parse_static_top_level(ParseContext *c) -{ - advance_and_verify(c, TOKEN_STATIC); - Decl *init = decl_calloc(); - if (!tok_is(c, TOKEN_IDENT)) - { - if (token_is_any_type(c->tok)) - { - SEMA_ERROR_HERE("'static' can only used with local variables, to hide global variables and functions, use 'private'."); - return poisoned_decl; - } - SEMA_ERROR_HERE("Expected 'static initialize' or 'static finalize'."); - return poisoned_decl; - } - init->decl_kind = DECL_INITIALIZE; - if (c->data.string == kw_finalize) - { - init->decl_kind = DECL_FINALIZE; - } - else if (c->data.string != kw_initialize) - { - SEMA_ERROR_HERE("Expected 'static initialize' or 'static finalize'."); - return poisoned_decl; - } - advance(c); - Attr *attr = NULL; - bool is_cond; - 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); - return init; -} /** @@ -2746,10 +2712,6 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **c_ref) case TOKEN_FN: decl = parse_func_definition(c, contracts, c->unit->is_interface_file); break; - case TOKEN_STATIC: - if (contracts) goto CONTRACT_NOT_ALLOWED; - decl = parse_static_top_level(c); - break; case TOKEN_CT_ASSERT: { if (contracts) goto CONTRACT_NOT_ALLOWED; @@ -2822,6 +2784,9 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **c_ref) case TOKEN_EOF: SEMA_ERROR_LAST("Expected a top level declaration."); return poisoned_decl; + case TOKEN_STATIC: + SEMA_ERROR_HERE("'static' is only used with local variable declarations."); + return poisoned_decl; case TOKEN_CT_CONST_IDENT: if (peek(c) == TOKEN_EQ) { diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 90085b623..9bfda393a 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -1626,14 +1626,8 @@ static const char *attribute_domain_to_string(AttributeDomain domain) return "def"; case ATTR_CALL: return "call"; - case ATTR_INITIALIZER: - return "static initializer"; - case ATTR_FINALIZER: - return "static finalizer"; case ATTR_DEFINE: return "define"; - case ATTR_XXLIZER: - UNREACHABLE } UNREACHABLE } @@ -1695,7 +1689,9 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, [ATTRIBUTE_DYNAMIC] = ATTR_FUNC, [ATTRIBUTE_EXPORT] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | EXPORTED_USER_DEFINED_TYPES, [ATTRIBUTE_EXTERN] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | USER_DEFINED_TYPES, + [ATTRIBUTE_FINALIZER] = ATTR_FUNC, [ATTRIBUTE_IF] = (AttributeDomain)~(ATTR_CALL | ATTR_LOCAL), + [ATTRIBUTE_INIT] = ATTR_FUNC, [ATTRIBUTE_INLINE] = ATTR_FUNC | ATTR_CALL, [ATTRIBUTE_INTERFACE] = ATTR_FUNC, [ATTRIBUTE_LITTLEENDIAN] = ATTR_BITSTRUCT, @@ -1711,15 +1707,14 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, [ATTRIBUTE_OPERATOR] = ATTR_MACRO | ATTR_FUNC, [ATTRIBUTE_OVERLAP] = ATTR_BITSTRUCT, [ATTRIBUTE_PACKED] = ATTR_STRUCT | ATTR_UNION, - [ATTRIBUTE_PRIORITY] = ATTR_XXLIZER, [ATTRIBUTE_PRIVATE] = ATTR_FUNC | ATTR_MACRO | ATTR_GLOBAL | ATTR_CONST | USER_DEFINED_TYPES | ATTR_DEFINE, [ATTRIBUTE_PUBLIC] = ATTR_FUNC | ATTR_MACRO | ATTR_GLOBAL | ATTR_CONST | USER_DEFINED_TYPES | ATTR_DEFINE, [ATTRIBUTE_PURE] = ATTR_CALL, [ATTRIBUTE_REFLECT] = ATTR_FUNC | ATTR_GLOBAL | ATTR_CONST | USER_DEFINED_TYPES, [ATTRIBUTE_SECTION] = ATTR_FUNC | ATTR_CONST | ATTR_GLOBAL, [ATTRIBUTE_TEST] = ATTR_FUNC, - [ATTRIBUTE_UNUSED] = (AttributeDomain)~(ATTR_CALL | ATTR_XXLIZER), - [ATTRIBUTE_USED] = (AttributeDomain)~(ATTR_CALL | ATTR_XXLIZER ), + [ATTRIBUTE_UNUSED] = (AttributeDomain)~(ATTR_CALL), + [ATTRIBUTE_USED] = (AttributeDomain)~(ATTR_CALL), [ATTRIBUTE_WASM] = ATTR_FUNC, [ATTRIBUTE_WEAK] = ATTR_FUNC | ATTR_CONST | ATTR_GLOBAL, [ATTRIBUTE_WINMAIN] = ATTR_FUNC, @@ -1878,6 +1873,28 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, } if (!expr->const_expr.b) *erase_decl = true; return true; + case ATTRIBUTE_FINALIZER: + decl->func_decl.attr_finalizer = true; + // Ugly + goto PARSE; + case ATTRIBUTE_INIT: + decl->func_decl.attr_init = true; + PARSE:; + if (expr) + { + if (!sema_analyse_expr(context, expr)) return false; + if (!expr_is_const_int(expr)) + { + RETURN_SEMA_ERROR(attr, "Expected an integer value."); + } + uint64_t prio = decl->func_decl.priority = expr->const_expr.ixx.i.low; + if (expr_const_will_overflow(&expr->const_expr, TYPE_U16) || prio > MAX_PRIORITY || prio < 1) + { + RETURN_SEMA_ERROR(attr, "The priority must be a value between 1 and %d", MAX_PRIORITY); + } + } + if (!decl->func_decl.priority) decl->func_decl.priority = MAX_PRIORITY; + return true; case ATTRIBUTE_SECTION: case ATTRIBUTE_EXTERN: if (context->unit->module->is_generic) @@ -1968,19 +1985,6 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, case ATTRIBUTE_USED: decl->is_must_use = true; break; - case ATTRIBUTE_PRIORITY: - if (!expr || !expr_is_const_int(expr)) goto ERROR_PRIORITY; - { - Int i = expr->const_expr.ixx; - if (!int_fits(i, TYPE_I64)) goto ERROR_PRIORITY; - int64_t priority = int_to_i64(i); - if (priority < 1 || priority > MAX_PRIORITY) goto ERROR_PRIORITY; - decl->xxlizer.priority = priority; - return true; - } - ERROR_PRIORITY: - SEMA_ERROR(attr, "Expected an argument to '@priority' between 1 and %d.", MAX_PRIORITY); - return decl_poison(decl); case ATTRIBUTE_PURE: // Only used for calls. UNREACHABLE @@ -2472,54 +2476,6 @@ static inline bool sema_analyse_func_macro(SemaContext *context, Decl *decl, boo return true; } -static inline bool sema_analyse_xxlizer(SemaContext *context, Decl *decl, bool *erase_decl) -{ - if (!sema_analyse_attributes(context, - decl, - decl->attributes, - decl->decl_kind == DECL_INITIALIZE ? ATTR_INITIALIZER : ATTR_FINALIZER, - erase_decl)) return decl_poison(decl); - if (*erase_decl) return true; - if (decl->xxlizer.priority == 0) decl->xxlizer.priority = MAX_PRIORITY; - context->call_env = (CallEnv) { .kind = decl->decl_kind == DECL_INITIALIZE ? CALL_ENV_INITIALIZER : CALL_ENV_FINALIZER }; - context->rtype = type_void; - context->active_scope = (DynamicScope) { - .scope_id = 0, - .depth = 0, - .label_start = 0, - .current_local = 0 - }; - - // Clear returns - vec_resize(context->returns, 0); - context->scope_id = 0; - context->continue_target = NULL; - context->next_target = 0; - context->next_switch = 0; - context->break_target = 0; - Ast *body = astptr(decl->xxlizer.init); - - // Insert an implicit return - AstId *next_id = &body->compound_stmt.first_stmt; - if (!*next_id) - { - decl->xxlizer.init = 0; - } - SourceSpan span = body->span; - if (*next_id) - { - Ast *last = ast_last(astptr(*next_id)); - // Cleanup later - if (last->ast_kind == AST_RETURN_STMT) goto SKIP_NEW_RETURN; - span = last->span; - next_id = &last->next; - } - Ast *ret = new_ast(AST_RETURN_STMT, span); - ast_append(&next_id, ret); -SKIP_NEW_RETURN: - return sema_analyse_statement(context, body); -} - static inline bool sema_analyse_func(SemaContext *context, Decl *decl, bool *erase_decl) { DEBUG_LOG("----Analysing function %s", decl->name); @@ -2530,24 +2486,42 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl, bool *era bool is_test = decl->func_decl.attr_test; bool is_benchmark = decl->func_decl.attr_benchmark; + bool is_init_finalizer = decl->func_decl.attr_init || decl->func_decl.attr_finalizer; Signature *sig = &decl->func_decl.signature; - if (is_test || is_benchmark) + if (is_init_finalizer && (is_test || is_benchmark)) + { + RETURN_SEMA_ERROR(decl, "Test and benchmark functions may not also be marked '@init' or '@finalizer'."); + } + if (is_test || is_benchmark || is_init_finalizer) { if (vec_size(sig->params)) { - SEMA_ERROR(sig->params[0], "'@test' and '@benchmark' functions may not take any parameters."); - return false; + SEMA_ERROR(sig->params[0], "%s functions may not take any parameters.", + is_init_finalizer ? "'@init' and '@finalizer'" : "'@test' and '@benchmark'"); + return decl_poison(decl); } TypeInfo *rtype_info = type_infoptr(sig->rtype); if (!sema_resolve_type_info(context, rtype_info)) return false; - if (type_no_optional(rtype_info->type) != type_void) + Type *rtype = rtype_info->type; + if (is_init_finalizer) { - SEMA_ERROR(rtype_info, "'@test' and '@benchmark' functions may only return 'void' or 'void!'."); - return false; + if (rtype->canonical != type_void) + { + SEMA_ERROR(rtype_info, "'@init' and '@finalizer' functions may only return 'void'."); + return decl_poison(decl); + } } - if (rtype_info->type == type_void) + else { - rtype_info->type = type_get_optional(rtype_info->type); + if (type_no_optional(rtype) != type_void) + { + SEMA_ERROR(rtype_info, "'@test' and '@benchmark' functions may only return 'void' or 'void!'."); + return decl_poison(decl); + } + if (rtype->canonical == type_void) + { + rtype_info->type = type_get_optional(rtype); + } } } @@ -2574,6 +2548,11 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl, bool *era } if (decl->func_decl.type_parent) { + if (is_init_finalizer) + { + SEMA_ERROR(decl, "Methods may not have '@init' or '@finalizer' attributes."); + return decl_poison(decl); + } if (is_test || is_benchmark) { SEMA_ERROR(decl, "Methods may not be annotated %s.", is_test ? "@test" : "@benchmark"); @@ -3551,10 +3530,6 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl) case DECL_DEFINE: if (!sema_analyse_define(context, decl, &erase_decl)) goto FAILED; break; - case DECL_INITIALIZE: - case DECL_FINALIZE: - if (!sema_analyse_xxlizer(context, decl, &erase_decl)) goto FAILED; - break; case DECL_POISONED: case DECL_IMPORT: case DECL_ENUM_CONSTANT: diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 0bdbe8c2c..dacb0301d 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -682,8 +682,6 @@ static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr) case DECL_TYPEDEF: case DECL_DECLARRAY: case DECL_BODYPARAM: - case DECL_INITIALIZE: - case DECL_FINALIZE: case DECL_CT_INCLUDE: case DECL_CT_EXEC: case DECL_GLOBALS: diff --git a/src/compiler/sema_liveness.c b/src/compiler/sema_liveness.c index 662859493..213e446d8 100644 --- a/src/compiler/sema_liveness.c +++ b/src/compiler/sema_liveness.c @@ -511,7 +511,7 @@ void sema_trace_liveness(void) FOREACH_BEGIN(Module *module, global_context.module_list) FOREACH_BEGIN(CompilationUnit *unit, module->units) FOREACH_BEGIN(Decl *function, unit->functions) - if (function->is_export || function->no_strip || + if (function->is_export || function->no_strip || function->func_decl.attr_finalizer || function->func_decl.attr_init || (function->func_decl.attr_test && keep_tests) || (function->func_decl.attr_benchmark && keep_benchmarks)) sema_trace_decl_liveness(function); FOREACH_END(); @@ -524,9 +524,6 @@ void sema_trace_liveness(void) FOREACH_BEGIN(Decl *method, unit->local_method_extensions) if (method->is_export || method->no_strip) sema_trace_decl_liveness(method); FOREACH_END(); - FOREACH_BEGIN(Decl *xxlizer, unit->xxlizers) - sema_trace_decl_liveness(xxlizer); - FOREACH_END(); FOREACH_END(); FOREACH_END(); } @@ -621,10 +618,6 @@ static void sema_trace_decl_liveness(Decl *decl) break; } return; - case DECL_INITIALIZE: - case DECL_FINALIZE: - sema_trace_stmt_liveness(astptrzero(decl->xxlizer.init)); - return; case DECL_DECLARRAY: UNREACHABLE } diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index 9c8b5a6c0..7662d1014 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -612,10 +612,6 @@ void sema_analysis_pass_functions(Module *module) CompilationUnit *unit = module->units[index]; SemaContext context; sema_context_init(&context, unit); - VECEACH(unit->xxlizers, i) - { - sema_analyse_decl(&context, unit->xxlizers[i]); - } VECEACH(unit->methods, i) { analyse_func_body(&context, unit->methods[i]); diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index ad5077752..c2687e678 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -275,8 +275,6 @@ static bool sema_resolve_type_identifier(SemaContext *context, TypeInfo *type_in case DECL_ATTRIBUTE: SEMA_ERROR(type_info, "This is not a type."); return type_info_poison(type_info); - case DECL_INITIALIZE: - case DECL_FINALIZE: case DECL_CT_ASSERT: case DECL_CT_ECHO: case DECL_DECLARRAY: diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index defdb1821..e6ff34b41 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -187,8 +187,6 @@ static void register_generic_decls(CompilationUnit *unit, Decl **decls) case DECL_CT_ASSERT: case DECL_CT_ECHO: case DECL_DECLARRAY: - case DECL_INITIALIZE: - case DECL_FINALIZE: case DECL_ERASED: case DECL_FNTYPE: continue; diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index 9bee1f7a3..2892d3800 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -324,7 +324,9 @@ void symtab_init(uint32_t capacity) attribute_list[ATTRIBUTE_DYNAMIC] = KW_DEF("@dynamic"); attribute_list[ATTRIBUTE_EXPORT] = KW_DEF("@export"); attribute_list[ATTRIBUTE_EXTERN] = KW_DEF("@extern"); + attribute_list[ATTRIBUTE_FINALIZER] = KW_DEF("@finalizer"); attribute_list[ATTRIBUTE_IF] = KW_DEF("@if"); + attribute_list[ATTRIBUTE_INIT] = KW_DEF("@init"); attribute_list[ATTRIBUTE_INLINE] = KW_DEF("@inline"); attribute_list[ATTRIBUTE_INTERFACE] = KW_DEF("@interface"); attribute_list[ATTRIBUTE_LITTLEENDIAN] = KW_DEF("@littleendian"); @@ -340,7 +342,6 @@ void symtab_init(uint32_t capacity) attribute_list[ATTRIBUTE_OPERATOR] = KW_DEF("@operator"); attribute_list[ATTRIBUTE_OVERLAP] = KW_DEF("@overlap"); attribute_list[ATTRIBUTE_PACKED] = KW_DEF("@packed"); - attribute_list[ATTRIBUTE_PRIORITY] = KW_DEF("@priority"); attribute_list[ATTRIBUTE_PRIVATE] = KW_DEF("@private"); attribute_list[ATTRIBUTE_PURE] = kw_at_pure; attribute_list[ATTRIBUTE_PUBLIC] = KW_DEF("@public"); diff --git a/src/version.h b/src/version.h index f8b1b2e32..717b976e1 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.666" \ No newline at end of file +#define COMPILER_VERSION "0.4.668" \ No newline at end of file diff --git a/test/test_suite/globals/static_global.c3 b/test/test_suite/globals/static_global.c3 index b8fdf0397..ddd5ccb27 100644 --- a/test/test_suite/globals/static_global.c3 +++ b/test/test_suite/globals/static_global.c3 @@ -1 +1 @@ -static int ifej; // #error: 'static' can only used with local variables, to hide global variables \ No newline at end of file +static int ifej; // #error: 'static' is only used \ No newline at end of file diff --git a/test/test_suite/initialize/initialize_bad_prio.c3 b/test/test_suite/initialize/initialize_bad_prio.c3 index 97674d114..b1876c821 100644 --- a/test/test_suite/initialize/initialize_bad_prio.c3 +++ b/test/test_suite/initialize/initialize_bad_prio.c3 @@ -1,16 +1,16 @@ -static initialize @priority("hello") // #error: Expected an argument to '@priority' +fn void init1() @init("hello") // #error: Expected an integer value { } -static initialize @priority(1, 2) // #error: Too many arguments for +fn void init2() @init(1, 2) // #error: Too many arguments for { } -static initialize @priority(0) // #error: Expected an argument to '@priority' +fn void init3() @init(0) // #error: The priority must be a value { } -static initialize @priority(65536) // #error: Expected an argument to '@priority' +fn void init4() @init(65536) // #error: The priority must be a value { } \ No newline at end of file diff --git a/test/test_suite/initialize/initialize_finalize.c3t b/test/test_suite/initialize/initialize_finalize.c3t index d50ae84cc..9898ecf88 100644 --- a/test/test_suite/initialize/initialize_finalize.c3t +++ b/test/test_suite/initialize/initialize_finalize.c3t @@ -8,55 +8,56 @@ fn void main() } extern fn void puts(char*); -static initialize @priority(300) +fn void startup2() @init(300) { puts("Hello startup2"); } -static initialize +fn void start_main() @init { puts("Let's start main..."); } -static initialize @priority(200) +fn void startup1() @init(200) { puts("Hello startup"); } -static initialize +fn void empty_startup() @init {} -static finalize +fn void shutdown() @finalizer { puts("Bye bye"); } /* #expect: test.ll -@llvm.global_ctors = appending global [3 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 300, ptr @.static_initialize.0, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @.static_initialize.1, ptr null }, { i32, ptr, ptr } { i32 200, ptr @.static_initialize.2, ptr null }] -@llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @.static_finalize.0, ptr null }] +@llvm.global_ctors = appending global [4 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 300, ptr @test.startup2, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @test.start_main, ptr null }, { i32, ptr, ptr } { i32 200, ptr @test.startup1, ptr null }, { i32, ptr, ptr } { i32 65535, ptr @test.empty_startup, ptr null }] +@llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @test.shutdown, ptr null }] -define internal void @.static_initialize.0() { +define void @test.startup2() #0 { entry: - call void @puts(ptr @.str) + call void @puts(ptr @.str.1) ret void } -; Function Attrs: nounwind -declare void @puts(ptr) #0 - -define internal void @.static_initialize.1() { +define void @test.start_main() #0 { entry: - call void @puts(ptr @.str.1) + call void @puts(ptr @.str.2) ret void } -define internal void @.static_initialize.2() { +define void @test.startup1() #0 { +entry: + call void @puts(ptr @.str.3) + ret void +} +define void @test.empty_startup() #0 { entry: - call void @puts(ptr @.str.2) ret void } -define internal void @.static_finalize.0() { +define void @test.shutdown() #0 { entry: - call void @puts(ptr @.str.3) + call void @puts(ptr @.str.4) ret void } \ No newline at end of file diff --git a/test/test_suite/initialize/initialize_jump.c3 b/test/test_suite/initialize/initialize_jump.c3 index 199cb8d93..f223cd455 100644 --- a/test/test_suite/initialize/initialize_jump.c3 +++ b/test/test_suite/initialize/initialize_jump.c3 @@ -1,9 +1,9 @@ -static initialize +fn void foo() @init { return; // This is fine } -static initialize +fn int foo2() @init // #error: '@init' and '@finalizer' functions may only { - return 123; // #error: cannot implicitly + return 123; } \ No newline at end of file diff --git a/test/test_suite/initialize/initialize_parse_error.c3 b/test/test_suite/initialize/initialize_parse_error.c3 index b1b361c91..f07a83415 100644 --- a/test/test_suite/initialize/initialize_parse_error.c3 +++ b/test/test_suite/initialize/initialize_parse_error.c3 @@ -1 +1 @@ -static foo {} ; // #error: Expected 'static initialize' +static foo {} ; // #error: 'static' is only used diff --git a/test/test_suite/initialize/initialize_prio.c3 b/test/test_suite/initialize/initialize_prio.c3 index 87f929f01..360254fe7 100644 --- a/test/test_suite/initialize/initialize_prio.c3 +++ b/test/test_suite/initialize/initialize_prio.c3 @@ -1,3 +1,3 @@ -static initialize @priority() // #error: An expression was expected. +fn void test() @init() // #error: An expression was expected. { } diff --git a/test/test_suite/initialize/initializer_var.c3t b/test/test_suite/initialize/initializer_var.c3t index 38348df72..8f73423fc 100644 --- a/test/test_suite/initialize/initializer_var.c3t +++ b/test/test_suite/initialize/initializer_var.c3t @@ -1,6 +1,6 @@ module test; -static initialize +fn void init() @init { int a; a = 1; diff --git a/test/unit/stdlib/threads/pool.c3 b/test/unit/stdlib/threads/pool.c3 index ab72d7bf3..669bcdb4d 100644 --- a/test/unit/stdlib/threads/pool.c3 +++ b/test/unit/stdlib/threads/pool.c3 @@ -51,11 +51,11 @@ int x; Mutex work_done; -static initialize { +fn void startup() @init { work_done.init()!!; } -static finalize { +fn void shutdown() @finalizer { work_done.destroy()!!; }