修复了一些问题

This commit is contained in:
TermiNexus committed 2026-09-17 14:52:37 +08:00
1 parent 43e7cdd2cc
commit 6af2dea917
16 files changed
+253 -154

No files matched your search

+16 -1
View File
@@ -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()}")
+18 -18
View File
@@ -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)
+2 -2
View File
@@ -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
+9 -9
View File
@@ -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 哨兵 → 误报
+9 -22
View File
@@ -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)])
+17 -31
View File
@@ -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:
@@ -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 指向同一结构体类型(原逻辑)→ 整对象拷贝。
+2 -2
View File
@@ -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] == '.':
+22 -16
View File
@@ -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
+17 -17
View File
@@ -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',
@@ -860,7 +860,7 @@ class ImportHandle(BaseHandle):
def _AnnotationStructName(self, annotation: ast.AST) -> str | None:
"""从注解里提取「指针指向的类」短名(递归,0 判定返回 None)
覆盖形态:`X` / `mod.X` / `rowptr[X]` / `t.CPtr[X]` / 联合 `A | B`(两翼都试)。
覆盖形态:`X` / `mod.X` / `rawptr[X]` / `t.CPtr[X]` / 联合 `A | B`(两翼都试)。
存储类与限定符标记(`t.CExtern` / `t.CExport` / `t.CPtr` 等)不算类名,
由 `_MARKER_ANNOT_NAMES` 过滤;返回的是**短名**,调用方再解析成
`Gen.structs` 真实键。
@@ -879,7 +879,7 @@ class ImportHandle(BaseHandle):
_bn = _base.id
elif isinstance(_base, ast.Attribute):
_bn = _base.attr
if _bn in ('rowptr', 'CPtr', 'CArrayPtr'):
if _bn in ('rawptr', 'CPtr', 'CArrayPtr'):
_sl: ast.AST = annotation.slice
if hasattr(ast, 'Index') and isinstance(_sl, ast.Index):
_sl = _sl.value
@@ -901,7 +901,7 @@ class ImportHandle(BaseHandle):
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
@@ -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 哨兵 → 误报
+6 -6
View File
@@ -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)
+12
View File
@@ -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
+87 -4
View File
@@ -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 反查函数内任意地址即可得到
"<file>.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 <file>
# 并丢弃整份 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:
+4 -4
View File
@@ -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()
+12 -2
View File
@@ -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 -> 右值文本),供命名元数据判重
+3 -3
View File
@@ -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,
+17 -17
View File
@@ -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)