mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Replace static initializer with @init / @finalizer
This commit is contained in:
committed by
Christoffer Lerno
parent
757a5b58e8
commit
4cc30c0d33
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 ---
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.4.666"
|
||||
#define COMPILER_VERSION "0.4.668"
|
||||
@@ -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
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
static foo {} ; // #error: Expected 'static initialize'
|
||||
static foo {} ; // #error: 'static' is only used
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
static initialize @priority() // #error: An expression was expected.
|
||||
fn void test() @init() // #error: An expression was expected.
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module test;
|
||||
|
||||
static initialize
|
||||
fn void init() @init
|
||||
{
|
||||
int a;
|
||||
a = 1;
|
||||
|
||||
@@ -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()!!;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user