fix(stub): declare 侧识别 t.CPtr[...] 段,与定义侧指针层级口径对齐

t.CUInt8T | t.CPtr[t.CPtr] 在定义侧(TypeGenResolve._is_cptr_subscript)按指针层级合并得 i8**,但声明侧段判据只认整段等于 t.CPtr/CPtr,下标段落入普通段解析后取首段 => i8,造成跨模块 define/declare 签名不一致(实参 1 字节 vs 写入 8 字节)

新增 t.CPtr[/c.CPtr[ 段的识别与递归解析(与同文件 rowptr[...] 分支同构),数外层 Ptr 层数 N 后按 Ptr^N 合并;裸 t.CPtr 段路径未动,未放宽 fail-fast

注: TPC 侧 LLVMTypeMapper._resolve_bitor 与 SymbolUtils.IsCPtrNode 同源缺陷未改,两套编译器需同时修以免产物分叉
This commit is contained in:
TermiNexus committed 2026-09-15 23:58:39 +08:00
1 parent de86a1ed70
commit 31b8dccffd
1 file changed
+81 -1
+81 -1
View File
@@ -1198,6 +1198,31 @@ def _resolve_single_vpi_type_str(pool: rowptr[memhub.MemBuddy],
if inner_ty_rp is not None:
return llvmlite.Ptr(pool, inner_ty_rp)
return None
# t.CPtr[T] / c.CPtr[T] 下标指针(含嵌套,如 t.CPtr[t.CPtr] → Ptr(Ptr(i8))):
# 与定义侧 TypeGenResolve.resolve_annotation_type 的 Subscript(CPtr) 分支
# (TypeGenResolve.vp L2769-2790)同口径 Ptr(resolve(T)),T 自身可含指针层级。
# 先例:上方 rowptr[T] 分支(L1187-1200)同形(前缀 + 尾 ']' 判定 + 递归 + Ptr 包装)。
# vpi 注解文本按源码原样缓存(如 `out: t.CUInt8T | t.CPtr[t.CPtr]`),本函数
# 此前对该形态一律返回 None → 段被丢弃 → 联合坍缩到首段(i8),与定义侧
# i8** 不一致(跨模块 declare/define ABI 错位;见 _resolve_vpi_ret_annot_str
# 段循环内的同源判据)。
cptr_sub_pfx: sizet = 0
if string.strncmp(seg, "t.CPtr[", 7) == 0 or string.strncmp(seg, "c.CPtr[", 7) == 0:
cptr_sub_pfx = 7
if cptr_sub_pfx > 0:
seg_len_cp: sizet = string.strlen(seg)
if seg_len_cp > cptr_sub_pfx + 1 and seg[seg_len_cp - 1] == ']':
inner_len_cp: sizet = seg_len_cp - cptr_sub_pfx - 1
inner_buf_cp: bytes = stdlib.malloc(inner_len_cp + 1)
if inner_buf_cp is not None:
string.strncpy(inner_buf_cp, seg + cptr_sub_pfx, inner_len_cp)
inner_buf_cp[inner_len_cp] = '\0'
inner_ty_cp: llvmlite.LLVMType | t.CPtr = _resolve_single_vpi_type_str(
pool, inner_buf_cp)
stdlib.free(inner_buf_cp)
if inner_ty_cp is not None:
return llvmlite.Ptr(pool, inner_ty_cp)
return None
# t.XXX / c.XXX 内置类型映射
if string.strncmp(seg, "t.", 2) == 0 or string.strncmp(seg, "c.", 2) == 0:
attr_nm: str = seg + 2
@@ -1326,6 +1351,16 @@ def _resolve_vpi_ret_annot_str(pool: rowptr[memhub.MemBuddy],
first_qual: int = 0
first_wl: int = 0
first_td: int = 0
# CPtr 下标段(t.CPtr[T]/c.CPtr[T],含嵌套)的联合合并参数:
# cptr_sub_lvl = 该段解析后的外层 Ptr 层数 N(如 t.CPtr[t.CPtr] ⇒ 2);
# cptr_sub_ty = 该段解析出的类型本身(无另一侧基类型时即结果)。
# 判据与定义侧 TypeGenResolve.vp 的 `X | t.CPtr[T]` 分支(L2596-2639)同口径:
# CPtr 侧贡献 N 层指针、另一侧提供基类型 ⇒ 结果 Ptr^N(基类型)。
# 与 has_cptr(裸 t.CPtr 段)分开记录:裸标记路径恒"追加 1 层"且有 struct
# 吸收特例(定义侧 L2540-2594),下标路径无吸收(定义侧 L2610-2639),
# 两者在定义侧分属互斥分支(_is_cptr_marker / _is_cptr_subscript)。
cptr_sub_lvl: int = 0
cptr_sub_ty: llvmlite.LLVMType | t.CPtr = None
buf_len: sizet = string.strlen(ret_annot)
pos: sizet = 0
@@ -1347,7 +1382,35 @@ def _resolve_vpi_ret_annot_str(pool: rowptr[memhub.MemBuddy],
break
string.strncpy(seg_buf, ret_annot + seg_start, seg_len2)
seg_buf[seg_len2] = '\0'
if string.strcmp(seg_buf, "t.CPtr") == 0 or string.strcmp(seg_buf, "CPtr") == 0:
# CPtr 下标段(t.CPtr[T]/c.CPtr[T],含嵌套如 t.CPtr[t.CPtr]):
# 必须先行识别,不能落普通段分支取 first_ty——定义侧
# TypeGenResolve.vp L2596-2639 对 `X | t.CPtr[T]` 是"CPtr 侧贡献
# N 层指针、另一侧给基类型 ⇒ Ptr^N(X)",与"把该段本身当联合取值"
# 语义不同(如 X=struct S、t.CPtr[t.CPtr]:定义侧 Ptr(Ptr(S)),
# 取该段本身则得 i8**)。此处只记录 N 与段类型,末尾统一合并。
if string.strncmp(seg_buf, "t.CPtr[", 7) == 0 or string.strncmp(seg_buf, "c.CPtr[", 7) == 0:
seg_ty_cs: llvmlite.LLVMType | t.CPtr = _resolve_single_vpi_type_str(pool, seg_buf)
if seg_ty_cs is not None:
# 计算外层 Ptr 嵌套数(定义侧 L2616-2632 同口径)。注意不能在
# case body 内更新 while 条件变量(自举编译的 match 会写到 subject
# 快照槽 → 条件读旧槽死循环,见 TypeGenResolve.vp L2620-2624):
# case 绑定 pointee 到局部变量,match 外更新循环变量。
lvl_cs: int = 0
cur_cs: llvmlite.LLVMType | t.CPtr = seg_ty_cs
while cur_cs is not None:
nxt_cs: llvmlite.LLVMType | t.CPtr = None
match cur_cs:
case llvmlite.LLVMType.Ptr(pointee_cs):
lvl_cs += 1
nxt_cs = pointee_cs
case _:
break
cur_cs = nxt_cs
# 多下标段取最大层数(定义侧按最外层联合右值合并,等价于层数累加)
if lvl_cs > cptr_sub_lvl:
cptr_sub_lvl = lvl_cs
cptr_sub_ty = seg_ty_cs
elif string.strcmp(seg_buf, "t.CPtr") == 0 or string.strcmp(seg_buf, "CPtr") == 0:
has_cptr = 1
elif string.strcmp(seg_buf, "t.CVoid") == 0 or string.strcmp(seg_buf, "CVoid") == 0:
has_cvoid = 1
@@ -1425,6 +1488,23 @@ def _resolve_vpi_ret_annot_str(pool: rowptr[memhub.MemBuddy],
return llvmlite.Ptr(pool, first_ty)
return i8_ptr_ty
return i8_ptr_ty
# CPtr 下标段联合合并(定义侧 TypeGenResolve.vp L2596-2639 同口径):
# 有另一侧基类型 first_ty → 结果 = Ptr^N(first_ty)(N=cptr_sub_lvl)
# 仅 CPtr 下标段自身 → 结果 = 该段解析类型本身(等价定义侧
# Subscript(CPtr) 分支 L2769-2790 的 Ptr^N(inner))
# 下标段无 struct 吸收(定义侧该分支不吸收),故不与上方 has_cptr 分支的
# 吸收判据混用。has_cptr(裸 t.CPtr 段)在上一分支已全部返回,二者不叠加:
# 定义侧裸标记(_is_cptr_marker)与下标标记(_is_cptr_subscript)亦互斥,
# `X | t.CPtr | t.CPtr[...]` 这类混合写法本函数不建模(保持 has_cptr 旧行为)。
if cptr_sub_lvl > 0:
if first_ty is None:
return cptr_sub_ty
res_ty_cs: llvmlite.LLVMType | t.CPtr = first_ty
wrap_i_cs: int = 0
while wrap_i_cs < cptr_sub_lvl:
res_ty_cs = llvmlite.Ptr(pool, res_ty_cs)
wrap_i_cs += 1
return res_ty_cs
if has_cvoid != 0:
# t.CVoid | t.State:State 是装饰器标记(编译侧忽略),t.CVoid → void。
# 此前缺此分支 → first_ty=None → 返回 None → 跨模块函数返回类型