diff --git a/App/lib/core/Gen/ExprGenAttr.vp b/App/lib/core/Gen/ExprGenAttr.vp index 02646ac..993cf4f 100644 --- a/App/lib/core/Gen/ExprGenAttr.vp +++ b/App/lib/core/Gen/ExprGenAttr.vp @@ -16,6 +16,7 @@ import lib.core.Handles.HandlesExpr as HandlesExpr import lib.core.Handles.HandlesExprCall as HandlesExprCall import lib.Stub.StubMerger as StubMerger import lib.Stub.StubMerger.StubMergerStore as StubMergerStore +import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild import lib.core.VLogger as VLogger import lib.Projectrans.Config as Config import lib.Projectrans.Utils as Utils @@ -263,6 +264,13 @@ class ExprGenAttr(ExprGenBase.ExprGenBase): gv_q: str = self.Gen.FuncGenBase._mangle_name_with_sha1( self._lookup_module_sha1(mod_path_w), at.attr) gv: llvmlite.GlobalVariable | t.CPtr = self.find_global_in_module(mod, gv_q) + # CExport 全局(定义端裸名 @_sched_ptr):mangled 名查不到时回退裸名精确 + # 查找。此前只查 mangled 名 → 找不到 → 新建 mangled external global 声明 + # (@"ef5b0ba0dc895058._sched_ptr")→ 与定义端裸名不匹配 → ld.lld + # undefined symbol: ef5b0ba0dc895058._sched_ptr(idt.vp L134 + # sched._sched_ptr 根因)。 + if gv is None: + gv = self.find_global_in_module(mod, at.attr) if gv is not None and gv.Ty is not None: # 用 gv.Name(完整名,带 SHA1 前缀时与定义端一致)构造引用, # 避免裸名 @_mbuddy 在多模块各自带前缀定义下 undefined symbol @@ -642,18 +650,41 @@ class ExprGenAttr(ExprGenBase.ExprGenBase): qual_buf: str = pool.alloc(qual_len) if qual_buf is not None: viperlib.snprintf(qual_buf, qual_len, "%s.%s", inner_nm.id, inner_at.attr) - if self.Gen.ImportsGen.is_module_imported(trans._imported_modules, qual_buf) == 1: + # 模块已知性:显式 import(w32.win32file)或全局模块注册表登记 + #(包 __init__.vp 内 from . import X 注册的 pkg.X,如 intr.idt) + mod_known_n: int = self.Gen.ImportsGen.is_module_imported( + trans._imported_modules, qual_buf) + if mod_known_n == 0 and self._lookup_module_sha1(qual_buf) is not None: + # 未显式 import 的已知子模块:先注入其 .vpi 声明到当前模块, + # 否则 find_global_in_module 找不到该模块的 CExport 全局(@idt) + #(main.vp intr.idt.idt[32] 根因) + StubMergerBuild.LoadDepVpiIntoModule( + pool, mod, qual_buf, trans._from_imports, + self.Gen.TypeGenBase.get_temp_dir(), trans) + mod_known_n = 1 + if mod_known_n != 0: # 查找全局变量 at.attr(带限定模块 SHA1 前缀精确匹配, # 避免多模块同名全局后缀匹配串扰;sha1 未知退化裸名) gv_nested_q: str = self.Gen.FuncGenBase._mangle_name_with_sha1( self._lookup_module_sha1(qual_buf), at.attr) gv_nested: llvmlite.GlobalVariable | t.CPtr = self.find_global_in_module(mod, gv_nested_q) + # CExport 全局(定义端裸名 @idt)mangled 名查不到时回退 + # 裸名精确查找(对齐读路径 _resolve_module_attribute_global) + if gv_nested is None: + gv_nested = self.find_global_in_module(mod, at.attr) if gv_nested is not None and gv_nested.Ty is not None: gv_ref_nested: llvmlite.Value | t.CPtr = self.make_global_ref( pool, gv_nested.Name, gv_nested.Ty) if gv_ref_nested is not None and gv_ref_nested.Ty is not None: load_ty_nested: llvmlite.LLVMType | t.CPtr = gv_ref_nested.Ty.Pointee if load_ty_nested is not None: + # 模块级全局数组(如 idt.idt: CArray[T, N])按 C 语义 + # 返回基址指针(对齐读路径 L629-634),下标/取址继续 GEP + match load_ty_nested: + case llvmlite.LLVMType.Array(_, _): + return gv_ref_nested + case _: + pass return llvmlite.build_load(builder, load_ty_nested, gv_ref_nested) # 未找到全局: 尝试 CDefine 常量查找 # 对于 w32.win32base.INVALID_HANDLE_VALUE 等嵌套模块属性访问, @@ -801,7 +832,7 @@ class ExprGenAttr(ExprGenBase.ExprGenBase): if base_class is not None: cur_sha1: str = trans.ModuleSha1 field_info = self.Gen.StructGen.lookup_field_by_class( - base_class, at.attr, cur_sha1) + base_class, at.attr, cur_sha1, at, trans._from_imports) # REnum 变体字段别名回退:base_class 是 REnum 类时,变体 # 字段名(如 LLVMType.Pointee → _p2 槽位)不是普通字段, # lookup_field_by_class 查不到(LLVMType"字段 Pointee 未找到" @@ -868,6 +899,15 @@ class ExprGenAttr(ExprGenBase.ExprGenBase): annot_struct: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct( field_info.AnnotClassName) if annot_struct is not None and annot_struct.Ty is not None: + # 确保目标结构体类型在当前模块有声明(可能未定义/未 opaque): + # 联合字段 AnnotClassName 可能解析到本模块未 import 的类 + # (如 __types 的 ParamNode.Next 误解析到 __function.Param), + # bitcast 引用未定义类型 → opt ASan 报 "use of undefined type"。 + # _scan_type_for_cross_module_refs 只扫 Ptr(Struct) 模式, + # 因此传 Ptr(Ty) 让结构体名本身被 opaque 声明。 + # opaque 声明足以支撑指针 bitcast(不访问字段),行为不变。 + llvmlite.module_ensure_opaque_for_type( + mod, pool, llvmlite.Ptr(pool, annot_struct.Ty)) annot_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, annot_struct.Ty) return llvmlite.build_bitcast(builder, loaded_val, annot_ptr_ty) return loaded_val @@ -962,11 +1002,14 @@ class ExprGenAttr(ExprGenBase.ExprGenBase): if parent_class is None: return None # 在父类中查 at.attr 字段,返回其注解类名 - cur_sha1: str = None - if trans is not None: - cur_sha1 = trans.ModuleSha1 - fe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field_by_class( - parent_class, at.attr, cur_sha1) + cur_sha1: str = None + if trans is not None: + cur_sha1 = trans.ModuleSha1 + lfi_pc: str = None + if trans is not None: + lfi_pc = trans._from_imports + fe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field_by_class( + parent_class, at.attr, cur_sha1, at, lfi_pc) if fe is None: return None return self.Gen.StructGen.get_field_annot_class_name(fe) @@ -1098,10 +1141,12 @@ class ExprGenAttr(ExprGenBase.ExprGenBase): base_class = self._resolve_attr_field_class(pool, trans, at.value) if base_class is not None: cur_sha1: str = None + lfi_gp: str = None if trans is not None: cur_sha1 = trans.ModuleSha1 + lfi_gp = trans._from_imports field_info = self.Gen.StructGen.lookup_field_by_class( - base_class, at.attr, cur_sha1) + base_class, at.attr, cur_sha1, at, lfi_gp) # REnum 变体字段别名回退(同 translate_attribute L5046-5062): # get_attribute_ptr 赋值路径的按需过滤同样需要——struct_ty 简化 # i8 时主路径 REnum 别名查找被跳过(LLVMType.Pointee 报错根因)