fix(Handles/PythonParser/DeclarationGenerator): 补齐 3 处"调用了不存在成员"的死路径 + 1 处被 hasattr 掩盖的静默降级
类别:a(编译器缺陷)
现场:翻译 TransPyV/App/lib/core/Gen/Call/CallGenLeafKit.vp 时终止编译
RuntimeError: 翻译 ... 失败: 'ClassHandle' object has no attribute '_PreRegisterClassMembers'
(FuncGen.py:965 有调用,方法全仓无定义)
按要求做了全仓静态扫描(ast:属性访问 vs 全仓属性定义;symtable:未定义全局名),共修 4 处:
1) HandlesClassDef.ClassHandle._PreRegisterClassMembers(缺失 → 实现)
调用点:FuncGen._get_member_offset 的"struct body 已存在、class_members[类名] 为空"分支
—— 该类的成员表在本次翻译里从未被收集,而按名定位字段槽位必须有表。
实现与既有两处成员收集段同源(CollectAnnAssignMember → 追加 (名, 类型)),但**只做收集**:
· 不展平继承前缀(调用方随后经 _member_base → EnsureClassMembersFlattened 补齐);
· 不调用 _generate_structs(body 已存在,重入 set_body 会把残缺布局永久固化);
· 只追加尚无同名的条目(幂等,重复命中不会把表撑长)。
跳过 __provides__/__requires__/__require_must__(非布局槽位),并登记字段限定符。
2) HandlesExprAttr.ExprAttrHandle._load_bitfield_member(缺失 → 实现)
读路径 7 处调用(位域分支)全部指向不存在的方法 ⇒ 任何位域字段读取都会 AttributeError。
实现与 HandlesAssign._store_bitfield_member 严格对称:位域类 body 只有一个 storage 槽
(elements[0]),字段位置由 class_member_bitoffsets/bitfields/signeds 表达,
读取 = `(storage >> 位偏移) & ((1<<位宽)-1)`,有符号字段再做符号扩展;
缺位偏移 / 位宽 ≤ 0 / struct 未具化 / storage 非整数一律 fail-fast(不返回 i32 兜底)。
3) PythonParserMixin 的 __set_default__ 分支(幽灵调用 → 明确报未支持)
原调用 self._handle_set_default_in_parse(...) 全仓无定义。核实:该注解在 TransPyC/lib 内
无任何消费端(只有 t.py 的定义与 StubGen/Converter 的"剥离该调用保留类型"),
includes 全仓亦无源使用 ⇒ 不静默丢弃源码语义,改为 NotImplementedError 明确报"未支持"。
4) DeclarationGenerator._llvm_type_size_str 的数组分支(静默降级 → 修好)
原写作 `self._ARR_TYPE_RE`(少一个 A)并以 hasattr 守卫 —— 该属性全仓从未定义 ⇒ 守卫恒假
⇒ 数组字段一律落到"未知类型 → 8",与 docstring 声明的"_EmitREnumLlvm 尺寸口径对齐"不符。
改用本类已定义的 _ARRAY_TYPE_RE,并去掉守卫(属性再丢失应当响亮失败)。
核验:compileall 全 lib 通过;属性扫描剩余 26 条全为仓外对象(logging / vast AST /
llvmlite Value·Instruction·IRBuilder / 内置 Exception.args / __class__ / __dict__);
symtable 未定义全局名仅 __file__(运行时内置)。未新增/放宽任何 fail-fast。
This commit is contained in:
1 parent
52ea21f082
commit
c2f53852ee
4 files changed
+134
-2
No files matched your search
@@ -1969,6 +1969,61 @@ class ClassHandle(BaseHandle):
|
||||
Gen.builder = saved_builder
|
||||
Gen.func = saved_func
|
||||
|
||||
def _PreRegisterClassMembers(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin) -> None:
|
||||
"""兜底:把一个类的**自有字段**从 ClassDef 体收集进 `Gen.class_members[类名]`。
|
||||
|
||||
调用点:[FuncGen._get_member_offset] 的"struct body 已存在、而
|
||||
`class_members[类名]` 为空"分支——该类的成员表在本次翻译里从未被收集
|
||||
(时序/跨模块窗口),而按名定位字段槽位必须有表。
|
||||
此前本方法**全仓无定义**(调用点却存在)⇒ 一旦进入即
|
||||
`AttributeError: 'ClassHandle' object has no attribute '_PreRegisterClassMembers'`
|
||||
(现场:翻译 TransPyV/App/lib/core/Gen/Call/CallGenLeafKit.vp 终止编译)。
|
||||
|
||||
判据与实现刻意与既有两处成员收集段同源:
|
||||
- `_EmitClassLlvm` 的自有字段段(`CollectAnnAssignMember` → 追加 `(名, 类型)`);
|
||||
- `HandlesImports._EmitExternalClassDeclLlvm` 的同名段。
|
||||
但**只做收集**:
|
||||
- 不展平继承前缀——调用方随后经 `_member_base` →
|
||||
`EnsureClassMembersFlattened` 按父类补齐(表空且有父类时会被前置);
|
||||
- 不调用 `_generate_structs()`:body 已存在,重入 `set_body` 会把残缺布局
|
||||
永久固化(llvmlite 的 `set_body` 只能设一次,见
|
||||
HandlesImports._EmitExternalClassDeclLlvm 的 `_collecting_members_set` 说明);
|
||||
- 只追加**尚无同名**的条目(幂等:重复命中不会把表撑长,也就不会让
|
||||
`base + 表内下标` 整体后移)。
|
||||
"""
|
||||
if Node is None or Gen is None:
|
||||
return
|
||||
ClassName: str = getattr(Node, 'name', None)
|
||||
if not ClassName:
|
||||
return
|
||||
if ClassName not in Gen.class_members:
|
||||
Gen.class_members[ClassName] = []
|
||||
_Existing: set[str] = {n for n, _ in Gen.class_members[ClassName]}
|
||||
Gen._collecting_members_set.add(ClassName)
|
||||
try:
|
||||
for item in Node.body:
|
||||
# 编译期元数据字段(__provides__/__requires__/__require_must__)不是布局槽位
|
||||
if isinstance(item, ast.AnnAssign) and isinstance(item.target, ast.Name):
|
||||
if item.target.id in ('__provides__', '__requires__', '__require_must__'):
|
||||
continue
|
||||
parsed = self.CollectAnnAssignMember(item, Gen)
|
||||
if not parsed:
|
||||
continue
|
||||
VarName, MemberType, TypeInfo = parsed
|
||||
if VarName in _Existing:
|
||||
continue
|
||||
Gen.class_members[ClassName].append((VarName, MemberType))
|
||||
_Existing.add(VarName)
|
||||
Gen.RegisterFieldQualifiers(ClassName, VarName, TypeInfo, item.annotation)
|
||||
_Signeds: dict = getattr(Gen, 'class_member_signeds', {}).get(ClassName)
|
||||
if isinstance(_Signeds, dict):
|
||||
_Signeds[VarName] = None
|
||||
_BitFields: dict = getattr(Gen, 'class_member_bitfields', {}).get(ClassName)
|
||||
if isinstance(_BitFields, dict):
|
||||
_BitFields[VarName] = 0
|
||||
finally:
|
||||
Gen._collecting_members_set.discard(ClassName)
|
||||
|
||||
def _BuildScalarConstant(self, node: ast.AST, llvm_type: ir.Type, Gen: LlvmGeneratorMixin | None = None) -> ir.Constant | None:
|
||||
"""构建标量常量,委托给统一的 _BuildScalarConstantUnified 方法。"""
|
||||
if Gen is None:
|
||||
|
||||
Reference in new issue
Block a user