fix(gen): 值语义聚合槽允许隐式值拷贝,修 self.field = param 的 Foo* -> Foo 误报

This commit is contained in:
TermiNexus committed 2026-10-12 16:42:52 +08:00
1 parent 3384941cd1
commit 7c11c589f7
1 file changed
+26 -3
+26 -3
View File
@@ -455,7 +455,7 @@ novirtual class ExprGenBase:
if callee is None: return None
ent: GenTypes.StructEntry* = self.Gen.StructGen.find_struct(callee)
if ent is not None and ent.Ty is not None: return ent.Ty
# REnum variant ctor `EnumType.Variant(...)`: the callee is not a struct
# REnum variant ctor `EnumType.Variant(...)`: the callee is not a struct
# name, but materializes the base enum, so return that aggregate type.
if cl.func.kind() == ast.ASTKind.Attribute:
# Take the segment left of the variant name as the enum class name
@@ -474,6 +474,24 @@ novirtual class ExprGenBase:
"""Are a and b the same aggregate type; 1=yes / 0=no."""
if a is None or b is None: return 0
return self.Gen.AssignGen._stg_ty_equal(pool, a, b)
# _agg_value_slot_ty - 值语义槽:源表达式的变量槽**自身**持有聚合物(`x: Foo`,Spec.PtrLevel == 0)。
# 形参按「聚合一律按指针传」的 ABI 到达,但它在被调者里同样物化在自己的槽中,读槽即值拷贝;
# 真·指针值(`p: Foo*`,Spec.PtrLevel >= 1)返回 None,仍必须显式解引用(c.deref(p) / *p)。
# 返回该聚合类型;不适用时 None。
def _agg_value_slot_ty(self, node: ast.AST*, val: mlirlite.Value*, trans: HT.Translator*) -> mlirlite.LLVMType*:
"""Aggregate type when the source is a variable slot holding the aggregate by value; else None."""
n: ast.AST* = self._value_node_of(node)
if n is None or n.kind() != ast.ASTKind.Name: return None
nm: str = (ast.Name*(n)).id
if nm is None or trans is None: return None
ve: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm)
if ve is None or ve.Alloca is None or ve.Spec is None: return None
# 必须是槽本身(若已被加载成指针值,说明源本来就是个指针,不豁免)。
if ve.Alloca is not val: return None
# 声明的就是 T*(PtrLevel>=1):真指针,必须显式解引用。
if ve.Spec.PtrLevel != 0: return None
if self.is_ptr_type(ve.Alloca.Ty) == 0: return None
return ve.Alloca.Ty.Pointee
# Type coercion: int sext/trunc, float fpext/fptrunc, int<->float si2fp/fp2si.
def coerce_to_type(self, builder: mlirlite.IRBuilder*, val: mlirlite.Value*, target_ty: mlirlite.LLVMType*, node: ast.AST* = None, trans: HT.Translator* = None) -> mlirlite.Value*:
"""Coerce val to target_ty: int sext/trunc, float fpext/fptrunc, int/float conversions."""
@@ -564,7 +582,7 @@ novirtual class ExprGenBase:
if val_bits != 0 and target_fbits != 0: return mlirlite.build_si2fp(builder, val, target_ty)
# float -> int
if val_fbits != 0 and target_bits != 0: return mlirlite.build_fp2si(builder, val, target_ty)
# Aggregate value -> pointer: spill a temp to the entry block and pass its
# Aggregate value -> pointer: spill a temp to the entry block and pass its
# address (TPV never passes aggregates by value).
if self.is_ptr_type(val.Ty) == 0 and self.is_ptr_type(target_ty) != 0:
vk_agg: int = val.Ty.kind()
@@ -596,6 +614,11 @@ novirtual class ExprGenBase:
# Rule 3: implicit ptr -> value for non-basic types (Foo* -> Foo) is
# forbidden, except "construction materialization" (see _ctor_call_agg_ty).
ctor_p2v: mlirlite.LLVMType* = self._ctor_call_agg_ty(node)
# 值语义槽豁免:源是变量槽自身持有聚合物(`x: Foo`;形参虽按「聚合按指针传」的
# ABI 到达,也物化在自己的槽中)时,读槽 = 值拷贝(`self.f = elem` 这类写法)。
slot_p2v: mlirlite.LLVMType* = self._agg_value_slot_ty(node, val, trans)
if self._same_agg_ty(builder.Pool, slot_p2v, target_ty) != 0:
return mlirlite.build_load(builder, target_ty, val)
if self._same_agg_ty(builder.Pool, ctor_p2v, target_ty) == 0:
m_p2v: str = "implicit value/pointer conversion for non-basic types is forbidden (except construction materialization): a pointer type cannot be implicitly converted to a non-basic value (Foo* -> Foo); to dereference use c.deref(p) / *p explicitly, or cast explicitly"
p2v_txt: str = GenApi.escape_fstring_copy(f"; source type {self._type_text(builder.Pool, val.Ty)} -> target value type {self._type_text(builder.Pool, target_ty)}")
@@ -620,7 +643,7 @@ novirtual class ExprGenBase:
if val is None or val.Ty is None: return 0
return self.Gen.ExprGenOps.should_zext_widen(pool, val, None, node, trans)
# translate_ptr_arith: ptr +/- int via getelementptr (index scaled by pointee
# translate_ptr_arith: ptr +/- int via getelementptr (index scaled by pointee
# size); array pointees ([N x ty]*) decay to element pointers first.
def translate_ptr_arith(self, pool: memhub.MemBuddy*, builder: mlirlite.IRBuilder*, ptr_val: mlirlite.Value*, int_val: mlirlite.Value*, op: int) -> mlirlite.Value*:
"""Pointer arithmetic: ptr +/- int via GEP with the index scaled by element size."""