- Too deeply nested scopes was a fatal crash and not a regular semantic error. #2796

This commit is contained in:
Christoffer Lerno
2026-01-22 15:13:01 +01:00
parent 6a78864b6c
commit b14053df41
6 changed files with 40 additions and 31 deletions

View File

@@ -1714,7 +1714,7 @@ INLINE bool sema_set_default_argument(SemaContext *context, CalledDecl *callee,
new_context->inlined_at = &inlined_at;
}
bool success;
SCOPE_START
SCOPE_START(arg->span)
new_context->original_module = context->original_module;
success = sema_analyse_parameter(new_context, arg, param, callee->definition, optional, no_match_ref,
callee->macro, false);
@@ -2869,7 +2869,7 @@ static inline bool sema_expr_setup_call_analysis(SemaContext *context, CalledDec
macro_context->block_exit_ref = block_exit_ref;
context_change_scope_with_flags(macro_context, SCOPE_MACRO);
context_change_scope_with_flags(macro_context, SCOPE_MACRO, call_expr->span);
macro_context->block_return_defer = macro_context->active_scope.defer_last;
return true;
@@ -3051,7 +3051,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
DynamicScope old_scope = context->active_scope;
// Create a scope, since the macro itself will not.
context_change_scope_with_flags(context, SCOPE_NONE);
context_change_scope_with_flags(context, SCOPE_NONE, call_expr->span);
SemaContext macro_context;
Type *rtype = typeget(sig->rtype);
@@ -3371,7 +3371,7 @@ static bool sema_call_analyse_body_expansion(SemaContext *macro_context, Expr *c
call->body_expansion_expr.values = args;
call->body_expansion_expr.declarations = macro_context->yield_params;
AstId last_defer = context->active_scope.defer_last;
SCOPE_START
SCOPE_START(call->span);
unsigned ct_context = sema_context_push_ct_stack(context);
if (macro_defer)
{
@@ -8586,7 +8586,7 @@ static inline bool sema_rewrite_expr_as_macro_block(SemaContext *context, Expr *
bool success;
Ast *compound_stmt = ast_new(AST_COMPOUND_STMT, expr->span);
compound_stmt->compound_stmt.first_stmt = start;
SCOPE_START_WITH_FLAGS(SCOPE_MACRO)
SCOPE_START_WITH_FLAGS(SCOPE_MACRO, compound_stmt->span)
success = sema_analyse_stmt_chain(context, compound_stmt);
SCOPE_END;
context->expected_block_type = old_expected_block;

View File

@@ -23,11 +23,11 @@
#define RETURN_VAL_SEMA_ERROR(val__, _node, ...) do { sema_error_at(context, (_node)->span, __VA_ARGS__); return (val__); } while (0)
#define RETURN_NULL_SEMA_ERROR(_node, ...) do { sema_error_at(context, (_node)->span, __VA_ARGS__); return NULL; } while (0)
#define RETURN_SEMA_ERROR_AT(span__, ...) do { sema_error_at(context, span__, __VA_ARGS__); return false; } while (0)
#define SCOPE_OUTER_START do { DynamicScope stored_scope = context->active_scope; context_change_scope_with_flags(context, SCOPE_NONE);
#define SCOPE_OUTER_START(span__) do { DynamicScope stored_scope = context->active_scope; context_change_scope_with_flags(context, SCOPE_NONE, span__);
#define SCOPE_OUTER_END ASSERT(context->active_scope.defer_last == context->active_scope.defer_start); context->active_scope = stored_scope; } while(0)
#define SCOPE_START SCOPE_START_WITH_FLAGS(SCOPE_NONE)
#define SCOPE_START_WITH_FLAGS(flags) do { DynamicScope old_scope = context->active_scope; context_change_scope_with_flags(context, flags);
#define SCOPE_START_WITH_LABEL(label) do { DynamicScope old_scope = context->active_scope; context_change_scope_for_label(context, label);
#define SCOPE_START(span__) SCOPE_START_WITH_FLAGS(SCOPE_NONE, span__)
#define SCOPE_START_WITH_FLAGS(flags, span__) do { DynamicScope old_scope = context->active_scope; context_change_scope_with_flags(context, flags, span__);
#define SCOPE_START_WITH_LABEL(label, span__) do { DynamicScope old_scope = context->active_scope; context_change_scope_for_label(context, label, span__);
#define SCOPE_END ASSERT(context->active_scope.defer_last == context->active_scope.defer_start); context->active_scope = old_scope; } while(0)
#define SCOPE_POP_ERROR() ((bool)(context->active_scope = old_scope, false))
#define SCOPE_ERROR_END_OUTER() do { context->active_scope = stored_scope; } while(0)
@@ -51,8 +51,8 @@ const char *context_filename(SemaContext *context);
AstId context_get_defers(SemaContext *context, AstId defer_bottom, bool is_success);
void context_pop_defers(SemaContext *context, AstId *next);
void context_pop_defers_and_replace_ast(SemaContext *context, Ast *ast);
void context_change_scope_for_label(SemaContext *context, DeclId label);
void context_change_scope_with_flags(SemaContext *context, ScopeFlags flags);
void context_change_scope_for_label(SemaContext *context, DeclId label, SourceSpan span);
void context_change_scope_with_flags(SemaContext *context, ScopeFlags flags, SourceSpan span);
SemaContext *context_transform_for_eval(SemaContext *context, SemaContext *temp_context, CompilationUnit *eval_unit);
TokenType sema_splitpathref(const char *string, ArraySize len, Path **path_ref, const char **ident_ref);

View File

@@ -247,7 +247,7 @@ static inline bool sema_analyse_compound_stmt(SemaContext *context, Ast *stateme
{
bool success;
EndJump ends_with_jump;
SCOPE_START
SCOPE_START(statement->span)
success = sema_analyse_compound_statement_no_scope(context, statement);
ends_with_jump = context->active_scope.end_jump;
SCOPE_END;
@@ -532,7 +532,7 @@ static bool sema_analyse_macro_constant_ensures(SemaContext *context, Expr *ret_
// And set our new one.
context->return_expr = ret_expr;
bool success = true;
SCOPE_START_WITH_FLAGS(SCOPE_ENSURE_MACRO);
SCOPE_START_WITH_FLAGS(SCOPE_ENSURE_MACRO, ret_expr->span);
while (doc_directive)
{
Ast *directive = astptr(doc_directive);
@@ -757,7 +757,7 @@ static inline bool sema_analyse_return_stmt(SemaContext *context, Ast *statement
if (directive->contract_stmt.kind == CONTRACT_ENSURE)
{
bool success;
SCOPE_START_WITH_FLAGS(SCOPE_ENSURE);
SCOPE_START_WITH_FLAGS(SCOPE_ENSURE, statement->span);
success = assert_create_from_contract(context, directive, &append_id, statement->span);
SCOPE_END;
if (!success) return false;
@@ -1347,7 +1347,7 @@ bool sema_analyse_defer_stmt_body(SemaContext *context, Ast *statement)
}
body->compound_stmt.parent_defer = astid(statement);
bool success = true;
SCOPE_START
SCOPE_START(statement->span)
context->active_scope.defer_last = 0;
context->active_scope.defer_start = 0;
@@ -1434,7 +1434,7 @@ static inline bool sema_analyse_for_stmt(SemaContext *context, Ast *statement)
RETURN_SEMA_ERROR(body, "A do loop must use { } around its body.");
}
// Enter for scope
SCOPE_OUTER_START
SCOPE_OUTER_START(statement->span)
if (statement->for_stmt.init)
{
@@ -1442,7 +1442,7 @@ static inline bool sema_analyse_for_stmt(SemaContext *context, Ast *statement)
}
// Conditional scope start
SCOPE_START_WITH_LABEL(statement->for_stmt.flow.label)
SCOPE_START_WITH_LABEL(statement->for_stmt.flow.label, statement->span)
if (!do_loop)
{
@@ -1466,7 +1466,7 @@ static inline bool sema_analyse_for_stmt(SemaContext *context, Ast *statement)
if (statement->for_stmt.flow.skip_first)
{
SCOPE_START
SCOPE_START(statement->span)
if (!sema_analyse_for_cond(context, &statement->for_stmt.cond, &is_infinite) || !success)
{
SCOPE_ERROR_END_OUTER();
@@ -1484,7 +1484,7 @@ static inline bool sema_analyse_for_stmt(SemaContext *context, Ast *statement)
if (success && statement->for_stmt.incr)
{
// Incr scope start
SCOPE_START
SCOPE_START(statement->span)
success = sema_analyse_expr_rvalue(context, exprptr(statement->for_stmt.incr));
// Incr scope end
SCOPE_END;
@@ -1537,7 +1537,7 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen
}
}
// Conditional scope start
SCOPE_START
SCOPE_START(statement->span)
// In the case of foreach (int x : { 1, 2, 3 }) we will infer the int[] type, so pick out the number of elements.
Type *inferred_type = variable_type_info ? type_get_inferred_array(type_no_optional(variable_type_info->type)) : NULL;
@@ -1984,7 +1984,7 @@ static inline bool sema_analyse_if_stmt(SemaContext *context, Ast *statement)
CondResult result = COND_MISSING;
bool is_invalid = false;
bool reverse = false;
SCOPE_OUTER_START
SCOPE_OUTER_START(statement->span)
success = sema_analyse_cond(context, cond, COND_TYPE_UNWRAP_BOOL, &result);
if (success && cond->expr_kind == EXPR_COND)
@@ -2027,7 +2027,7 @@ static inline bool sema_analyse_if_stmt(SemaContext *context, Ast *statement)
}
}
SCOPE_START_WITH_LABEL(statement->if_stmt.flow.label);
SCOPE_START_WITH_LABEL(statement->if_stmt.flow.label, then->span);
if (result == COND_FALSE) context->active_scope.is_dead = true;
success = success && sema_analyse_statement(context, then);
then_jump = context->active_scope.end_jump.active && !(statement->if_stmt.flow.label && statement->if_stmt.flow.has_break);
@@ -2039,11 +2039,11 @@ static inline bool sema_analyse_if_stmt(SemaContext *context, Ast *statement)
{
bool store_break = statement->if_stmt.flow.has_break;
statement->if_stmt.flow.has_break = false;
SCOPE_START_WITH_LABEL(statement->if_stmt.flow.label);
SCOPE_START_WITH_LABEL(statement->if_stmt.flow.label, statement->span);
if (result == COND_TRUE) context->active_scope.is_dead = true;
sema_remove_unwraps_from_try(context, cond);
sema_unwrappable_from_catch_in_else(context, cond);
success = success && sema_analyse_statement(context, else_body);
success = sema_analyse_statement(context, else_body);
else_jump = context->active_scope.end_jump.active && !(statement->if_stmt.flow.label && statement->if_stmt.flow.has_break);
SCOPE_END;
statement->if_stmt.flow.has_break |= store_break;
@@ -2636,7 +2636,7 @@ FOUND:;
for (unsigned i = 0; i < case_count; i++)
{
Ast *stmt = cases[i];
SCOPE_START
SCOPE_START(statement->span)
PUSH_BREAK(statement);
Ast *next = (i < case_count - 1) ? cases[i + 1] : NULL;
PUSH_NEXT(next, statement);
@@ -2984,7 +2984,7 @@ static inline bool sema_analyse_switch_stmt(SemaContext *context, Ast *statement
{
statement->switch_stmt.scope_defer = context->active_scope.in_defer;
SCOPE_START_WITH_LABEL(statement->switch_stmt.flow.label);
SCOPE_START_WITH_LABEL(statement->switch_stmt.flow.label, statement->span);
Expr *cond = exprptrzero(statement->switch_stmt.cond);
Type *switch_type;
@@ -3471,7 +3471,7 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func)
Ast *body = astptr(func->func_decl.body);
Decl **lambda_params = NULL;
SCOPE_START
SCOPE_START(func->span)
ASSERT(context->active_scope.depth == 1);
FOREACH(Decl *, param, signature->params)
{

View File

@@ -8,12 +8,13 @@
char swizzle[256] = { ['x'] = 0x01, ['y'] = 0x02, ['z'] = 0x03, ['w'] = 0x04,
['r'] = 0x11, ['g'] = 0x12, ['b'] = 0x13, ['a'] = 0x14 };
void context_change_scope_with_flags(SemaContext *context, ScopeFlags flags)
void context_change_scope_with_flags(SemaContext *context, ScopeFlags flags, SourceSpan span)
{
unsigned depth = context->active_scope.depth + 1;
if (depth > MAX_SCOPE_DEPTH)
{
FATAL_ERROR("Too deeply nested scopes.");
sema_error_at(context, span, "Resolution failed due to too deeply nested scopes (%u).", depth);
exit_compiler(COMPILER_SUCCESS_EXIT);
}
bool scope_is_dead = context->active_scope.is_dead;
@@ -57,9 +58,9 @@ const char *context_filename(SemaContext *context)
return file->full_path;
}
void context_change_scope_for_label(SemaContext *context, DeclId label_id)
void context_change_scope_for_label(SemaContext *context, DeclId label_id, SourceSpan span)
{
context_change_scope_with_flags(context, SCOPE_NONE);
context_change_scope_with_flags(context, SCOPE_NONE, span);
if (label_id)
{