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:
1 parent
4c39db17c6
commit
6a672037c2
1 file changed
+54
-1
@@ -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
|
||||
|
||||
Reference in new issue
Block a user