feat(codegen): 单目 & 支持对构造调用/函数调用结果取址

与 TransPyV 侧 ExprGenOps._addrof_of_call 同口径:复用 _HandleUnaryOpLlvm 已求值的 OperandVal;构造调用 _HandleClassNewLlvm 返回临时对象的 Ptr(Struct),原样返回;其它类型落到 allocaEntry 临时槽。避免二次求值导致 __before_init__/__init__ 跑两遍。
This commit is contained in:
TermiNexus committed 2026-09-27 15:16:08 +08:00
1 parent ae02431dd2
commit 5825e7e000
1 file changed
+18 -1
+18 -1
View File
@@ -288,9 +288,26 @@ class ExprOpsHandle(BaseHandle):
SubPtr: ir.Value | None = self.Trans.ExprAttrHandle.HandleSubscriptPtrLlvm(Node.operand)
if SubPtr and isinstance(SubPtr.type, ir.PointerType):
return SubPtr
elif isinstance(Node.operand, ast.Call):
# &<call>() → rvalue 取址。复用上面已求值的 OperandVal,绝不二次求值
# (构造调用会再跑一遍 __before_init__/__init__)。
# · 构造调用(_HandleClassNewLlvm)返回的就是临时对象的栈存储指针
# Ptr(Struct) —— 该指针即"栈构造结构体的地址"本身,原样返回;
# 不能再套 alloca+store(会得到 Ptr(Ptr(Struct)),赋值端还得
# load 一次回落,语义也从"对象地址"变"槽地址")。
# · 其它返回值(标量、按值返回的结构体值):入口临时槽承载——
# allocaEntry 同类型槽 → store → 返回槽地址(与 TransPyV 侧
# ExprGenOps._addrof_of_call 同口径)。
OperandType: ir.Type = OperandVal.type
if isinstance(OperandType, ir.PointerType) \
and isinstance(OperandType.pointee, (ir.IdentifiedStructType, ir.LiteralStructType)):
return OperandVal
TmpSlot: ir.Value = Gen._allocaEntry(OperandType, name="addrof_tmp")
Gen.builder.store(OperandVal, TmpSlot)
return TmpSlot
raise TypeError(
f"[fast-fail] 单目 '&' 取地址的操作数必须是左值"
f"(Name/Attribute/Subscript),实际为 {type(Node.operand).__name__}"
f"(Name/Attribute/Subscript)或构造调用/函数调用结果,实际为 {type(Node.operand).__name__}"
)
return None