fix(decl): stub 跳过联合形态 CDefine + 模块属性访问回退 _all_define_constants

链接报 undefined symbol: STD_INPUT/OUTPUT/ERROR_HANDLE。根因两处:① DeclarationGenerator._generate_global_decl 的 CDefine 跳过判据只认裸 t.CDefine,而 define X: T = V 展开为注解 T | t.CDefine,于是 stub 里写出 @STD_OUTPUT_HANDLE = external global i32(该符号无人定义);② 模块属性访问 win32file.STD_OUTPUT_HANDLE 的 _try_resolve_nested_cdefine 只查 SymbolTable/_define_constants,缺裸名路径已有的 _all_define_constants 回退,解析落空后转去加载那条错误的 stub 全局 → 链接期未定义符号。改为 AnnotationContainsName 判据 + 补 _all_define_constants 回退(仅在本模块无同名全局时,避免遮蔽真实模块全局)。
This commit is contained in:
TermiNexus committed 2026-10-10 20:29:59 +08:00
1 parent 18d753999d
commit 1050e5a23a
2 files changed
+25 -1

No files matched your search

+7 -1
View File
@@ -253,7 +253,13 @@ class DeclarationGenerator:
if not isinstance(node.target, ast.Name):
return None
var_name: str = node.target.id
if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CDefine':
# CDefine 是编译期常量,不是变量:stub 里**不得**生成 external global。
# `define X: T = V` 会展开为注解 `T | t.CDefine`,故判据必须能识别**联合形态**——
# 原判据只认裸 `t.CDefine`(注解为单个 Attribute),联合注解会漏判 →
# stub 出现 `@X = external global i32` → 其他模块引用它时变成未定义符号(链接失败),
# 且会遮住跨模块 CDefine 常量回退(同名全局优先于常量)。与 _check_annotation_for_export
# 一样用递归判据。
if AnnotationContainsName(node.annotation, 'CDefine'):
return None
if isinstance(node.annotation, ast.Attribute) and hasattr(node.annotation, 'attr') and node.annotation.attr == 'CTypedef':
return None
+18
View File
@@ -2215,6 +2215,24 @@ class ExprAttrHandle(BaseHandle):
return ir.Constant(ir.IntType(32), val)
elif isinstance(val, float):
return ir.Constant(ir.FloatType(), val)
# 回退:_all_define_constants(Phase2Translator 从所有 .pyi 预提取的跨模块 CDefine,
# 与 _HandleNameLlvm 的裸名回退同源)。此前只覆盖裸名/from-import,**模块属性访问**
# (如 `win32file.STD_OUTPUT_HANDLE`)走到这里就落空 → 转去基座求值 + 字段/全局加载,
# 命中 stub 里那条错误的 `@STD_OUTPUT_HANDLE = external global`,最终链接期未定义符号。
# 与裸名路径同口径:仅当本模块没有同名全局时才用常量(避免遮蔽真正的模块全局)。
_mod_globals: Any = getattr(Gen, 'module', None)
_has_mod_global: bool = _mod_globals is not None and attr_name in getattr(_mod_globals, 'globals', {})
if not _has_mod_global:
all_dc: dict[str, Any] = getattr(Gen, '_all_define_constants', None) or getattr(self.Trans, '_all_define_constants', None) or {}
for key2 in (attr_name, full_path):
if key2 in all_dc:
val2: Any = all_dc[key2]
if isinstance(val2, int):
if val2 > 0x7FFFFFFF or val2 < -0x80000000:
return ir.Constant(ir.IntType(64), val2 & 0xFFFFFFFFFFFFFFFF)
return ir.Constant(ir.IntType(32), val2)
elif isinstance(val2, float):
return ir.Constant(ir.FloatType(), val2)
return None
def _try_resolve_cross_module_enum(self, module_alias: str, enum_class_name: str, member_name: str) -> ir.Value | None: