fix(classdef,base,attr): 成员注解解析静默兜底改 fail-fast;新增按需输出的字段布局探针
HandlesBase.CollectAnnAssignMember: 注解解析返回 None / _ctype_to_llvm 得 void / 抛异常三处静默 i32、i8* 兜底改 fail-fast,报错带成员名+注解原文+BaseType/PtrCount 现场 HandlesClassDef: 方法内 self.x: T = ... 的同类三处兜底同样改 fail-fast(带类名/成员名/注解原文) HandlesExprAttr: 新增 _diag_member_layout(默认静默,仅当 offset 为 None / members[offset] 名不符 / 类型与 elements[offset] 不一致时打一行,上限 15 行)
This commit is contained in:
1 parent
c83fc752c6
commit
50cea6c7b3
3 files changed
+104
-16
No files matched your search
@@ -1001,21 +1001,21 @@ class BaseHandle:
|
||||
) -> tuple[str, _ir.Type, CTypeInfo | None] | None:
|
||||
"""从 ast.AnnAssign 节点解析成员信息。
|
||||
|
||||
返回 (VarName, MemberType, TypeInfo);TypeInfo 为 None 表示解析回退到 i32。
|
||||
返回 (VarName, MemberType, TypeInfo)。
|
||||
|
||||
**不再静默兜底**(原实现:注解解析返回 None → i32;_ctype_to_llvm 得 void → i8*;
|
||||
任何异常 → i32 + TypeInfo=None)。这些兜底会把"注解没解析出来"伪装成一个
|
||||
具体类型,下游于是报出与真因无关的错——实测:`free_lists: uint64*`(脱糖为
|
||||
`uint64 | t.CPtr`)在解析异常时被当成 **i32**,`self.free_lists = base`(i8*)
|
||||
便误报"指针隐式转整数已禁止"。类型信息缺失一律响亮失败。
|
||||
非 AnnAssign/Name 目标时返回 None。
|
||||
"""
|
||||
if not isinstance(item, ast.AnnAssign) or not isinstance(item.target, ast.Name):
|
||||
return None
|
||||
VarName: str = item.target.id
|
||||
AnnotationText: str = ast.unparse(item.annotation)
|
||||
try:
|
||||
TypeInfo: CTypeInfo | None = self.ResolveAnnotationType(item.annotation)
|
||||
if TypeInfo is None:
|
||||
TypeInfo = CTypeInfo()
|
||||
TypeInfo.BaseType = t.CInt()
|
||||
MemberType: _ir.Type = Gen._ctype_to_llvm(TypeInfo)
|
||||
if isinstance(MemberType, _ir.VoidType):
|
||||
MemberType = _ir.PointerType(_ir.IntType(8))
|
||||
return VarName, MemberType, TypeInfo
|
||||
except RecursionError:
|
||||
# RecursionError 不是"可忽略异常":它是类型解析/声明发射链**成环**的
|
||||
# 真缺陷信号。此前被下方 `except Exception` 吞成一行
|
||||
@@ -1026,8 +1026,25 @@ class BaseHandle:
|
||||
# 让环路根因暴露在错误栈顶,不再被 WARN 掩埋。
|
||||
raise
|
||||
except Exception as e:
|
||||
_vlog().warning(f"HandlesBase: 忽略异常 {e}", exc_info=e)
|
||||
return VarName, _ir.IntType(32), None
|
||||
raise ValueError(
|
||||
f"[FATAL] 成员 '{VarName}' 的注解 '{AnnotationText}' 解析失败:"
|
||||
f"{type(e).__name__}: {e} —— 拒绝静默退化为 i32"
|
||||
) from e
|
||||
if TypeInfo is None:
|
||||
raise ValueError(
|
||||
f"[FATAL] 成员 '{VarName}' 的注解 '{AnnotationText}' 解析不出类型"
|
||||
f"(ResolveAnnotationType 返回 None)—— 拒绝静默退化为 i32"
|
||||
)
|
||||
MemberType: _ir.Type = Gen._ctype_to_llvm(TypeInfo)
|
||||
if isinstance(MemberType, _ir.VoidType):
|
||||
raise ValueError(
|
||||
f"[FATAL] 成员 '{VarName}' 的注解 '{AnnotationText}' 解析为 void"
|
||||
f"(BaseType={getattr(TypeInfo, 'BaseType', None)} "
|
||||
f"PtrCount={getattr(TypeInfo, 'PtrCount', None)} "
|
||||
f"IsTypedef={getattr(TypeInfo, 'IsTypedef', None)} "
|
||||
f"Name={getattr(TypeInfo, 'Name', None)})—— 拒绝静默退化为 i8*"
|
||||
)
|
||||
return VarName, MemberType, TypeInfo
|
||||
|
||||
def LookupFunctionSymbol(self, name: str, *, module_path: str | None = None) -> CTypeInfo | None:
|
||||
"""查找函数符号,先尝试 module_path.name,再回退到 name。
|
||||
|
||||
@@ -1273,17 +1273,37 @@ class ClassHandle(BaseHandle):
|
||||
and node.target.value.id == 'self'):
|
||||
VarName: str = node.target.attr
|
||||
if VarName not in existing_members:
|
||||
# fail-fast(项目约定:类型信息缺失立即终止,不兜底)。
|
||||
# 此前三处静默 i32 兜底(FromNode 返回 None / _ctype_to_llvm 得 void /
|
||||
# 解析抛异常)会把"声明没解析出来"伪装成"该成员是 i32",下游赋值/取址
|
||||
# 检查于是报出与真因无关的错——实测:`free_lists: uint64*` 被当成 i32,
|
||||
# `self.free_lists = base`(i8*) 因此误报"指针隐式转整数已禁止"。
|
||||
AnnotationText: str = ast.unparse(node.annotation)
|
||||
try:
|
||||
TypeInfo: CTypeInfo | None = CTypeInfo.FromNode(node.annotation, self.Trans.SymbolTable)
|
||||
if TypeInfo is None:
|
||||
TypeInfo = CTypeInfo()
|
||||
TypeInfo.BaseType = t.CInt()
|
||||
raise ValueError(
|
||||
f"[FATAL] 类 '{ClassName}' 成员 '{VarName}' 的注解 "
|
||||
f"'{AnnotationText}' 解析不出类型(CTypeInfo.FromNode 返回 None)"
|
||||
f"—— 拒绝静默当作 i32"
|
||||
)
|
||||
MemberType: ir.Type = Gen._ctype_to_llvm(TypeInfo)
|
||||
if isinstance(MemberType, ir.VoidType):
|
||||
MemberType = ir.IntType(32)
|
||||
except Exception as e: # 回退:成员类型解析失败时使用默认 i32
|
||||
_vlog().warning(f"HandlesClassDef: 忽略异常 {e}", exc_info=e)
|
||||
MemberType = ir.IntType(32)
|
||||
raise ValueError(
|
||||
f"[FATAL] 类 '{ClassName}' 成员 '{VarName}' 的注解 "
|
||||
f"'{AnnotationText}' 解析为 void(BaseType="
|
||||
f"{getattr(TypeInfo, 'BaseType', None)} PtrCount="
|
||||
f"{getattr(TypeInfo, 'PtrCount', None)} IsTypedef="
|
||||
f"{getattr(TypeInfo, 'IsTypedef', None)} Name="
|
||||
f"{getattr(TypeInfo, 'Name', None)})—— 拒绝静默当作 i32"
|
||||
)
|
||||
except Exception as e: # 成员类型解析失败:带注解原文与类/成员名终止
|
||||
if isinstance(e, ValueError) and str(e).startswith('[FATAL]'):
|
||||
raise
|
||||
raise ValueError(
|
||||
f"[FATAL] 类 '{ClassName}' 成员 '{VarName}' 的注解 "
|
||||
f"'{AnnotationText}' 解析失败:{type(e).__name__}: {e}"
|
||||
) from e
|
||||
Gen.class_members[ClassName].append((VarName, MemberType))
|
||||
Gen.class_member_signeds[ClassName][VarName] = None
|
||||
Gen.class_member_bitfields[ClassName][VarName] = 0
|
||||
|
||||
@@ -866,6 +866,7 @@ class ExprAttrHandle(BaseHandle):
|
||||
if Node.attr in Gen.class_member_bitoffsets.get(ResolvedKey, {}):
|
||||
return self._load_bitfield_member(CastedObj, ResolvedKey, Node.attr)
|
||||
offset: int | None = Gen._get_member_offset(Node.attr, ResolvedKey)
|
||||
self._diag_member_layout(Gen, ResolvedKey, Node.attr, offset)
|
||||
if offset is None:
|
||||
return None
|
||||
if offset < len(st.elements) and isinstance(st.elements[offset], ir.VoidType):
|
||||
@@ -896,6 +897,7 @@ class ExprAttrHandle(BaseHandle):
|
||||
if Node.attr in bitfield_offsets:
|
||||
return self._load_bitfield_member(ObjVal, CN, Node.attr)
|
||||
offset = Gen._get_member_offset(Node.attr, CN)
|
||||
self._diag_member_layout(Gen, CN, Node.attr, offset)
|
||||
if offset is None:
|
||||
break
|
||||
# 泛型基础类型字段特化(根本修复):
|
||||
@@ -1625,6 +1627,55 @@ class ExprAttrHandle(BaseHandle):
|
||||
return Gen.builder.gep(obj_val, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"{target.attr}_ptr")
|
||||
return None
|
||||
|
||||
def _diag_member_layout(self, Gen: LlvmCodeGenerator, ClassName: str, FieldName: str,
|
||||
Offset: int | None) -> None:
|
||||
"""字段布局对照探针(**只在"索引/类型对不上"时打一行**,默认完全静默)。
|
||||
|
||||
判据(打印条件,任一成立才打):
|
||||
· offset 为 None(该字段没能解析出索引);或
|
||||
· members[offset] 的名字不是本次查询的字段名(= 名字→索引表与结构体布局错位,
|
||||
即"往 elements[offset] 上取类型/取值"会取到别的字段);或
|
||||
· members[offset] 的声明类型与 elements[offset] 不是同一类型(含指针/整数错配,
|
||||
如 `Constant.lineno` 取到 `MemManager*`)。
|
||||
只打关键三元组 + 两表长度;长度不等时再补一行字段名清单(短)。
|
||||
上限 15 行,按 (类, 字段) 去重,避免刷屏。
|
||||
"""
|
||||
try:
|
||||
Seen: set = getattr(self, '_MemberLayoutDumped', None)
|
||||
if Seen is None:
|
||||
Seen = set()
|
||||
self._MemberLayoutDumped = Seen
|
||||
self._MemberLayoutDumpCount = 0
|
||||
Key: tuple = (ClassName, FieldName)
|
||||
if Key in Seen:
|
||||
return
|
||||
Members: list = list(Gen.class_members.get(ClassName, []))
|
||||
ST: Any = Gen.structs.get(ClassName)
|
||||
if isinstance(ST, ir.IdentifiedStructType) and ST.elements is not None:
|
||||
Elems: list = list(ST.elements)
|
||||
else:
|
||||
Elems = []
|
||||
NameAt: str = ''
|
||||
TypeAt: Any = None
|
||||
if Offset is not None and 0 <= Offset < len(Members):
|
||||
NameAt, TypeAt = Members[Offset][0], Members[Offset][1]
|
||||
ElemAt: Any = Elems[Offset] if (Offset is not None and 0 <= Offset < len(Elems)) else None
|
||||
TypeSame: bool = (TypeAt is ElemAt) or (TypeAt is not None and str(TypeAt) == str(ElemAt))
|
||||
Suspicious: bool = (Offset is None) or (NameAt != FieldName) or (not TypeSame)
|
||||
if not Suspicious:
|
||||
return
|
||||
if getattr(self, '_MemberLayoutDumpCount', 0) >= 15:
|
||||
return
|
||||
Seen.add(Key)
|
||||
self._MemberLayoutDumpCount = getattr(self, '_MemberLayoutDumpCount', 0) + 1
|
||||
print(f'[DIAG] 字段布局错位 {ClassName}.{FieldName}: offset={Offset} '
|
||||
f'members[offset]名={NameAt!r} 声明类型={TypeAt} element类型={ElemAt} '
|
||||
f'| members={len(Members)} elements={len(Elems)}', flush=True)
|
||||
if len(Members) != len(Elems):
|
||||
print(f' members 名序=[{", ".join(n for n, _t in Members)}]', flush=True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _resolve_struct_class_for_attr(self, Node: ast.AST, Gen: LlvmCodeGenerator) -> str | None:
|
||||
if isinstance(Node, ast.Name):
|
||||
VarName: str = Node.id
|
||||
|
||||
Reference in new issue
Block a user