fix(类型): str/bytes 聚合指针检查豁免字符数组衰减,并统一判据真源
误报现场:includes/os/_win32.vp:207 `name: str = find_data.cFileName`。WIN32_FIND_DATAA.cFileName 是 [260 x i8],字段访问得到 Ptr(Array(i8,260)),其指针在 C 语义下天然衰减为 char*/str,属合法赋值,原判据把 Ptr(Array) 一律当真而误杀。 新增 ExprGenBase._str_rejects_ptr_kind(单一真源:1=结构体/类/联合指针、2=非字符数组指针、3=函数指针、0=可接受;[N x i8] 豁免)供 fail_if_str_annot_agg_ptr 与 CallGenLib 跨模块实参检查共用,消除两处重复的 kind 判定,避免同规则两处演化。
This commit is contained in:
1 parent
bf2f38acd2
commit
c035a82394
2 files changed
+41
-27
No files matched your search
@@ -269,21 +269,13 @@ novirtual class CallGenLib(CallGenBase.CallGenBase):
|
||||
# ⇒ 后续把该指针当 C 字符串用时生成非法 IR(现场:把 Function* 传给
|
||||
# `callee: str`,发射出 `call i32 @(i32 7)` 空符号名,直到 llc 才炸)。
|
||||
# 判据:定义侧形参注解**恰为**裸 str/bytes(组合段如 `str|t.CPtr` 不
|
||||
# 等值、不受影响),且实参是指向聚合类型(Struct/Array/Func)的指针。
|
||||
if self.Gen.ExprGenBase.is_ptr_type(cur.Ty) != 0:
|
||||
pointee_a: llvmlite.LLVMType* = cur.Ty.Pointee
|
||||
if pointee_a is not None:
|
||||
pk_a: int = pointee_a.kind()
|
||||
if pk_a == llvmlite.LLVMType.Struct \
|
||||
or pk_a == llvmlite.LLVMType.Array \
|
||||
or pk_a == llvmlite.LLVMType.Func:
|
||||
if VpiReader._vpi_param_annot_seg_is(sha1_buf, cls_nm, meth_nm, idx, "str") != 0 \
|
||||
or VpiReader._vpi_param_annot_seg_is(sha1_buf, cls_nm, meth_nm, idx, "bytes") != 0:
|
||||
self.Gen.TypeGenErr.fatal_error(arg_node,
|
||||
"str/bytes 形参不接受指向非基本类型(结构体/类/数组/函数)的指针:"
|
||||
"两者在 IR 层同为 i8*,但语义不同(str/bytes 不是通用指针通配)。"
|
||||
"若确需传递指针,请改用 t.CPtr/rawptr 形参或显式转换(如 t.CPtr(p))",
|
||||
"CastError")
|
||||
# 等值、不受影响),且实参是指向聚合类型的指针。判据与报错统一委托
|
||||
# ExprGenBase._str_rejects_ptr_kind / fail_if_str_annot_agg_ptr(单一
|
||||
# 真源,字符数组 [N x i8] 衰减与其在同模块路径同口径豁免)。
|
||||
if self.Gen.ExprGenBase._str_rejects_ptr_kind(cur) != 0:
|
||||
if VpiReader._vpi_param_annot_seg_is(sha1_buf, cls_nm, meth_nm, idx, "str") != 0 \
|
||||
or VpiReader._vpi_param_annot_seg_is(sha1_buf, cls_nm, meth_nm, idx, "bytes") != 0:
|
||||
self.Gen.ExprGenBase.fail_if_str_annot_agg_ptr(cur, 1, arg_node)
|
||||
node_v = self._coerce_arg_value_to_ty(pool, builder, cur, tgt_ty, arg_node, trans, tpl_src)
|
||||
if new_head is None:
|
||||
new_head = node_v
|
||||
|
||||
@@ -455,16 +455,16 @@ novirtual class ExprGenBase:
|
||||
if nm is None or nm.id is None:
|
||||
return 0
|
||||
return self._annot_name_is_bare_str(nm.id)
|
||||
def fail_if_str_annot_agg_ptr(self, val: llvmlite.Value*,
|
||||
annot_is_str: int,
|
||||
node: ast.AST* = None) -> int:
|
||||
"""注解侧是裸 str/bytes 而值是指向聚合类型的指针 → fail-fast(返回 1)
|
||||
def _str_rejects_ptr_kind(self, val: llvmlite.Value*) -> int:
|
||||
"""val 是否为「str/bytes 不应接受」的聚合指针(1/2/3=是,0=否)
|
||||
|
||||
判据:val 是一级指针且被指类型是聚合(Struct/Array/Func)——即"结构体/
|
||||
类/联合/数组/函数指针"。显式转换(如 t.CPtr(p))的产物 pointee 是 i8,
|
||||
不触发本检查,故显式转换不受影响。
|
||||
1 = 结构体/类/联合指针;2 = 非字符数组指针;3 = 函数指针。
|
||||
**字符数组([N x i8])豁免**:它自身就是字符串本体,其指针在 C 语义下
|
||||
天然衰减为 char*/str(现场:includes/os/_win32.vp:207
|
||||
`name: str = find_data.cFileName`,WIN32_FIND_DATAA.cFileName 是 [260 x i8])。
|
||||
多级指针/基本类型指针一律 0(不在本规则范围内)。
|
||||
"""
|
||||
if annot_is_str == 0 or val is None or val.Ty is None:
|
||||
if val is None or val.Ty is None:
|
||||
return 0
|
||||
if self.is_ptr_type(val.Ty) == 0:
|
||||
return 0
|
||||
@@ -472,12 +472,34 @@ novirtual class ExprGenBase:
|
||||
if pointee is None:
|
||||
return 0
|
||||
pk: int = pointee.kind()
|
||||
if pk != llvmlite.LLVMType.Struct \
|
||||
and pk != llvmlite.LLVMType.Array \
|
||||
and pk != llvmlite.LLVMType.Func:
|
||||
if pk == llvmlite.LLVMType.Struct:
|
||||
return 1
|
||||
if pk == llvmlite.LLVMType.Func:
|
||||
return 3
|
||||
if pk == llvmlite.LLVMType.Array:
|
||||
match pointee:
|
||||
case llvmlite.LLVMType.Array(elem, _):
|
||||
if self.get_llvm_type_bits(elem) == 8:
|
||||
return 0
|
||||
case _:
|
||||
pass
|
||||
return 2
|
||||
return 0
|
||||
def fail_if_str_annot_agg_ptr(self, val: llvmlite.Value*,
|
||||
annot_is_str: int,
|
||||
node: ast.AST* = None) -> int:
|
||||
"""注解侧是裸 str/bytes 而值是指向聚合类型的指针 → fail-fast(返回 1)
|
||||
|
||||
判据见 _str_rejects_ptr_kind(结构体/类/联合/非字符数组/函数指针拒绝;
|
||||
字符数组衰减豁免)。显式转换(如 t.CPtr(p))的产物 pointee 是 i8,
|
||||
不触发本检查,故显式转换不受影响。
|
||||
"""
|
||||
if annot_is_str == 0 or val is None or val.Ty is None:
|
||||
return 0
|
||||
if self._str_rejects_ptr_kind(val) == 0:
|
||||
return 0
|
||||
self.Gen.TypeGenErr.fatal_error(self._value_node_of(node),
|
||||
"str/bytes 不接受指向非基本类型(结构体/类/数组/函数)的指针:两者在 IR 层"
|
||||
"str/bytes 不接受指向非基本类型(结构体/类/非字符数组/函数)的指针:两者在 IR 层"
|
||||
"同为 i8*,但语义不同(str/bytes 不是通用指针通配)。若确需传递指针,"
|
||||
"请改用 t.CPtr/rawptr 形参,或显式转换(如 t.CPtr(p))", "CastError")
|
||||
return 1
|
||||
|
||||
Reference in new issue
Block a user