Fix issue testing if something is global. Remove ScopeId. Adding comments to code.

This commit is contained in:
Christoffer Lerno
2025-10-11 13:50:06 +02:00
parent 3430240c2a
commit ae33d1a206
9 changed files with 67 additions and 29 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,7 @@
alias c = main;
void* e = &c;
fn int main()
{
return 0;
}