From 6af2dea917af923a39f15895b44d42a43daccf6d Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 17 Sep 2026 14:52:37 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/Projectrans/Phase2Translator.py | 17 +- lib/core/Handles/HandlesAnnAssign.py | 36 ++-- lib/core/Handles/HandlesBase.py | 4 +- lib/core/Handles/HandlesClassDef.py | 18 +- lib/core/Handles/HandlesExprBuiltin.py | 31 +-- lib/core/Handles/HandlesExprCall.py | 74 +++---- lib/core/Handles/HandlesExprUtils.py | 4 +- lib/core/Handles/HandlesFunctions.py | 38 ++-- lib/core/Handles/HandlesImports.py | 276 ++++++++++++------------- lib/core/Handles/HandlesTypeMerge.py | 12 +- lib/core/LLVMCG/BaseGen.py | 12 ++ lib/core/LLVMCG/DebugInfo.py | 91 +++++++- lib/core/LLVMCG/FuncGen.py | 8 +- lib/core/LLVMCG/IRMetadataFix.py | 14 +- lib/core/SymbolExtractor.py | 6 +- lib/core/TypeAnnotationResolver.py | 34 +-- 16 files changed, 387 insertions(+), 288 deletions(-) diff --git a/lib/Projectrans/Phase2Translator.py b/lib/Projectrans/Phase2Translator.py index c91344d..3bb9fd5 100644 --- a/lib/Projectrans/Phase2Translator.py +++ b/lib/Projectrans/Phase2Translator.py @@ -2309,6 +2309,12 @@ class Phase2Translator: break final_lines2 = ll_content_no_types.splitlines(True) ll_content = ''.join(final_lines2[:header_end]) + '\n'.join(final_type_defs) + '\n' + ''.join(final_lines2[header_end:]) + # 写盘前先规整元数据:本文件的 IR 是「本模块 + 各依赖 .stub.ll/ + # .text.ll 片段」拼接而成,每份片段都自带从 !0 起编号的 DI 元数据, + # 未规整直接落盘的话,任何读该文件的 opt/llc(含另一并发构建进程) + # 都会报 "Metadata id is already used"。规整后盘上产物本身即合法 IR, + # _llc_compile 内的规整随之成为幂等 no-op。 + ll_content = SanitizeIRMetadata(ll_content) dso_ll_path = ll_path[:-3] + '_dso.ll' with open(dso_ll_path, 'w', encoding='utf-8') as f: f.write(ll_content) @@ -3127,6 +3133,9 @@ class Phase2Translator: insert_pos = len(other_lines) ll_content = ''.join(other_lines[:insert_pos]) + ''.join(type_def_lines) + ''.join(other_lines[insert_pos:]) + # 同 App 路径:写盘前规整元数据(拼接片段各自带 !0..!N 的 DI 元数据), + # 让盘上产物本身即合法 IR,不依赖 _llc_compile 里那次事后规整。 + ll_content = SanitizeIRMetadata(ll_content) dso_ll_path = ll_path[:-3] + '_dso.ll' with open(dso_ll_path, 'w', encoding='utf-8') as f: f.write(ll_content) @@ -3883,7 +3892,13 @@ SECTIONS { _vlog().success(f" 生成: {exe_path}") file_size = os.path.getsize(exe_path) _vlog().info(f" [大小] {file_size} 字节") - if not is_binary: + # --dwarf 构建(含 --asan 自动开启)必须保留 DWARF: + # 该模式存在的唯一意义是崩溃时反查 ".vp:行", + # 而 _strip_debug_sections 会 llvm-strip --strip-debug 掉全部 + # .debug_* 段(实测 exe 体积 13378048 → 11895296, + # llvm-symbolizer 对含 main 在内的所有地址返回 ??:0:0)。 + # 非 dwarf 构建保持原有剥离行为(产物零变化)。 + if not is_binary and not self.dwarf_enabled: self._strip_debug_sections(exe_path) else: _vlog().error(f" 链接失败: {result.stderr.strip()}") diff --git a/lib/core/Handles/HandlesAnnAssign.py b/lib/core/Handles/HandlesAnnAssign.py index 8040a2e..88f5824 100644 --- a/lib/core/Handles/HandlesAnnAssign.py +++ b/lib/core/Handles/HandlesAnnAssign.py @@ -541,32 +541,32 @@ class AnnAssignHandle(BaseHandle): Gen.global_struct_class[VarName] = TypeInfo.Name # 联合指针注解(X | t.CPtr)短名回退:resolver 对模块限定 struct # 段(如 llvmlite.Value)无法精确 in Gen.structs(键可能是 'Value' - # 或带 sha1 前缀),Name 常退化为指针别名 'rowptr'(被注册成 opaque - # struct)→ 变量 var_struct_class 登记为 rowptr → 字段访问 - # "属性 'Next' 在类 'rowptr' 中找不到"(FuncGenMixin.vp L307)。 + # 或带 sha1 前缀),Name 常退化为指针别名 'rawptr'(被注册成 opaque + # struct)→ 变量 var_struct_class 登记为 rawptr → 字段访问 + # "属性 'Next' 在类 'rawptr' 中找不到"(FuncGenMixin.vp L307)。 # FindStructNameInAnnotation 以 attr/短名命中,找回真实类名。 if (isinstance(Node.annotation, ast.BinOp) and isinstance(Node.annotation.op, ast.BitOr)): _union_struct_name2: str | None = FindStructNameInAnnotation(Node.annotation, Gen.structs) # resolver 对模块限定 struct 联合(llvmlite.Value | t.CPtr)常给出 - # 指针占位名(如 '{sha1}.rowptr')且该占位恰好注册在 Gen.structs, + # 指针占位名(如 '{sha1}.rawptr')且该占位恰好注册在 Gen.structs, # 使上方 TypeInfo.Name in Gen.structs 通过并登记错误类名 → 字段 - # 访问 "属性 'Next' 在类 'rowptr' 中找不到"。凡短名命中真实类 + # 访问 "属性 'Next' 在类 'rawptr' 中找不到"。凡短名命中真实类 # (attr 精确 in structs),一律覆盖为真实类名(Value)。 if _union_struct_name2 and _union_struct_name2 in Gen.structs: if Gen.var_struct_class.get(VarName) != _union_struct_name2: Gen.var_struct_class[VarName] = _union_struct_name2 if getattr(Gen, 'global_struct_class', None) is not None: Gen.global_struct_class[VarName] = _union_struct_name2 - # Subscript rowptr[X] / t.CPtr[X] 注解的本地结构指针变量(如 - # includes/ast/parser.vp _fix_store_ctx 里 `tp: rowptr[Tuple] = - # (rowptr[Tuple])(node)`,随后 `tp_elts = tp.elts`):TypeMerge 的 - # builtins 分支把 rowptr[X] 折叠为 i8*(PtrCount=1/CVoid),既不登记 + # Subscript rawptr[X] / t.CPtr[X] 注解的本地结构指针变量(如 + # includes/ast/parser.vp _fix_store_ctx 里 `tp: rawptr[Tuple] = + # (rawptr[Tuple])(node)`,随后 `tp_elts = tp.elts`):TypeMerge 的 + # builtins 分支把 rawptr[X] 折叠为 i8*(PtrCount=1/CVoid),既不登记 # var_struct_class 也不保留内层 X —— 单级 Name 字段取值(tp.elts) # 在属性访问层 ClassName 解析为 None → 求值 None → 赋值被 fail-fast # 拦截(parser.vp L427 bootstrap 根因)。与上方 BinOp 联合的短名回退 # 对称:把内层 X 解析为真实 struct 键(兼容短名 / 带 class_sha1 前缀 - # 的键)并登记;仅在缺失或指针占位(rowptr…)时覆盖,不碰已精确登记值。 + # 的键)并登记;仅在缺失或指针占位(rawptr…)时覆盖,不碰已精确登记值。 _rst_sub: ast.AST | None = None if isinstance(Node.annotation, ast.Subscript): _rst_v: ast.expr = Node.annotation.value @@ -575,7 +575,7 @@ class AnnAssignHandle(BaseHandle): _rst_nm = _rst_v.id elif isinstance(_rst_v, ast.Attribute) and isinstance(_rst_v.value, ast.Name): _rst_nm = f'{_rst_v.value.id}.{_rst_v.attr}' - if _rst_nm in ('rowptr', 't.CPtr'): + if _rst_nm in ('rawptr', 't.CPtr'): _rst_sub = Node.annotation if _rst_sub is not None: _rst_sl: ast.AST = _rst_sub.slice @@ -602,8 +602,8 @@ class AnnAssignHandle(BaseHandle): break if _rst_tk: _rst_cur: str | None = Gen.var_struct_class.get(VarName) - _rst_need: bool = (not _rst_cur or _rst_cur == 'rowptr' or '.rowptr' in _rst_cur - or _rst_cur.startswith('rowptr[')) + _rst_need: bool = (not _rst_cur or _rst_cur == 'rawptr' or '.rawptr' in _rst_cur + or _rst_cur.startswith('rawptr[')) if _rst_need and _rst_cur != _rst_tk: Gen.var_struct_class[VarName] = _rst_tk if getattr(Gen, 'global_struct_class', None) is not None: @@ -776,11 +776,11 @@ class AnnAssignHandle(BaseHandle): _cn_short: str = CN.split('.')[-1] if '.' in CN else CN if _IsGenericTpName(_cn_short): continue - # rowptr 占位 struct('rowptr' / '{sha1}.rowptr' / 'rowptr[...]')是 + # rawptr 占位 struct('rawptr' / '{sha1}.rawptr' / 'rawptr[...]')是 # 模块限定联合 X | t.CPtr 被 resolver 退化的产物(无真实字段), # 绝不能覆盖注解已解析出的真实类名(如 Value)→ env_size_val.Next - # 报 "属性在类 'rowptr' 中找不到"(FuncGenMixin.vp L307 根因)。 - if CN == 'rowptr' or CN.endswith('.rowptr') or CN.startswith('rowptr['): + # 报 "属性在类 'rawptr' 中找不到"(FuncGenMixin.vp L307 根因)。 + if CN == 'rawptr' or CN.endswith('.rawptr') or CN.startswith('rawptr['): continue if pointee is ST or pointee == ST: # 若注解是泛型特化(如 ndarray[t.CDouble] | t.CPtr), @@ -907,8 +907,8 @@ class AnnAssignHandle(BaseHandle): if isinstance(pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): for CN, ST in Gen.structs.items(): if pointee == ST: - # rowptr 占位 struct 不参与覆盖(见 L706-711 说明) - if CN == 'rowptr' or CN.endswith('.rowptr') or CN.startswith('rowptr['): + # rawptr 占位 struct 不参与覆盖(见 L706-711 说明) + if CN == 'rawptr' or CN.endswith('.rawptr') or CN.startswith('rawptr['): break Gen._var_to_heap_ptr[VarName] = InitValue # 不覆盖已设置的特化名(含 '['):opaque 基础类型(如 ndarray) diff --git a/lib/core/Handles/HandlesBase.py b/lib/core/Handles/HandlesBase.py index a0c5c06..7204231 100644 --- a/lib/core/Handles/HandlesBase.py +++ b/lib/core/Handles/HandlesBase.py @@ -769,7 +769,7 @@ class BaseHandle: 局部变量注解走 TypeMergeHandler.GetCTypeInfo(_HandleSubscript 泛型 分支),函数参数却走 ResolveAnnotationType → Subscript 非 BinOp 直接 CTypeInfo.FromNode → TypeAnnotationResolver 不识别泛型模板,容器 - (list[X] / rowptr[list[X]] / GSList[X] / rowptr[GSList[X]])被折叠成 + (list[X] / rawptr[list[X]] / GSList[X] / rawptr[GSList[X]])被折叠成 i8* → 参数无 var_struct_class → 方法调用 FakeDuck 兜底错绑兄弟类 (如 parser.vp _append_str_value 的 values.append 被编成 AST.append 虚调用,this=list* 读 vtable 崩溃)。此处对命中泛型模板的 Subscript @@ -793,7 +793,7 @@ class BaseHandle: def _SubscriptHitsGenericTemplate(self, annotation: ast.Subscript) -> bool: """判断 Subscript 是否命中泛型模板:裸模板名(list[X]/GSList[X]), - 或 rowptr/t.CPtr 裸指针 typedef 内嵌模板名(rowptr[list[X]] 等)。""" + 或 rawptr/t.CPtr 裸指针 typedef 内嵌模板名(rawptr[list[X]] 等)。""" tpls: Any = getattr(getattr(self.Trans, 'ClassHandler', None), '_generic_class_templates', None) if not tpls: return False diff --git a/lib/core/Handles/HandlesClassDef.py b/lib/core/Handles/HandlesClassDef.py index e015b5f..417300a 100644 --- a/lib/core/Handles/HandlesClassDef.py +++ b/lib/core/Handles/HandlesClassDef.py @@ -821,9 +821,9 @@ class ClassHandle(BaseHandle): if ClassName not in Gen.class_member_element_class: Gen.class_member_element_class[ClassName] = {} Gen.class_member_element_class[ClassName][VarName] = spec_in_anno - # Subscript 容器字段(list[X] / rowptr[list[X]]):非 BinOp 联合, + # Subscript 容器字段(list[X] / rawptr[list[X]]):非 BinOp 联合, # 上面的 i8*/BinOp 分支不命中 → 容器身份丢失 → 字段方法调用 - # (get/len…)分派失败 "Undefined method 'get' in class 'rowptr'" + # (get/len…)分派失败 "Undefined method 'get' in class 'rawptr'" # (Converter.vp L190)。与 HandlesImports 对称,用与特化生成端 # 同源的 _resolve_type_arg_str 记录 element_class。 if isinstance(item.annotation, ast.Subscript): @@ -833,13 +833,13 @@ class ClassHandle(BaseHandle): _elem_slice_c: ast.AST | None = None if _subname_c == 'list': _elem_slice_c = _ann_sub_c.slice - elif _subname_c == 'rowptr': + elif _subname_c == 'rawptr': _slice_c: ast.AST = _ann_sub_c.slice if isinstance(_slice_c, ast.Subscript): - # rowptr[泛型容器](rowptr[list[X]] / rowptr[GSList[Param]]): + # rawptr[泛型容器](rawptr[list[X]] / rawptr[GSList[Param]]): # 容器身份 = 泛型特化名。list 继续走 _elem_slice_c 统一登记; # 其余泛型容器直接登记 element_class(阻塞 B 根因链一环: - # 原实现只认内层 list,rowptr[GSList[Param]] 在此空转并跳过 + # 原实现只认内层 list,rawptr[GSList[Param]] 在此空转并跳过 # 裸结构分支 → element_class 缺失 → 字段/局部变量方法分派 # 丢失容器身份,FakeDuck 错绑 LinkedNode.append 写穿)。 _inner_sub_c: ast.Subscript = _slice_c @@ -858,11 +858,11 @@ class ClassHandle(BaseHandle): Gen.class_member_element_class[ClassName] = {} Gen.class_member_element_class[ClassName][VarName] = _ec_gc else: - # rowptr[裸结构](如 rowptr[Token]):跨模块 stub 会把自引用/类内 + # rawptr[裸结构](如 rawptr[Token]):跨模块 stub 会把自引用/类内 # 指针字段退化为 i8*,链式成员访问(a.b.c)需 element_class 恢复 # struct 身份走 char*→struct cast。HEAD 态 `Token | t.CPtr` 联合 - # 由上方 BinOp 分支登记;rowptr 重构后此分支补齐(阻塞 A 根因)。 - # 与 HandlesImports 的 rowptr 分支对称。 + # 由上方 BinOp 分支登记;rawptr 重构后此分支补齐(阻塞 A 根因)。 + # 与 HandlesImports 的 rawptr 分支对称。 _slc_name_c: str | None = None if isinstance(_slice_c, ast.Name): _slc_name_c = _slice_c.id @@ -879,7 +879,7 @@ class ClassHandle(BaseHandle): else: # 短名模糊扫描(对齐 HandlesAnnAssign 变量侧 # 补偿 L597-602):跨模块 `mod.Class` 形态的 - # rowptr[Class] 字段在 class_sha1_map 尚无该短名 + # rawptr[Class] 字段在 class_sha1_map 尚无该短名 # 时上面两路全 miss → element_class 静默缺失 → # 字段方法调用(factory.PermPool.alloc)链尾类名 # 丢失 → TPC 调用分派返回 i32 0 哨兵 → 误报 diff --git a/lib/core/Handles/HandlesExprBuiltin.py b/lib/core/Handles/HandlesExprBuiltin.py index 7fedf90..a3ecbab 100644 --- a/lib/core/Handles/HandlesExprBuiltin.py +++ b/lib/core/Handles/HandlesExprBuiltin.py @@ -164,7 +164,14 @@ class ExprBuiltinHandle(BaseHandle): str_val = Gen.builder.call(Gen._get_function(f'{ClassName}.__str__'), [arg_val], name=f"call_{ClassName}.__str__") return str_val return arg_val - return self._EmitStringFromValue(arg_val) + # str 是类型名(= t.CChar* = i8*),str(x) ≡ (str)(x) 类型转换: + # 整型(u64/sizet 地址、char 码)→ inttoptr,与 TPV + # CallGenDispatch._tc_h3_stdarg_cast 的 str 分支同语义 + # (CallGenCtor._translate_t_type_cast 的「整数 → 指针: inttoptr」)。 + # 曾用 _EmitStringFromValue 把整数 snprintf 进栈缓冲并返回栈地址 + # → free/写入即 bad-free(StubMergerBuild.vp 崩溃根因)。 + if isinstance(arg_val.type, ir.IntType): + return Gen.builder.inttoptr(arg_val, ir.IntType(8).as_pointer(), name="str_int2ptr") return ir.Constant(ir.IntType(8).as_pointer(), None) elif FuncName == 'bytes': # bytes() — 类型转换为 i8* 指针 (等同于 t.CPtr / str) @@ -567,7 +574,7 @@ class ExprBuiltinHandle(BaseHandle): Gen: LlvmGeneratorMixin = self.Trans.LlvmGen # len(obj.attr):obj 可为 self 或任意局部变量(VpiReader 的 # len(simp.names) 即非 self 场景)。字段静态类型若退化为 i8* - # (跨模块 stub 的 rowptr[list[...]],stub 不注入字段类型),通用 + # (跨模块 stub 的 rawptr[list[...]],stub 不注入字段类型),通用 # strlen 分支会把 list 容器头当字符串扫 → 垃圾长度 → 越界 get → # 读任意地址(VpiReader.vp _ParseVpiIntoModuleImpl 读 -1 根因)。 # 此处按字段的 class_member_element_class 侧信道(记录 list 特化名) @@ -887,26 +894,6 @@ class ExprBuiltinHandle(BaseHandle): return Gen.builder.gep(char_ptr, [ir.Constant(ir.IntType(32), 0)], name="chr_result") return ir.Constant(ir.IntType(8).as_pointer(), None) - def _EmitStringFromValue(self, val: ir.Value) -> ir.Value: - Gen: LlvmGeneratorMixin = self.Trans.LlvmGen - if isinstance(val.type, ir.IntType): - if val.type.width == 8: - buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 2)) - null_ptr = Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 1)], name="null_byte") - Gen.builder.store(ir.Constant(ir.IntType(8), 0), null_ptr) - Gen.builder.store(val, buf) - return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result") - buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 32)) - snprintf_func = Gen.get_or_declare_c_func('snprintf', ir.FunctionType(ir.IntType(32), [ - ir.PointerType(ir.IntType(8)), - ir.IntType(64), - ir.PointerType(ir.IntType(8)) - ], var_arg=True)) - fmt_ptr = Gen.emit_constant("%d", 'string') - Gen.builder.call(snprintf_func, [buf, ir.Constant(ir.IntType(64), 32), fmt_ptr, val]) - return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result") - return ir.Constant(ir.IntType(8).as_pointer(), None) - def _HandleMallocLlvm(self, args: list[ast.expr]) -> ir.Value: Gen: LlvmGeneratorMixin = self.Trans.LlvmGen malloc_type: ir.FunctionType = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)]) diff --git a/lib/core/Handles/HandlesExprCall.py b/lib/core/Handles/HandlesExprCall.py index 3bf7679..f9ce022 100644 --- a/lib/core/Handles/HandlesExprCall.py +++ b/lib/core/Handles/HandlesExprCall.py @@ -481,10 +481,10 @@ class ExprCallHandle(BaseHandle): ) if _p2_cptr: if isinstance(_tg_td, ir.PointerType): - return self._emit_rowptr_cast(Node, Gen, _tg_td) + return self._emit_rawptr_cast(Node, Gen, _tg_td) _tg_ptr_td: ir.Type = ir.PointerType(_tg_td) - return self._emit_rowptr_cast(Node, Gen, _tg_ptr_td) - return self._emit_rowptr_cast(Node, Gen, _tg_td) + return self._emit_rawptr_cast(Node, Gen, _tg_ptr_td) + return self._emit_rawptr_cast(Node, Gen, _tg_td) except Exception: pass raise Exception(f"Undefined function: '{FuncName}'") @@ -492,7 +492,7 @@ class ExprCallHandle(BaseHandle): # Handle list[int](mb) syntax — generic class constructor with explicit type args # Handle xxx[T](x) syntax — generic function call with explicit type args sub: ast.Subscript = Node.func - # (rowptr[X])(expr) / (t.CPtr[X])(expr):内建裸指针转换(无泛型模板)。 + # (rawptr[X])(expr) / (t.CPtr[X])(expr):内建裸指针转换(无泛型模板)。 # 不拦截 → 泛型模板查不到 → 落 L850 "Unsupported call expression" # (StubMergerCollect.vp L271 bootstrap 根因)。 _sub_nm: str | None = None @@ -500,7 +500,7 @@ class ExprCallHandle(BaseHandle): _sub_nm = sub.value.id elif isinstance(sub.value, ast.Attribute) and isinstance(sub.value.value, ast.Name) and sub.value.value.id == 't' and sub.value.attr == 'CPtr': _sub_nm = 't.CPtr' - if _sub_nm in ('rowptr', 't.CPtr'): + if _sub_nm in ('rawptr', 't.CPtr'): return self._HandleSubscriptPtrCastLlvm(Node, sub) if isinstance(sub.value, ast.Name): FuncName: str = sub.value.id @@ -1990,11 +1990,11 @@ class ExprCallHandle(BaseHandle): return ArgVal def _HandleSubscriptPtrCastLlvm(self, Node: ast.Call, sub: ast.Subscript) -> ir.Value: - """(rowptr[X])(expr) / (t.CPtr[X])(expr) 内建指针转换:expr → X* + """(rawptr[X])(expr) / (t.CPtr[X])(expr) 内建指针转换:expr → X* - rowptr 是编译器内建裸指针语法(无 SymbolTable typedef 条目、无泛型模板), + rawptr 是编译器内建裸指针语法(无 SymbolTable typedef 条目、无泛型模板), 此前 Subscript 调用仅查泛型模板 → 落空后报 "Unsupported call expression" - (StubMergerCollect.vp `(rowptr[FileEntry])(t.CVoid(...))` bootstrap 根因)。 + (StubMergerCollect.vp `(rawptr[FileEntry])(t.CVoid(...))` bootstrap 根因)。 目标类型经 TypeMergeHandler.GetCTypeInfo 解析 Subscript 类型节点获得。 """ Gen: LlvmGeneratorMixin = self.Trans.LlvmGen @@ -2006,7 +2006,7 @@ class ExprCallHandle(BaseHandle): except Exception: TargetType = None if TargetType is None or isinstance(TargetType, ir.VoidType): - # 回退:rowptr[X] 语义 = X*(X 为已注册 struct/类,可能模块限定名) + # 回退:rawptr[X] 语义 = X*(X 为已注册 struct/类,可能模块限定名) s_name: str | None = None _sl = getattr(sub, 'slice', None) if isinstance(_sl, ast.Attribute): @@ -2017,9 +2017,9 @@ class ExprCallHandle(BaseHandle): TargetType = ir.PointerType(Gen.structs[s_name]) else: TargetType = ir.PointerType(ir.IntType(8)) - return self._emit_rowptr_cast(Node, Gen, TargetType) + return self._emit_rawptr_cast(Node, Gen, TargetType) - def _emit_rowptr_cast(self, Node: ast.Call, Gen: LlvmGeneratorMixin, TargetType: ir.Type) -> ir.Value: + def _emit_rawptr_cast(self, Node: ast.Call, Gen: LlvmGeneratorMixin, TargetType: ir.Type) -> ir.Value: """按 _HandleTypedefCastLlvm 的指针语义执行 bitcast/inttoptr 转换""" if not Node.args: if isinstance(TargetType, ir.PointerType): @@ -2040,15 +2040,15 @@ class ExprCallHandle(BaseHandle): return ArgVal if isinstance(TargetType, ir.PointerType): if isinstance(ArgVal.type, ir.PointerType): - return Gen.builder.bitcast(ArgVal, TargetType, name="bitcast_rowptr_cast") + return Gen.builder.bitcast(ArgVal, TargetType, name="bitcast_rawptr_cast") if isinstance(ArgVal.type, ir.IntType): - return Gen.builder.inttoptr(ArgVal, TargetType, name="inttoptr_rowptr_cast") + return Gen.builder.inttoptr(ArgVal, TargetType, name="inttoptr_rawptr_cast") if isinstance(ArgVal.type, ir.BaseStructType): - alloca = Gen.builder.alloca(ArgVal.type, name="struct_alloca_rowptr") + alloca = Gen.builder.alloca(ArgVal.type, name="struct_alloca_rawptr") Gen.builder.store(ArgVal, alloca, align=8) - return Gen.builder.bitcast(alloca, TargetType, name="bitcast_struct_rowptr") + return Gen.builder.bitcast(alloca, TargetType, name="bitcast_struct_rawptr") if isinstance(TargetType, ir.IntType) and isinstance(ArgVal.type, ir.PointerType): - return Gen.builder.ptrtoint(ArgVal, TargetType, name="ptrtoint_rowptr_cast") + return Gen.builder.ptrtoint(ArgVal, TargetType, name="ptrtoint_rawptr_cast") return ArgVal def _HandleInlineExpandLlvm(self, Node: ast.Call, sym_info: CTypeInfo) -> None: @@ -3301,19 +3301,19 @@ class ExprCallHandle(BaseHandle): if func: # 多继承 this 调整:继承方法定义在无 vtable 父类且字段区偏移 > 0 时, # 把 self 定位到父类第一个用户字段在子类中的位置并 bitcast 成父类指针。 - # receiver 为 i8*/泛型指针(CVTable 抽象基类如 ast.AST 无独立 - # struct 类型、联合字段存储为 i8*)时 vtable 槽恒在对象偏移 0: - # bitcast 到 ClassName 的 struct(无则建 opaque 占位)再 GEP, - # 否则 gep(i8) 报 "'IntType' object has no attribute 'gep'"。 - if (isinstance(ObjVal.type, ir.PointerType) - and not isinstance(ObjVal.type.pointee, - (ir.IdentifiedStructType, ir.LiteralStructType))): - _vt_st_rc: ir.Type = Gen.structs.get(ClassName) - if _vt_st_rc is None: - _vt_st_rc = Gen._get_or_create_struct(ClassName) - ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(_vt_st_rc), - name=f"vt_cast_{ClassName}") - self_arg = self._adjust_this_for_inherited_method(Gen, ObjVal, ClassName, method_anc) + # receiver 为 i8*/泛型指针(CVTable 抽象基类如 ast.AST 无独立 + # struct 类型、联合字段存储为 i8*)时 vtable 槽恒在对象偏移 0: + # bitcast 到 ClassName 的 struct(无则建 opaque 占位)再 GEP, + # 否则 gep(i8) 报 "'IntType' object has no attribute 'gep'"。 + if (isinstance(ObjVal.type, ir.PointerType) + and not isinstance(ObjVal.type.pointee, + (ir.IdentifiedStructType, ir.LiteralStructType))): + _vt_st_rc: ir.Type = Gen.structs.get(ClassName) + if _vt_st_rc is None: + _vt_st_rc = Gen._get_or_create_struct(ClassName) + ObjVal = Gen.builder.bitcast(ObjVal, ir.PointerType(_vt_st_rc), + name=f"vt_cast_{ClassName}") + self_arg = self._adjust_this_for_inherited_method(Gen, ObjVal, ClassName, method_anc) VtableSlotPtr = Gen.builder.gep(ObjVal, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), 0)], name=f"vtable_slot_{ClassName}") VtablePtr = Gen._load(VtableSlotPtr, name=f"vtable_ptr_{ClassName}") VtableArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods)) @@ -4110,20 +4110,6 @@ class ExprCallHandle(BaseHandle): return Gen.builder.gep(char_ptr, [ir.Constant(ir.IntType(32), 0)], name="chr_result") return ir.Constant(ir.IntType(8).as_pointer(), None) - def _EmitStringFromValue(self, val: ir.Value) -> ir.Value: - Gen = self.Trans.LlvmGen - if isinstance(val.type, ir.IntType): - buf = Gen._alloca(ir.IntType(8), name="str_buf", size=ir.Constant(ir.IntType(32), 32)) - snprintf_func = Gen.get_or_declare_c_func('snprintf', ir.FunctionType(ir.IntType(32), [ - ir.PointerType(ir.IntType(8)), - ir.IntType(32), - ir.PointerType(ir.IntType(8)) - ])) - fmt_ptr = Gen.emit_constant("%d", 'string') - Gen.builder.call(snprintf_func, [buf, ir.Constant(ir.IntType(32), 32), fmt_ptr, val]) - return Gen.builder.gep(buf, [ir.Constant(ir.IntType(32), 0)], name="str_result") - return ir.Constant(ir.IntType(8).as_pointer(), None) - def _HandleMallocLlvm(self, args: list[ast.AST]) -> ir.Value: Gen = self.Trans.LlvmGen malloc_type = ir.FunctionType(ir.PointerType(ir.IntType(8)), [ir.IntType(64)]) @@ -4352,7 +4338,7 @@ class ExprCallHandle(BaseHandle): # pointee 不是指针类型(ptr 指向"可容纳该结构体的槽"而非指针槽) # → 整对象拷贝。典型:c.DerefAs(result_ty_ptr, result_ty),其中 # result_ty = LLVMType.Ptr(...) 为 REnum boxed 值,result_ty_ptr - # 因 rowptr[REnum] 被解析成 i32*(LLVMType 首字段 i32)而 pointee + # 因 rawptr[REnum] 被解析成 i32*(LLVMType 首字段 i32)而 pointee # 非结构体,原 pointee-equal 判断失配 → 误落"存储指针值"分支 # (只写 8 字节),导致 REnum tag/字段全部丢失。 # 2) ptr 与 val 指向同一结构体类型(原逻辑)→ 整对象拷贝。 diff --git a/lib/core/Handles/HandlesExprUtils.py b/lib/core/Handles/HandlesExprUtils.py index 713c613..721a1f1 100644 --- a/lib/core/Handles/HandlesExprUtils.py +++ b/lib/core/Handles/HandlesExprUtils.py @@ -58,8 +58,8 @@ class ExprUtils: # 对齐 _HandleLenLlvm L3445-3454:class_member_element_class / # class_members 的键是裸类名,而 var_struct_class 可能带 sha1 前缀 # (如 'd81b22c853de40a2.Call')。直查会 miss → 容器字段 - # (list[...] / rowptr[list[...]],如 ast.Call.args)方法分派失败 - # → "Undefined method 'get' in class 'rowptr'"。剥前缀 + MRO 链查 + # (list[...] / rawptr[list[...]],如 ast.Call.args)方法分派失败 + # → "Undefined method 'get' in class 'rawptr'"。剥前缀 + MRO 链查 # element_class(list 特化名,如 list[...ASTptr])优先。 _bare: str = BaseClass if len(_bare) > 17 and _bare[16] == '.': diff --git a/lib/core/Handles/HandlesFunctions.py b/lib/core/Handles/HandlesFunctions.py index 8869590..98e8701 100644 --- a/lib/core/Handles/HandlesFunctions.py +++ b/lib/core/Handles/HandlesFunctions.py @@ -1709,6 +1709,24 @@ class FunctionHandle(BaseHandle): EntryBlock = func.append_basic_block(name="entry") Gen.builder = Gen._NewIrBuilder(EntryBlock) Gen.func = func + # 函数级 + 语句级 DWARF 调试元数据(--dwarf / --asan 自动开启):建 + # DISubprogram 挂 func.metadata["dbg"],并把本 builder 的默认调试位置设为 + # 入口 DILocation(line/column = 该 def 语句的位置)—— 之后本函数体内每条 + # 新建指令自动带 !dbg,逐语句位置由 Gen._set_node_info 覆盖。这样函数体内 + # 所有 call(对同模块有定义的被调函数)都有合法 !dbg,llc 不再报 + # "inlinable function call in a function with debug info must have a !dbg + # location" 而丢弃整份 DI。declare/extern 在此之前已 return,不会被挂 + # !dbg;未启用时 _GetDebugInfo() 返回 None,不产生任何 IR 差异(零影响)。 + _DbgInfo = Gen._GetDebugInfo() + if _DbgInfo is not None: + try: + _DbgInfo.PushFunction( + Gen.builder, func, getattr(Node, 'lineno', 0) or 0, + getattr(Node, 'col_offset', 0) + 1) + except Exception as _e: + if _config_mode == "strict": + raise + _vlog().warning(f"发射调试元数据失败: {_e}", "Exception") Gen.variables = {} Gen._reg_values = {} Gen.global_vars = set() @@ -1943,22 +1961,6 @@ class FunctionHandle(BaseHandle): except Exception: pass raise - # 函数级 DWARF 调试元数据(--dwarf / --asan 自动开启):为每个 define 建 - # DISubprogram 挂 func.metadata["dbg"],并在入口块第一条指令挂 DILocation - # (line/column = 该 def 语句的位置),使 DWARF 行表至少有一条覆盖函数地址 - # 区间的行。declare/extern 在此之前已 return,不会被挂 !dbg;未启用时 - # _GetDebugInfo() 返回 None,不产生任何 IR 差异(零影响)。 - _DbgInfo = Gen._GetDebugInfo() - if _DbgInfo is not None: - try: - _DbgLoc = _DbgInfo.AttachFunction( - func, getattr(Node, 'lineno', 0) or 0, getattr(Node, 'col_offset', 0) + 1) - if EntryBlock.instructions: - EntryBlock.instructions[0].metadata['dbg'] = _DbgLoc - except Exception as _e: - if _config_mode == "strict": - raise - _vlog().warning(f"发射调试元数据失败: {_e}", "Exception") if not Gen.builder.block.is_terminated: if 'naked' in fn_attrs: Gen.builder.unreachable() @@ -2009,6 +2011,10 @@ class FunctionHandle(BaseHandle): Gen.builder.ret(ir.Constant(ActualReturnType, None)) else: Gen.builder.ret_void() + # 离开函数体:停用本 builder 的默认调试位置(含 SP 绑定),防止遗留状态 + # 被后续模块级指令误用(未启用 --dwarf 时 _DbgInfo 为 None,不做任何事)。 + if _DbgInfo is not None: + _DbgInfo.PopFunction(Gen.builder) Gen.builder = None Gen.func = None Gen._current_class_name = _saved_class_name diff --git a/lib/core/Handles/HandlesImports.py b/lib/core/Handles/HandlesImports.py index c9b71e7..f305f21 100644 --- a/lib/core/Handles/HandlesImports.py +++ b/lib/core/Handles/HandlesImports.py @@ -18,7 +18,7 @@ from lib.core.SymbolUtils import ParseListAnnotation, ExtractTypeNameFromBinOp, # 注解里的存储类 / 限定符标记:这些名字**不是类名**(联合注解里与指针类混写, -# 如 `t.CExtern | rowptr[CompilerFactory]`),提取"指针指向的类"时必须滤掉。 +# 如 `t.CExtern | rawptr[CompilerFactory]`),提取"指针指向的类"时必须滤掉。 _MARKER_ANNOT_NAMES: frozenset[str] = frozenset({ 'CExtern', 'CExport', 'CStatic', 'CInline', 'CConst', 'CVolatile', 'CRegister', 'CAuto', 'CDefine', 'CTypedef', 'CPostdefinition', 'CPtr', 'CArrayPtr', 'CVoid', @@ -590,9 +590,9 @@ class ImportHandle(BaseHandle): HandlesFile = os.path.abspath(inspect.getfile(self.__class__)) TransPyCRoot = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(HandlesFile)))) - FullModulePath = None - # includes 只认项目(project.vpj includes → LibraryPaths)目录,禁止回退仓库硬编码 - # TransPyCRoot/includes:仓库副本缺失时回退会造成声明解析时序错乱(memhub 未注册→i32)。 + FullModulePath = None + # includes 只认项目(project.vpj includes → LibraryPaths)目录,禁止回退仓库硬编码 + # TransPyCRoot/includes:仓库副本缺失时回退会造成声明解析时序错乱(memhub 未注册→i32)。 SearchDirs = list(self.Trans.LibraryPaths) for LibPath in SearchDirs: @@ -857,51 +857,51 @@ class ImportHandle(BaseHandle): if module_name: self._LoadDeclarationsFromStubLlvm(module_name, Gen) - def _AnnotationStructName(self, annotation: ast.AST) -> str | None: - """从注解里提取「指针指向的类」短名(递归,0 判定返回 None) - - 覆盖形态:`X` / `mod.X` / `rowptr[X]` / `t.CPtr[X]` / 联合 `A | B`(两翼都试)。 - 存储类与限定符标记(`t.CExtern` / `t.CExport` / `t.CPtr` 等)不算类名, - 由 `_MARKER_ANNOT_NAMES` 过滤;返回的是**短名**,调用方再解析成 - `Gen.structs` 真实键。 - """ - if annotation is None: - return None - if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): - _left: str | None = self._AnnotationStructName(annotation.left) - if _left: - return _left - return self._AnnotationStructName(annotation.right) - if isinstance(annotation, ast.Subscript): - _base: ast.AST = annotation.value - _bn: str = '' - if isinstance(_base, ast.Name): - _bn = _base.id - elif isinstance(_base, ast.Attribute): - _bn = _base.attr - if _bn in ('rowptr', 'CPtr', 'CArrayPtr'): - _sl: ast.AST = annotation.slice - if hasattr(ast, 'Index') and isinstance(_sl, ast.Index): - _sl = _sl.value - return self._AnnotationStructName(_sl) - return None - if isinstance(annotation, ast.Name): - if annotation.id in _MARKER_ANNOT_NAMES: - return None - return annotation.id - if isinstance(annotation, ast.Attribute): - # `mod.Class`:mod 为 t/c 时是内建标记/内建类型名,不作为类的键 - if isinstance(annotation.value, ast.Name) and annotation.value.id in ('t', 'c'): - return None - if annotation.attr in _MARKER_ANNOT_NAMES: - return None - return annotation.attr - return None - + def _AnnotationStructName(self, annotation: ast.AST) -> str | None: + """从注解里提取「指针指向的类」短名(递归,0 判定返回 None) + + 覆盖形态:`X` / `mod.X` / `rawptr[X]` / `t.CPtr[X]` / 联合 `A | B`(两翼都试)。 + 存储类与限定符标记(`t.CExtern` / `t.CExport` / `t.CPtr` 等)不算类名, + 由 `_MARKER_ANNOT_NAMES` 过滤;返回的是**短名**,调用方再解析成 + `Gen.structs` 真实键。 + """ + if annotation is None: + return None + if isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr): + _left: str | None = self._AnnotationStructName(annotation.left) + if _left: + return _left + return self._AnnotationStructName(annotation.right) + if isinstance(annotation, ast.Subscript): + _base: ast.AST = annotation.value + _bn: str = '' + if isinstance(_base, ast.Name): + _bn = _base.id + elif isinstance(_base, ast.Attribute): + _bn = _base.attr + if _bn in ('rawptr', 'CPtr', 'CArrayPtr'): + _sl: ast.AST = annotation.slice + if hasattr(ast, 'Index') and isinstance(_sl, ast.Index): + _sl = _sl.value + return self._AnnotationStructName(_sl) + return None + if isinstance(annotation, ast.Name): + if annotation.id in _MARKER_ANNOT_NAMES: + return None + return annotation.id + if isinstance(annotation, ast.Attribute): + # `mod.Class`:mod 为 t/c 时是内建标记/内建类型名,不作为类的键 + if isinstance(annotation.value, ast.Name) and annotation.value.id in ('t', 'c'): + return None + if annotation.attr in _MARKER_ANNOT_NAMES: + return None + return annotation.attr + return None + def _ResolveAnnotationStructKey(self, Gen: LlvmGeneratorMixin, name: str) -> str | None: """把注解里的类短名解析为 `Gen.structs` 的真实键(0 命中返回 None) - 三条路径与类字段侧的 `rowptr[裸结构]` 登记保持一致:裸名直查 / + 三条路径与类字段侧的 `rawptr[裸结构]` 登记保持一致:裸名直查 / `class_sha1_map` 加前缀 / 全量短名模糊扫描(跨模块类在 `class_sha1_map` 尚未登记该短名时靠这条兜住)。 """ @@ -928,7 +928,7 @@ class ImportHandle(BaseHandle): is_string_val = False TypeInfo = None # 【跨模块模块级变量的**类登记**】`CTypeInfo.FromNode` 对 - # `X | t.CPtr` / `rowptr[X]` 注解只给出指针占位(rowptr[X] 折叠成 i8*), + # `X | t.CPtr` / `rawptr[X]` 注解只给出指针占位(rawptr[X] 折叠成 i8*), # 且本函数**只算类型、不登记变量类** → 消费侧 `Mod.Var.Field` 链在 # `_get_var_class` 里解析为空:StructGenMixin.vp:139 "属性访问未能解析出 # 目标类型/成员"、CallGenLeafKit.vp:589 / ClassGenVTable.vp:99 误报 @@ -942,8 +942,8 @@ class ImportHandle(BaseHandle): _eg_tk: str | None = self._ResolveAnnotationStructKey(Gen, _eg_tn) if _eg_tk: _eg_cur: str | None = Gen.var_struct_class.get(VarName) - if (not _eg_cur or _eg_cur == 'rowptr' or _eg_cur.endswith('.rowptr') - or _eg_cur.startswith('rowptr[')): + if (not _eg_cur or _eg_cur == 'rawptr' or _eg_cur.endswith('.rawptr') + or _eg_cur.startswith('rawptr[')): Gen.var_struct_class[VarName] = _eg_tk if getattr(Gen, 'global_struct_class', None) is not None: Gen.global_struct_class[VarName] = _eg_tk @@ -1521,85 +1521,85 @@ class ImportHandle(BaseHandle): if ReexportName2 not in Gen.functions: Gen.functions[ReexportName2] = func - def _ClassifyExternalClass(self, Node: ast.ClassDef) -> tuple: - """遍历 Node.bases/decorator_list 做类别判断(纯函数、与 Gen 无关)。 - - 结果由 _EmitExternalClassDeclLlvm 按 (source_sha1, class_name) 类级缓存, - 同一 worker 进程内多个任务对同一跨模块类重复调用时跳过本遍历。 - 返回 (IsGenericClass, IsCenum, IsRenum, IsCpythonObject, IsCVTable, - IsNoVTable, IsPacked)。 - - PEP 695 泛型类(如 GSListNode[T])特殊:跨模块继承展平需要从泛型基类 - 获取字段(如 Next),否则子类(如 Value(GSListNode[Value]))的 - class_members 会缺少继承字段;但泛型类的方法声明必须跳过(方法参数 - 类型 T 会被解析为 opaque struct,LLVM 不允许 opaque struct 作为值参数)。 - """ - IsGenericClass: bool = hasattr(Node, 'type_params') and bool(Node.type_params) - IsCenum = False - IsRenum = False - IsCpythonObject = False - IsCVTable = False - IsNoVTable = False - if Node.bases: - for base in Node.bases: - if getattr(base, 'attr', None): - if base.attr == 'REnum': - IsRenum = True - break - elif base.attr == 'CEnum' or base.attr == 'Enum': - IsCenum = True - break - elif getattr(base, 'id', None): - if base.id == 'REnum': - IsRenum = True - break - elif base.id == 'CEnum' or base.id == 'Enum': - IsCenum = True - break - if not IsCenum and not IsRenum and getattr(Node, 'decorator_list', None): - for decorator in Node.decorator_list: - if isinstance(decorator, ast.Attribute): - if getattr(decorator.value, 'id', None) == 't': - if decorator.attr == 'Object': - IsCpythonObject = True - elif decorator.attr == 'CVTable': - IsCVTable = True - elif decorator.attr == 'NoVTable': - IsNoVTable = True - elif decorator.attr == 'REnum': - IsRenum = True - elif decorator.attr == 'CEnum' or decorator.attr == 'Enum': - IsCenum = True - elif isinstance(decorator, ast.Call): - if isinstance(decorator.func, ast.Attribute): - if getattr(decorator.func.value, 'id', None) == 't': - if decorator.func.attr == 'Object': - IsCpythonObject = True - elif decorator.func.attr == 'CVTable': - IsCVTable = True - elif decorator.func.attr == 'NoVTable': - IsNoVTable = True - elif isinstance(decorator.func, ast.Name): - if decorator.func.id == 'Object': - IsCpythonObject = True - elif decorator.func.id == 'CVTable': - IsCVTable = True - elif decorator.func.id == 'NoVTable': - IsNoVTable = True - IsPacked = False - if getattr(Node, 'decorator_list', None): - for decorator in Node.decorator_list: - if isinstance(decorator, ast.Call): - if isinstance(decorator.func, ast.Attribute): - if getattr(decorator.func.value, 'id', None) == 'c' and decorator.func.attr == 'Attribute': - for arg in decorator.args: - if isinstance(arg, ast.Attribute): - if isinstance(arg.value, ast.Attribute): - if getattr(arg.value.value, 'id', None) == 't' and arg.value.attr == 'attr' and arg.attr == 'packed': - IsPacked = True - return (IsGenericClass, IsCenum, IsRenum, IsCpythonObject, - IsCVTable, IsNoVTable, IsPacked) - + def _ClassifyExternalClass(self, Node: ast.ClassDef) -> tuple: + """遍历 Node.bases/decorator_list 做类别判断(纯函数、与 Gen 无关)。 + + 结果由 _EmitExternalClassDeclLlvm 按 (source_sha1, class_name) 类级缓存, + 同一 worker 进程内多个任务对同一跨模块类重复调用时跳过本遍历。 + 返回 (IsGenericClass, IsCenum, IsRenum, IsCpythonObject, IsCVTable, + IsNoVTable, IsPacked)。 + + PEP 695 泛型类(如 GSListNode[T])特殊:跨模块继承展平需要从泛型基类 + 获取字段(如 Next),否则子类(如 Value(GSListNode[Value]))的 + class_members 会缺少继承字段;但泛型类的方法声明必须跳过(方法参数 + 类型 T 会被解析为 opaque struct,LLVM 不允许 opaque struct 作为值参数)。 + """ + IsGenericClass: bool = hasattr(Node, 'type_params') and bool(Node.type_params) + IsCenum = False + IsRenum = False + IsCpythonObject = False + IsCVTable = False + IsNoVTable = False + if Node.bases: + for base in Node.bases: + if getattr(base, 'attr', None): + if base.attr == 'REnum': + IsRenum = True + break + elif base.attr == 'CEnum' or base.attr == 'Enum': + IsCenum = True + break + elif getattr(base, 'id', None): + if base.id == 'REnum': + IsRenum = True + break + elif base.id == 'CEnum' or base.id == 'Enum': + IsCenum = True + break + if not IsCenum and not IsRenum and getattr(Node, 'decorator_list', None): + for decorator in Node.decorator_list: + if isinstance(decorator, ast.Attribute): + if getattr(decorator.value, 'id', None) == 't': + if decorator.attr == 'Object': + IsCpythonObject = True + elif decorator.attr == 'CVTable': + IsCVTable = True + elif decorator.attr == 'NoVTable': + IsNoVTable = True + elif decorator.attr == 'REnum': + IsRenum = True + elif decorator.attr == 'CEnum' or decorator.attr == 'Enum': + IsCenum = True + elif isinstance(decorator, ast.Call): + if isinstance(decorator.func, ast.Attribute): + if getattr(decorator.func.value, 'id', None) == 't': + if decorator.func.attr == 'Object': + IsCpythonObject = True + elif decorator.func.attr == 'CVTable': + IsCVTable = True + elif decorator.func.attr == 'NoVTable': + IsNoVTable = True + elif isinstance(decorator.func, ast.Name): + if decorator.func.id == 'Object': + IsCpythonObject = True + elif decorator.func.id == 'CVTable': + IsCVTable = True + elif decorator.func.id == 'NoVTable': + IsNoVTable = True + IsPacked = False + if getattr(Node, 'decorator_list', None): + for decorator in Node.decorator_list: + if isinstance(decorator, ast.Call): + if isinstance(decorator.func, ast.Attribute): + if getattr(decorator.func.value, 'id', None) == 'c' and decorator.func.attr == 'Attribute': + for arg in decorator.args: + if isinstance(arg, ast.Attribute): + if isinstance(arg.value, ast.Attribute): + if getattr(arg.value.value, 'id', None) == 't' and arg.value.attr == 'attr' and arg.attr == 'packed': + IsPacked = True + return (IsGenericClass, IsCenum, IsRenum, IsCpythonObject, + IsCVTable, IsNoVTable, IsPacked) + def _EmitExternalClassDeclLlvm(self, Node: ast.ClassDef, Gen: LlvmGeneratorMixin, module_name: str | None = None, actual_module_name: str | None = None, source_sha1: str | None = None) -> None: ClassName = Node.name # Compute source_sha1 up front (moved from mid-function) so it can serve as @@ -1900,10 +1900,10 @@ class ImportHandle(BaseHandle): if ClassName not in Gen.class_member_element_class: Gen.class_member_element_class[ClassName] = {} Gen.class_member_element_class[ClassName][VarName] = spec_in_anno - # Subscript 容器字段(list[X] / rowptr[list[X]],如 includes/ast - # 的 Call.args / Import.names: rowptr[list[rowptr[AST]]]):非 BinOp + # Subscript 容器字段(list[X] / rawptr[list[X]],如 includes/ast + # 的 Call.args / Import.names: rawptr[list[rawptr[AST]]]):非 BinOp # 联合,上面两分支不命中 → 容器身份丢失 → 字段方法调用(get/len…) - # 分派失败报 "Undefined method 'get' in class 'rowptr'"(Converter.vp)。 + # 分派失败报 "Undefined method 'get' in class 'rawptr'"(Converter.vp)。 # 用与特化生成端同源的 _resolve_type_arg_str 构造 element_class, # 键名与 Gen.structs 中 list 特化名保持一致。 if isinstance(item.annotation, ast.Subscript): @@ -1913,13 +1913,13 @@ class ImportHandle(BaseHandle): _elem_slice_s: ast.AST | None = None if _subname_s == 'list': _elem_slice_s = _ann_sub_s.slice - elif _subname_s == 'rowptr': + elif _subname_s == 'rawptr': _slice_s: ast.AST = _ann_sub_s.slice if isinstance(_slice_s, ast.Subscript): - # rowptr[泛型容器](rowptr[list[X]] / rowptr[GSList[Param]]): + # rawptr[泛型容器](rawptr[list[X]] / rawptr[GSList[Param]]): # 容器身份 = 泛型特化名。list 继续走 _elem_slice_s 统一登记; # 其余泛型容器直接登记 element_class(阻塞 B 根因链一环: - # 原实现只认内层 list,rowptr[GSList[Param]] 在此空转并跳过 + # 原实现只认内层 list,rawptr[GSList[Param]] 在此空转并跳过 # 裸结构分支 → element_class 缺失 → 字段/局部变量方法分派 # 丢失容器身份,FakeDuck 错绑 LinkedNode.append 写穿)。 _inner_sub_s: ast.Subscript = _slice_s @@ -1938,11 +1938,11 @@ class ImportHandle(BaseHandle): Gen.class_member_element_class[ClassName] = {} Gen.class_member_element_class[ClassName][VarName] = _ec_gs else: - # rowptr[裸结构](如 rowptr[Token]):跨模块 stub 会把自引用/类内 + # rawptr[裸结构](如 rawptr[Token]):跨模块 stub 会把自引用/类内 # 指针字段退化为 i8*,链式成员访问(a.b.c)需 element_class 恢复 # struct 身份走 char*→struct cast。HEAD 态 `Token | t.CPtr` 联合 - # 由上方 BinOp 分支登记;rowptr 重构后此分支补齐(阻塞 A 根因)。 - # 与 HandlesClassDef 的 rowptr 分支对称。 + # 由上方 BinOp 分支登记;rawptr 重构后此分支补齐(阻塞 A 根因)。 + # 与 HandlesClassDef 的 rawptr 分支对称。 _slc_name_s: str | None = None if isinstance(_slice_s, ast.Name): _slc_name_s = _slice_s.id @@ -1959,7 +1959,7 @@ class ImportHandle(BaseHandle): else: # 短名模糊扫描(对齐 HandlesAnnAssign 变量侧 # 补偿 L597-602):跨模块 `mod.Class` 形态的 - # rowptr[Class] 字段在 class_sha1_map 尚无该短名 + # rawptr[Class] 字段在 class_sha1_map 尚无该短名 # 时上面两路全 miss → element_class 静默缺失 → # 字段方法调用(factory.PermPool.alloc)链尾类名 # 丢失 → TPC 调用分派返回 i32 0 哨兵 → 误报 diff --git a/lib/core/Handles/HandlesTypeMerge.py b/lib/core/Handles/HandlesTypeMerge.py index e72e70b..21e8965 100644 --- a/lib/core/Handles/HandlesTypeMerge.py +++ b/lib/core/Handles/HandlesTypeMerge.py @@ -121,7 +121,7 @@ class HandlesTypeMerge(BaseHandle): Result.PtrCount = 1 # struct 变量默认为指针 return Result # [builtins 最后匹配] 常规路径全部 miss 后查 includes/builtins.vp 的 - # CTypedef(size_t → t.CSizeT、rowptr → t.CPtr 内置等),对齐 + # CTypedef(size_t → t.CSizeT、rawptr → t.CPtr 内置等),对齐 # TypeAnnotationResolver._from_node_name 兜底,避免裸名被误判为 # 命名结构体(main2.vp `a: size_t` → alloca %...size_t 根因)。 try: @@ -695,13 +695,13 @@ class HandlesTypeMerge(BaseHandle): if hasattr(self.Trans, 'ExprCallHandle') and self.Trans.ExprCallHandle is not None: self.Trans.ExprCallHandle._ResolveGenericSlice(node) else: - # [修复-阻塞B] rowptr 包裹泛型特化(rowptr[GSList[Param]]): + # [修复-阻塞B] rawptr 包裹泛型特化(rawptr[GSList[Param]]): # slice 是 Subscript 且内层 base 命中泛型模板时,若委托 TAR, # 内层 GSList[Param] 会被折叠成 i8* → declare_only 特化从不触发、 # 变量/字段容器身份丢失 → 方法调用 FakeDuck 兜底错绑兄弟类 # (LinkedNode.append 48B 语义写穿 24B GSList)。此处按裸泛型 - # 特化(GSList[Param])同语义解析:PtrCount=1(rowptr 与裸名 - # 同为 1 层指针,对齐 element_class 侧 rowptr[list[X]]==list[X] + # 特化(GSList[Param])同语义解析:PtrCount=1(rawptr 与裸名 + # 同为 1 层指针,对齐 element_class 侧 rawptr[list[X]]==list[X] # 约定),并触发 declare_only 特化(struct + sha1 注册;方法体 # 由方法调用时 _try_complete_generic_specialization 补发)。 _inner_gsub: ast.Subscript | None = None @@ -727,9 +727,9 @@ class HandlesTypeMerge(BaseHandle): self.Trans.ExprCallHandle._ResolveGenericSlice(_inner_gsub) return ResultInfo # [builtins 最后匹配] base 为 builtins 指针 typedef - # (rowptr → t.CPtr):rowptr[X] 等价 X*(对齐 TPV + # (rawptr → t.CPtr):rawptr[X] 等价 X*(对齐 TPV # Subscript 语义),委托 TypeAnnotationResolver 统一解析, - # 避免被误当作 'rowptr[X]' 结构体/数组维度处理。 + # 避免被误当作 'rawptr[X]' 结构体/数组维度处理。 try: from lib.core.TypeAnnotationResolver import TypeAnnotationResolver as _TAR _tar_sub: CTypeInfo = _TAR.from_node(node, self.Trans.SymbolTable) diff --git a/lib/core/LLVMCG/BaseGen.py b/lib/core/LLVMCG/BaseGen.py index 8405a20..584ad50 100644 --- a/lib/core/LLVMCG/BaseGen.py +++ b/lib/core/LLVMCG/BaseGen.py @@ -580,6 +580,18 @@ class BaseGenMixin: self._current_node_info = f"line {self._current_lineno}" if extra_info: self._current_node_info += f" ({extra_info})" + # 语句/指令级 DWARF 位置(--dwarf / --asan):每进入一条语句就把当前 + # builder 的默认调试位置切到该 AST 节点的行/列(col_offset 是 0-based, + # +1 转 1-based;无位置时为 0 → 回退函数入口 DILocation)。此后该语句生成 + # 的所有指令(含 call)自动带本函数 scope 的 !dbg,llc 不再因缺 !dbg 丢弃 + # 整份 DI。未启用时 dwarf_enabled=False,一次都不触碰 builder.debug_metadata + # (零影响:_GetDebugInfo() 也不会被调用)。 + if self.dwarf_enabled and self.builder is not None: + _DbgInfo = self._GetDebugInfo() + if _DbgInfo is not None: + _DbgInfo.SetStatement( + self.builder, self._current_lineno, + getattr(node, 'col_offset', -1) + 1) def _set_source_info(self, filepath: str) -> None: self._current_source_file = filepath diff --git a/lib/core/LLVMCG/DebugInfo.py b/lib/core/LLVMCG/DebugInfo.py index bf14710..484de97 100644 --- a/lib/core/LLVMCG/DebugInfo.py +++ b/lib/core/LLVMCG/DebugInfo.py @@ -7,10 +7,11 @@ class DebugInfoEmitter: """函数级 DWARF 调试元数据发射器(llvmlite 文本 IR)。 每个 Module 一份 DICompileUnit + DIFile;每个 define 一份 DISubprogram - (is_distinct=True)挂在 func.metadata["dbg"] 上;函数入口第一条指令挂 - DILocation(line=该函数 def 行,column=该行 col),使 LLVM 行表至少有一条 - 覆盖函数地址区间的行 —— ASan / llvm-symbolizer 反查函数内任意地址即可得到 - ".vp:函数起始行"。 + (is_distinct=True)挂在 func.metadata["dbg"] 上;函数体发射期间把 builder 的 + 默认调试位置设为 "当前函数 SP + 当前语句行/列" 的 DILocation,于是每条新建 + 指令(含所有 call)都自动带本函数 scope 的 !dbg —— 既有语句级粒度,又保证 + llc 的 "inlinable function call ... must have a !dbg location" 校验通过、 + 不丢弃 DI。没有语句上下文时回退到函数入口位置(line=def 行、column=def 列)。 仅在 --dwarf(或 --asan 自动开启)时被实例化;把 Module 落成 .ll 文本之前 必须调用 Finalize() 补模块级 !llvm.dbg.cu 与 !llvm.module.flags @@ -83,6 +84,88 @@ class DebugInfoEmitter: "scope": sp, }) + # ---------- 语句/指令级位置:按 Builder 上下文管理当前 DILocation ---------- + # + # llvmlite 的 IRBuilder 支持"预设调试位置自动挂载":IRBuilder._insert 里 + # `if self.debug_metadata is not None and 'dbg' not in instr.metadata: + # instr.metadata['dbg'] = self.debug_metadata` + # 即设置 builder.debug_metadata 之后,该 builder 新建的每条指令都会自动带 + # `!dbg !N`。函数带 DISubprogram 时 llc 要求函数体内每个 call(对同模块有 + # 定义的被调函数)都有 !dbg,否则报 + # inlinable function call in a function with debug info must have a !dbg + # warning: ignoring invalid debug info in + # 并丢弃整份 DI(llvm-dwarfdump 拿不到行表)。 + # + # 当前 SP/入口位置直接存放在 IRBuilder 对象上(_TpcDbgSp / _TpcDbgEntry), + # 而不是发射器自身:builder 是"每函数一个"的(见 LlvmCodeGenerator. + # _NewIrBuilder 的唯一调用点 _EmitFunctionLlvm,且已有 body 的函数被 + # existing_blocks 守卫提前返回),因此 + # * 嵌套/特化函数发射会临时换 builder,恢复后自动回到外层函数的 SP, + # 不会把 scope 指向别的函数; + # * 新函数 = 新 builder = debug_metadata 默认 None,天然不跨函数/模块残留, + # 也无需在函数结束时强制清理(PopFunction 只是显式停用,防误用)。 + + def PushFunction(self, Builder: ir.IRBuilder, func: ir.Function, + Line: int, Column: int) -> ir.DIValue: + """进入函数体:建 DISubprogram(func.metadata["dbg"])并把 Builder 的 + 默认调试位置设为入口 DILocation(line=def 行、column=def 列)。 + + 返回入口 DILocation。此后该 Builder 新建的每条指令都自动带该位置,直到 + SetStatement 覆盖 —— 保证函数体内所有 call 至少有合法 !dbg(llc 不再 + 因缺 !dbg 丢弃 DI)。 + """ + Entry: ir.DIValue = self.AttachFunction(func, Line, Column) + Builder._TpcDbgSp = func.metadata["dbg"] + Builder._TpcDbgEntry = Entry + Builder.debug_metadata = Entry + return Entry + + def SetStatement(self, Builder: ir.IRBuilder, Line: int, Column: int) -> None: + """把 Builder 的默认调试位置切到(Line, Column)。 + + 该语句之后新建的指令都带这个位置(scope 恒为当前函数 SP)。未 PushFunction + 过的 Builder(无 DI 的函数、模块级代码、lambda/async 自建 builder)不做 + 任何事 —— 这些函数没有 DISubprogram,llc 不要求 !dbg,也绝不改动 + builder.debug_metadata 的默认值。Line<=0(AST 无位置)回退到 + CurrentOrEntry()。 + """ + Sp: ir.DIValue | None = getattr(Builder, '_TpcDbgSp', None) + if Sp is None: + return + if Line <= 0: + Builder.debug_metadata = self.CurrentOrEntry(Builder) + return + Builder.debug_metadata = self.Module.add_debug_info("DILocation", { + "line": Line, + "column": Column if Column > 0 else 1, + "scope": Sp, + }) + + def CurrentOrEntry(self, Builder: ir.IRBuilder) -> ir.DIValue | None: + """当前默认位置;尚未设置过语句位置时回退到函数入口 DILocation。 + + (add_debug_info 自带 (kind, operands) 缓存,同 (SP, 行, 列) 复用同一 + DILocation 节点,不会因逐语句调用撑大元数据。) + """ + Current: ir.DIValue | None = getattr(Builder, 'debug_metadata', None) + if Current is not None: + return Current + return getattr(Builder, '_TpcDbgEntry', None) + + def Clear(self, Builder: ir.IRBuilder) -> None: + """停用该 Builder 的默认调试位置(debug_metadata 置回 None)。""" + Builder.debug_metadata = None + + def PopFunction(self, Builder: ir.IRBuilder) -> None: + """离开函数体:停用默认位置并作废该 Builder 的 SP 绑定。 + + Builder 随后被丢弃(或由调用方恢复为外层函数的 builder),SP 上下文不会 + 跨函数残留。 + """ + self.Clear(Builder) + Builder._TpcDbgSp = None + Builder._TpcDbgEntry = None + def Finalize(self) -> None: """落 .ll 文本之前补模块级 named metadata;无任何函数时不做(no-op)。""" if self.Finalized or self._CompileUnit is None: diff --git a/lib/core/LLVMCG/FuncGen.py b/lib/core/LLVMCG/FuncGen.py index 3154d29..e1c83ec 100644 --- a/lib/core/LLVMCG/FuncGen.py +++ b/lib/core/LLVMCG/FuncGen.py @@ -251,12 +251,12 @@ class FuncGenMixin: # 查表全部 miss 返回 None → _gep_and_Load_member 静默返回 None → # AnnAssign InitValue 为 None → 变量 alloca 未初始化 → 运行期读垃圾指针。 ClassName = self._extract_short_name(ClassName) - # rowptr[X] / t.CPtr[X] 指针包装归一:rowptr[X] 是内建裸指针类型 - # (X*),非真实类——接收者注解/类型名为 'rowptr[AST]' 时字段访问 + # rawptr[X] / t.CPtr[X] 指针包装归一:rawptr[X] 是内建裸指针类型 + # (X*),非真实类——接收者注解/类型名为 'rawptr[AST]' 时字段访问 # (child.parent)应作用于内层 struct X,否则查 class_members 全 miss - # → fast-fail "属性 'parent' 在类 'rowptr[AST]' 中找不到(struct=opaque)" + # → fast-fail "属性 'parent' 在类 'rawptr[AST]' 中找不到(struct=opaque)" # (includes/ast/base.vp _set_parent_list bootstrap 根因)。 - if ClassName.startswith('rowptr[') or ClassName.startswith('t.CPtr['): + if ClassName.startswith('rawptr[') or ClassName.startswith('t.CPtr['): _lb_rc: int = ClassName.find('[') if ClassName.endswith(']') and _lb_rc > 0: _inner_rc: str = ClassName[_lb_rc + 1:-1].strip() diff --git a/lib/core/LLVMCG/IRMetadataFix.py b/lib/core/LLVMCG/IRMetadataFix.py index 68d5cb7..4276567 100644 --- a/lib/core/LLVMCG/IRMetadataFix.py +++ b/lib/core/LLVMCG/IRMetadataFix.py @@ -180,12 +180,22 @@ def SanitizeIRMetadata(text: str) -> str: BlockIsIdentity.append(Identity) # 4) 改写全文引用(定义体右值、define/指令行的 !dbg、命名元数据列表) + # 定义行左侧的 id 是上一步刚分配的新编号,绝不能再当引用改写:本块的 + # 新编号区间可能与它自己的旧局部编号区间重叠(例如新编号恰好也是本块 + # 旧 id 843 → Mapping[843]=1686),一旦改写左侧就会出现两个定义共用同一 + # id,opt/llc 随即报 "Metadata id is already used"(本 bug 实测残留 276 个 + # 重复 id)。故定义行只改写 '=' 之后的右值。 for k in range(LineCount): Index: int = Owner[k] if Index < 0 or BlockIsIdentity[Index] or not BlockMaps[Index]: continue - Fixed: str = _RewriteReferences(Lines[k], BlockMaps[Index]) - if Fixed != Lines[k]: + Line: str = Lines[k] + Head: re.Match | None = _Definition.match(Line) + if Head: + Fixed: str = Line[:Head.end()] + _RewriteReferences(Line[Head.end():], BlockMaps[Index]) + else: + Fixed = _RewriteReferences(Line, BlockMaps[Index]) + if Fixed != Line: Lines[k] = Fixed # 5) 定义体索引(新 id -> 右值文本),供命名元数据判重 diff --git a/lib/core/SymbolExtractor.py b/lib/core/SymbolExtractor.py index c73a022..6e80042 100644 --- a/lib/core/SymbolExtractor.py +++ b/lib/core/SymbolExtractor.py @@ -277,9 +277,9 @@ class ASTSymbolExtractor: value_node=node.value, )) else: - # rowptr 是编译器内置语法(TPC/TPV 双端),不可重定义: - # 忽略任何对 rowptr 的 typedef 声明,防止覆盖内置裸指针语义 - if var_name == 'rowptr': + # rawptr 是编译器内置语法(TPC/TPV 双端),不可重定义: + # 忽略任何对 rawptr 的 typedef 声明,防止覆盖内置裸指针语义 + if var_name == 'rawptr': return result.typedefs.append(TypedefSymbolData( name=var_name, diff --git a/lib/core/TypeAnnotationResolver.py b/lib/core/TypeAnnotationResolver.py index 6f83771..a239610 100644 --- a/lib/core/TypeAnnotationResolver.py +++ b/lib/core/TypeAnnotationResolver.py @@ -18,15 +18,15 @@ if TYPE_CHECKING: class TypeAnnotationResolver: """从 AST 节点解析类型注解,独立于 CTypeInfo 数据模型。""" - # 编译器内置语法:rowptr(TPC/TPV 双端内置,不可重定义) - # rowptr[T] 固定表示"裸指针,指向原始类型 T"(等价 t.CPtr[T]); - # 单独 rowptr 等价 t.CPtr(void*)。 - _BUILTIN_ROWPTR_NAME: str = 'rowptr' + # 编译器内置语法:rawptr(TPC/TPV 双端内置,不可重定义) + # rawptr[T] 固定表示"裸指针,指向原始类型 T"(等价 t.CPtr[T]); + # 单独 rawptr 等价 t.CPtr(void*)。 + _BUILTIN_ROWPTR_NAME: str = 'rawptr' _BUILTIN_ROWPTR_VALUE: str = 't.CPtr' @classmethod - def _builtin_rowptr_info(cls) -> CTypeInfo: - """返回内置 rowptr 的 CTypeInfo(t.CPtr 语义:BaseType=CVoid, PtrCount=1)""" + def _builtin_rawptr_info(cls) -> CTypeInfo: + """返回内置 rawptr 的 CTypeInfo(t.CPtr 语义:BaseType=CVoid, PtrCount=1)""" info: CTypeInfo = CTypeInfo() info.BaseType = t.CVoid() info.PtrCount = 1 @@ -97,7 +97,7 @@ class TypeAnnotationResolver: # ============================================================ # builtins 最后匹配(对齐 TPV TypeGenResolve._lookup_builtins_typedef): # 所有常规注解解析路径 miss 后,扫描 includes/builtins.vp 的 - # "NAME: t.CTypedef = TYPE" 声明作为最终兜底(rowptr/size_t 等)。 + # "NAME: t.CTypedef = TYPE" 声明作为最终兜底(rawptr/size_t 等)。 # builtins 始终纳入编译链但不在 App 文件 import 闭包,其 typedef 不随 # from_imports 注入,故需按源文件扫描兜底。 # ============================================================ @@ -259,11 +259,11 @@ class TypeAnnotationResolver: @classmethod def builtins_typedef_value(cls, TypeName: str) -> str | None: - """返回 builtins.vp 中 CTypedef 声明的原始类型值(如 rowptr → 't.CPtr') + """返回 builtins.vp 中 CTypedef 声明的原始类型值(如 rawptr → 't.CPtr') 供 stub 生成 / 类型字符串消费端判断"base[arg]"下标是否为 builtins 指针 - typedef(rowptr[AST] → AST*),防止字符串化产物被误建为 phantom 结构体。 - rowptr 已内置于编译器(语法保留字):即使 builtins.vp 不再声明、 + typedef(rawptr[AST] → AST*),防止字符串化产物被误建为 phantom 结构体。 + rawptr 已内置于编译器(语法保留字):即使 builtins.vp 不再声明、 或用户自行 typedef,也始终返回内置值(不可重定义)。 """ if not TypeName: @@ -279,12 +279,12 @@ class TypeAnnotationResolver: 命中(该名字确为 builtins typedef)返回解析出的 CTypeInfo, miss 返回 None(交由调用方走原有兜底)。 - rowptr 为编译器内置语法:优先于一切外部声明(不可重定义)。 + rawptr 为编译器内置语法:优先于一切外部声明(不可重定义)。 """ if not TypeName: return None if TypeName == cls._BUILTIN_ROWPTR_NAME: - return cls._builtin_rowptr_info() + return cls._builtin_rawptr_info() data: dict = cls._scan_builtins() type_str: str | None = data['typedefs'].get(TypeName) if type_str is None: @@ -301,10 +301,10 @@ class TypeAnnotationResolver: def _from_node_name(Node: ast.Name, SymbolTable: dict | SymbolTable) -> CTypeInfo: """处理 ast.Name 节点""" TypeName: str = Node.id - # 编译器内置语法 rowptr(不可重定义):单独 rowptr 等价 t.CPtr(void*), + # 编译器内置语法 rawptr(不可重定义):单独 rawptr 等价 t.CPtr(void*), # 优先于 SymbolTable/任何 typedef 声明。 if TypeName == TypeAnnotationResolver._BUILTIN_ROWPTR_NAME: - return TypeAnnotationResolver._builtin_rowptr_info() + return TypeAnnotationResolver._builtin_rawptr_info() TypeObj: type | None = CTypeHelper.GetTModuleCType(TypeName) if TypeObj is None: TypeObj = getattr(t, TypeName, None) @@ -454,7 +454,7 @@ class TypeAnnotationResolver: Result.PtrCount = 1 return Result # [builtins 最后匹配] 常规路径全部 miss 后的最终兜底: - # 扫描 includes/builtins.vp 的 CTypedef 声明(rowptr/size_t 等, + # 扫描 includes/builtins.vp 的 CTypedef 声明(rawptr/size_t 等, # 对齐 TPV TypeGenResolve)。命中返回解析结果,miss 走 from_type_name。 builtins_info: CTypeInfo | None = TypeAnnotationResolver._lookup_builtins_typedef(TypeName, SymbolTable) if builtins_info is not None: @@ -800,8 +800,8 @@ class TypeAnnotationResolver: ReturnTypeInfo = TypeAnnotationResolver.from_node(return_node, SymbolTable) Result.FuncPtrReturn = ReturnTypeInfo if ReturnTypeInfo else CTypeInfo.VoidTypeInfo() return Result - # [builtins 最后匹配] 裸名 builtins typedef 下标(rowptr[int] → Ptr(int)): - # 与 TPV Subscript 分支同口径——base 是 builtins typedef(rowptr → t.CPtr), + # [builtins 最后匹配] 裸名 builtins typedef 下标(rawptr[int] → Ptr(int)): + # 与 TPV Subscript 分支同口径——base 是 builtins typedef(rawptr → t.CPtr), # 结果 = 切片类型外包 base 的指针层数。 if isinstance(base, ast.Name): base_info: CTypeInfo | None = TypeAnnotationResolver._lookup_builtins_typedef(base.id, SymbolTable)