fix(type): 联合类型 A|t.CPtr 判据由白名单改为解析成功即保留,stub 侧同步
定义侧 TypeGenResolve.resolve_annotation_type 的 BinOp(A | t.CPtr) 分支:裸名 pointee 的保留判据由“硬编码名字白名单 + 必须是已注册 struct”改为“以解析是否 成功为准”——命中统一口径 resolve_typedef_or_map(CTypedef 动态表 → builtins → stdint/w32.win32base 库源 → map_t_type)且结果非指针即保留该已解析类型。 于是 sizet | t.CPtr ⇒ i64*(原静默退化为 i8*)。 修复前的故障:TPV2 Phase1 的 includes/ast/tokens.vp _kw_index_put 按 i8* 处理 哈希槽,slot[0] 只做 1 字节读写,指针被截断成低字节 0xd0,随后被当 KwEntry* 解引用 → ASan 读地址 0xd0 崩溃(TPC 侧同 sha 为 alloca i64*/load i64/store i64)。 stub/declare 侧 VpiReader._resolve_vpi_ret_annot_str 同步同一判据:新增 first_td 标记,对裸名(无 '.')、非白名单、非指针的解析结果复用同一个 GenApi.resolve_typedef_or_map 判定,命中即保留 pointee。声明侧与定义侧现在 同型(sizet/uint64/INT/u32 等别名两侧都得到 i64*/i32*),同型即收敛, 不再需要把 declare 侧坍缩为 i8* 去迁就定义侧。 既有路径行为不变:泛型参数名、内建标量白名单(int/char/str/bytes/bool/float/ double)、解析失败与裸枚举名的 i8* 兜底;指针别名(BYTEPTR/HANDLE/VOIDPTR) 因解析结果为 Ptr(...) 不置位 first_td,仍坍缩 i8*,与定义侧 td_res_is_ptr 守卫对称。
This commit is contained in:
1 parent
c1859a111c
commit
60100fa6af
2 files changed
+65
-6
No files matched your search
@@ -1317,10 +1317,15 @@ def _resolve_vpi_ret_annot_str(pool: rowptr[memhub.MemBuddy],
|
||||
has_cvoid: int = 0
|
||||
first_ty: llvmlite.LLVMType | t.CPtr = None
|
||||
# 产生 first_ty 那一段文本的属性(供末尾 has_cptr 分支复刻定义侧规则,N12):
|
||||
# first_qual=1 段是限定名(含 '.',如 uint64 / mod.Class)
|
||||
# first_qual=1 段是限定名(含 '.',如 mod.Class / t.CInt64T)
|
||||
# first_wl =1 段是白名单裸标量名(int/char/str/bytes/bool/float/double)
|
||||
# first_td =1 段是裸 typedef 别名且已成功解析出**非指针**类型(N13,
|
||||
# 如 sizet/uint64 ⇒ i64):判据=“解析是否成功”,与定义侧
|
||||
# TypeGenResolve.resolve_annotation_type 的 BinOp(A | t.CPtr)
|
||||
# 分支同源(同一 resolve_typedef_or_map 口径)。
|
||||
first_qual: int = 0
|
||||
first_wl: int = 0
|
||||
first_td: int = 0
|
||||
|
||||
buf_len: sizet = string.strlen(ret_annot)
|
||||
pos: sizet = 0
|
||||
@@ -1364,6 +1369,22 @@ def _resolve_vpi_ret_annot_str(pool: rowptr[memhub.MemBuddy],
|
||||
string.strcmp(seg_buf, "float") == 0 or \
|
||||
string.strcmp(seg_buf, "double") == 0:
|
||||
first_wl = 1
|
||||
# 裸名 typedef 别名保真(N13,与定义侧同源):sizet/uint64/INT/u32
|
||||
# 等别名经上面 _resolve_single_vpi_type_str 已成功解析出标量
|
||||
# (sizet ⇒ i64、INT/u32 ⇒ i32),只是"不是 struct 且不在白名单"
|
||||
# 就被下方坍缩成 i8* → declare 侧 i8* 而定义侧(已同步改为
|
||||
# "解析成功即保留")为 i64* → 跨模块同型收敛被破坏。
|
||||
# 判据直接用与定义侧同一个 API GenApi.resolve_typedef_or_map
|
||||
# (委托 TypeGenResolve.resolve_typedef_or_map:CTypedef 动态表 →
|
||||
# builtins → stdint/w32.win32base 库源 → map_t_type),
|
||||
# 命中即置位保留;不另立手写名字白名单。
|
||||
# 仅对**非指针**解析结果置位:指针别名(BYTEPTR/HANDLE/VOIDPTR
|
||||
# 解析为 Ptr(...))不置位 → 仍坍缩 i8*,与定义侧守卫
|
||||
# (td_res_is_ptr != 0 时不套用 typedef 保真)对称。
|
||||
if first_qual == 0 and first_wl == 0:
|
||||
if first_ty.kind() != llvmlite.LLVMType.Ptr:
|
||||
if GenApi.resolve_typedef_or_map(pool, seg_buf, None, None) is not None:
|
||||
first_td = 1
|
||||
stdlib.free(seg_buf)
|
||||
pos += 1 # 跳过 '|'
|
||||
|
||||
@@ -1371,11 +1392,18 @@ def _resolve_vpi_ret_annot_str(pool: rowptr[memhub.MemBuddy],
|
||||
if has_cvoid != 0:
|
||||
return i8_ptr_ty
|
||||
if first_ty is not None:
|
||||
# 复刻定义侧规则(N12):限定名 / 白名单裸标量 / 已注册结构体 → 保留
|
||||
# pointee;其余**裸名**(如 uint64/uint32 等 typedef 别名、裸枚举名)
|
||||
# → 联合坍缩为 i8*,与 resolve_annotation_type 一致,避免
|
||||
# `save_buf: uint64 | t.CPtr` 定义侧 i8* 而 stub 侧 i64* 跨模块不收敛。
|
||||
if first_qual != 0 or first_wl != 0:
|
||||
# 复刻定义侧规则(N12/N13):限定名 / 白名单裸标量 / 已注册结构体 /
|
||||
# 可解析的裸 typedef 别名(非指针)→ 保留 pointee;其余(解析失败、
|
||||
# 裸枚举名、指针别名)→ 联合坍缩为 i8*,与 resolve_annotation_type 一致。
|
||||
# 收敛依据(替换旧理由"避免定义侧 i8* 而 declare i64* 跨模块不收敛"):
|
||||
# 定义侧同一分支已改为"解析成功即保留(非指针)",`sizet | t.CPtr` 定义侧
|
||||
# ⇒ i64*(见 TypeGenResolve.vp BinOp(A | t.CPtr) 的 typedef 别名保真判定),
|
||||
# 本侧经同一 GenApi.resolve_typedef_or_map 命中后亦 ⇒ Ptr(i64) = i64*;
|
||||
# **两侧同型即收敛**,不再需要把 declare 侧坍缩成 i8* 去迁就定义侧。
|
||||
# 仍坍缩 i8* 的三类与定义侧对称:解析失败兜底;裸枚举名(定义侧
|
||||
# get_struct_type miss 同样落 i8*);指针别名(first_td 不置位,对应定义侧
|
||||
# td_res_is_ptr != 0 的守卫)。
|
||||
if first_qual != 0 or first_wl != 0 or first_td != 0:
|
||||
return llvmlite.Ptr(pool, first_ty)
|
||||
if first_ty.kind() == llvmlite.LLVMType.Struct:
|
||||
return llvmlite.Ptr(pool, first_ty)
|
||||
|
||||
@@ -2500,6 +2500,37 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
string.strcmp(other_nm_b.id, "float") == 0 or \
|
||||
string.strcmp(other_nm_b.id, "double") == 0:
|
||||
keep_other_ty = 1
|
||||
# typedef 别名保真(判据=“解析是否成功”,非白名单扩名):
|
||||
# sizet/uint64/CSizeT 等别名经 resolve_annotation_type 已
|
||||
# 成功解析出标量,却因“不是已注册 struct 且不在白名单”被
|
||||
# 丢弃 → other_ty=None → 下方 get_struct_type("sizet") miss
|
||||
# → 联合静默退化为 i8*:哈希槽 slot[0] 只做 1 字节读写、
|
||||
# 指针被截断成低字节 0xd0,随后被当 KwEntry* 解引用(TPV2
|
||||
# Phase1 includes/ast/tokens.vp _kw_index_put ASan 读地址
|
||||
# 0xd0 崩根因;TPC 侧同 sha 为 alloca i64*/load i64/store i64)。
|
||||
# 用统一口径 resolve_typedef_or_map(CTypedef 动态表 →
|
||||
# builtins → stdint/w32.win32base 库源 → map_t_type)判定
|
||||
# 该裸名是否是可解析的 typedef/别名;命中即保留本次已解析出
|
||||
# 的类型,参与“基类型 + 指针层数”合并(对齐 TPC
|
||||
# HandlesTypeMerge._MergeAllComponentTypes L887-946:
|
||||
# sizet | t.CPtr ⇒ 基类型 i64 + 1 层指针 = i64*)。
|
||||
# 仅保留非指针结果:Ptr(...)(类 __new__ 的 Ptr(struct)、
|
||||
# 指针别名)继续走下方 get_struct_type 回退与解析失败兜底,
|
||||
# 该两条既有路径行为逐字节不变。
|
||||
if keep_other_ty == 0 and other_node is not None and other_node.kind() == ast.ASTKind.Name:
|
||||
other_nm_td: ast.Name | t.CPtr = (ast.Name | t.CPtr)(other_node)
|
||||
if other_nm_td.id is not None:
|
||||
td_res_is_ptr: int = 0
|
||||
match other_ty:
|
||||
case llvmlite.LLVMType.Ptr(_):
|
||||
td_res_is_ptr = 1
|
||||
case _:
|
||||
td_res_is_ptr = 0
|
||||
if td_res_is_ptr == 0:
|
||||
td_alias_ty: llvmlite.LLVMType | t.CPtr = self.resolve_typedef_or_map(
|
||||
pool, other_nm_td.id, imported_modules, from_imports, trans)
|
||||
if td_alias_ty is not None:
|
||||
keep_other_ty = 1
|
||||
if keep_other_ty == 0:
|
||||
other_ty = None
|
||||
if other_ty is None:
|
||||
|
||||
Reference in new issue
Block a user