From 201c881b43effdffceec33e93843d25f33c77016 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 16 Oct 2026 20:19:51 +0800 Subject: [PATCH] =?UTF-8?q?fix(assign):=20=E6=8B=A6=E6=88=AA=E6=B3=A8?= =?UTF-8?q?=E8=A7=A3=E4=B8=BA=E7=B1=BB=E5=80=BC=E7=B1=BB=E5=9E=8B=E4=BD=86?= =?UTF-8?q?=E5=8F=B3=E5=80=BC=E5=8F=96=E5=9C=B0=E5=9D=80=E7=9A=84=20typo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dirp: devfs_directory = &directories[d](注解漏写 *)此前会静默通过,把栈/表元素地址塞进值语义槽位,导致 vptr/父指针悬垂、对象被就地覆写。在 translate_annassign 中新增 fail-fast:注解解析为 struct(类值类型)而右值是取地址表达式(&x 或 c.Addr(x))时报 TypeError 并提示补 *。新增 _is_addr_of_expr 助手,只认取地址,不含 *p 解引用,避免误伤值拷贝。 --- App/lib/core/Gen/AssignGenMixin.vp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index 487ce50..33f0b9a 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -1527,6 +1527,28 @@ novirtual class AssignGenMixin: if string.strcmp(at.attr, "Ptr") == 0: return 1 return 0 + def _is_addr_of_expr(self, node: ast.AST*) -> int: + """Return 1 only for an explicit address-of expression (`&x` / `c.Addr(x)`). + + Distinct from _is_addrlike_call, which also counts deref/cast forms: assigning a *deref* + result (`*p`) to a value-typed variable is a legitimate value copy, so only `&x` indicates + a missing `*` in the annotation. + """ + if node is None: return 0 + if node.kind() == ast.ASTKind.UnaryOp: + uo_ao: ast.UnaryOp* = ast.UnaryOp*(node) + if uo_ao.op == ast.OpKind.AddrOf: return 1 + return 0 + if node.kind() != ast.ASTKind.Call: return 0 + cl_ao: ast.Call* = ast.Call*(node) + if cl_ao.func is None or cl_ao.func.kind() != ast.ASTKind.Attribute: return 0 + at_ao: ast.Attribute* = ast.Attribute*(cl_ao.func) + if at_ao.value is None or at_ao.value.kind() != ast.ASTKind.Name: return 0 + vn_ao: ast.Name* = ast.Name*(at_ao.value) + if vn_ao.id is None or string.strcmp(vn_ao.id, "c") != 0: return 0 + if at_ao.attr is not None and string.strcmp(at_ao.attr, "Addr") == 0: return 1 + return 0 + def _DerefPunBits(self, pool: memhub.MemBuddy*, ty: mlirlite.LLVMType*) -> int: """位型 pun(`*a = *b`)的标量位宽:浮点取浮点位宽、整数取整型位宽、指针按 64、其余返回 0。 @@ -2508,6 +2530,13 @@ novirtual class AssignGenMixin: if var_ty is not None and self.Gen.StmtGenDecl._is_void_type(var_ty) != 0: self.Gen.TypeGenErr.fatal_error(aa, f"cannot declare a variable of void type '{nm.id}' (void may only be used for void* and typedef aliases)", "TypeError") + # 注解漏 `*` 的 typo:注解解析成"类(值类型)",右值却是取地址表达式(`&x`)。 + # 这在类"引用表示"的宽容规则下会被静默接受,随后把栈/元素地址塞进值语义的槽位 + # (典型症状:vptr/父指针指向栈区、对象被就地覆写)。明确报错并提示补 `*`。 + if var_ty is not None and aa.value is not None and self._is_addr_of_expr(aa.value) == 1: + if var_ty.kind() == mlirlite.LLVMType.Struct: + self.Gen.TypeGenErr.fatal_error(aa, f"type annotation of '{nm.id}' is a class value type but the initializer is an address ('&...'): did you forget '*'? Write the pointer type ('T*') for a pointer target, or initialize with a value (e.g. 'T(...)')", "TypeError") + # t.Callable function pointer: register the return-type signature callable_ret: mlirlite.LLVMType* = self.Gen.TypeGenErr.try_extract_callable_ret(pool, annot, trans._imported_modules, trans._from_imports, trans) if callable_ret is not None: