fix(assign): 拦截注解为类值类型但右值取地址的 typo
dirp: devfs_directory = &directories[d](注解漏写 *)此前会静默通过,把栈/表元素地址塞进值语义槽位,导致 vptr/父指针悬垂、对象被就地覆写。在 translate_annassign 中新增 fail-fast:注解解析为 struct(类值类型)而右值是取地址表达式(&x 或 c.Addr(x))时报 TypeError 并提示补 *。新增 _is_addr_of_expr 助手,只认取地址,不含 *p 解引用,避免误伤值拷贝。
This commit is contained in:
1 parent
19feb40e8c
commit
201c881b43
1 file changed
+29
@@ -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:
|
||||
|
||||
Reference in new issue
Block a user