fix(gen): while 1 无限循环无 break 判定 merge 不可达
HandlesWhile 翻译 while 后无条件置 _ctrl_merge_reachable=1,导致末句为 `while 1:`(条件常量真且循环体仅 return 无 break)的函数在收尾检查被 误判"流程掉出末尾未显式 return"(vrandom.gammavariate TypeError)。 新增 _IsConstTrue/_StmtHasBreak(跳过嵌套循环子树):常量真且无本层 break 时 merge 结构性不可达 → 置 0,函数收尾对末句 While 生成 unreachable。
This commit is contained in:
1 parent
b2e69c2f75
commit
f5b3e46543
1 file changed
+67
@@ -143,6 +143,13 @@ class WhileHandle(HandlesBase.Mixin):
|
||||
llvmlite.position_at_end(builder, end_bb)
|
||||
# 追加90:while 的 cond_br 恒引用 end_bb → merge 恒可达(需正常收尾)
|
||||
trans._ctrl_merge_reachable = 1
|
||||
# 无限循环(条件常量真 1/True)且循环体无本层 break → 运行时无任何边
|
||||
# 到达 end 块(merge 结构性不可达)→ 置 0,函数收尾对末句 While 生成
|
||||
# unreachable(追加90:无 br 到达 merge 时才安全;否则 llc O2 把
|
||||
# br-to-unreachable 优化为 fall-through → 双分支执行崩溃)。
|
||||
# 修复 vrandom.gammavariate 的 while 1 全 return 被误判"流程掉出末尾"。
|
||||
if _IsConstTrue(while_node.test) != 0 and _StmtHasBreak(body) == 0:
|
||||
trans._ctrl_merge_reachable = 0
|
||||
return 0
|
||||
|
||||
|
||||
@@ -157,3 +164,63 @@ def NewWhileHandle(pool: memhub.MemBuddy | t.CPtr,
|
||||
if g is not None:
|
||||
return g.NewWhileHandle(pool, trans)
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 无限循环判定辅助(merge 可达性)
|
||||
#
|
||||
# _IsConstTrue: while 条件为常量真(CONST_INT 非 0 / CONST_BOOL 真)
|
||||
# _NodeHasBreak / _StmtHasBreak: 扫描本层 break(跳过嵌套 While/For
|
||||
# 子树——嵌套循环的 break 归内层,不影响外层 merge 可达性)
|
||||
# ============================================================
|
||||
def _IsConstTrue(test: ast.AST | t.CPtr) -> int:
|
||||
"""while 条件为常量真(1 / True)返回 1"""
|
||||
if test is None:
|
||||
return 0
|
||||
if test.kind() == ast.ASTKind.Constant:
|
||||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(test)
|
||||
if cn.const_kind == ast.CONST_INT and cn.int_val != 0:
|
||||
return 1
|
||||
if cn.const_kind == ast.CONST_BOOL and cn.int_val != 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def _NodeHasBreak(node: ast.AST | t.CPtr) -> int:
|
||||
"""递归扫描节点子树(跳过嵌套 While/For 子树),含 Break 返回 1"""
|
||||
if node is None:
|
||||
return 0
|
||||
ch: list[ast.AST | t.CPtr] | t.CPtr = node.children
|
||||
if ch is not None:
|
||||
n: t.CSizeT = len(ch)
|
||||
for bi in range(n):
|
||||
c: ast.AST | t.CPtr = ch.get(bi)
|
||||
if c is None:
|
||||
continue
|
||||
k: int = c.kind()
|
||||
if k == ast.ASTKind.Break:
|
||||
return 1
|
||||
if k == ast.ASTKind.While or k == ast.ASTKind.For:
|
||||
continue
|
||||
if _NodeHasBreak(c) != 0:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def _StmtHasBreak(body: list[ast.AST | t.CPtr] | t.CPtr) -> int:
|
||||
"""语句列表是否含本层 break(嵌套循环的 break 归内层)"""
|
||||
if body is None:
|
||||
return 0
|
||||
n: t.CSizeT = len(body)
|
||||
for bi in range(n):
|
||||
s: ast.AST | t.CPtr = body.get(bi)
|
||||
if s is None:
|
||||
continue
|
||||
k: int = s.kind()
|
||||
if k == ast.ASTKind.Break:
|
||||
return 1
|
||||
if k == ast.ASTKind.While or k == ast.ASTKind.For:
|
||||
continue
|
||||
if _NodeHasBreak(s) != 0:
|
||||
return 1
|
||||
return 0
|
||||
Reference in new issue
Block a user