fix(type): const 等限定联合不再被误判为 str*/bytes*
_is_ptr_element_annotation 原先只要注解联合里出现 str/bytes 就返回 1(按 i8** 处理,
8 字节元素步长),于是 const str(t.CConst | str,实际仍是 i8*)的下标取到的是指针。
现在要求联合必须带 CPtr 标记(真正的 str*/bytes*)才判定;模块级全局的同一处逻辑
(TranslatorGenMixin)同步收紧。新增 _annotation_has_cptr_marker 供两处复用。
复现:def F(p: str) -> int: / path: const str = p / ch: char = path[i]
-> CastError 指针转整数(形参位置的 const str 一直正常,仅局部/全局错)
This commit is contained in:
1 parent
fb3d3787e6
commit
5993affd9c
2 files changed
+27
-4
No files matched your search
@@ -517,6 +517,24 @@ novirtual class AssignGenMixin:
|
||||
if self._annotation_contains_name(bop.right, name) != 0: return 1
|
||||
return 0
|
||||
|
||||
def _annotation_has_cptr_marker(self, annot: ast.AST*) -> int:
|
||||
"""Return 1 if the annotation union carries a CPtr marker (the star form `<base> | t.CPtr`)."""
|
||||
if annot is None: return 0
|
||||
k: int = annot.kind()
|
||||
if k == ast.ASTKind.Attribute:
|
||||
at: ast.Attribute* = ast.Attribute*(annot)
|
||||
if at.attr is not None and string.strcmp(at.attr, "CPtr") == 0: return 1
|
||||
return 0
|
||||
if k == ast.ASTKind.Name:
|
||||
nm: ast.Name* = ast.Name*(annot)
|
||||
if nm.id is not None and string.strcmp(nm.id, "CPtr") == 0: return 1
|
||||
return 0
|
||||
if k == ast.ASTKind.BinOp:
|
||||
bop: ast.BinOp* = ast.BinOp*(annot)
|
||||
if self._annotation_has_cptr_marker(bop.left) != 0: return 1
|
||||
if self._annotation_has_cptr_marker(bop.right) != 0: return 1
|
||||
return 0
|
||||
|
||||
# _is_ptr_element_annotation - check whether an annotation is bytes* or str*
|
||||
# bytes*/str* => 8-byte element stride (i8**); char*/int8* => 1-byte stride.
|
||||
def _is_ptr_element_annotation(self, annot: ast.AST*) -> int:
|
||||
@@ -526,8 +544,12 @@ novirtual class AssignGenMixin:
|
||||
if k != ast.ASTKind.BinOp: return 0
|
||||
bop: ast.BinOp* = ast.BinOp*(annot)
|
||||
if bop.op != ast.OpKind.BitOr: return 0
|
||||
if self._annotation_contains_name(annot, "str") != 0: return 1
|
||||
if self._annotation_contains_name(annot, "bytes") != 0: return 1
|
||||
# str/bytes are already i8*; only the union WITH a pointer marker (str*/bytes*) is i8** and
|
||||
# needs 8-byte element slots. A union that merely carries them (e.g. `const str`, which is
|
||||
# t.CConst | str and stays i8*) must keep the 1-byte stride.
|
||||
if self._annotation_has_cptr_marker(annot) != 0:
|
||||
if self._annotation_contains_name(annot, "str") != 0: return 1
|
||||
if self._annotation_contains_name(annot, "bytes") != 0: return 1
|
||||
# Generic type param / nested union | t.CPtr: scalars use their own size, pointers use 8-byte slots
|
||||
if self._is_generic_tp_or_nested(bop.left) != 0 or self._is_generic_tp_or_nested(bop.right) != 0:
|
||||
gp_nm: str = None
|
||||
|
||||
@@ -859,8 +859,9 @@ novirtual class TranslatorGenMixin:
|
||||
if aa_ml.annotation.kind() == ast.ASTKind.BinOp:
|
||||
bop_ml: ast.BinOp* = ast.BinOp*(aa_ml.annotation)
|
||||
if bop_ml.op == ast.OpKind.BitOr:
|
||||
if self.Gen.AssignGen._annotation_contains_name(aa_ml.annotation, "str") != 0 or self.Gen.AssignGen._annotation_contains_name(aa_ml.annotation, "bytes") != 0:
|
||||
self.Gen.VarGen.set_var_ptr_element(trans.SymTab, var_name)
|
||||
if self.Gen.AssignGen._annotation_has_cptr_marker(aa_ml.annotation) != 0:
|
||||
if self.Gen.AssignGen._annotation_contains_name(aa_ml.annotation, "str") != 0 or self.Gen.AssignGen._annotation_contains_name(aa_ml.annotation, "bytes") != 0:
|
||||
self.Gen.VarGen.set_var_ptr_element(trans.SymTab, var_name)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
Reference in new issue
Block a user