fix(gen): 补全新语法 &/* 的取地址与解引用路径

(*p).attr 属性基址:_get_cderef_attr_base 增加 UnaryOp(Deref) 分支(读写都要求 GEP 指针本身,而非加载后的结构体值)。_is_addrlike_call 增加 AddrOf/Deref 分支:指针型右值不应走模块全局的『静态存储对象拷贝』分支。
This commit is contained in:
TermiNexus committed 2026-10-05 19:58:45 +08:00
1 parent df2de5ecfa
commit 374921623b
2 files changed
+24 -4

No files matched your search

+11 -2
View File
@@ -562,8 +562,17 @@ novirtual class AssignGenMixin:
return 1 if string.strcmp(buf_a, buf_b) == 0 else 0
def _is_addrlike_call(self, node: ast.AST*) -> int:
"""Return 1 if the rhs is an explicit c.Addr/c.Deref-style pointer call."""
if node is None or node.kind() != ast.ASTKind.Call: return 0
"""Return 1 if the rhs is an explicit pointer expression (c.Addr/c.Deref/c.Cast/c.Ptr call, or new-syntax `&x` / `*p`)."""
if node is None: return 0
# New syntax (R3/R4): `&x` and `*p` parse as UnaryOp(AddrOf) / UnaryOp(Deref) and replace the
# c.Addr / c.Deref call forms. A pointer-valued RHS must not take the module-global
# "object with static storage -> copy the object" branch, so both forms count as addrlike.
if node.kind() == ast.ASTKind.UnaryOp:
uo_al: ast.UnaryOp* = ast.UnaryOp*(node)
if uo_al.op == ast.OpKind.AddrOf: return 1
if uo_al.op == ast.OpKind.Deref: return 1
return 0
if node.kind() != ast.ASTKind.Call: return 0
cl: ast.Call* = ast.Call*(node)
if cl.func is None or cl.func.kind() != ast.ASTKind.Attribute: return 0
at: ast.Attribute* = ast.Attribute*(cl.func)
+13 -2
View File
@@ -236,8 +236,19 @@ novirtual class ExprGenAttr(ExprGenBase.ExprGenBase):
# _get_cderef_attr_base - base pointer of a c.Deref(ptr).attr access (like *p.a → p->a): return the ptr
# itself, not the loaded struct value; None for non-c.Deref forms (_deref_if_ptr_ptr resolves the level).
def _get_cderef_attr_base(self, builder: mlirlite.IRBuilder*, pool: memhub.MemBuddy*, mod: mlirlite.LLVMModule*, at_value: ast.AST*, trans: HT.Translator* = None) -> mlirlite.Value*:
"""Return the ptr itself if at.value is a c.Deref(ptr) call, else None (no load)."""
if at_value is None or at_value.kind() != ast.ASTKind.Call: return None
"""Return the ptr itself for a dereferenced attribute base (`c.Deref(ptr).attr` / `(*ptr).attr`), else None (no load)."""
if at_value is None: return None
# New syntax form: `(*ptr).attr` is AST UnaryOp(OpKind.Deref) — identical semantics to the legacy
# `c.Deref(ptr).attr`. Without this branch the attribute write path sees a *loaded struct value*
# as the base and fails with "base=非指针类型,无法做属性写入"; the read path silently does an
# extra struct load. Both must GEP the pointer itself (R4 migration of `c.Deref` -> `*`).
if at_value.kind() == ast.ASTKind.UnaryOp:
uo_cd: ast.UnaryOp* = ast.UnaryOp*(at_value)
if uo_cd.op != ast.OpKind.Deref or uo_cd.operand is None: return None
inner_uo: mlirlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, uo_cd.operand, None, 0, trans)
if inner_uo is not None and self.is_ptr_type(inner_uo.Ty) != 0: return inner_uo
return None
if at_value.kind() != ast.ASTKind.Call: return None
cl_cd: ast.Call* = ast.Call*(at_value)
if cl_cd.func is None or cl_cd.func.kind() != ast.ASTKind.Attribute: return None
f_cd: ast.Attribute* = ast.Attribute*(cl_cd.func)