fix(tpc): 类型静默降级改 fail-fast + 成员槽写入失败附来源明细
a 编译器缺陷:类型信息缺失时静默兜底会掩盖上游根因,兜出来的"看着合理"的类型
(如 i8**)又会让下游报出与真因无关的错。按既定铁律改为响亮失败:
1) HandlesImports._parse_llvm_type:被指类型是具名聚合(%...)却在
create_structs=True 下取不到结构体时,原静默 `return PointerType(i8)` ——
结构体指针被悄悄变成通用指针,外层再套一层即成 i8**。改 fail-fast。
(create_structs=False 属"尚未加载",非异常,保持原样。)
2) HandlesTypeMerge._HandleSubscript:新增判据自洽守卫 —— base 是指针标记
(rawptr / t.CPtr / 裸名 CPtr / 别名)而 IsPtrSubscriptNode 未命中时,
历史上会落到 CollectAll 当"数组下标"解析、静默产出「基座 void + 多层指针」
(i8**)。现 fail-fast(判据分裂即内部不变量被破坏)。
3) HandlesAssign._HandleAttributeStoreLlvm(`self.字段 = 值`):成员槽写入失败
时追加「成员槽来源」明细 —— class_members 声明侧(项数/base/下标/声明槽类型)
+ 布局侧(struct IR 名/元素数/elements[offset])+ structs 键数与是否同一对象,
使"声明侧退化"与"布局侧退化"一眼可分,杜绝再靠猜。
现场:TransPyV/App/lib/core/Gen/Generator.vp:193 `self.ExprGenConst = SubExprGenConst`
→ 指针隐式转换已禁止(层数不同):不能把指针类型
%"cfd1f3d0d7e87fea.ExprGenConst"* 隐式转为 i8**
This commit is contained in:
1 parent
49f0386c33
commit
c49dc1d915
3 files changed
+90
-2
No files matched your search
@@ -847,7 +847,19 @@ class AssignHandle(BaseHandle):
|
||||
Gen._store(Value, Gen.variables[VarName])
|
||||
return
|
||||
MemberPtr: ir.Value = Gen.builder.gep(SelfPtr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=AttrName)
|
||||
self._StoreWithCoerce(Value, MemberPtr)
|
||||
# 成员槽写入失败时补「来源明细」:槽类型的两个来源(class_members
|
||||
# 声明侧 / struct body 布局侧)是两条独立链,不一致时会静默写进
|
||||
# 类型完全不同的槽。报文里逐项列出两侧数据,直接判定谁退化了
|
||||
# (现场:Generator.ExprGenConst 声明 %"...ExprGenConst"* 却落到 i8**)。
|
||||
try:
|
||||
self._StoreWithCoerce(Value, MemberPtr)
|
||||
except Exception as _Me:
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError as _FFE
|
||||
if not isinstance(_Me, _FFE):
|
||||
raise
|
||||
raise _FFE(
|
||||
f"{_Me}{self._DescribeMemberSlot(Gen, ClassName, AttrName, offset, SelfPtr)}"
|
||||
) from _Me
|
||||
elif isinstance(Target.value, ast.Name):
|
||||
VarName: str = Target.value.id
|
||||
|
||||
@@ -1533,6 +1545,55 @@ class AssignHandle(BaseHandle):
|
||||
f"(`rawptr[T] | t.CPtr` 或 `rawptr[rawptr[T]]`)后再赋值;"
|
||||
f"或把基座显式转为 t.CPtr(无类型指针)后按 8 字节指针语义写入。{SrcInfo}")
|
||||
|
||||
def _DescribeMemberSlot(self, Gen: "Translator.LlvmGen", ClassName: str | None,
|
||||
FieldName: str, Offset: int, SelfPtr: ir.Value) -> str:
|
||||
"""`self.字段 = 值` 成员槽写入失败的**来源明细**(供 fail-fast 报文引用)。
|
||||
|
||||
槽类型有两个**互相独立**的来源,必须自洽:
|
||||
- 声明侧:`Gen.class_members[类][下标]`(CollectAnnAssignMember / .vpi 加载);
|
||||
- 布局侧:`SelfPtr` 所指 struct 的 `elements[offset]`(StructGen / stub 解析)。
|
||||
两者不一致时,GEP 会把值写进**类型完全不同**的槽(不是"转换",是越界/错位),
|
||||
现场:Generator.ExprGenConst 声明 `%"...ExprGenConst"*` 却落到 `i8**`。
|
||||
此处把两侧数据逐项列出,直接判定是声明侧退化还是布局侧退化(含 structs
|
||||
键空间大小与"是否同一对象",用于识别裸名 / sha1 全名双条目)。
|
||||
"""
|
||||
Lines: list[str] = []
|
||||
try:
|
||||
Members: list = Gen.class_members.get(ClassName) or []
|
||||
Base: int = Gen._member_base(ClassName)
|
||||
Idx: int = Offset - Base
|
||||
Declared: Any = Members[Idx][1] if 0 <= Idx < len(Members) else None
|
||||
Lines.append(
|
||||
f" class_members[{ClassName}] 项数={len(Members)} base={Base} "
|
||||
f"下标={Idx} 声明槽类型={Declared}")
|
||||
except Exception as _e1:
|
||||
Lines.append(f" class_members 读取失败: {type(_e1).__name__}: {_e1}")
|
||||
Layout: Any = None
|
||||
try:
|
||||
Layout = getattr(SelfPtr.type, 'pointee', None)
|
||||
Elems: Any = getattr(Layout, 'elements', None)
|
||||
try:
|
||||
LayoutName: Any = getattr(Layout, 'name', None)
|
||||
except Exception:
|
||||
LayoutName = '<未命名>'
|
||||
Elem: Any = None
|
||||
if Elems is not None and 0 <= Offset < len(Elems):
|
||||
Elem = Elems[Offset]
|
||||
Lines.append(
|
||||
f" 布局 struct name={LayoutName!r} 元素数="
|
||||
f"{len(Elems) if Elems is not None else None} elements[{Offset}]={Elem}")
|
||||
except Exception as _e2:
|
||||
Lines.append(f" 布局 struct 读取失败: {type(_e2).__name__}: {_e2}")
|
||||
try:
|
||||
_Structs: dict = getattr(Gen, 'structs', {}) or {}
|
||||
_ByName: Any = _Structs.get(ClassName)
|
||||
Lines.append(
|
||||
f" structs 键数={len(_Structs)} structs[{ClassName}] 与布局同一对象="
|
||||
f"{_ByName is Layout}")
|
||||
except Exception:
|
||||
pass
|
||||
return f"\n [成员槽来源] self.{FieldName} = ...\n" + "\n".join(Lines)
|
||||
|
||||
def _StoreWithCoerce(self, Value: ir.Value, Ptr: ir.Value, Node: ast.AST | None = None) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
if isinstance(Ptr.type, ir.PointerType):
|
||||
|
||||
@@ -3585,6 +3585,18 @@ class ImportHandle(BaseHandle):
|
||||
pointee_type = self._parse_llvm_type(pointee, Gen, source_sha1=source_sha1, create_structs=create_structs)
|
||||
if pointee_type is not None:
|
||||
return ir.PointerType(pointee_type)
|
||||
# 被指类型是**具名聚合**(`%...`)却在"允许建结构体"模式下解析不出来:
|
||||
# 具名类型必然可由 _get_or_create_struct 兜出,取不到即内部不变量已被破坏
|
||||
# (成员表/布局两链不同源、名字带多余前缀等)。静默退化成 i8* 会把
|
||||
# 「结构体指针」悄悄变成通用指针,外层再套一层即成 i8**(现场:
|
||||
# Generator.ExprGenConst 声明 %"...ExprGenConst"* 却落到 i8**)。
|
||||
# create_structs=False 时未加载不属异常 ⇒ 只在该模式下响亮失败。
|
||||
if create_structs and pointee.startswith('%'):
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError as _FFE
|
||||
raise _FFE(
|
||||
f"具名类型指针的被指类型解析失败:'{type_str}' 的被指部分 '{pointee}'"
|
||||
f" 在 create_structs=True 下仍取不到结构体(source_sha1={source_sha1})"
|
||||
f"—— 拒绝静默退化为 i8*(会使结构体指针变通用指针,再套一层即 i8**)")
|
||||
return ir.PointerType(ir.IntType(8))
|
||||
|
||||
if type_str.startswith('[') and ']' in type_str:
|
||||
|
||||
@@ -5,7 +5,7 @@ if TYPE_CHECKING:
|
||||
from typing import List
|
||||
from lib.core.Handles.HandlesBase import BaseHandle, CTypeHelper, CTypeInfo
|
||||
from lib.core.SymbolUtils import (
|
||||
IsTModule, IsListAnnotation, IsPtrSubscriptNode,
|
||||
IsTModule, IsListAnnotation, IsPtrSubscriptNode, IsCPtrMarkerNode,
|
||||
DesugarPtrSubscriptToUnion)
|
||||
from lib.includes import t
|
||||
import lib._bootstrap # noqa: F401 设置 sys.path(项目根 + lib/includes)
|
||||
@@ -495,6 +495,21 @@ class HandlesTypeMerge(BaseHandle):
|
||||
if IsPtrSubscriptNode(Node, self.Trans.SymbolTable):
|
||||
return self.MergeTypes(DesugarPtrSubscriptToUnion(Node, self.Trans.SymbolTable))
|
||||
|
||||
# 判据自洽守卫(fail-fast):base 是指针标记(`rawptr` / `t.CPtr` / 裸名
|
||||
# `CPtr` / 别名 `X[...]`,见 IsPtrSubscriptNode)却被上面那条判据漏掉 ⇒
|
||||
# 两处判据分裂(内部不变量被破坏)。历史行为是落到下方 CollectAll 当成
|
||||
# 「数组下标」解析,**静默**产出"基座 void + 多层指针"(如 i8**),与
|
||||
# declare 端的结构体指针分裂(现场:Generator.ExprGenConst 声明
|
||||
# `%"...ExprGenConst"*` 却落到 i8**)。按「不许静默降级」改为响亮失败,
|
||||
# 暴露上游根因。
|
||||
if (isinstance(Node.value, ast.Name) and Node.value.id == 'rawptr') \
|
||||
or IsCPtrMarkerNode(Node.value, self.Trans.SymbolTable):
|
||||
from lib.core.LLVMCG.FuncGen import FailFastError
|
||||
raise FailFastError(
|
||||
f"指针下标判据分裂:注解 '{ast.unparse(Node)}' 的 base 是指针标记,"
|
||||
f"但 IsPtrSubscriptNode 未命中 —— 拒绝落到 CollectAll 静默产出"
|
||||
f"「基座 void 的多层指针」(结构体指针会被悄悄变成 i8**)")
|
||||
|
||||
def CollectAll(node: ast.AST, ParentIsArrayPtr: bool = False) -> CTypeInfo:
|
||||
"""鏀堕泦绫诲瀷淇℃伅锛岃繑鍥?CTypeInfo"""
|
||||
if isinstance(node, ast.Subscript):
|
||||
|
||||
Reference in new issue
Block a user