diff --git a/App/lib/core/Gen/Class/ClassGenVTable.vp b/App/lib/core/Gen/Class/ClassGenVTable.vp index bccb49e..92e3665 100644 --- a/App/lib/core/Gen/Class/ClassGenVTable.vp +++ b/App/lib/core/Gen/Class/ClassGenVTable.vp @@ -989,14 +989,12 @@ novirtual class ClassGenVTable(ClassGenBase.ClassGenBase): _is_void = 1 if _is_void != 0: llvmlite.build_ret_void(func_builder) - elif last_is_ctrl != 0 and (trans._ctrl_merge_reachable == 0 \ - or self.Gen.MatchGen.MatchHasWildcardArm(last_stmt3_m) != 0): - # 非 void 方法末句是控制流且 merge 块结构性不可达(全分支 return,无 br + elif last_is_ctrl != 0 and trans._ctrl_merge_reachable == 0: + # 非 void 方法末句是控制流且 merge 块**结构性**不可达(全分支 return,无 br # 到 merge)→ LLVM 语义 unreachable。merge 可达时须正常收尾(下方 - # ConstZero / fail-fast),否则 llc O2 把 br-to-unreachable 优化为 - # fall-through → 双分支执行崩溃。 - # 追加92:末句 match 含无 guard 的 `case _:` 穷尽通配臂时同样不可达 - # (同 FuncGenDef 模块级函数口径)。 + # ConstZero / fail-fast):可达块的 unreachable 是 UB,llc 不生成指令 ⇒ + # 执行掉进布局紧随其后的块(同 FuncGenDef 模块级函数口径;实测反例见该处 + # 注释里的 _TypePrintDepth 用 snprintf 返回值当 tag 走进 switch 跳转表)。 llvmlite.build_unreachable(func_builder) elif fd.returns is None: # 无返回类型注解 → 无返回值过程方法,默认零值返回 diff --git a/App/lib/core/Gen/Func/FuncGenDef.vp b/App/lib/core/Gen/Func/FuncGenDef.vp index ad01f24..ba04b92 100644 --- a/App/lib/core/Gen/Func/FuncGenDef.vp +++ b/App/lib/core/Gen/Func/FuncGenDef.vp @@ -977,19 +977,21 @@ novirtual class FuncGenDef(CallGenBase.CallGenBase): _is_void = 1 if _is_void != 0: llvmlite.build_ret_void(func_builder) - elif last_is_ctrl != 0 and (trans._ctrl_merge_reachable == 0 \ - or self.Gen.MatchGen.MatchHasWildcardArm(last_stmt3) != 0): - # 追加90:非 void 函数末句是控制流且 merge 块结构性不可达 - # (全分支 return,无 br 到 merge)→ LLVM 语义 unreachable。 - # 注意:merge 可达(分支 br 到 merge,如 testcheck.check 的 - # if/else 无 return)时不是结构性不可达,需正常收尾(下方 - # ConstZero / fail-fast)。原实现无条件 unreachable 使 llc - # O2 把 br-to-unreachable 优化为 fall-through → 双分支执行 - # 崩溃(FuncTest check PASS+FAIL 双打印) - # 追加92:末句 match 含无 guard 的 `case _:` 通配臂时 match 穷尽 - # (不存在全臂不命中的路径),流程同样不可能掉出末尾——不能 - # 仅凭 _ctrl_merge_reachable 判定(如 ioctl 的 4 具体臂 + case _: - # 平移逐臂终止性追踪一旦失真即误报"流程掉出末尾")。 + elif last_is_ctrl != 0 and trans._ctrl_merge_reachable == 0: + # 追加90:非 void 函数末句是控制流且 merge 块**结构性**不可达 + # (全分支 return,无 br 到 merge)→ LLVM 语义 unreachable。 + # merge 可达(分支 br 到 merge,如 testcheck.check 的 if/else 无 return) + # 时不是结构性不可达,需正常收尾(下方 ConstZero / fail-fast):可达块的 + # unreachable 是 UB,llc 不生成任何指令 ⇒ 执行掉进布局紧随其后的块。 + # ★ 可达性判据**只用 `_ctrl_merge_reachable`**(MatchGenMixin 逐臂真正 + # `br end_bb` 时才置 1,并由"用本 match 自身的 br 记录覆盖"写回): + # 实测反面教材 —— includes/llvmlite/__types.vp::_TypePrintDepth 末句 + # `match ty:` 带 `case _:`,各臂只 snprintf 后 br 到 merge;旧判据(追加92 + # 的 MatchHasWildcardArm 子句)按"穷尽 ⇒ 流程不可能掉出末尾"推断,给这个 + # 可达 merge 生成了 unreachable ⇒ 打印完 "i32" 后掉进同一 switch 的跳转表, + # 用上一条 snprintf 的返回值("i%d" → 3)当 tag 取 table[3] = Array 臂, + # 把 Int 的 Bits(32) 当指针递归解引用 ⇒ AV at 0x20。 + # 穷尽性 ≠ 各臂都终止:只有"有没有 br 到 merge"才是可达性。 llvmlite.build_unreachable(func_builder) elif fd.returns is None: # 无返回类型注解 → 无返回值过程函数,默认零值返回 diff --git a/App/lib/core/Gen/MatchGenMixin.vp b/App/lib/core/Gen/MatchGenMixin.vp index 2d6772d..6cc8985 100644 --- a/App/lib/core/Gen/MatchGenMixin.vp +++ b/App/lib/core/Gen/MatchGenMixin.vp @@ -57,62 +57,6 @@ novirtual class MatchGenMixin: llvmlite.build_unreachable(builder) return 1 - # ============================================================ - # MatchHasWildcardArm - match 是否含穷尽通配臂(无 guard 的 `case _`) - # - # 用途:函数/方法体末句是 match 且 merge 块未终止时的收尾判定。穷尽 match - # 不存在"全部臂都不命中"的路径 ⇒ 流程不可能掉出末尾(与 If/While 全分支 - # return 同语义),此时应生成 unreachable 而非 fail-fast "流程掉出末尾"。 - # - # 判据:`case _:` 解析为 MatchAs(pattern=None)(parser.vp 通配分支); - # `case _ | X:` 解析为 MatchOr 含该形态。带 guard 的 `case _ if c:` 条件为 - # 假时不命中 ⇒ 不穷尽,必须排除。 - # 返回 1=含穷尽通配臂 / 0=否则(含 node 非 Match)。 - # ============================================================ - def MatchHasWildcardArm(self, node: ast.AST*) -> int: - if node is None: - return 0 - if node.kind() != ast.ASTKind.Match: - return 0 - m: ast.Match* = ast.Match*(node) - cases: list[ast.AST*]* = m.cases - if cases is None: - return 0 - cn: sizet = len(cases) - ci: sizet = 0 - while ci < cn: - case_node: ast.AST* = cases.get(ci) - if case_node is not None and case_node.kind() == ast.ASTKind.MatchCase: - mc: rawptr[ast.MatchCase] = rawptr[ast.MatchCase](case_node) - if mc.guard is None and self._IsWildcardPattern(mc.pattern) != 0: - return 1 - ci = ci + 1 - return 0 - - # ============================================================ - # _IsWildcardPattern - pattern 是否为无绑定通配 `_`(含 as/or 组合) - # ============================================================ - def _IsWildcardPattern(self, pat: ast.AST*) -> int: - if pat is None: - return 0 - pk: int = pat.kind() - if pk == ast.ASTKind.MatchAs: - ma: rawptr[ast.MatchAs] = rawptr[ast.MatchAs](pat) - if ma.pattern is None: - return 1 - return self._IsWildcardPattern(ma.pattern) - if pk == ast.ASTKind.MatchOr: - mo: rawptr[ast.MatchOr] = rawptr[ast.MatchOr](pat) - pl: list[ast.AST*]* = mo.patterns - if pl is not None: - pn: sizet = len(pl) - pi: sizet = 0 - while pi < pn: - if self._IsWildcardPattern(pl.get(pi)) != 0: - return 1 - pi = pi + 1 - return 0 - # ============================================================ # translate_match - match 语句主入口,返回 0 # (迁移自 HandlesMatch.MatchHandle.Handle)