diff --git a/App/lib/core/Gen/Expr/ExprGenBase.vp b/App/lib/core/Gen/Expr/ExprGenBase.vp index f5ac0fc..b9852b8 100644 --- a/App/lib/core/Gen/Expr/ExprGenBase.vp +++ b/App/lib/core/Gen/Expr/ExprGenBase.vp @@ -8,6 +8,7 @@ import string import viperlib import lib.core.Gen.Translator as HT import lib.Projectrans.Utils as Utils +import lib.core.Gen.Type.TypeSpec as TSpec # ============================================================ @@ -151,25 +152,13 @@ class ExprGenBase: # - 不同级指针(1 vs 2) → 禁止(fast-fail) # ============================================================ def get_ptr_level(self, ty: llvmlite.LLVMType | t.CPtr) -> int: - """计算指针层级,0=非指针, 1=一级指针, 2=二级指针...""" - if ty is None: - return 0 - level: int = 0 - cur: llvmlite.LLVMType | t.CPtr = ty - while cur is not None: - # 同类编译 bug(见 TypeGenResolve L1463 注释):case body 直接 - # 更新 while 条件变量(cur = pointee)时自举编译出的 match 把赋值 - # 写到 subject 快照槽,while 条件读旧槽 → 死循环。改法:case - # 绑定到局部变量,match 外更新循环变量。 - nxt_cur: llvmlite.LLVMType | t.CPtr = None - match cur: - case llvmlite.LLVMType.Ptr(pointee): - level += 1 - nxt_cur = pointee - case _: - break - cur = nxt_cur - return level + """计算指针层级,0=非指针, 1=一级指针, 2=二级指针... + + [S3 切读·指针层级块] 实现已收拢到 `TSpec.SpecTypePtrLevel` + (该块在 TypeSpec 模块中的**唯一实现**),此处只做委托,不再保留同码副本。 + 原实现里记录的「match codegen 缺陷」规避说明随实现一并移入 TypeSpec。 + """ + return TSpec.SpecTypePtrLevel(ty) # ============================================================ # _is_zero_int_literal - 判断 AST 节点是否为整数字面量 0 # diff --git a/App/lib/core/Gen/Expr/ExprGenOps.vp b/App/lib/core/Gen/Expr/ExprGenOps.vp index 16dd993..4408edf 100644 --- a/App/lib/core/Gen/Expr/ExprGenOps.vp +++ b/App/lib/core/Gen/Expr/ExprGenOps.vp @@ -534,48 +534,39 @@ class ExprGenOps(ExprGenBase.ExprGenBase): d += 1 return 0 # ============================================================ - # S2 双写(无符号判定块)——独立真源与旧判定比对,不一致即 fatal + # S3 切读(无符号判定块)——**新真源优先**,旧路径降级为兜底 # - # 新真源:TypeGenCType.spec_sign_of_annot(精确名白名单 + CTypedef 链逐层展开), - # 与旧路径(strstr 子串扫描 + 只展开一层)**完全独立**,故能暴露 A2~A5 类错判。 - # 读仍走旧路径(S3 才切读);此处只做一致性闸门(D6-3 决策:直接 fatal)。 - # - # 只在**新真源明确表态**时比对:别名/复合注解若新真源返回 UNKNOWN - # (尚未覆盖),则不参与比对,避免用"未知"误杀旧路径的正确判定。 + # 真源:TypeGenCType.spec_sign_of_annot(精确名白名单 + CTypedef 链逐层展开)。 + # 切读策略(D5「旧路径留兜底」): + # - 新真源**明确表态**(UNSIGNED/SIGNED)→ 直接采用(不再看旧子串表); + # - 新真源返回 UNKNOWN(类名 / sha1 前缀名 / 未登记别名等尚未覆盖)→ 回退旧路径。 + # S2 的「双写一致性闸门」在切读后已无意义(读就取新真源,比对恒等),故撤除。 # ============================================================ def _spec_sign_from_annot(self, annot: str) -> int: - """新真源入口:注解 → TS_SIGN_*(UNKNOWN 表示不表态)""" + """真源入口:注解 → TS_SIGN_*(UNKNOWN 表示不表态)""" return self.Gen.TypeGenCType.spec_sign_of_annot(annot, 0) - def _spec_sign_check(self, text: str, old_unsigned: int) -> None: - """S2 一致性闸门:新真源明确表态且与旧判定不一致 → fatal""" - if text is None: - return - new_sign: int = self._spec_sign_from_annot(text) - if new_sign == TSpec.TS_SIGN_UNKNOWN: - return - new_unsigned: int = 0 - if new_sign == TSpec.TS_SIGN_UNSIGNED: - new_unsigned = 1 - if new_unsigned == old_unsigned: - return - old_txt: str = "signed" - if old_unsigned != 0: - old_txt = "unsigned" - new_txt: str = "signed" - if new_unsigned != 0: - new_txt = "unsigned" - msg: str = f"[S2 符号性双写] 注解 '{text}':旧判定={old_txt},新真源={new_txt}" - self.Gen.TypeGenErr.fatal_error(None, msg, "TypeError") def _type_name_unsigned(self, type_name: str) -> int: - """[S2 双写] 类型名无符号判定 + 独立真源比对""" - old: int = self._type_name_unsigned_legacy(type_name) - self._spec_sign_check(type_name, old) - return old + """[S3 切读] 类型名无符号判定:新真源优先,未表态时回退旧路径 + + 注:旧路径在此**按需**调用(仅新真源不表态时),避免热路径上无谓的 + 子串扫描 + CTypedef 链查表双份开销。 + """ + if type_name is not None: + s: int = self._spec_sign_from_annot(type_name) + if s == TSpec.TS_SIGN_UNSIGNED: + return 1 + if s == TSpec.TS_SIGN_SIGNED: + return 0 + return self._type_name_unsigned_legacy(type_name) def _annot_str_unsigned(self, annot: str) -> int: - """[S2 双写] 注解串无符号判定 + 独立真源比对""" - old: int = self._annot_str_unsigned_legacy(annot) - self._spec_sign_check(annot, old) - return old + """[S3 切读] 注解串无符号判定:新真源优先,未表态时回退旧路径""" + if annot is not None: + s: int = self._spec_sign_from_annot(annot) + if s == TSpec.TS_SIGN_UNSIGNED: + return 1 + if s == TSpec.TS_SIGN_SIGNED: + return 0 + return self._annot_str_unsigned_legacy(annot) def translate_compare(self, builder: llvmlite.IRBuilder | t.CPtr, pool: memhub.MemBuddy | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, diff --git a/App/lib/core/Gen/Type/TypeGenCType.vp b/App/lib/core/Gen/Type/TypeGenCType.vp index 76240e3..8e10b7e 100644 --- a/App/lib/core/Gen/Type/TypeGenCType.vp +++ b/App/lib/core/Gen/Type/TypeGenCType.vp @@ -156,12 +156,13 @@ class TypeGenCType(TypeGenBase.TypeGenBase): return ts return None # ============================================================ - # 独立符号性真源(S2 双写比对用;与旧 _annot_str_unsigned 完全独立) + # 符号性真源(**S3 起无符号判定的读入口**;S2 阶段曾用作双写比对基准) # - # 旧实现:strstr 子串扫描 + CTypedef 只展开一层 ⇒ 两类错判: - # A4 `BYTEPTR` 含 `BYTE` 被判无符号;A5 sha1 前缀名含 `uint32` 命中; + # 旧实现(现降级为「真源不表态时的兜底」):strstr 子串扫描 + CTypedef 只展开一层 + # ⇒ 两类错判:A4 `BYTEPTR` 含 `BYTE` 被判无符号;A5 sha1 前缀名含 `uint32` 命中; # 多层别名(WCHAR→WORD→t.CUInt16T)因只展开一层而漏判。 - # 本实现:精确名白名单(TSpec.SpecSignFromTypeNameSpan)+ 别名链逐层展开。 + # 本实现:精确名白名单(TSpec.SpecSignFromTypeNameSpan)+ 别名链逐层展开, + # 不表态时返回 TS_SIGN_UNKNOWN(由调用方决定是否回退旧路径)。 # ============================================================ def spec_sign_of_annot(self, text: str, depth: int = 0) -> int: """按注解文本判定其整数值符号性(独立真源),未覆盖返回 TS_SIGN_UNKNOWN""" diff --git a/App/lib/core/Gen/Type/TypeSpec.vp b/App/lib/core/Gen/Type/TypeSpec.vp index 845a939..31655f6 100644 --- a/App/lib/core/Gen/Type/TypeSpec.vp +++ b/App/lib/core/Gen/Type/TypeSpec.vp @@ -787,6 +787,35 @@ def SpecBitWidth(sp: TypeSpec | t.CPtr) -> int: return sp.Bits +# ============================================================ +# SpecTypePtrLevel - LLVM 类型 → 指针层级(**指针层级块的唯一实现**) +# +# S3 起由 ExprGenBase.get_ptr_level 委托调用(原实现是 Gen 层里的同码副本, +# 现收拢到本模块,成为该块切读 TypeSpec 的入口)。 +# 返回 0=非指针 / 1=一级指针 / 2=二级指针 / 3+… +# +# ⚠️ 规避自举 match codegen 缺陷(原 get_ptr_level 注释所记):`case` 体内 +# **直接更新外层 while 条件变量**会把赋值写进 subject 快照槽,while 条件读旧槽 +# ⇒ 死循环。故此处 `case` 只绑定局部 `nxt`,循环变量在 match **外**更新。 +# ============================================================ +def SpecTypePtrLevel(ty: llvmlite.LLVMType | t.CPtr) -> int: + """计算指针层级,0=非指针,1=一级指针,2=二级指针…""" + if ty is None: + return 0 + level: int = 0 + cur: llvmlite.LLVMType | t.CPtr = ty + while cur is not None: + nxt: llvmlite.LLVMType | t.CPtr = None + match cur: + case llvmlite.LLVMType.Ptr(pointee): + level += 1 + nxt = pointee + case _: + break + cur = nxt + return level + + # ============================================================ # SpecFromLLVMType - 已解析 LLVM 类型 → TypeSpec(结构翻译) #