Replace static initializer with @init / @finalizer

This commit is contained in:
Christoffer Lerno
2023-10-03 12:28:42 +02:00
committed by Christoffer Lerno
parent 757a5b58e8
commit 4cc30c0d33
28 changed files with 120 additions and 264 deletions

View File

@@ -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);

View File

@@ -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.

View File

@@ -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";

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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,

View File

@@ -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";

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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 ---

View File

@@ -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)
{

View File

@@ -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:

View File

@@ -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:

View File

@@ -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 @@ RETRY:
break;
}
return;
case DECL_INITIALIZE:
case DECL_FINALIZE:
sema_trace_stmt_liveness(astptrzero(decl->xxlizer.init));
return;
case DECL_DECLARRAY:
UNREACHABLE
}

View File

@@ -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]);

View File

@@ -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:

View File

@@ -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;

View File

@@ -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");

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.666"
#define COMPILER_VERSION "0.4.668"

View File

@@ -1 +1 @@
static int ifej; // #error: 'static' can only used with local variables, to hide global variables
static int ifej; // #error: 'static' is only used

View File

@@ -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
{
}

View File

@@ -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() {
entry:
call void @puts(ptr @.str)
ret void
}
; Function Attrs: nounwind
declare void @puts(ptr) #0
define internal void @.static_initialize.1() {
define void @test.startup2() #0 {
entry:
call void @puts(ptr @.str.1)
ret void
}
define internal void @.static_initialize.2() {
define void @test.start_main() #0 {
entry:
call void @puts(ptr @.str.2)
ret void
}
define internal void @.static_finalize.0() {
define void @test.startup1() #0 {
entry:
call void @puts(ptr @.str.3)
ret void
}
define void @test.empty_startup() #0 {
entry:
ret void
}
define void @test.shutdown() #0 {
entry:
call void @puts(ptr @.str.4)
ret void
}

View File

@@ -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;
}

View File

@@ -1 +1 @@
static foo {} ; // #error: Expected 'static initialize'
static foo {} ; // #error: 'static' is only used

View File

@@ -1,3 +1,3 @@
static initialize @priority() // #error: An expression was expected.
fn void test() @init() // #error: An expression was expected.
{
}

View File

@@ -1,6 +1,6 @@
module test;
static initialize
fn void init() @init
{
int a;
a = 1;

View File

@@ -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()!!;
}