fix(codegen): 新规范迁移暴露的 4 类解析/代码生成缺陷

1) HandlesExpr._HandleConstantLlvm 引号判定用 AST lineno 直查磁盘行,漏了 _inject_auto_imports 注入行的偏移 N,取到错行;改用 _DiskLineno 还原,并把 col_offset(UTF-8 字节偏移)转字符偏移后再切片。2) Phase2Translator 新增 _DedupComdatDecls:_dso.ll 由各依赖片段拼接,每片段各带同名 comdat 声明,llc 报 redefinition of comdat;在 _AddWeakComdat 入口与两处落盘点去重。3) LLVMTypeMapper._resolve_name 补存储类/类型限定符标记分支(CExport/CExtern/CConst… 返回空串,由 _resolve_bitor 取另一侧真实类型),与 _resolve_attribute 同口径。4) 短别名(int/int64/sizet/char…)在 typedef 右值与类型转换调用处解析不到:SymbolTypeResolver._resolve_typedef_from_value 与 LLVMTypeMapper.resolve_typedef_value_type 的 ast.Name 分支补 builtins typedef / BuiltinTypeMap 兜底(BaseType 可能是 CType 实例,须取 type(x).__name__),HandlesExprCall 的类型转换求值补 _lookup_builtins_typedef 回退并保留双参数 CPtr 指针包装。验证:TransPyV 自举 includes 52/52 + App 76/76 全通过;TPV 顺序回归 77/77。
This commit is contained in:
TermiNexus committed 2026-10-05 09:25:02 +08:00
1 parent 65f0e87193
commit 07ba7a4fe5
5 files changed
+141 -11

No files matched your search

+36 -2
View File
@@ -1089,6 +1089,33 @@ def _count_braces_outside_strings(text: str) -> int:
_LLVM_UNQUOTED_NAME_RE: re.Pattern[str] = re.compile(
r'[-a-zA-Z$._][-a-zA-Z$._0-9]*\Z')
# comdat 声明行:`$name = comdat any` / `$"name" = comdat any`(允许行首缩进)
_RE_COMDAT_DECL: re.Pattern[str] = re.compile(r'^\s*\$("?)([^"=\s]+)\1\s*=\s*comdat\b')
def _DedupComdatDecls(ll_content: str) -> str:
"""删除重复的 `$name = comdat any` 声明(保留首次出现)。
落盘的 `_dso.ll` 是「本模块 + 各依赖 .stub.ll/.text.ll 片段」拼接而成,
每个片段各自带一份同名 comdat 声明(片段生成时也会各自补 comdat)。同名
声明出现两次即 llc 报 `redefinition of comdat '$…'`(现场:泛型特化
`list[<sha1>.AST*].__before_init__` 在同一文件里出现 4 次)。comdat 声明
在顶层可位于任意位置,保留首次出现即可,语义不变。
"""
if '= comdat' not in ll_content:
return ll_content
seen: set[str] = set()
kept: list[str] = []
for line in ll_content.splitlines(True):
m = _RE_COMDAT_DECL.match(line)
if m is not None:
name: str = m.group(2)
if name in seen:
continue
seen.add(name)
kept.append(line)
return ''.join(kept)
def _AddWeakComdat(ll_content: str) -> str:
"""为 weak/linkonce 系列 函数/全局 定义补 COMDAT(COFF/PE 必需)。
@@ -1096,13 +1123,15 @@ def _AddWeakComdat(ll_content: str) -> str:
COFF 下无 COMDAT 的 weak/linkonce 定义会被 llc 展开成强符号
`.weak.<name>.default`(weak external 的实现副本)。同一弱定义出现在
多个模块时(泛型特化方法如 `e94ef9e139461915.list[rawptr[AST]].
__before_init__`、跨模块共享常量如 PYI_BUF_SIZE),副本同名 →
__before_init__`、`linkonce`/`weak` 标注的跨模块共享常量),副本同名 →
ld.lld 报 duplicate symbol。补 COMDAT(any) 后 llc 输出单一 COMDAT
成员,链接器自动去重(llc/ld.lld 端到端已实验验证)。
"""
if (' linkonce ' not in ll_content and ' linkonce_odr ' not in ll_content
and ' weak_odr ' not in ll_content and ' weak ' not in ll_content):
return ll_content
return _DedupComdatDecls(ll_content)
# 拼接而来的片段可能各自已带同名 comdat 声明 ⇒ 先去重,再做本次补全
ll_content = _DedupComdatDecls(ll_content)
weak_links = 'linkonce|linkonce_odr|weak|weak_odr|extern_weak'
comdat_names: list[str] = []
@@ -2968,6 +2997,9 @@ class Phase2Translator:
# 都会报 "Metadata id is already used"。规整后盘上产物本身即合法 IR,
# _llc_compile 内的规整随之成为幂等 no-op。
ll_content = SanitizeIRMetadata(ll_content)
# 拼接片段各自带一份同名 comdat 声明 ⇒ 落盘前统一去重:
# llc 对同一 comdat 声明出现两次即报 redefinition of comdat
ll_content = _DedupComdatDecls(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)
@@ -3878,6 +3910,8 @@ class Phase2Translator:
# 同 App 路径:写盘前规整元数据(拼接片段各自带 !0..!N 的 DI 元数据),
# 让盘上产物本身即合法 IR,不依赖 _llc_compile 里那次事后规整。
ll_content = SanitizeIRMetadata(ll_content)
# 同 App 路径:拼接片段各自带一份同名 comdat 声明 ⇒ 落盘前统一去重
ll_content = _DedupComdatDecls(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)