refactor(tpv): S3 无符号判定切读真源,指针层级收拢到 TypeSpec

- ExprGenOps: _type_name_unsigned / _annot_str_unsigned 改为真源优先(UNSIGNED->1 / SIGNED->0),仅真源不表态 UNKNOWN 时按需回退旧子串路径(热路径避免双份开销)
- ExprGenOps: 删除 S2 的双写一致性闸门 _spec_sign_check(切读后读即取真源,比对恒等、无意义)
- TypeSpec: 新增 SpecTypePtrLevel -- 指针层级推导的唯一实现,原 get_ptr_level 记录的 match codegen 缺陷规避写法随实现移入
- ExprGenBase: get_ptr_level 删去同码副本,改为委托 TSpec.SpecTypePtrLevel(行为等价)
- TypeGenCType: spec_sign_of_annot 注释更新为无符号判定的读入口
- 注: 值级切读(读 Spec.PtrLevel)仍需条目双写(VarEntry.Spec / FieldEntry.Spec 等)接线,S2 路线 C 未做,留待下一步
This commit is contained in:
TermiNexus committed 2026-09-11 20:40:26 +08:00
1 parent b7100e9dc1
commit f0deff931d
4 files changed
+69 -59

No files matched your search

+8 -19
View File
@@ -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
#
+27 -36
View File
@@ -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,
+5 -4
View File
@@ -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"""
+29
View File
@@ -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(结构翻译)
#