diff --git a/lib/core/Handles/HandlesBase.py b/lib/core/Handles/HandlesBase.py index 8837868..5d48440 100644 --- a/lib/core/Handles/HandlesBase.py +++ b/lib/core/Handles/HandlesBase.py @@ -555,6 +555,55 @@ class BaseHandle: return f"Subscript({BaseHandle._ExprShape(Node.value, Depth + 1)})" return type(Node).__name__ + def _DescribeAttrBase(self, Gen: Any, Node: ast.Attribute) -> str: + """属性读返回 None 时的**基址事实**(供 fail-fast 报文取证,不改变任何判定)。 + + 两类根因:① 类名登记退化(var_struct_class 存 'rawptr' / 'rawptr[X]' / 折叠态, + 或压根没登记);② 登记名与 Gen.structs / class_members 的键不同源(短名 vs + sha1 全名)。另有一条**必须验伪**的可能:基座是强转调用 `(T*(x)).attr` + (parser 统一产成 Call(func=BinOp(BitOr)))时,HandlesExprAttr 的 + `_handle_attr_call_result` 自带 `_FailFastAttrCallBase` 详细 fail-fast + (FailFastError 全仓无 except,必上抛)——若仍走到本诊断,即说明那条 + fail-fast 未被走到,属**另一处缺口**,故显式标注该事实。 + """ + _base: ast.AST = Node.value + _parts: list[str] = [f"基座形态={BaseHandle._ExprShape(_base)}"] + if isinstance(_base, ast.Name): + _bn: str = _base.id + _vc: str | None = None + _alloc: Any = None + try: + _vc = (getattr(Gen, 'var_struct_class', None) or {}).get(_bn) + if not _vc: + _vc = (getattr(Gen, 'global_struct_class', None) or {}).get(_bn) + _alloc = (getattr(Gen, 'variables', None) or {}).get(_bn) + except Exception: # noqa: BLE001 + pass + _parts.append(f"'{_bn}' 的 var_struct_class={_vc!r}") + _parts.append(f"alloca 类型={getattr(_alloc, 'type', None)}") + _parts.append("该名在 Gen.structs=" + + ('是' if _vc and _vc in Gen.structs else ('否' if _vc else '—'))) + _parts.append("class_members=" + + (f"{len(Gen.class_members.get(_vc) or [])} 个字段" + if _vc and _vc in Gen.class_members else '无该键')) + if _vc and _vc in Gen.class_members: + _parts.append(f"字段名单={[m[0] for m in Gen.class_members[_vc]][:12]}") + elif (isinstance(_base, ast.Call) and isinstance(_base.func, ast.BinOp) + and isinstance(_base.func.op, ast.BitOr)): + _cls: str | None = None + try: + _cls = self.Trans.ExprAttrHandle._extract_union_base_class(_base.func) + except Exception: # noqa: BLE001 + _cls = None + _parts.append(f"联合基类名={_cls!r}") + _parts.append(f"短名 in structs={'是' if _cls and _cls in Gen.structs else '否'}") + _parts.append("class_members=" + + (f"{len(Gen.class_members.get(_cls) or [])} 个字段" + if _cls in Gen.class_members else '无该键')) + _parts.append("注: 强转基座形态本应走 _FailFastAttrCallBase 详细报文," + "此处仍是本条 ⇒ 那条 fail-fast 未触发") + return ";".join(_parts) + @staticmethod def _ExprText(Node: ast.AST) -> str: """把表达式节点渲染成源码文本(如 func.Blocks.Head、list[X*] * uint64(v)),供错误信息使用""" @@ -684,48 +733,10 @@ class BaseHandle: f"{(',注解 ' + ann_text) if ann_text else ''}。位置 {loc}" f"{(',源码: ' + code_line) if code_line else ''}") # 【基址诊断】属性读返回 None 时报出**基座真实形态 + 类名登记事实**,不再从 - # "求值为空"反推。两类根因:① 类名登记退化(var_struct_class 存 'rawptr' / - # 'rawptr[X]' / 折叠态,或压根没登记);② 登记名与 Gen.structs / class_members - # 的键不同源(短名 vs sha1 全名)。另有一条**必须验伪**的可能:基座是强转调用 - # `(T*(x)).attr`(parser 统一产成 Call(func=BinOp(BitOr)))时,HandlesExprAttr - # 的 `_handle_attr_call_result` 自带 `_FailFastAttrCallBase` 详细 fail-fast - # (FailFastError 全仓无 except,必上抛)——若这里仍是通用报文,即说明那条 - # fail-fast 未被走到,属**另一处缺口**,故显式标注该事实。 + # "求值为空"反推(同一份事实也供 _RequireArgValue 的实参求值失败路径使用, + # 见 HandlesExprCall._RequireArgValue)。 if isinstance(Node, ast.Attribute): - _base: ast.AST = Node.value - _parts: list[str] = [f"基座形态={BaseHandle._ExprShape(_base)}"] - if isinstance(_base, ast.Name): - _bn: str = _base.id - _vc: str | None = None - _alloc: Any = None - try: - _vc = (getattr(Gen, 'var_struct_class', None) or {}).get(_bn) - if not _vc: - _vc = (getattr(Gen, 'global_struct_class', None) or {}).get(_bn) - _alloc = (getattr(Gen, 'variables', None) or {}).get(_bn) - except Exception: # noqa: BLE001 - pass - _parts.append(f"'{_bn}' 的 var_struct_class={_vc!r}") - _parts.append(f"alloca 类型={getattr(_alloc, 'type', None)}") - _parts.append(f"该名在 Gen.structs={'是' if _vc and _vc in Gen.structs else ('否' if _vc else '—')}") - _parts.append("class_members=" - + (f"{len(Gen.class_members.get(_vc) or [])} 个字段" - if _vc and _vc in Gen.class_members else '无该键')) - elif (isinstance(_base, ast.Call) and isinstance(_base.func, ast.BinOp) - and isinstance(_base.func.op, ast.BitOr)): - _cls: str | None = None - try: - _cls = self.Trans.ExprAttrHandle._extract_union_base_class(_base.func) - except Exception: # noqa: BLE001 - _cls = None - _parts.append(f"联合基类名={_cls!r}") - _parts.append(f"短名 in structs={'是' if _cls and _cls in Gen.structs else '否'}") - _parts.append("class_members=" - + (f"{len(Gen.class_members.get(_cls) or [])} 个字段" - if _cls in Gen.class_members else '无该键')) - _parts.append("注: 强转基座形态本应走 _FailFastAttrCallBase 详细报文," - "此处仍是通用报文 ⇒ 那条 fail-fast 未触发") - msg += "\n│ 基址诊断: " + ";".join(_parts) + msg += "\n│ 基址诊断: " + self._DescribeAttrBase(Gen, Node) _vlog().compile_error(msg, src_file, lineno, code_line) sys.exit(1) diff --git a/lib/core/Handles/HandlesExprCall.py b/lib/core/Handles/HandlesExprCall.py index 46f22f7..1652101 100644 --- a/lib/core/Handles/HandlesExprCall.py +++ b/lib/core/Handles/HandlesExprCall.py @@ -443,6 +443,15 @@ class ExprCallHandle(BaseHandle): loc: str = f"{src_file}:{lineno}" if col >= 0: loc += f":{col}" + # 实参是属性读时补同一份基址事实(与 HandlesBase._RaiseUnresolvedExpr 共用 + # `_DescribeAttrBase`):属性读取值失败的两类根因(类名登记退化 / 键不同源) + # 必须一眼可见,不再从"求值失败"反推。 + _base_facts: str = '' + if isinstance(ArgNode, ast.Attribute): + try: + _base_facts = self._DescribeAttrBase(Gen, ArgNode) + except Exception: # noqa: BLE001 + _base_facts = '' raise Exception( f"[TransPyC] 调用实参编译期求值为空: 被调者 '{Callee}' 的第 {ArgIndex} 个实参 " f"'{expr_text}'({ArgKind} 形态)求值失败;已终止编译,不丢弃该实参" @@ -450,6 +459,7 @@ class ExprCallHandle(BaseHandle): f"常见根因:枚举成员/名称未登记、跨模块符号查找失败、类定义在声明期结构体不完整。" f"位置 {loc}" f"{(',源码: ' + code_line) if code_line else ''}" + f"{chr(10) + '│ 基址诊断: ' + _base_facts if _base_facts else ''}" ) def _HandleCallLlvm(self, Node: ast.Call) -> ir.Value: