fix(attr): 修复联合类型转换 (X | t.CPtr)(arg) 后属性访问被丢弃

TPC 联合转换对非 CType 类(ast.Name/ast.Call 等类名)目标类型解析失败,
结果退回 Ptr(i8) 或错误类型,_handle_attr_call_result 的
find_struct_by_pointee 失败后返回 None,属性访问被静默丢弃——
((ast.Name|t.CPtr)(ov)).id 编译产物 store 0 次(TPV with 语句 asname
未绑定、pool 未定义根因)。修复:从联合 BinOp 提取真实基础类并
bitcast 到 Ptr(类) 再定位成员偏移;新增 _extract_union_base_class
辅助(跳过 CPtr/存储类/限定符修饰符)。
This commit is contained in:
TermiNexus committed 2026-08-13 07:44:43 +08:00
1 parent 4c39db17c6
commit 6a672037c2
1 file changed
+54 -1
+54 -1
View File
@@ -761,7 +761,25 @@ class ExprAttrHandle(BaseHandle):
ObjVal = inner_val
if ObjVal is None:
ObjVal = self.HandleExprLlvm(Node.value)
if not ObjVal or not isinstance(ObjVal.type, ir.PointerType):
if not ObjVal:
return None
# 联合类型转换 (X | t.CPtr)(arg) 的属性访问(治本修复):
# TPC 联合转换对非 CType 类(如 ast.Name / ast.Call)目标类型解析失败,
# 结果可能退回 Ptr(i8) 或错误类型,导致下方 find_struct_by_pointee 失败、
# 属性访问被静默丢弃——((ast.Name|t.CPtr)(ov)).id 编译后 store 0 次
# (with 语句 asname 未绑定、pool 未定义根因)。从联合 BinOp 提取真实
# 基础类并 bitcast 到 Ptr(类) 再访问成员。
if isinstance(Node.value, ast.Call) and isinstance(Node.value.func, ast.BinOp) \
and isinstance(Node.value.func.op, ast.BitOr):
union_cls: str | None = self._extract_union_base_class(Node.value.func)
if union_cls and union_cls in Gen.structs:
target_ty: Any = ir.PointerType(Gen.structs[union_cls])
if isinstance(ObjVal.type, ir.PointerType):
if ObjVal.type != target_ty:
ObjVal = Gen.builder.bitcast(ObjVal, target_ty, name="cast_union_attr")
elif isinstance(ObjVal.type, ir.IntType):
ObjVal = Gen.builder.inttoptr(ObjVal, target_ty, name="int2ptr_union_attr")
if not isinstance(ObjVal.type, ir.PointerType):
return None
pointee: Any = ObjVal.type.pointee
if isinstance(pointee, ir.PointerType):
@@ -789,6 +807,41 @@ class ExprAttrHandle(BaseHandle):
return None
return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st)
def _extract_union_base_class(self, NodeFunc: ast.BinOp) -> str | None:
"""从 (X | t.CPtr) 联合 BinOp 提取第一个非指针/非修饰符的类名
X 可以是任意类(如 ast.Name / ast.Call / memhub.MemPool),不限于
t.CType 子类——联合转换 (X | t.CPtr)(arg) 的属性访问需要真实类名
才能 bitcast 到 Ptr(类) 并定位成员偏移。
"""
if not isinstance(NodeFunc, ast.BinOp) or not isinstance(NodeFunc.op, ast.BitOr):
return None
skip_names = {
'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline',
'CStatic', 'CExtern', 'CExport', 'CAuto', 'CRegister',
'CDefine', 'CPass', 'CTypeDefault', 'State',
'BigEndian', 'LittleEndian',
}
operands: list = []
def _collect(node: ast.AST) -> None:
if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr):
_collect(node.left)
_collect(node.right)
else:
operands.append(node)
_collect(NodeFunc)
for op in operands:
name: str | None = None
if isinstance(op, ast.Attribute):
name = op.attr
elif isinstance(op, ast.Name):
name = op.id
if name and name not in skip_names:
return name
return None
def _handle_attr_subscript_result(self, Node: ast.Attribute) -> ir.Value | None:
"""处理 arr[i].attr 属性访问"""
Gen: LlvmCodeGenerator = self.Trans.LlvmGen