diff --git a/lib/core/Handles/HandlesBase.py b/lib/core/Handles/HandlesBase.py index ce64180..191a46c 100644 --- a/lib/core/Handles/HandlesBase.py +++ b/lib/core/Handles/HandlesBase.py @@ -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。 diff --git a/lib/core/Handles/HandlesClassDef.py b/lib/core/Handles/HandlesClassDef.py index de9a044..5f409bf 100644 --- a/lib/core/Handles/HandlesClassDef.py +++ b/lib/core/Handles/HandlesClassDef.py @@ -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 diff --git a/lib/core/Handles/HandlesExprAttr.py b/lib/core/Handles/HandlesExprAttr.py index 7ba840b..8726e5d 100644 --- a/lib/core/Handles/HandlesExprAttr.py +++ b/lib/core/Handles/HandlesExprAttr.py @@ -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