stage1 解决defer实现的缺陷

This commit is contained in:
zzy committed 2026-09-17 16:44:50 +08:00
1 parent 2594a81034
commit 5de4937637
2 files changed
+63 -33

No files matched your search

+62 -33
View File
@@ -28,6 +28,26 @@ static void emit_break_stmt(spl_ast2ir_t *a, spl_ast_node_t *n);
static spl_ir_node_ref_t emit_expr(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
static spl_ir_node_ref_t emit_lvalue(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
/* Emit one exit path without consuming the lexical registrations needed by
* sibling paths. A private stack also allows cleanup bodies to register defer. */
static void emit_deferred_until(spl_ast2ir_t *a, usize base) {
if (vec_size(a->defer_stack) <= base)
return;
spl_defer_stack_t saved = a->defer_stack;
vec_init(a->defer_stack);
for (usize i = 0; i < vec_size(saved); ++i)
vec_push(a->defer_stack, vec_at(saved, i));
while (!a->ir->terminated && vec_size(a->defer_stack) > base) {
spl_ast_node_ref_t body = vec_pop(a->defer_stack);
emit_stmt(a, body);
}
vec_free(a->defer_stack);
a->defer_stack = saved;
}
static void emit_decl(spl_ast2ir_t *a, spl_ast_node_ref_t ref);
static spl_ir_node_ref_t emit_var_decl(spl_ast2ir_t *a, spl_ast_node_t *n);
static void emit_pattern_bind(spl_ast2ir_t *a, spl_ast_node_ref_t pat_ref,
@@ -1105,11 +1125,16 @@ static spl_ir_node_ref_t emit_expr_raw(spl_ast2ir_t *a, spl_ast_node_ref_t ref)
return node;
}
case SPL_AST_EXPR_BLOCK: {
for (usize i = 0; i < vec_size(n->block.stmts); ++i)
usize defer_base = vec_size(a->defer_stack);
for (usize i = 0; i < vec_size(n->block.stmts) && !a->ir->terminated; ++i)
emit_stmt(a, vec_at(n->block.stmts, i));
if (n->block.tail_expr)
return emit_expr(a, n->block.tail_expr);
return 0;
spl_ir_node_ref_t value = 0;
if (!a->ir->terminated && n->block.tail_expr)
value = emit_expr(a, n->block.tail_expr);
if (!a->ir->terminated)
emit_deferred_until(a, defer_base);
a->defer_stack.size = defer_base;
return value;
}
case SPL_AST_EXPR_IF:
case SPL_AST_EXPR_IFVAR:
@@ -1422,6 +1447,7 @@ static spl_ir_node_ref_t emit_loop_like(spl_ast2ir_t *a, spl_ast_node_ref_t ref)
spl_loop_ctx_t ctx = {0};
ctx.cont_blk = cont_blk;
ctx.defer_base = vec_size(a->defer_stack);
ctx.label = NULL;
ctx.result_slot = result_slot;
ctx.result_tid = result_t;
@@ -1480,29 +1506,34 @@ static void emit_break_stmt(spl_ast2ir_t *a, spl_ast_node_t *n) {
lbl = ln->label.name;
}
spl_loop_ctx_t *target = NULL;
usize target_index = vec_size(a->loop_stack);
if (lbl) {
for (usize i = vec_size(a->loop_stack); i > 0; --i) {
spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1);
if (c->label && strcmp(c->label, lbl) == 0) {
target = c;
target_index = i - 1;
break;
}
}
} else {
target = &vec_at(a->loop_stack, vec_size(a->loop_stack) - 1);
target_index = vec_size(a->loop_stack) - 1;
}
if (!target)
if (target_index == vec_size(a->loop_stack))
return;
if (n->statement_break.expr && target->result_slot) {
/* Emitting a value or a cleanup can grow/reallocate loop_stack. */
spl_loop_ctx_t target = vec_at(a->loop_stack, target_index);
if (n->statement_break.expr && target.result_slot) {
spl_ir_node_ref_t bv = emit_expr(a, n->statement_break.expr);
if (bv)
spl_ir_builder_mem_store(a->ir, target->result_tid, target->result_slot, bv);
spl_ir_builder_mem_store(a->ir, target.result_tid, target.result_slot, bv);
}
emit_deferred_until(a, target.defer_base);
if (a->ir->terminated)
return;
spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir);
vec_push(target->breaks, jmp);
vec_push(vec_at(a->loop_stack, target_index).breaks, jmp);
}
static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
@@ -1518,11 +1549,9 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
if (n->statement_ret.expr)
v = emit_expr(a, n->statement_ret.expr);
while (vec_size(a->defer_stack) > a->cur_defer_base) {
spl_ast_node_ref_t d = vec_pop(a->defer_stack);
emit_stmt(a, d);
}
emit_deferred_until(a, a->cur_defer_base);
if (!a->ir->terminated)
spl_ir_builder_control_ret(a->ir, ret_ir, v);
return;
}
@@ -1566,21 +1595,26 @@ static void emit_stmt(spl_ast2ir_t *a, spl_ast_node_ref_t ref) {
lbl = ln->label.name;
}
spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir);
usize target_index = vec_size(a->loop_stack) - 1;
if (lbl) {
target_index = vec_size(a->loop_stack);
for (usize i = vec_size(a->loop_stack); i > 0; --i) {
spl_loop_ctx_t *c = &vec_at(a->loop_stack, i - 1);
if (c->label && strcmp(c->label, lbl) == 0) {
spl_ir_builder_control_jmp_fixup(a->ir, jmp, c->cont_blk);
target_index = i - 1;
break;
}
}
}
if (target_index == vec_size(a->loop_stack))
return;
}
}
return;
}
usize cont = vec_at(a->loop_stack, vec_size(a->loop_stack) - 1).cont_blk;
spl_ir_builder_control_jmp_fixup(a->ir, jmp, cont);
spl_loop_ctx_t target = vec_at(a->loop_stack, target_index);
emit_deferred_until(a, target.defer_base);
if (!a->ir->terminated) {
spl_ir_node_ref_t jmp = spl_ir_builder_control_jmp(a->ir);
spl_ir_builder_control_jmp_fixup(a->ir, jmp, target.cont_blk);
}
return;
}
case SPL_AST_EXPR_BLOCK:
@@ -1691,12 +1725,10 @@ static void emit_fn_body(spl_ast2ir_t *a, spl_ast_node_t *n) {
if (n->fn_decl.body)
emit_expr(a, n->fn_decl.body);
if (!a->ir->terminated) {
while (vec_size(a->defer_stack) > defer_base) {
spl_ast_node_ref_t d = vec_pop(a->defer_stack);
emit_stmt(a, d);
}
if (!a->ir->terminated)
emit_deferred_until(a, defer_base);
if (!a->ir->terminated) {
if (ret_is_unit) {
spl_ir_builder_control_ret(a->ir, ret_ir, 0);
} else if (ret_ir) {
@@ -1707,10 +1739,7 @@ static void emit_fn_body(spl_ast2ir_t *a, spl_ast_node_t *n) {
}
}
while (vec_size(a->defer_stack) > defer_base) {
spl_ast_node_ref_t d = vec_pop(a->defer_stack);
(void)d;
}
a->defer_stack.size = defer_base;
while (vec_size(a->loop_stack) > loop_base) {
spl_loop_ctx_t *top = &vec_at(a->loop_stack, vec_size(a->loop_stack) - 1);
vec_free(top->breaks);
+1
View File
@@ -9,6 +9,7 @@ typedef MAP(spl_def_id_t, spl_ir_node_ref_t) spl_def2ir_map_t;
typedef struct {
usize cont_blk;
usize defer_base;
const char *label;
spl_ir_node_ref_vec_t breaks;
spl_ir_node_ref_t result_slot;