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:
1 parent
b7100e9dc1
commit
f0deff931d
4 files changed
+69
-59
No files matched your search
@@ -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
|
||||
#
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"""
|
||||
|
||||
@@ -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(结构翻译)
|
||||
#
|
||||
|
||||
Reference in new issue
Block a user