fix(match): case 体末句控制流全 return 补 unreachable 不 br end_bb

根因(ClassGenEnum._get_type_align 掉出末尾):case 体末句是 If/控制流且
全分支 return 时,处理器把 builder 停在无 terminator 的 merge 块,case
循环的 is_terminated 误判未终止 → 补 br end_bb → rm/sq/sm_merge_reach=1
→ 全 case return 的 match 被误判 merge 可达 → 函数收尾 fail-fast
'流程掉出末尾'。新增模块级 _case_tail_unreachable:末句控制流
(If/While/For/Match)且 _ctrl_merge_reachable==0 时补 unreachable,
与 HandlesIf L309-315 / ClassGenVTable L1084 同语义;应用于 renum/
sequence/simple 三路的 case 体与 default 收尾(不含 Try/With,其处理器
不维护该标志)。
This commit is contained in:
TermiNexus committed 2026-08-19 03:16:16 +08:00
1 parent fa52fbd4e5
commit 4d7a6db31a
1 file changed
+62 -9
+62 -9
View File
@@ -44,6 +44,44 @@ MAX_MATCH_CASES: t.CDefine = 32
SCOPE_MATCH: t.CDefine = 6
# ============================================================
# _case_tail_unreachable - case 体末尾结构性不可达判定
#
# case 体翻译后当前块若未终止,且末句是控制流语句(If/While/For/Match)
# 且其 merge 结构性不可达(全分支 return,如 case Int(bits): if ... return)
# 时,当前块是控制流的 merge(无 terminator),与 HandlesIf L309-315/
# ClassGenVTable L1084 同语义补 unreachable。返回 1= 已补 unreachable
# (调用方不应 br end_bb);0= 正常收尾(应 br end_bb)。
#
# 根因(ClassGenEnum._get_type_align):case 体末句 If 全 return 时,If
# 处理器把 builder 停在无 terminator 的 merge 块,case 循环的
# is_terminated 检查误判"未终止" → 补 br end_bb → rm_merge_reach=1 →
# 全 case return 的 match 被误判 merge 可达 → 函数收尾 fail-fast
# "流程掉出末尾"。不含 Try/With:其处理器不维护 _ctrl_merge_reachable,
# 避免残留值误判。
# ============================================================
def _case_tail_unreachable(trans: HT.Translator | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
body_list: list[ast.AST | t.CPtr] | t.CPtr) -> int:
if trans is None or builder is None:
return 0
if llvmlite.builder_cur_block_is_terminated(builder) != 0:
return 0
if body_list is None or len(body_list) == 0:
return 0
lst: ast.AST | t.CPtr = body_list.get(len(body_list) - 1)
if lst is None:
return 0
lk: int = lst.kind()
if lk != ast.ASTKind.If and lk != ast.ASTKind.While \
and lk != ast.ASTKind.For and lk != ast.ASTKind.Match:
return 0
if trans._ctrl_merge_reachable != 0:
return 0
llvmlite.build_unreachable(builder)
return 1
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式)
#
@@ -519,8 +557,10 @@ class MatchHandle(HandlesBase.Mixin):
HandlesVar.exit_scope(trans.SymTab)
# 若未终止且无 NoBreak,跳到 end
# 末句控制流全 return(结构性不可达)时补 unreachable,不 br end_bb
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
and nb == 0:
and nb == 0 \
and _case_tail_unreachable(trans, builder, body_list) == 0:
llvmlite.build_br(builder, end_bb)
trans._ctrl_merge_reachable = 1
rm_merge_reach = 1
@@ -537,6 +577,7 @@ class MatchHandle(HandlesBase.Mixin):
rm_merge_reach = 1
else:
# 有显式 default:翻译 default case body(找到 is_def==1 的 case)
dbody: list[ast.AST | t.CPtr] | t.CPtr = None
di: int = 0
while di < collected:
if def_arr[di] == 1:
@@ -545,7 +586,7 @@ class MatchHandle(HandlesBase.Mixin):
dmc: ast.MatchCase | t.CPtr = (
ast.MatchCase | t.CPtr)(dcase)
HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH)
dbody: list[ast.AST | t.CPtr] | t.CPtr = dmc.children
dbody = dmc.children
if dbody is not None:
dn: t.CSizeT = len(dbody)
dj: int = 0
@@ -557,7 +598,9 @@ class MatchHandle(HandlesBase.Mixin):
HandlesVar.exit_scope(trans.SymTab)
break
di = di + 1
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
# 末句控制流全 return → 补 unreachable(不 br end_bb)
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
and _case_tail_unreachable(trans, builder, dbody) == 0:
llvmlite.build_br(builder, end_bb)
trans._ctrl_merge_reachable = 1
rm_merge_reach = 1
@@ -988,7 +1031,9 @@ class MatchHandle(HandlesBase.Mixin):
HandlesBody.translate_stmt(trans, stmt)
bi = bi + 1
HandlesVar.exit_scope(trans.SymTab)
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
# 末句控制流全 return → 补 unreachable(不 br end,无 fallthrough)
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
and _case_tail_unreachable(trans, builder, body_list2) == 0:
if nb_arr[ci] == 0:
llvmlite.build_br(builder, end_bb)
else:
@@ -1011,6 +1056,7 @@ class MatchHandle(HandlesBase.Mixin):
# 7. default 块
llvmlite.position_at_end(builder, default_bb)
dbody: list[ast.AST | t.CPtr] | t.CPtr = None
if has_default == 1:
di: int = 0
while di < collected:
@@ -1020,7 +1066,7 @@ class MatchHandle(HandlesBase.Mixin):
dmc: ast.MatchCase | t.CPtr = (
ast.MatchCase | t.CPtr)(dnode)
HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH)
dbody: list[ast.AST | t.CPtr] | t.CPtr = dmc.children
dbody = dmc.children
if dbody is not None:
dn: t.CSizeT = len(dbody)
dj: int = 0
@@ -1032,7 +1078,9 @@ class MatchHandle(HandlesBase.Mixin):
HandlesVar.exit_scope(trans.SymTab)
break
di = di + 1
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
# 末句控制流全 return → 补 unreachable(不 br end_bb)
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
and _case_tail_unreachable(trans, builder, dbody) == 0:
llvmlite.build_br(builder, end_bb)
sq_merge_reach = 1
@@ -1227,8 +1275,10 @@ class MatchHandle(HandlesBase.Mixin):
HandlesVar.exit_scope(trans.SymTab)
# 末句控制流全 return → 补 unreachable(不 br end_bb)
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
and nb == 0:
and nb == 0 \
and _case_tail_unreachable(trans, builder, body_list) == 0:
llvmlite.build_br(builder, end_bb)
trans._ctrl_merge_reachable = 1
sm_merge_reach = 1
@@ -1243,6 +1293,7 @@ class MatchHandle(HandlesBase.Mixin):
trans._ctrl_merge_reachable = 1
sm_merge_reach = 1
else:
dbody: list[ast.AST | t.CPtr] | t.CPtr = None
di: int = 0
while di < collected:
if def_arr[di] == 1:
@@ -1251,7 +1302,7 @@ class MatchHandle(HandlesBase.Mixin):
dmc: ast.MatchCase | t.CPtr = (
ast.MatchCase | t.CPtr)(dcase)
HandlesVar.enter_scope(trans.SymTab, SCOPE_MATCH)
dbody: list[ast.AST | t.CPtr] | t.CPtr = dmc.children
dbody = dmc.children
if dbody is not None:
dn: t.CSizeT = len(dbody)
dj: int = 0
@@ -1263,7 +1314,9 @@ class MatchHandle(HandlesBase.Mixin):
HandlesVar.exit_scope(trans.SymTab)
break
di = di + 1
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
# 末句控制流全 return → 补 unreachable(不 br end_bb)
if llvmlite.builder_cur_block_is_terminated(builder) == 0 \
and _case_tail_unreachable(trans, builder, dbody) == 0:
llvmlite.build_br(builder, end_bb)
trans._ctrl_merge_reachable = 1
sm_merge_reach = 1