from __future__ import annotations from typing import TYPE_CHECKING, Any if TYPE_CHECKING: from lib.core.translator import Translator from lib.core.LlvmCodeGenerator import LlvmCodeGenerator import vast as ast import copy import traceback import llvmlite.ir as ir from lib.core.Handles.HandlesBase import BaseHandle, CTypeInfo, FuncMeta from lib.core.SymbolUtils import ( IsTModule, FindStructNameInAnnotationWithContext, AnnotationContainsName, IsPtrSubscriptNode, DesugarPtrSubscriptToUnion) from lib.core.VLogger import get_logger as _vlog from lib.constants.config import mode as _config_mode from lib.includes import t from lib.includes.t import CTypeRegistry # t 模块存储类标记装饰器名称集合 _T_STORAGE_DECORATORS = frozenset({'CExport', 'CExtern', 'CStatic', 'State', 'CInline', 'TLS'}) # `@c.CReturn` 装饰器已移除;任何地方遇到都必须 fail-fast,不得静默忽略或改写。 _CRETURN_REMOVED_HINT: str = ( "`@c.CReturn` 已移除:请改用返回注解 `-> tuple[ty1, ty2, ...]`(多返回值打包为 struct)" ) def _RejectCReturnDecorator(node: ast.AST, decorators: list[ast.AST]) -> None: """扫到 `@c.CReturn` 装饰器即 fail-fast 报错(该装饰器已移除)。""" for decorator in decorators: if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute): if decorator.func.attr == 'CReturn': func_name: str = getattr(node, 'name', '') raise SyntaxError(f"函数 '{func_name}':{_CRETURN_REMOVED_HINT}") def _IsVoidOrDeclAnnotation(Annot: ast.AST) -> bool: """判断函数返回注解是否为 void 或 extern/export 声明型辅助符号。 void:None / t.CVoid,含 `|` 联合形式(注解中 `|` 表示 and), 如 `-> t.CVoid | t.CExport`(sprintf 先例)→ 掉出末尾 ret void 合法。 声明型辅助符号:t.State(extern)/ t.CExport(export)/ t.CExtern—— 此类函数返回注解被改写为 `<原类型> | 辅助符号` 且 body 为空(extern 声明), 掉出末尾是正常形态,必须豁免 fail-fast。 """ if isinstance(Annot, ast.Constant): return Annot.value is None if isinstance(Annot, ast.Attribute): return getattr(Annot, 'attr', '') in ('CVoid', 'State', 'CExport', 'CExtern') if isinstance(Annot, ast.BinOp) and isinstance(Annot.op, ast.BitOr): return _IsVoidOrDeclAnnotation(Annot.left) or _IsVoidOrDeclAnnotation(Annot.right) return False def _IsVoidOrDeclAnnotation(Annot: ast.AST) -> bool: """判断函数返回注解是否为 void 或 extern/export 声明型辅助符号。 void:None / t.CVoid,含 `|` 联合形式(注解中 `|` 表示 and), 如 `-> t.CVoid | t.CExport`(sprintf 先例)→ 掉出末尾 ret void 合法。 声明型辅助符号:t.State(extern)/ t.CExport(export)/ t.CExtern—— 此类函数返回注解被改写为 `<原类型> | 辅助符号` 且 body 为空(extern 声明), 掉出末尾是正常形态,必须豁免 fail-fast。 """ if isinstance(Annot, ast.Constant): return Annot.value is None if isinstance(Annot, ast.Attribute): return getattr(Annot, 'attr', '') in ('CVoid', 'State', 'CExport', 'CExtern') if isinstance(Annot, ast.BinOp) and isinstance(Annot.op, ast.BitOr): return _IsVoidOrDeclAnnotation(Annot.left) or _IsVoidOrDeclAnnotation(Annot.right) return False class FunctionHandle(BaseHandle): @staticmethod def _ExtractFuncMeta(decorator_list: list[ast.AST]) -> FuncMeta: meta: FuncMeta = FuncMeta.NONE if not decorator_list: return meta for d in decorator_list: if isinstance(d, ast.Name): if d.id == 'staticmethod': meta |= FuncMeta.STATIC_METHOD elif d.id == 'property': meta |= FuncMeta.PROPERTY_GETTER elif d.id == 'classmethod': meta |= FuncMeta.CLASS_METHOD elif isinstance(d, ast.Attribute): if isinstance(d.value, ast.Name): # 支持 @property.setter 和 @propname.setter 两种形式 # @propname.setter 中 propname 是之前用 @property 定义的同名属性 if d.value.id == 'property' or d.attr in ('setter', 'getter', 'deleter'): if d.attr == 'setter': meta |= FuncMeta.PROPERTY_SETTER elif d.attr == 'getter': meta |= FuncMeta.PROPERTY_GETTER elif d.attr == 'deleter': meta |= FuncMeta.PROPERTY_DELETER return meta def _extract_decorator_storage_flags(self, Node: ast.FunctionDef) -> dict[str, bool]: """从装饰器列表中提取 t 模块存储类标记 支持 @t.CExport, @t.CExtern, @t.CStatic, @t.State, @t.CInline 也支持 from t import CExport 等别名形式 Returns: dict with keys: 'is_export', 'is_extern', 'is_static', 'is_state', 'is_inline' """ flags: dict[str, bool] = { 'is_export': False, 'is_extern': False, 'is_static': False, 'is_state': False, 'is_inline': False, } if not Node.decorator_list: return flags symtab: object = self.Trans.SymbolTable for decorator in Node.decorator_list: attr_name: str | None = None # @t.CExport 形式 if isinstance(decorator, ast.Attribute) and isinstance(decorator.value, ast.Name): if IsTModule(decorator.value.id, symtab): attr_name = decorator.attr # @CExport 形式 (from t import CExport) elif isinstance(decorator, ast.Name): cls: type | None = getattr(t, decorator.id, None) if cls is None and hasattr(symtab, '_t_type_symbols'): cls = symtab._t_type_symbols.get(decorator.id) if cls is not None and isinstance(cls, type) and issubclass(cls, t.CType): attr_name = cls.__name__ if attr_name and attr_name in _T_STORAGE_DECORATORS: if attr_name == 'CExport': flags['is_export'] = True elif attr_name == 'CExtern': flags['is_extern'] = True elif attr_name == 'CStatic': flags['is_static'] = True elif attr_name == 'State': flags['is_state'] = True elif attr_name == 'CInline': flags['is_inline'] = True return flags @staticmethod def _is_t_storage_decorator(decorator: ast.AST, symtab: object) -> bool: """检查装饰器是否是 t 模块存储类标记(用于排除 behavior_decorators)""" attr_name: str | None = None if isinstance(decorator, ast.Attribute) and isinstance(decorator.value, ast.Name): if IsTModule(decorator.value.id, symtab): attr_name = decorator.attr elif isinstance(decorator, ast.Name): cls: type | None = getattr(t, decorator.id, None) if cls is None and hasattr(symtab, '_t_type_symbols'): cls = symtab._t_type_symbols.get(decorator.id) if cls is not None and isinstance(cls, type) and issubclass(cls, t.CType): attr_name = cls.__name__ elif decorator.id in _T_STORAGE_DECORATORS and hasattr(t, decorator.id): # TLS 是普通函数标记,不是 CType 子类 attr_name = decorator.id return attr_name in _T_STORAGE_DECORATORS if attr_name else False # ------------------------------------------------------------------ # 函数签名公共辅助:以下三个方法供 _GetFunctionSignatureLlvm 与 # _EmitFunctionLlvm 共享,避免 ~80 行重复代码。 # ------------------------------------------------------------------ def _compute_func_name_meta(self, Node: ast.FunctionDef, ClassName: str | None) -> tuple[str, str, FuncMeta]: """计算函数全名(含 setter/deleter 后缀)和 func_meta Returns: (FuncName, RawFuncName, func_meta) """ RawFuncName: str = Node.name FuncName: str = f"{ClassName}.{RawFuncName}" if ClassName else RawFuncName func_meta: FuncMeta = self._ExtractFuncMeta(Node.decorator_list) # property setter/deleter 使用不同的函数名后缀,避免与 getter 冲突 if FuncMeta.PROPERTY_SETTER in func_meta: FuncName = FuncName + '$set' elif FuncMeta.PROPERTY_DELETER in func_meta: FuncName = FuncName + '$del' return FuncName, RawFuncName, func_meta def _resolve_method_class(self, Node: ast.FunctionDef, ClassName: str | None, func_meta: FuncMeta, FuncName: str, Gen: LlvmCodeGenerator) -> tuple[bool, bool, str | None]: """判定函数是否是实例方法 / 类方法,并解析所属类名 Returns: (IsMethod, IsClassMethod, ResolvedClassName) """ RawFuncName: str = Node.name IsMethod: bool = False IsClassMethod: bool = False ResolvedClassName: str | None = ClassName if not ResolvedClassName: for potential_class in Gen.class_methods: if FuncName.startswith(f"{potential_class}."): IsMethod = True ResolvedClassName = potential_class break else: IsMethod = FuncMeta.STATIC_METHOD not in func_meta and FuncMeta.CLASS_METHOD not in func_meta IsClassMethod = FuncMeta.CLASS_METHOD in func_meta if RawFuncName == '__init__': IsMethod = False return IsMethod, IsClassMethod, ResolvedClassName def _apply_struct_self_cls_types(self, ParamTypes: list[ir.Type], ParamNames: list[str], IsMethod: bool, IsClassMethod: bool, ResolvedClassName: str | None, Gen: LlvmCodeGenerator) -> bool: """根据 IsMethod / IsClassMethod 调整 self/cls 参数的 LLVM 类型 - 若是实例方法且无 self 参数,自动插入一个 struct 指针类型; 此时调用方需要同步插入对应的 ParamTypeStrs(本方法不维护)。 - 若是 @classmethod,将 cls 参数覆盖为 struct 指针类型。 Returns: True 表示为实例方法自动插入了 self 参数;False 表示未插入。 """ if not ResolvedClassName or ResolvedClassName not in Gen.structs: return False # 治本修复:同名类 sha1 冲突检测。 # 当多个模块定义同名类(如 stmts.py:Module 和 __module.py:Module)时, # Gen.structs[short_name] 可能指向错误模块的 struct(set_body 已锁定错误布局)。 # 通过 class_sha1_map 获取当前类的源模块 sha1,查找以 sha1 为前缀的完整 struct。 TargetStruct: ir.IdentifiedStructType = Gen.structs[ResolvedClassName] ClassSha1Map: dict[str, str] = getattr(Gen, 'class_sha1_map', {}) ExpectedSha1: str | None = ClassSha1Map.get(ResolvedClassName) if ExpectedSha1 and isinstance(TargetStruct, ir.IdentifiedStructType): ExistingSha1: str = Gen._extract_struct_sha1(TargetStruct) if ExistingSha1 and ExistingSha1 != ExpectedSha1: # sha1 冲突:查找或创建正确的 struct FullKey: str = f"{ExpectedSha1}.{ResolvedClassName}" if FullKey in Gen.structs: TargetStruct = Gen.structs[FullKey] else: # 创建新 struct 并从 stub 加载 body TargetStruct = Gen._get_or_create_struct(ResolvedClassName, source_sha1=ExpectedSha1) if hasattr(self.Trans, 'ImportHandler'): self.Trans.ImportHandler._TryLoadStructFromStub(ResolvedClassName, Gen, source_sha1=ExpectedSha1) if FullKey in Gen.structs: TargetStruct = Gen.structs[FullKey] # 安全回退:如果新 struct 仍为 opaque(body 未加载),回退到原始短名 struct, # 避免方法编译生成无效 GEP(访问 opaque struct 元素)导致运行时崩溃。 if isinstance(TargetStruct, ir.IdentifiedStructType): try: _is_opaque: bool = TargetStruct.is_opaque except (AssertionError, AttributeError): _is_opaque = False if _is_opaque: TargetStruct = Gen.structs[ResolvedClassName] if IsMethod: StructPtrType: ir.PointerType = ir.PointerType(TargetStruct) SelfIdx: int = next((i for i, n in enumerate(ParamNames) if n == "self"), -1) if SelfIdx >= 0: ParamTypes[SelfIdx] = StructPtrType return False ParamTypes.insert(0, StructPtrType) ParamNames.insert(0, "self") return True # 非方法但属于类(如 staticmethod / 顶层函数位于类下) SelfIdx = next((i for i, n in enumerate(ParamNames) if n == "self"), -1) if SelfIdx >= 0: StructPtrType = ir.PointerType(TargetStruct) ParamTypes[SelfIdx] = StructPtrType if IsClassMethod: ClsIdx: int = next((i for i, n in enumerate(ParamNames) if n == "cls"), -1) if ClsIdx >= 0: StructPtrType = ir.PointerType(TargetStruct) ParamTypes[ClsIdx] = StructPtrType return False def _body_contains_raise(self, body: list[ast.AST]) -> bool: for node in ast.walk(ast.Module(body=body, type_ignores=[])): if isinstance(node, ast.Raise): if node.exc: if isinstance(node.exc, ast.Name) and node.exc.id == 'StopIteration': continue if isinstance(node.exc, ast.Call) and isinstance(node.exc.func, ast.Name) and node.exc.func.id == 'StopIteration': continue return True if isinstance(node, ast.Call): called_name: str | None = None if isinstance(node.func, ast.Name): called_name = node.func.id elif isinstance(node.func, ast.Attribute): called_name = node.func.attr if called_name: Gen: LlvmCodeGenerator = self.Trans.LlvmGen for prefix in ['', f'{called_name}.', f'__']: for suffix in ['', f'.{called_name}']: fname: str = f'{prefix}{called_name}{suffix}' if fname in Gen.functions: func: Any = Gen.functions[fname] if len(func.args) > 0: for arg in func.args: if hasattr(arg, 'name') and arg.name in ('__eh_msg_out__', '__eh_code_out__'): return True break return False _LLVM_ATTR_NAMES = frozenset({ 'nobuiltin', 'nounwind', 'noredzone', 'willreturn', 'mustprogress', 'optnone', 'noinline', 'alwaysinline', 'readnone', 'readonly', 'writeonly', 'inaccessiblememonly', 'inaccessiblemem_or_argmemonly', }) def _ExtractLLVMAttrs(self, node: ast.AST) -> list[str]: attrs: list[str] = [] if isinstance(node, ast.BinOp): attrs.extend(self._ExtractLLVMAttrs(node.left)) attrs.extend(self._ExtractLLVMAttrs(node.right)) elif isinstance(node, ast.Attribute): attr_name: str | None = self._GetAttrLLVMName(node) if attr_name: attrs.append(attr_name) return attrs def _GetAttrLLVMName(self, node: ast.AST) -> str | None: if not isinstance(node, ast.Attribute): return None if node.attr not in self._LLVM_ATTR_NAMES: return None value: ast.AST = node.value if not isinstance(value, ast.Attribute) or value.attr != 'llvm': return None inner: ast.AST = value.value if not isinstance(inner, ast.Attribute) or inner.attr != 'attr': return None if not isinstance(inner.value, ast.Name) or inner.value.id != 't': return None return node.attr def _infer_return_type_from_body(self, Node: ast.AST, Gen: LlvmCodeGenerator | None = None, ClassName: str | None = None) -> tuple[str, bool] | None: local_var_types: dict[str, tuple[str, bool]] = {} for child in ast.walk(Node): if isinstance(child, ast.Assign) and len(child.targets) == 1: target: ast.AST = child.targets[0] if isinstance(target, ast.Name) and isinstance(child.value, ast.Subscript): sub: ast.Subscript = child.value if (isinstance(sub.value, ast.Attribute) and isinstance(sub.value.value, ast.Name) and sub.value.value.id == 'self' and ClassName and ClassName in Gen.class_members): member_name: str = sub.value.attr for m_name, m_type in Gen.class_members[ClassName]: if m_name == member_name: if isinstance(m_type, ir.ArrayType): elem_type: ir.Type = m_type.element if isinstance(elem_type, ir.FloatType): local_var_types[target.id] = ('float', False) elif isinstance(elem_type, ir.DoubleType): local_var_types[target.id] = ('double', False) elif isinstance(elem_type, ir.IntType): if elem_type.width == 8: local_var_types[target.id] = ('char', False) else: local_var_types[target.id] = ('int', False) elif isinstance(elem_type, ir.PointerType): if isinstance(elem_type.pointee, ir.IntType) and elem_type.pointee.width == 8: local_var_types[target.id] = ('char', True) else: local_var_types[target.id] = ('void', True) elif isinstance(elem_type, ir.IdentifiedStructType): struct_name: str = elem_type.name if struct_name: for sn, st in Gen.structs.items(): if st.name == struct_name or sn == struct_name: local_var_types[target.id] = (sn, False) break else: local_var_types[target.id] = (elem_type.name, False) elif isinstance(m_type, ir.PointerType): pointee: ir.Type = m_type.pointee if isinstance(pointee, ir.FloatType): local_var_types[target.id] = ('float', False) elif isinstance(pointee, ir.DoubleType): local_var_types[target.id] = ('double', False) elif isinstance(pointee, ir.IntType): if pointee.width == 8: local_var_types[target.id] = ('char', False) else: local_var_types[target.id] = ('int', False) elif isinstance(pointee, ir.PointerType): local_var_types[target.id] = ('void', True) elif isinstance(pointee, ir.IdentifiedStructType): for sn, st in Gen.structs.items(): if st == pointee or st.name == pointee.name: local_var_types[target.id] = (sn, True) break break for child in ast.walk(Node): if isinstance(child, ast.Return) and child.value: val: ast.AST = child.value if isinstance(val, ast.Name) and val.id == 'self' and ClassName: return (ClassName, True) if isinstance(val, ast.Call): if isinstance(val.func, ast.Name): callee: str = val.func.id if callee == 'malloc': return ('char', True) if callee == 'chr': return ('char', False) if Gen and callee in Gen.functions: func: Any = Gen.functions[callee] if hasattr(func, 'ftype'): ret_type: ir.Type = func.ftype.return_type if isinstance(ret_type, ir.PointerType): if isinstance(ret_type.pointee, ir.IntType) and ret_type.pointee.width == 8: return ('char', True) return ('void', True) elif isinstance(ret_type, ir.IntType): if ret_type.width == 8: return ('char', False) return ('int', False) elif isinstance(ret_type, ir.VoidType): return ('void', False) elif isinstance(val.func, ast.Attribute): pass callee_name: str | None = None if isinstance(val.func, ast.Name): callee_name = val.func.id elif isinstance(val.func, ast.Attribute): callee_name = getattr(val.func, 'attr', None) if callee_name: sym: Any = self.Trans.SymbolTable.lookup(callee_name) if sym and isinstance(sym, dict): ret_type_str: str = sym.get('return_type', '') if ret_type_str and ret_type_str != 'int': IsPtr: bool = sym.get('IsPtr', False) return (ret_type_str, IsPtr) elif isinstance(val, ast.Constant): if val.value is None: return ('char', True) elif isinstance(val.value, str) and len(val.value) <= 1: return ('char', True) elif isinstance(val, ast.Name): var_name: str = val.id if var_name in local_var_types: return local_var_types[var_name] var_info: Any = self.Trans.SymbolTable.lookup(var_name) if var_info and isinstance(var_info, dict): var_type: str = var_info.get('type', '') if var_type and var_type != 'int': IsPtr: bool = var_info.get('IsPtr', False) return (var_type, IsPtr) elif isinstance(val, ast.Subscript): if (isinstance(val.value, ast.Attribute) and isinstance(val.value.value, ast.Name) and val.value.value.id == 'self' and ClassName): member_name: str = val.value.attr if ClassName in Gen.class_members: for m_name, m_type in Gen.class_members[ClassName]: if m_name == member_name: if isinstance(m_type, ir.ArrayType): elem_type: ir.Type = m_type.element if isinstance(elem_type, ir.FloatType): return ('float', False) elif isinstance(elem_type, ir.DoubleType): return ('double', False) elif isinstance(elem_type, ir.IntType): if elem_type.width == 8: return ('char', False) return ('int', False) elif isinstance(elem_type, ir.PointerType): if isinstance(elem_type.pointee, ir.IntType) and elem_type.pointee.width == 8: return ('char', True) return ('void', True) elif isinstance(elem_type, ir.IdentifiedStructType): struct_name: str = elem_type.name if struct_name: for sn, st in Gen.structs.items(): if st.name == struct_name or sn == struct_name: return (sn, False) return (elem_type.name, False) elif isinstance(m_type, ir.PointerType): pointee: ir.Type = m_type.pointee if isinstance(pointee, ir.FloatType): return ('float', False) elif isinstance(pointee, ir.DoubleType): return ('double', False) elif isinstance(pointee, ir.IntType): if pointee.width == 8: return ('char', False) return ('int', False) elif isinstance(pointee, ir.PointerType): return ('void', True) elif isinstance(pointee, ir.IdentifiedStructType): for sn, st in Gen.structs.items(): if st == pointee or st.name == pointee.name: return (sn, True) return (pointee.name, True) break if isinstance(val.value, ast.Name): var_name: str = val.value.id var_info: Any = self.Trans.SymbolTable.lookup(var_name) if var_info and isinstance(var_info, dict): var_type: str = var_info.get('type', '') if var_type.startswith('list[') or var_type.startswith('List[') or var_type.startswith('t.CArray['): inner: str = var_type[var_type.index('[') + 1:var_type.rindex(']')] parts: list[str] = inner.split(',') elem_type_str: str = parts[0].strip() if elem_type_str and elem_type_str != 'int': IsPtr: bool = var_info.get('IsPtr', False) return (elem_type_str, IsPtr) return None def _GetFunctionSignatureLlvm(self, Node: ast.FunctionDef, Gen: LlvmCodeGenerator, ClassName: str | None = None, extra_params: list[tuple[str, Any]] | None = None) -> tuple[str, ir.FunctionType, Any, list[Any], list[ast.AST], bool, str | None, bool]: FuncName, RawFuncName, func_meta = self._compute_func_name_meta(Node, ClassName) if Node.decorator_list: _RejectCReturnDecorator(Node, Node.decorator_list) MultiRetTypes: list[ast.AST] = [] if Node.returns: llvm_attrs: list[str] = self._ExtractLLVMAttrs(Node.returns) if llvm_attrs: if not hasattr(self, '_pending_llvm_attrs'): self._pending_llvm_attrs = {} self._pending_llvm_attrs[FuncName] = llvm_attrs if isinstance(Node.returns, ast.Subscript) and isinstance(Node.returns.value, ast.Name) and Node.returns.value.id == 'tuple': slice_node: ast.AST = Node.returns.slice if isinstance(slice_node, ast.Tuple): for elt in slice_node.elts: MultiRetTypes.append(elt) else: MultiRetTypes.append(slice_node) IsPtr: bool = False ReturnTypeInfo: Any = None if Node.returns: if MultiRetTypes: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CVoid() else: try: if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr): ReturnTypeInfo = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.returns) if not isinstance(ReturnTypeInfo, CTypeInfo): ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CVoid() if ((ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState) or (ReturnTypeInfo.PtrCount >= 2 and ReturnTypeInfo.BaseType is None)): def _FindNonVoidCTypeInfo(node: ast.AST) -> Any: if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): results: list[Any] = [] for child in [node.left, node.right]: r: Any = _FindNonVoidCTypeInfo(child) if r and not r.IsVoid: results.append(r) for r in results: if not r.IsPtr and not r.IsStruct: return r return results[0] if results else None try: SideInfo: Any = CTypeInfo.FromNode(node, self.Trans.SymbolTable) if SideInfo: return SideInfo except Exception as _e: if _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") return None found: Any = _FindNonVoidCTypeInfo(Node.returns) if found and not found.IsVoid: ReturnTypeInfo = found if ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CInt() # define 宏函数(返回注解含 t.CDefine,如 `int | t.CDefine`): # 标记为编译期内联宏(alwaysinline),对齐裸 `-> t.CDefine` 路径 # (合并路径丢失 IsDefine 时仍能命中) if AnnotationContainsName(Node.returns, 'CDefine'): if not hasattr(self, '_cdefine_funcs'): self._cdefine_funcs = set() self._cdefine_funcs.add(FuncName) else: is_str_type: bool = False if isinstance(Node.returns, ast.Name) and Node.returns.id in ('str', 'bytes'): is_str_type = True # 走 ResolveAnnotationType 而非 CTypeInfo.FromNode:指针下标 # 返回注解(rawptr[T] / t.CPtr[T])需走 TypeMerge 通用解析, # 否则内层跨模块类解析不出 → CVoid/1(i8*)。 ReturnTypeInfo = self.ResolveAnnotationType(Node.returns) if ReturnTypeInfo and ReturnTypeInfo.IsDefine: inferred: Any = self._infer_return_type_from_body(Node, Gen, ClassName) if inferred: ReturnTypeInfo = CTypeInfo.FromTypeName(inferred[0]) ReturnTypeInfo.PtrCount = 1 if inferred[1] else 0 else: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CInt() if not hasattr(self, '_cdefine_funcs'): self._cdefine_funcs = set() self._cdefine_funcs.add(FuncName) elif ReturnTypeInfo and ReturnTypeInfo.IsState: if ReturnTypeInfo.PtrCount > 0 or (ReturnTypeInfo.BaseType and not isinstance(ReturnTypeInfo.BaseType, t.CVoid)): pass else: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CVoid() if ReturnTypeInfo is None: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CVoid() # 仅指针层数 <=1 才算裸 str/bytes(i8*)。 # `str | t.CPtr` 合并后 IsStr=True 但 PtrCount=2(i8**,如 argv 数组),不能压平。 if is_str_type or (ReturnTypeInfo.IsStr and ReturnTypeInfo.PtrCount <= 1): ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CChar() ReturnTypeInfo.PtrCount = 1 # 检查泛型类返回类型 (如 list[str]) # 注意:_from_node_subscript 对未识别的泛型下标(如 list[str])返回空 CTypeInfo(BaseType=None), # 此时 IsVoid 为 False(因为 IsVoid 仅检查 t.CVoid 实例),需额外检测 BaseType is None if (isinstance(Node.returns, ast.Subscript) and isinstance(Node.returns.value, ast.Name) and hasattr(self.Trans.ClassHandler, '_generic_class_templates') and Node.returns.value.id in self.Trans.ClassHandler._generic_class_templates and (ReturnTypeInfo.IsVoid or ReturnTypeInfo.BaseType is None) and ReturnTypeInfo.PtrCount == 0): ret_class: str = Node.returns.value.id ret_slice: ast.AST = Node.returns.slice ret_type_args: list[str] = [] ret_type_names: list[str] = [] if isinstance(ret_slice, ast.Tuple): for elt in ret_slice.elts: if isinstance(elt, ast.Name): tn2: str = elt.id ts2: str = tn2 if tn2 == 'int': ts2, tn2 = 'int', 'CInt' ret_type_args.append(ts2) ret_type_names.append(tn2) elif isinstance(ret_slice, ast.Name): tn2: str = ret_slice.id ts2: str = tn2 if tn2 == 'int': ts2, tn2 = 'int', 'CInt' ret_type_args.append(ts2) ret_type_names.append(tn2) # 返回类型解析只需 struct 定义,不需方法体;使用 declare_only=True # 避免过早触发完整特化(此时 MemManager.alloc 可能尚未注册, # 导致 __new__ 的 pool.alloc(48) 解析失败,IR 块未终止)。 # 完整特化由后续类实例化(L3688/L3753)触发 declare_only=False。 spec_name2: str | None = self.Trans.ClassHandler._specialize_generic_class( ret_class, ret_type_args, Gen, type_names=ret_type_names, declare_only=True) if spec_name2 and spec_name2 in Gen.structs: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CStruct(name=spec_name2) ReturnTypeInfo.PtrCount = 1 if (ReturnTypeInfo.IsVoid or ReturnTypeInfo.BaseType is None) and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CInt() except Exception: # 回退:设置默认返回类型为 CInt ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CInt() else: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CInt() inferred: Any = self._infer_return_type_from_body(Node, Gen, ClassName) if inferred: ReturnTypeInfo = CTypeInfo.FromTypeName(inferred[0]) ReturnTypeInfo.PtrCount = 1 if inferred[1] else 0 IsPtr = ReturnTypeInfo.IsPtr if ReturnTypeInfo else False ReturnType: ir.Type = Gen._ctype_to_llvm(ReturnTypeInfo) # 此处原有 "Ptr(Ptr(Struct)) → Ptr(Struct)" 的压层(历史遗留):会把已解析的 # 多层指针返回类型(`-> rawptr[rawptr[X]]` / `-> X | t.CPtr | t.CPtr`) # 与泛型特化方法返回(`list[X**]` 的 get/pop/__getitem__/__next__)少算一层, # 与同函数的形参(`append(item: T)` 保留 `X**`)、声明端 # DeclarationGenerator._get_type_str 的 BinOp 分支(同样不压层,见 # '_is_bare_class_ref_annotation' 为假时逐层外包)以及 _EmitFunctionLlvm # 的定义体路径全部不一致。违反"多层指针已解析时照原样保留层数"。 # 实测(36 用例 A/B)删除后仅 `list[X**]` 的 4 个方法 declare 由 `X*` 变 # `X**`,与 append/set 的形参一致;stub 逐字节不变。 if isinstance(ReturnType, ir.IntType) and ReturnType.width == 8: if RawFuncName == '__str__': ReturnType = ir.PointerType(ir.IntType(8)) if isinstance(ReturnType, ir.VoidType) and FuncName == 'main': ReturnType = ir.IntType(32) IsMethod, IsClassMethod, ResolvedClassName = self._resolve_method_class(Node, ClassName, func_meta, FuncName, Gen) # __new__ methods should return a pointer to the struct (for heap allocation replacement) # 修复:前向声明也必须使用正确的返回类型,否则 _replace_function_decl 可能失败, # 导致 vtable 引用错误的函数类型(i32 而非 ClassName*) if RawFuncName == '__new__' and ResolvedClassName: StructType = Gen.structs.get(ResolvedClassName) if StructType: if isinstance(StructType, ir.PointerType): ReturnType = StructType else: ReturnType = ir.PointerType(StructType) ParamTypes: list[ir.Type] = [] ParamNames: list[str] = [] ParamTypeStrs: list[Any] = [] auto_addr_modes: list[str | None] = [] MultiRetLlvmTypes: list[ir.Type] = [] if MultiRetTypes: for i, ReturnTypeNode in enumerate(MultiRetTypes): ReturnTypeInfo = CTypeInfo.FromNode(ReturnTypeNode, self.Trans.SymbolTable) # 仅指针层数 <=1 才算裸 str/bytes(i8*)。 # `str | t.CPtr` 合并后 IsStr=True 但 PtrCount=2(i8**,如 argv 数组),不能压平。 if ReturnTypeInfo and ReturnTypeInfo.IsStr and ReturnTypeInfo.PtrCount <= 1: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CChar() ReturnTypeInfo.PtrCount = 1 if ReturnTypeInfo is None: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CInt() RetType: ir.Type = Gen._ctype_to_llvm(ReturnTypeInfo) MultiRetLlvmTypes.append(RetType) ReturnType = ir.LiteralStructType(MultiRetLlvmTypes) for Arg in Node.args.args: ParamIsUnsigned: bool = False if Arg.annotation: try: ParamTypeInfo: Any # 走 ResolveParamAnnotation(= ResolveAnnotationType + 泛型模板 # 识别):参数注解中的泛型容器(list[X] / rawptr[list[X]])与 # 指针下标(rawptr[X])需走 TypeMerge 通用解析,否则 # TypeAnnotationResolver 解析不出 → VoidType → 报 # "无法识别的参数类型注解"。 ParamTypeInfo = self.ResolveParamAnnotation(Arg.annotation) if ParamTypeInfo is None: ParamTypeInfo = CTypeInfo() ParamTypeInfo.BaseType = t.CInt() IsPtr = ParamTypeInfo.IsPtr if ParamTypeInfo and getattr(ParamTypeInfo, 'IsCpythonObject', False) and not IsPtr: IsPtr = True ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1) # 仅当指针层数 <=1 时才压平为 i8*(裸 str/bytes)。 # `str | t.CPtr` 合并后 IsStr=True 但 PtrCount=2(i8**,如 argv 数组), # 不能压平,否则形参类型错误导致 _adjust_args 多 load 一层崩溃。 if (ParamTypeInfo.IsStr and ParamTypeInfo.PtrCount <= 1) or (isinstance(Arg.annotation, ast.Name) and Arg.annotation.id in ('str', 'bytes')): ParamTypeInfo = CTypeInfo() ParamTypeInfo.BaseType = t.CChar() ParamTypeInfo.PtrCount = 1 IsPtr = True # C 语言中数组参数退化为指针:list[type, N] → type* if ParamTypeInfo.ArrayDims: ParamTypeInfo.ArrayDims = [] ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1) ParamType: ir.Type = Gen._ctype_to_llvm(ParamTypeInfo) # 参数类型不能是 VoidType:C 语言不允许 void 参数, # VoidType 说明类型注解无法识别(如跨模块 ast.expr),直接报错终止 if isinstance(ParamType, ir.VoidType): AnnStr: str = ast.unparse(Arg.annotation) if hasattr(ast, 'unparse') else str(Arg.annotation) raise SyntaxError( f"无法识别的参数类型注解: '{AnnStr}'(在函数 '{Node.name}' 的参数 '{Arg.arg}' 上)。" f"请使用有效的 TPV 类型(如 t.CPtr、ast.AST 或已注册的结构体)。" ) ParamTypeStr: Any = ParamTypeInfo except SyntaxError: raise except Exception as e: ParamType = ir.IntType(32) ParamTypeStr = CTypeInfo() ParamTypeStr.BaseType = t.CInt() else: if ClassName and Arg.arg != 'self': op_method_names: list[str] = ['__add__', '__sub__', '__mul__', '__truediv__', '__floordiv__', '__mod__', '__pow__', '__radd__', '__rsub__', '__rmul__', '__rtruediv__', '__rfloordiv__', '__rmod__', '__rpow__', '__iadd__', '__isub__', '__imul__', '__itruediv__', '__ifloordiv__', '__imod__', '__ipow__', '__eq__', '__ne__', '__lt__', '__le__', '__gt__', '__ge__', '__neg__', '__pos__', '__abs__', '__call__'] if RawFuncName in op_method_names and ClassName in Gen.structs: ParamType = ir.PointerType(Gen.structs[ClassName]) else: ParamType = ir.IntType(32) else: ParamType = ir.IntType(32) ParamTypeStr = CTypeInfo() ParamTypeStr.BaseType = t.CInt() ParamTypes.append(ParamType) ParamNames.append(Arg.arg) ParamTypeStrs.append(ParamTypeStr) # 检测 t.CNeedPtr / t.CAutoPtr 参数注解 auto_mode: str | None = None if ParamTypeStr is not None and hasattr(ParamTypeStr, 'BaseType') and ParamTypeStr.BaseType is not None: if isinstance(ParamTypeStr.BaseType, t.CAutoPtr): auto_mode = 'always' elif isinstance(ParamTypeStr.BaseType, t.CNeedPtr): auto_mode = 'need' auto_addr_modes.append(auto_mode) if self._apply_struct_self_cls_types(ParamTypes, ParamNames, IsMethod, IsClassMethod, ResolvedClassName, Gen): ParamTypeStrs.insert(0, f"struct {ResolvedClassName}") IsVariadic: bool = Node.args.vararg is not None if extra_params: for var_name, ptr_type in extra_params: ParamTypes.append(ptr_type) ParamNames.append(f'__nonlocal_{var_name}__') if IsMethod and RawFuncName == '__next__': ParamTypes.append(ir.PointerType(ir.IntType(1))) ParamNames.append('__stop_iter_flag__') HasRaise: bool = self._body_contains_raise(Node.body) if HasRaise and RawFuncName != 'main': ParamTypes.append(ir.PointerType(ir.PointerType(ir.IntType(8)))) ParamNames.append('__eh_msg_out__') ParamTypes.append(ir.PointerType(ir.IntType(32))) ParamNames.append('__eh_code_out__') FuncType: ir.FunctionType = ir.FunctionType(ReturnType, ParamTypes, var_arg=IsVariadic) # 存储 auto_addr_modes(为额外参数补 None) total_params: int = len(ParamTypes) while len(auto_addr_modes) < total_params: auto_addr_modes.append(None) Gen._auto_addr_params[FuncName] = auto_addr_modes return FuncName, FuncType, ReturnTypeInfo, ParamTypeStrs, MultiRetTypes, IsMethod, ResolvedClassName, IsVariadic def _is_generic_function(self, Node: ast.FunctionDef) -> bool: if hasattr(Node, 'type_params') and Node.type_params: return True return False def _mangle_generic_name(self, func_name: str, type_args: list[str], has_cexport: bool = False) -> str: mangled_args: list[str] = [] for ta in type_args: llvm_str: str | None = CTypeRegistry.NameToLLVM(ta) if llvm_str: if llvm_str in ('float', 'double', 'half', 'fp128'): mangled: str = 'f' + str(CTypeRegistry.GetClassByName(ta)().Size) else: mangled = llvm_str else: mangled = ta mangled_args.append(mangled) if has_cexport: return func_name + '_T_' + '_'.join(mangled_args) return func_name + '[' + ']['.join(mangled_args) + ']' def _apply_type_map_to_node(self, Node: ast.FunctionDef, type_map: dict[str, str], cptr_params: set[str] | None = None) -> None: for arg in Node.args.args: if arg.annotation: arg.annotation = self._replace_type_in_annotation(arg.annotation, type_map, cptr_params) if Node.returns: Node.returns = self._replace_type_in_annotation(Node.returns, type_map, cptr_params) self._apply_type_map_to_body(Node.body, type_map, cptr_params) def _replace_type_in_annotation(self, node: ast.AST, type_map: dict[str, str], cptr_params: set[str] | None = None) -> ast.AST: if isinstance(node, ast.Name): if node.id in type_map: replacement: str = type_map[node.id] return self._make_replacement_node(replacement) elif isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): if isinstance(node.left, ast.Name) and node.left.id in type_map: replacement: str = type_map[node.left.id] node.left = self._make_replacement_node(replacement) return node node.left = self._replace_type_in_annotation(node.left, type_map, cptr_params) node.right = self._replace_type_in_annotation(node.right, type_map, cptr_params) elif isinstance(node, ast.Attribute): if hasattr(node, 'attr') and node.attr in type_map: replacement: str = type_map[node.attr] return self._make_replacement_node(replacement) elif isinstance(node, ast.Subscript): # 嵌套泛型(如 list[T]):递归替换 value 和 slice 中的类型参数 node.value = self._replace_type_in_annotation(node.value, type_map, cptr_params) node.slice = self._replace_type_in_annotation(node.slice, type_map, cptr_params) return node def _make_replacement_node(self, replacement: str) -> ast.AST: """将 type_map 中的替换字符串转换为 AST 节点。 mangled 名称如 '.AST*' 需要还原为 AST | t.CPtr 结构, 否则类型解析会丢失 PtrCount 信息。 含点号的名称(如 '.AST')需解析为 ast.Attribute 链。 下标形态('rawptr[ast.AST]' / 'list[AST]' 等)必须整体解析为 Subscript: _make_name_node 只按 '.' 切分会把 'rawptr[ast.AST]' 拆成 Name('rawptr[ast') + Attribute('AST]'),两段都不是有效类型名 → 参数/返回注解解析为空 → VoidType → "无法识别的参数类型注解"。 指针下标(rawptr[T] / t.CPtr[T])再折叠为等价的 `T | t.CPtr`,与源码 联合写法同解析路径(对齐 TPV TypeGenResolve._parse_type_string 的 '[' 分支 + ClassGenGeneric._clone_annotation 的 T 替换)。 内层为已混淆名(数字开头,如 'rawptr[7565e081d88517ac.AST]')时 ast.parse 无法解析(数字开头的令牌),改用手工拆 base/slice(同 TPV TypeGenResolve._parse_type_string 的数字开头手工拆分分支)。 尾部 '*'(泛型实参 '.Node*' / '.Node**',来自 rawptr[T] / t.CPtr 的逐层 mangling)逐层还原为 `Node | t.CPtr [| t.CPtr]` → 对应 层数指针;只剥一层会把 'Node*' 当结构体名建出 phantom opaque (item 类型与特化名 '.Node**' 的语义不一致)。 尾部 'ptr'(旧规则 mangling,如 'Nodeptr' / 'ast.ASTptr')保留兼容: .vpi/stub 缓存里仍是旧名时按同样方式还原。 """ StarCount: int = len(replacement) - len(replacement.rstrip('*')) if StarCount > 0: BaseName: str = replacement[:len(replacement) - StarCount] base_node: ast.AST if BaseName in ('i8', 'void', 'void*'): # i8*(void*)在源码侧写作 t.CPtr;再叠加 StarCount-1 层 base_node = ast.Attribute( value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load()) StarCount -= 1 else: base_node = self._make_name_node(BaseName) node: ast.AST = base_node for _ in range(StarCount): node = ast.BinOp( left=node, op=ast.BitOr(), right=ast.Attribute( value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load()), ) return node if replacement.endswith('ptr'): # 提取基础名称:'sha1.ASTptr' → 'sha1.AST';'Nodeptrptr' → 'Node'(2 层) base: str = replacement levels: int = 0 while base.endswith('ptr') and len(base) > 3: base = base[:-3] levels += 1 node: ast.AST = self._make_name_node(base) for _ in range(levels): node = ast.BinOp( left=node, op=ast.BitOr(), right=ast.Attribute( value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load()), ) return node if '[' in replacement: SubNode: ast.AST | None = None try: SubNode = ast.parse(replacement, '', mode='eval').body except Exception: SubNode = None if not isinstance(SubNode, ast.Subscript): SubNode = self._parse_subscript_manually(replacement) if isinstance(SubNode, ast.Subscript): if IsPtrSubscriptNode(SubNode, self.Trans.SymbolTable): return DesugarPtrSubscriptToUnion(SubNode, self.Trans.SymbolTable) return SubNode return self._make_name_node(replacement) def _parse_subscript_manually(self, replacement: str) -> ast.AST | None: """手工拆分单实参下标字符串(ast.parse 因数字开头标识符失败时使用)。 处理 `[]`(整体以 ']' 结尾、单实参、无逗号;内层可为嵌套 单实参下标):'rawptr[7565e081d88517ac.AST]' → Subscript(Name('rawptr'), Attribute(Name('7565e081d88517ac'), 'AST')); 'rawptr[rawptr[7565e081d88517ac.AST]]' → 外层 Subscript 的 slice 递归 拆出内层 Subscript(嵌套 rawptr 需两层指针)。带逗号等复杂形态返回 None(交调用方按普通名称处理),不做字符串猜测。 """ open_idx: int = replacement.find('[') if open_idx <= 0 or not replacement.endswith(']'): return None inner: str = replacement[open_idx + 1:-1] if not inner or ',' in inner: return None base_name: str = replacement[:open_idx].strip() inner_name: str = inner.strip() if not base_name or not inner_name: return None slice_node: ast.AST | None if '[' in inner_name or inner_name.endswith('*'): # 嵌套单实参下标 / 指针层数内层(如 rawptr[rawptr[.CLS]]、 # .list[.X*]):递归按同一还原规则拆解 slice_node = self._make_replacement_node(inner_name) else: try: slice_node = ast.parse(inner_name, '', mode='eval').body except Exception: slice_node = self._make_name_node(inner_name) if slice_node is None: return None return ast.Subscript( value=self._make_name_node(base_name), slice=slice_node, ctx=ast.Load()) @staticmethod def _make_name_node(name: str) -> ast.AST: """将可能含点号的名称转换为 ast.Name 或 ast.Attribute 链。 'AST' -> ast.Name(id='AST') 'sha1.AST' -> ast.Attribute(value=ast.Name(id='sha1'), attr='AST') """ if '.' not in name: return ast.Name(id=name, ctx=ast.Load()) parts: list[str] = name.split('.') node: ast.AST = ast.Name(id=parts[0], ctx=ast.Load()) for part in parts[1:]: node = ast.Attribute(value=node, attr=part, ctx=ast.Load()) return node def _apply_type_map_to_body(self, body: list[ast.AST], type_map: dict[str, str], cptr_params: set[str] | None = None) -> None: for stmt in body: self._apply_type_map_to_stmt(stmt, type_map, cptr_params) def _apply_type_map_to_stmt(self, node: ast.AST, type_map: dict[str, str], cptr_params: set[str] | None = None) -> None: if isinstance(node, ast.Return) and node.value: self._apply_type_map_to_expr(node.value, type_map, cptr_params) elif isinstance(node, ast.Assign): for t in node.targets: self._apply_type_map_to_expr(t, type_map, cptr_params) self._apply_type_map_to_expr(node.value, type_map, cptr_params) elif isinstance(node, ast.AnnAssign): if node.annotation: node.annotation = self._replace_type_in_annotation(node.annotation, type_map, cptr_params) if node.value: self._apply_type_map_to_expr(node.value, type_map, cptr_params) elif isinstance(node, ast.AugAssign): self._apply_type_map_to_expr(node.target, type_map, cptr_params) self._apply_type_map_to_expr(node.value, type_map, cptr_params) elif isinstance(node, ast.Expr): self._apply_type_map_to_expr(node.value, type_map, cptr_params) elif isinstance(node, ast.If): self._apply_type_map_to_expr(node.test, type_map, cptr_params) for s in node.body: self._apply_type_map_to_stmt(s, type_map, cptr_params) for s in node.orelse: self._apply_type_map_to_stmt(s, type_map, cptr_params) elif isinstance(node, ast.For): self._apply_type_map_to_expr(node.iter, type_map, cptr_params) for s in node.body: self._apply_type_map_to_stmt(s, type_map, cptr_params) for s in node.orelse: self._apply_type_map_to_stmt(s, type_map, cptr_params) elif isinstance(node, ast.While): self._apply_type_map_to_expr(node.test, type_map, cptr_params) for s in node.body: self._apply_type_map_to_stmt(s, type_map, cptr_params) for s in node.orelse: self._apply_type_map_to_stmt(s, type_map, cptr_params) elif isinstance(node, ast.Try): for s in node.body: self._apply_type_map_to_stmt(s, type_map, cptr_params) for handler in node.handlers: for s in handler.body: self._apply_type_map_to_stmt(s, type_map, cptr_params) for s in node.orelse: self._apply_type_map_to_stmt(s, type_map, cptr_params) for s in node.finalbody: self._apply_type_map_to_stmt(s, type_map, cptr_params) elif isinstance(node, ast.With): for item in node.items: self._apply_type_map_to_expr(item.context_expr, type_map, cptr_params) if item.optional_vars: self._apply_type_map_to_expr(item.optional_vars, type_map, cptr_params) for s in node.body: self._apply_type_map_to_stmt(s, type_map, cptr_params) elif isinstance(node, ast.Raise): if node.exc: self._apply_type_map_to_expr(node.exc, type_map, cptr_params) if node.cause: self._apply_type_map_to_expr(node.cause, type_map, cptr_params) elif isinstance(node, ast.Assert): self._apply_type_map_to_expr(node.test, type_map, cptr_params) if node.msg: self._apply_type_map_to_expr(node.msg, type_map, cptr_params) def _apply_type_map_to_expr(self, node: ast.AST | None, type_map: dict[str, str], cptr_params: set[str] | None = None) -> None: if node is None: return if isinstance(node, ast.Call): if isinstance(node.func, ast.Name) and node.func.id in type_map: replacement: str = type_map[node.func.id] # 使用 _make_replacement_node 处理含点号的类型名(如 't.CUnsignedChar'), # 避免 T(0) 替换为 CUnsignedChar(0) 后因 CUnsignedChar 不在顶层作用域 # 而报 "Undefined function: 'CUnsignedChar'" node.func = self._make_replacement_node(replacement) elif isinstance(node.func, ast.Attribute): if isinstance(node.func.value, ast.Name) and node.func.value.id in type_map: replacement: str = type_map[node.func.value.id] # 指针类型参数(如 list[AST | t.CPtr] 中的 T)在表达式上下文中 # 需替换为 BinOp(AST | t.CPtr),使 __sizeof__ 等处理器能正确识别 # 指针语义并直接返回 8,避免触发 struct 加载和重入编译 if cptr_params and node.func.value.id in cptr_params: node.func.value = ast.BinOp( left=self._make_name_node(replacement), op=ast.BitOr(), right=ast.Attribute(value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load()) ) else: node.func.value = self._make_name_node(replacement) else: self._apply_type_map_to_expr(node.func.value, type_map, cptr_params) for arg in node.args: self._apply_type_map_to_expr(arg, type_map, cptr_params) elif isinstance(node, ast.Attribute): if isinstance(node.value, ast.Name) and node.value.id in type_map: replacement: str = type_map[node.value.id] if cptr_params and node.value.id in cptr_params: node.value = ast.BinOp( left=self._make_name_node(replacement), op=ast.BitOr(), right=ast.Attribute(value=ast.Name(id='t', ctx=ast.Load()), attr='CPtr', ctx=ast.Load()) ) else: node.value = ast.Name(id=replacement, ctx=ast.Load()) else: self._apply_type_map_to_expr(node.value, type_map, cptr_params) elif isinstance(node, ast.BinOp): self._apply_type_map_to_expr(node.left, type_map, cptr_params) self._apply_type_map_to_expr(node.right, type_map, cptr_params) elif isinstance(node, ast.UnaryOp): self._apply_type_map_to_expr(node.operand, type_map, cptr_params) elif isinstance(node, ast.Compare): self._apply_type_map_to_expr(node.left, type_map, cptr_params) for comp in node.comparators: self._apply_type_map_to_expr(comp, type_map, cptr_params) elif isinstance(node, ast.BoolOp): for val in node.values: self._apply_type_map_to_expr(val, type_map, cptr_params) elif isinstance(node, ast.IfExp): self._apply_type_map_to_expr(node.test, type_map, cptr_params) self._apply_type_map_to_expr(node.body, type_map, cptr_params) self._apply_type_map_to_expr(node.orelse, type_map, cptr_params) elif isinstance(node, ast.Subscript): self._apply_type_map_to_expr(node.value, type_map, cptr_params) self._apply_type_map_to_expr(node.slice, type_map, cptr_params) elif isinstance(node, ast.Name): if node.id in type_map: node.id = type_map[node.id] def _infer_type_arg_from_value(self, val: ir.Value, Gen: LlvmCodeGenerator) -> str: if val is None: return 'int' if isinstance(val.type, ir.IntType): if val.type.width == 64: return 'i64' elif val.type.width == 16: return 'i16' elif val.type.width == 8: return 'i8' return 'int' elif isinstance(val.type, ir.DoubleType): return 'double' elif isinstance(val.type, ir.FloatType): return 'float' elif isinstance(val.type, ir.PointerType): return 'void*' return 'int' def _specialize_generic_function(self, FuncName: str, type_args: list[str], Gen: LlvmCodeGenerator) -> str | None: if not hasattr(self, '_generic_templates') or FuncName not in self._generic_templates: return None template: dict[str, Any] = self._generic_templates[FuncName] Node: ast.FunctionDef = template['node'] type_param_names: list[str] = template['type_params'] ClassName: str | None = template['class_name'] if len(type_args) != len(type_param_names): return None spec_key: str = FuncName + '<' + ','.join(type_args) + '>' if not hasattr(self, '_generic_specializations'): self._generic_specializations = {} if spec_key in self._generic_specializations: return self._generic_specializations[spec_key] has_cexport: bool = False if Node.returns: try: RetTypeInfo: Any = None if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr): RetTypeInfo = self.Trans.TypeMergeHandler.MergeTypes(Node.returns) else: RetTypeInfo = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable) if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CExport): has_cexport = True except Exception as _e: if _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") spec_name: str = self._mangle_generic_name(FuncName, type_args, has_cexport) type_map: dict[str, str] = {} for i, tp_name in enumerate(type_param_names): type_map[tp_name] = type_args[i] SpecNode: ast.FunctionDef = copy.deepcopy(Node) SpecNode.type_params = [] SpecNode.name = spec_name self._apply_type_map_to_node(SpecNode, type_map) if has_cexport: if not hasattr(Gen, '_export_funcs'): Gen._export_funcs = set() Gen._export_funcs.add(spec_name) saved_builder: Any = Gen.builder saved_variables: dict[str, Any] = dict(Gen.variables) if Gen.variables else {} saved_direct_values: dict[str, Any] = dict(Gen._direct_values) if Gen._direct_values else {} saved_var_type_info: dict[str, Any] = dict(Gen.var_type_info) if Gen.var_type_info else {} saved_var_signedness: dict[str, Any] = dict(Gen.var_signedness) if Gen.var_signedness else {} saved_global_vars: set[str] = set(Gen.global_vars) if Gen.global_vars else set() saved_var_scopes: list[dict[str, Any]] = [dict(s) for s in self.Trans.VarScopes] if self.Trans.VarScopes else [] saved_func: Any = Gen.func saved_current_func_name: str | None = getattr(Gen, '_current_func_name', None) saved_block: Any = None if Gen.builder and Gen.builder.block and not Gen.builder.block.is_terminated: saved_block = Gen.builder.block self._EmitFunctionForwardDeclLlvm(SpecNode, Gen, ClassName=ClassName) self._EmitFunctionLlvm(SpecNode, Gen, ClassName=ClassName) Gen.builder = saved_builder if saved_block is not None and Gen.builder is not None: Gen.builder.position_at_end(saved_block) Gen.variables = saved_variables Gen._direct_values = saved_direct_values Gen.var_type_info = saved_var_type_info Gen.var_signedness = saved_var_signedness Gen.global_vars = saved_global_vars Gen.func = saved_func if saved_current_func_name is not None: Gen._current_func_name = saved_current_func_name self.Trans.VarScopes = saved_var_scopes self._generic_specializations[spec_key] = spec_name if not hasattr(self.Trans, '_generic_specializations'): self.Trans._generic_specializations = {} self.Trans._generic_specializations[spec_key] = spec_name return spec_name def _EmitFunctionForwardDeclLlvm(self, Node: ast.FunctionDef, Gen: LlvmCodeGenerator, ClassName: str | None = None) -> None: if self._is_generic_function(Node): if not hasattr(self, '_generic_templates'): self._generic_templates = {} RawFuncName: str = Node.name if ClassName: FuncName: str = f"{ClassName}.{RawFuncName}" else: FuncName = RawFuncName type_params: list[str] = [tp.name for tp in Node.type_params] self._generic_templates[FuncName] = { 'node': Node, 'type_params': type_params, 'class_name': ClassName, } return result: Any = self._GetFunctionSignatureLlvm(Node, Gen, ClassName) if result is None: return FuncName: str FuncType: ir.FunctionType ReturnTypeInfo: Any ParamTypeStrs: list[Any] MultiRetTypes: list[ast.AST] IsMethod: bool ResolvedClassName: str | None IsVariadic: bool FuncName, FuncType, ReturnTypeInfo, ParamTypeStrs, MultiRetTypes, IsMethod, ResolvedClassName, IsVariadic = result IsUserMarkedExport: bool = False if Node.returns: try: RetTypeInfo: Any = None RetTypeInfo = self.ResolveAnnotationType(Node.returns) if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CExport) and not RetTypeInfo.IsState: Gen._export_funcs.add(FuncName) IsUserMarkedExport = True if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CExtern): Gen._export_funcs.add(FuncName) IsUserMarkedExport = True if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.IsState: Gen._export_funcs.add(FuncName) # t.State 标记的函数必须保持原始名称,以便链接器解析 IsUserMarkedExport = True except Exception as _e: if _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") # 装饰器形式的存储类标记(@t.CExport / @t.CExtern / @t.State 等) deco_flags: dict[str, bool] = self._extract_decorator_storage_flags(Node) if deco_flags['is_export'] or deco_flags['is_extern'] or deco_flags['is_state']: Gen._export_funcs.add(FuncName) IsUserMarkedExport = True # 注册当前模块定义的函数名,使 _mangle_func_name 跳过 _export_extern_funcs 检查 # (_export_extern_funcs 是跨模块共享集合,包含所有 CExtern 函数名;当前模块定义的 # 同名用户函数应使用 SHA1 前缀,而非被误判为外部 C 函数返回裸名) Gen._current_module_func_names.add(FuncName) # 移除导入污染:用户函数未显式标记导出,但名称在 _export_funcs 中(来自导入的同名 C 库函数) if not IsUserMarkedExport and FuncName in Gen._export_funcs: Gen._export_funcs.discard(FuncName) MangledName: str = Gen._mangle_func_name(FuncName) need_new: bool = MangledName not in Gen.functions if not need_new: existing: Any = Gen.functions[MangledName] if getattr(existing, 'name', MangledName) != MangledName: need_new = True if need_new: try: func: ir.Function = ir.Function(Gen.module, FuncType, name=MangledName) func.attributes.add('noredzone') if hasattr(self, '_cdefine_funcs') and FuncName in self._cdefine_funcs: func.linkage = 'linkonce_odr' func.attributes.add('alwaysinline') if hasattr(self, '_pending_llvm_attrs') and FuncName in self._pending_llvm_attrs: for attr_name in self._pending_llvm_attrs[FuncName]: try: func.attributes.add(attr_name) except Exception as _e: if _config_mode == "strict": raise _vlog().warning(f"添加函数属性失败: {_e}", "Exception") Gen.functions[MangledName] = func if MangledName == FuncName or FuncName not in Gen._export_extern_funcs: Gen.functions[FuncName] = func except Exception as _e: if _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") else: existing = Gen.functions[MangledName] existing_type: ir.FunctionType | None = getattr(existing, 'ftype', None) if existing_type and existing_type != FuncType: Gen.functions[MangledName] = self._replace_function_decl(Gen, FuncName, FuncType) if MangledName == FuncName or FuncName not in Gen._export_extern_funcs: Gen.functions[FuncName] = Gen.functions[MangledName] elif not existing_type: try: Gen.functions[MangledName] = self._replace_function_decl(Gen, FuncName, FuncType) if MangledName == FuncName or FuncName not in Gen._export_extern_funcs: Gen.functions[FuncName] = Gen.functions[MangledName] except Exception as _e: if _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") self.Trans.FunctionDefCache[FuncName] = Node def _replace_function_decl(self, Gen: LlvmCodeGenerator, FuncName: str, NewFuncType: ir.FunctionType) -> ir.Function: MangledName: str = Gen._mangle_func_name(FuncName) old_func: Any = Gen.functions.get(MangledName) if old_func is None: try: return ir.Function(Gen.module, NewFuncType, name=MangledName) except Exception: # 回退:函数已存在时返回旧函数 return old_func try: old_name: str = old_func.name if old_name in getattr(Gen.module, 'globals', {}): del Gen.module.globals[old_name] module_scope: Any = getattr(Gen.module, 'scope', None) if getattr(module_scope, '_useset', None): module_scope._useset.discard(old_name) if getattr(Gen.module, '_guessed_names', None): Gen.module._guessed_names.discard(FuncName) new_func: ir.Function = ir.Function(Gen.module, NewFuncType, name=MangledName) Gen.functions[MangledName] = new_func if MangledName == FuncName or FuncName not in Gen._export_extern_funcs: Gen.functions[FuncName] = new_func return new_func except Exception as ex: traceback.print_exc() Gen.functions[MangledName] = old_func if MangledName == FuncName or FuncName not in Gen._export_extern_funcs: Gen.functions[FuncName] = old_func return old_func def _EmitFunctionLlvm(self, Node: ast.FunctionDef, Gen: LlvmCodeGenerator, ClassName: str | None = None, extra_params: list[tuple[str, ir.Type]] | None = None) -> ir.Function | None: if self._is_generic_function(Node): return FuncName, RawFuncName, func_meta = self._compute_func_name_meta(Node, ClassName) # 保存父级 _CurrentCpythonObjectClass,防止嵌套函数发射污染父方法类上下文 # (例如 HandleImport body 内触发 list[ast.ASTptr] 方法发射,结束后会清空 _CurrentCpythonObjectClass) saved_cpython_class: str | None = self.Trans._CurrentCpythonObjectClass MultiRetTypes = [] IsPtr = False fn_attrs = {} # 自定义行为装饰器列表,用于生成 wrapper 函数 # 任何 @name 或 @name(args) 只要不是内置装饰器,都视为自定义行为装饰器 behavior_decorators = [] # 内置装饰器名称,这些由编译器特殊处理,不作为行为装饰器 _BUILTIN_DECORATORS = {'staticmethod', 'property', 'classmethod'} _symtab: object = self.Trans.SymbolTable if Node.decorator_list: for decorator in Node.decorator_list: # 跳过 t 模块存储类标记装饰器(@t.CExport / @CExport 等) if self._is_t_storage_decorator(decorator, _symtab): continue # 识别自定义行为装饰器:@name(ast.Name 形式) if isinstance(decorator, ast.Name): if decorator.id not in _BUILTIN_DECORATORS: behavior_decorators.append({'name': decorator.id, 'args': [], 'kwargs': {}}) continue # 识别带参数的自定义行为装饰器:@name(arg1, key=val)(ast.Call + ast.Name 形式) if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Name): deco_name = decorator.func.id if deco_name not in _BUILTIN_DECORATORS: deco_info = {'name': deco_name, 'args': [], 'kwargs': {}} for arg in decorator.args: if isinstance(arg, ast.Constant): deco_info['args'].append(arg.value) for kw in decorator.keywords: if isinstance(kw.value, ast.Constant): deco_info['kwargs'][kw.arg] = kw.value.value behavior_decorators.append(deco_info) continue if isinstance(decorator, ast.Call) and isinstance(decorator.func, ast.Attribute): if decorator.func.attr == 'CReturn': _RejectCReturnDecorator(Node, [decorator]) elif decorator.func.attr == 'Attribute' and isinstance(decorator.func.value, ast.Name) and decorator.func.value.id == 'c': for arg in decorator.args: if isinstance(arg, ast.Call) and isinstance(arg.func, ast.Attribute): if isinstance(arg.func.value, ast.Attribute) and isinstance(arg.func.value.value, ast.Name) and IsTModule(arg.func.value.value.id, self.Trans.SymbolTable) and arg.func.value.attr == 'attr': attr_name = arg.func.attr str_args = [a.value for a in arg.args if isinstance(a, ast.Constant) and isinstance(a.value, str)] int_args = [a.value for a in arg.args if isinstance(a, ast.Constant) and isinstance(a.value, int)] if attr_name == 'section' and str_args: fn_attrs['section'] = str_args[0] elif attr_name == 'aligned' and int_args: fn_attrs['aligned'] = int_args[0] elif attr_name == 'visibility' and str_args: fn_attrs['visibility'] = str_args[0] elif attr_name in ('noreturn', 'always_inline', 'noinline', 'cold', 'hot', 'constructor', 'destructor', 'pure', 'const', 'malloc', 'returns_nonnull', 'used', 'naked', 'no_instrument_function', 'warn_unused_result', 'weak', 'fallthrough'): if not arg.args: fn_attrs[attr_name] = True elif isinstance(arg.func.value, ast.Attribute) and arg.func.value.attr == 'llvm' and isinstance(arg.func.value.value, ast.Attribute) and arg.func.value.value.attr == 'attr' and isinstance(arg.func.value.value.value, ast.Name) and IsTModule(arg.func.value.value.value.id, self.Trans.SymbolTable): llvm_attr_name = arg.func.attr if llvm_attr_name in self._LLVM_ATTR_NAMES: fn_attrs[f'llvm.{llvm_attr_name}'] = True elif isinstance(arg, ast.Attribute): if isinstance(arg.value, ast.Attribute) and isinstance(arg.value.value, ast.Name) and IsTModule(arg.value.value.id, self.Trans.SymbolTable) and arg.value.attr == 'attr': attr_name = arg.attr if attr_name in ('noreturn', 'always_inline', 'noinline', 'cold', 'hot', 'constructor', 'destructor', 'pure', 'const', 'malloc', 'returns_nonnull', 'used', 'naked', 'no_instrument_function', 'warn_unused_result', 'weak', 'fallthrough', 'packed'): fn_attrs[attr_name] = True elif isinstance(arg.value, ast.Attribute) and arg.value.attr == 'llvm' and isinstance(arg.value.value, ast.Attribute) and arg.value.value.attr == 'attr' and isinstance(arg.value.value.value, ast.Name) and IsTModule(arg.value.value.value.id, self.Trans.SymbolTable): llvm_attr_name = arg.attr if llvm_attr_name in self._LLVM_ATTR_NAMES: fn_attrs[f'llvm.{llvm_attr_name}'] = True # 检查 @t.TLS 装饰器(一次性初始化标记) is_tls_func: bool = False if Node.decorator_list: for decorator in Node.decorator_list: if isinstance(decorator, ast.Attribute) and isinstance(decorator.value, ast.Name): if IsTModule(decorator.value.id, _symtab) and decorator.attr == 'TLS': is_tls_func = True break elif isinstance(decorator, ast.Name) and decorator.id == 'TLS' and hasattr(t, 'TLS'): is_tls_func = True break if Node.returns: if isinstance(Node.returns, ast.Subscript) and isinstance(Node.returns.value, ast.Name) and Node.returns.value.id == 'tuple': slice_node = Node.returns.slice if isinstance(slice_node, ast.Tuple): for elt in slice_node.elts: MultiRetTypes.append(elt) else: MultiRetTypes.append(slice_node) # 先强制检查 str 类型注解 is_str_return = False ReturnTypeInfo = None if Node.returns: if isinstance(Node.returns, ast.Name) and Node.returns.id in ('str', 'bytes'): is_str_return = True else: try: rt_info = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable) # 仅指针层数 <=1 才算裸 str/bytes(i8*)。 # `str | t.CPtr` 合并后 IsStr=True 但 PtrCount=2(i8**,如 argv 数组), # 不能压平,否则返回类型错误。 if rt_info and rt_info.IsStr and rt_info.PtrCount <= 1: is_str_return = True except Exception as _e: if _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") if is_str_return: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CChar() ReturnTypeInfo.PtrCount = 1 elif Node.returns: if MultiRetTypes: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CVoid() else: try: if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr): ReturnTypeInfo = getattr(self.Trans, 'TypeMergeHandler', None) and self.Trans.TypeMergeHandler.MergeTypes(Node.returns) if not isinstance(ReturnTypeInfo, CTypeInfo): ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CVoid() if ((ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState) or (ReturnTypeInfo.PtrCount >= 2 and ReturnTypeInfo.BaseType is None)): def _FindNonVoidCTypeInfo(node): if isinstance(node, ast.BinOp) and isinstance(node.op, ast.BitOr): results = [] for child in [node.left, node.right]: r = _FindNonVoidCTypeInfo(child) if r and not r.IsVoid: results.append(r) for r in results: if not r.IsPtr and not r.IsStruct: return r return results[0] if results else None try: SideInfo = CTypeInfo.FromNode(node, self.Trans.SymbolTable) if SideInfo: return SideInfo except Exception as _e: if _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") return None found = _FindNonVoidCTypeInfo(Node.returns) if found and not found.IsVoid: ReturnTypeInfo = found if ReturnTypeInfo.IsVoid and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CInt() # define 宏函数(返回注解含 t.CDefine,如 `int | t.CDefine`): # 标记为编译期内联宏(alwaysinline),对齐裸 `-> t.CDefine` 路径 if AnnotationContainsName(Node.returns, 'CDefine'): if not hasattr(self, '_cdefine_funcs'): self._cdefine_funcs = set() self._cdefine_funcs.add(FuncName) else: is_str_type = False if isinstance(Node.returns, ast.Name) and Node.returns.id in ('str', 'bytes'): is_str_type = True # 与 _GetFunctionSignatureLlvm 同口径:指针下标返回注解 # (rawptr[T] / t.CPtr[T])走 ResolveAnnotationType 的 # TypeMerge 通用解析,避免内层跨模块类退化为 i8*。 ReturnTypeInfo = self.ResolveAnnotationType(Node.returns) if ReturnTypeInfo and ReturnTypeInfo.IsDefine: inferred = self._infer_return_type_from_body(Node, Gen, ClassName) if inferred: ReturnTypeInfo = CTypeInfo.FromTypeName(inferred[0]) ReturnTypeInfo.PtrCount = 1 if inferred[1] else 0 else: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CInt() if not hasattr(self, '_cdefine_funcs'): self._cdefine_funcs = set() self._cdefine_funcs.add(FuncName) elif ReturnTypeInfo and ReturnTypeInfo.IsState: pass # t.State is a modifier, preserve the actual return type if ReturnTypeInfo is None: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CVoid() # 仅指针层数 <=1 才算裸 str/bytes(i8*)。 # `str | t.CPtr` 合并后 IsStr=True 但 PtrCount=2(i8**,如 argv 数组),不能压平。 if is_str_type or (ReturnTypeInfo.IsStr and ReturnTypeInfo.PtrCount <= 1): ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CChar() ReturnTypeInfo.PtrCount = 1 # 检查泛型类返回类型 (如 list[str]) # 注意:_from_node_subscript 对未识别的泛型下标(如 list[str])返回空 CTypeInfo(BaseType=None), # 此时 IsVoid 为 False(因为 IsVoid 仅检查 t.CVoid 实例),需额外检测 BaseType is None if (isinstance(Node.returns, ast.Subscript) and isinstance(Node.returns.value, ast.Name) and hasattr(self.Trans.ClassHandler, '_generic_class_templates') and Node.returns.value.id in self.Trans.ClassHandler._generic_class_templates and (ReturnTypeInfo.IsVoid or ReturnTypeInfo.BaseType is None) and ReturnTypeInfo.PtrCount == 0): ret_class: str = Node.returns.value.id ret_slice: ast.AST = Node.returns.slice ret_type_args: list[str] = [] ret_type_names: list[str] = [] if isinstance(ret_slice, ast.Tuple): for elt in ret_slice.elts: if isinstance(elt, ast.Name): tn2: str = elt.id ts2: str = tn2 if tn2 == 'int': ts2, tn2 = 'int', 'CInt' ret_type_args.append(ts2) ret_type_names.append(tn2) elif isinstance(ret_slice, ast.Name): tn2: str = ret_slice.id ts2: str = tn2 if tn2 == 'int': ts2, tn2 = 'int', 'CInt' ret_type_args.append(ts2) ret_type_names.append(tn2) # 返回类型解析只需 struct 定义,不需方法体;使用 declare_only=True # 避免过早触发完整特化(此时 MemManager.alloc 可能尚未注册, # 导致 __new__ 的 pool.alloc(48) 解析失败,IR 块未终止)。 spec_name2: str | None = self.Trans.ClassHandler._specialize_generic_class( ret_class, ret_type_args, Gen, type_names=ret_type_names, declare_only=True) if spec_name2 and spec_name2 in Gen.structs: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CStruct(name=spec_name2) ReturnTypeInfo.PtrCount = 1 if (ReturnTypeInfo.IsVoid or ReturnTypeInfo.BaseType is None) and ReturnTypeInfo.PtrCount == 0 and not ReturnTypeInfo.IsState: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CInt() except Exception: # 回退:设置默认返回类型为 CInt ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CInt() else: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CInt() inferred = self._infer_return_type_from_body(Node, Gen, ClassName) if inferred: ReturnTypeInfo = CTypeInfo.FromTypeName(inferred[0]) ReturnTypeInfo.PtrCount = 1 if inferred[1] else 0 ReturnType = Gen._ctype_to_llvm(ReturnTypeInfo) if isinstance(ReturnType, ir.VoidType) and FuncName == 'main': ReturnType = ir.IntType(32) IsMethod, IsClassMethod, ResolvedClassName = self._resolve_method_class(Node, ClassName, func_meta, FuncName, Gen) # __new__ methods should return a pointer to the struct (for heap allocation replacement) if RawFuncName == '__new__' and ResolvedClassName: StructType = Gen.structs.get(ResolvedClassName) if StructType: if isinstance(StructType, ir.PointerType): ReturnType = StructType else: ReturnType = ir.PointerType(StructType) ParamTypes = [] ParamNames = [] ParamTypeStrs = [] auto_addr_modes_emit: list[str | None] = [] self.Trans.VarScopes.append({}) for Arg in Node.args.args: ParamIsUnsigned = False if Arg.annotation: try: ParamTypeInfo = self.ResolveParamAnnotation(Arg.annotation) if ParamTypeInfo is None: ParamTypeInfo = CTypeInfo() ParamTypeInfo.BaseType = t.CInt() IsPtr = ParamTypeInfo.IsPtr if ParamTypeInfo and getattr(ParamTypeInfo, 'IsCpythonObject', False) and not IsPtr: IsPtr = True ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1) # 仅当指针层数 <=1 时才压平为 i8*(裸 str/bytes)。 # `str | t.CPtr` 合并后 IsStr=True 但 PtrCount=2(i8**,如 argv 数组), # 不能压平,否则形参类型错误导致 _adjust_args 多 load 一层崩溃。 if (ParamTypeInfo.IsStr and ParamTypeInfo.PtrCount <= 1) or (isinstance(Arg.annotation, ast.Name) and Arg.annotation.id in ('str', 'bytes')): ParamTypeInfo = CTypeInfo() ParamTypeInfo.BaseType = t.CChar() ParamTypeInfo.PtrCount = 1 IsPtr = True # C 语言中数组参数退化为指针:list[type, N] → type* if ParamTypeInfo.ArrayDims: ParamTypeInfo.ArrayDims = [] ParamTypeInfo.PtrCount = max(ParamTypeInfo.PtrCount, 1) ParamType = Gen._ctype_to_llvm(ParamTypeInfo) # 参数类型不能是 VoidType:C 语言不允许 void 参数, # VoidType 说明类型注解无法识别(如跨模块 ast.expr),直接报错终止 if isinstance(ParamType, ir.VoidType): AnnStr: str = ast.unparse(Arg.annotation) if hasattr(ast, 'unparse') else str(Arg.annotation) raise SyntaxError( f"无法识别的参数类型注解: '{AnnStr}'(在函数 '{Node.name}' 的参数 '{Arg.arg}' 上)。" f"请使用有效的 TPV 类型(如 t.CPtr、ast.AST 或已注册的结构体)。" ) if ParamTypeInfo and ParamTypeInfo.IsFuncPtr: ParamType = ir.IntType(8).as_pointer() ParamIsUnsigned = ParamTypeInfo.IsUInt except SyntaxError: raise except Exception: # 回退:参数类型解析失败时使用默认 i32 ParamType = ir.IntType(32) ParamTypeInfo = CTypeInfo() ParamTypeInfo.BaseType = t.CInt() else: ParamType = ir.IntType(32) ParamTypeInfo = CTypeInfo() ParamTypeInfo.BaseType = t.CInt() ParamTypes.append(ParamType) ParamNames.append(Arg.arg) ParamTypeStrs.append(ParamTypeInfo) # 检测 t.CNeedPtr / t.CAutoPtr 参数注解 auto_mode_emit: str | None = None if ParamTypeInfo is not None and hasattr(ParamTypeInfo, 'BaseType') and ParamTypeInfo.BaseType is not None: if isinstance(ParamTypeInfo.BaseType, t.CAutoPtr): auto_mode_emit = 'always' elif isinstance(ParamTypeInfo.BaseType, t.CNeedPtr): auto_mode_emit = 'need' auto_addr_modes_emit.append(auto_mode_emit) Gen._record_var_signedness(Arg.arg, ParamIsUnsigned) self.Trans.VarScopes[-1][Arg.arg] = ParamTypeInfo if Arg.annotation: try: PInfo = self.ResolveAnnotationType(Arg.annotation) # const/volatile 形参登记(统一登记入口)。const 判据沿用形参历史 # 条件(IsParam=True,见 BaseGen.RegisterVarQualifiers 说明); # volatile / pointee-volatile 与 TransPyV 侧同口径。 Gen.RegisterVarQualifiers(Arg.arg, PInfo, Arg.annotation, IsParam=True) except Exception as _e: if _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") if MultiRetTypes: MultiRetLlvmTypes = [] for i, ReturnTypeNode in enumerate(MultiRetTypes): ReturnTypeInfo = CTypeInfo.FromNode(ReturnTypeNode, self.Trans.SymbolTable) # 仅指针层数 <=1 才算裸 str/bytes(i8*)。 # `str | t.CPtr` 合并后 IsStr=True 但 PtrCount=2(i8**,如 argv 数组),不能压平。 if ReturnTypeInfo and ReturnTypeInfo.IsStr and ReturnTypeInfo.PtrCount <= 1: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CChar() ReturnTypeInfo.PtrCount = 1 if ReturnTypeInfo is None: ReturnTypeInfo = CTypeInfo() ReturnTypeInfo.BaseType = t.CInt() RetType = Gen._ctype_to_llvm(ReturnTypeInfo) MultiRetLlvmTypes.append(RetType) ReturnType = ir.LiteralStructType(MultiRetLlvmTypes) self.Trans.CurrentMultiRetTypes = MultiRetTypes else: self.Trans.CurrentMultiRetTypes = None self._apply_struct_self_cls_types(ParamTypes, ParamNames, IsMethod, IsClassMethod, ResolvedClassName, Gen) IsVariadic = Node.args.vararg is not None if extra_params: for var_name, ptr_type in extra_params: ParamTypes.append(ptr_type) ParamNames.append(f'__nonlocal_{var_name}__') HasStopIterFlag = False if IsMethod and RawFuncName == '__next__': ParamTypes.append(ir.PointerType(ir.IntType(1))) ParamNames.append('__stop_iter_flag__') HasStopIterFlag = True HasRaise = self._body_contains_raise(Node.body) if HasRaise and RawFuncName != 'main': ParamTypes.append(ir.PointerType(ir.PointerType(ir.IntType(8)))) ParamNames.append('__eh_msg_out__') ParamTypes.append(ir.PointerType(ir.IntType(32))) ParamNames.append('__eh_code_out__') FuncType = ir.FunctionType(ReturnType, ParamTypes, var_arg=IsVariadic) # 存储 auto_addr_modes(为额外参数补 None) total_params_emit: int = len(ParamTypes) while len(auto_addr_modes_emit) < total_params_emit: auto_addr_modes_emit.append(None) Gen._auto_addr_params[FuncName] = auto_addr_modes_emit self.Trans.FunctionDefCache[FuncName] = Node IsInlineFunc = False IsExternFunc = False IsStateFunc = False IsUserMarkedExport: bool = False if Node.returns: try: RetTypeInfo = None RetTypeInfo = self.ResolveAnnotationType(Node.returns) if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CInline): IsInlineFunc = True if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CExport) and not RetTypeInfo.IsState: Gen._export_funcs.add(FuncName) IsUserMarkedExport = True if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, t.CExtern): IsExternFunc = True Gen._export_funcs.add(FuncName) IsUserMarkedExport = True if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.IsState: IsStateFunc = True Gen._export_funcs.add(FuncName) # 外部 C 函数声明必须保持原始名称 IsUserMarkedExport = True except Exception as _e: if _config_mode == "strict": self.Trans.LogWarning(f"异常被忽略: {_e}") # 装饰器形式的存储类标记(@t.CExport / @t.CExtern / @t.CStatic / @t.State / @t.CInline) deco_flags: dict[str, bool] = self._extract_decorator_storage_flags(Node) if deco_flags['is_inline']: IsInlineFunc = True if deco_flags['is_extern']: IsExternFunc = True if deco_flags['is_state']: IsStateFunc = True if deco_flags['is_export'] or deco_flags['is_extern'] or deco_flags['is_state']: Gen._export_funcs.add(FuncName) IsUserMarkedExport = True # 注册当前模块定义的函数名,使 _mangle_func_name 跳过 _export_extern_funcs 检查 Gen._current_module_func_names.add(FuncName) # 移除导入污染:用户函数未显式标记导出,但名称在 _export_funcs 中(来自导入的同名 C 库函数) if not IsUserMarkedExport and FuncName in Gen._export_funcs: Gen._export_funcs.discard(FuncName) MangledName = Gen._mangle_func_name(FuncName) if MangledName in Gen.functions: func = Gen.functions[MangledName] if getattr(func, 'name', MangledName) != MangledName: func = ir.Function(Gen.module, FuncType, name=MangledName) Gen.functions[MangledName] = func else: existing_type = getattr(func, 'ftype', None) if existing_type and existing_type != FuncType: func = self._replace_function_decl(Gen, FuncName, FuncType) else: func = ir.Function(Gen.module, FuncType, name=MangledName) Gen.functions[MangledName] = func if MangledName == FuncName or FuncName not in Gen._export_extern_funcs: Gen.functions[FuncName] = func func.attributes.add('noredzone') # 泛型特化类方法(如 GSList[NameEntry].__before_init__):多个模块各自 # 特化会生成同名定义(external linkage)→ ld.lld duplicate symbol warning。 # 特化方法代码由相同模板+类型参数生成,定义相同,设 linkonce_odr 让 # 链接器合并重复定义(linkonce_odr 的 alwaysinline 不适用,仅改 linkage)。 is_spec_generic_method: bool = '[' in FuncName if IsInlineFunc: func.linkage = 'linkonce_odr' func.attributes.add('alwaysinline') if is_spec_generic_method: func.linkage = 'linkonce_odr' if hasattr(self, '_cdefine_funcs') and FuncName in self._cdefine_funcs: func.linkage = 'linkonce_odr' func.attributes.add('alwaysinline') if fn_attrs: _LLVM_FN_ATTR_MAP = { 'noreturn': 'noreturn', 'always_inline': 'alwaysinline', 'noinline': 'noinline', 'cold': 'cold', 'hot': 'hot', 'constructor': 'constructor', 'destructor': 'destructor', 'malloc': 'malloc', 'returns_nonnull': 'returns_nonnull', 'used': 'used', 'naked': 'naked', 'no_instrument_function': 'no_instrument_function', 'warn_unused_result': 'warn_unused_result', 'fallthrough': 'fallthrough', 'pure': 'readonly', 'const': 'readnone', } if 'section' in fn_attrs: func.section = fn_attrs['section'] if 'visibility' in fn_attrs: func.linkage = 'internal' func.attributes.add('visibility') if fn_attrs.get('weak'): func.linkage = 'weak' for attr_name, llvm_name in _LLVM_FN_ATTR_MAP.items(): if fn_attrs.get(attr_name): try: func.attributes.add(llvm_name) except Exception as _e: if _config_mode == "strict": raise _vlog().warning(f"添加函数属性失败: {_e}", "Exception") for key in fn_attrs: if key.startswith('llvm.'): llvm_attr_name = key[5:] try: func.attributes.add(llvm_attr_name) except Exception as _e: # llvmlite 不支持某些较新的 LLVM 属性(如 willreturn, mustprogress) # 记录下来,后续通过 IR 后处理添加 if not hasattr(Gen, '_pending_str_attrs'): Gen._pending_str_attrs = {} Gen._pending_str_attrs.setdefault(MangledName, []).append(llvm_attr_name) if hasattr(self, '_pending_llvm_attrs') and FuncName in self._pending_llvm_attrs: for attr_name in self._pending_llvm_attrs.pop(FuncName): try: func.attributes.add(attr_name) except Exception as _e: # llvmlite 不支持的属性,记录下来后续通过 IR 后处理添加 if not hasattr(Gen, '_pending_str_attrs'): Gen._pending_str_attrs = {} Gen._pending_str_attrs.setdefault(MangledName, []).append(attr_name) # 记录自定义行为装饰器信息,供 DecoratorPass 使用 if behavior_decorators: Gen._decorated_funcs[MangledName] = { 'decorators': behavior_decorators, 'func_name': FuncName, 'func_type': FuncType, 'return_type': FuncType.return_type, 'param_types': [p.type for p in func.args], 'param_names': ParamNames, 'is_export': FuncName in Gen._export_funcs, } if IsExternFunc or IsStateFunc: return # 治本修复:如果函数已经有 body(blocks 不为空),跳过重复编译。 # 否则会导致同一函数被追加第二个 entry block(llvmlite 自动重命名为 entry.1), # 产生非法 IR:两个 entry block + 第二个 block 无前驱成为死代码。 # 触发场景:泛型特化路径 _EmitGenericSpecialization 先调用 _EmitFunctionForwardDeclLlvm # 再调用 _EmitFunctionLlvm,若特化在多个调用点被重复触发(如 list[str] 在 split/upper 等多处使用), # 同一 MangledName 会进入此函数两次,第二次会重复追加 entry block。 existing_blocks: list = getattr(func, 'blocks', []) if existing_blocks: return func 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() if 'aligned' in fn_attrs: Gen._emit_stack_align(fn_attrs['aligned']) # 保存当前的 var_type_info,以便函数结束时恢复 saved_var_type_info = Gen.var_type_info.copy() saved_var_type_assignments = Gen.var_type_assignments.copy() # 治本修复:保存并清空 _local_heap_ptrs / _var_to_heap_ptr。 # 当 with 上下文中的代码(如 s1.split(','))触发内联编译 list[str].__new__ 时, # 若不清空,__new__ 方法会继承外层 with 的 _local_heap_ptrs(含 %call_enter 条目), # 方法结束时 _emit_local_heap_frees 会尝试 bitcast/free %call_enter, # 但该值在 __new__ 作用域中不存在 → llc 报错 'use of undefined value'。 saved_local_heap_ptrs = list(Gen._local_heap_ptrs) saved_var_to_heap_ptr = dict(Gen._var_to_heap_ptr) Gen._local_heap_ptrs = [] Gen._var_to_heap_ptr = {} # 治本修复:保存 var_struct_class / global_struct_class。 # 当方法调用(如 a.delete())触发 _try_complete_generic_specialization 时, # 该路径走 _EmitFunctionLlvm 编译方法体,函数结尾会清空 var_struct_class。 # 若不保存/恢复,外层函数中已设置的 var_struct_class(如 b='ndarray[double]') # 会被清空,导致后续方法调用 fallback 匹配 opaque 基础类型(如 ndarray), # 生成对 stub declare(无方法体)的调用 → 链接报 undefined reference。 saved_var_struct_class = dict(Gen.var_struct_class) if Gen.var_struct_class else {} saved_global_struct_class = dict(Gen.global_struct_class) if getattr(Gen, 'global_struct_class', None) else {} # 函数内部定义的变量会在赋值时添加到 var_type_info 中 # 这样函数内部定义的元类型变量(如 a = t.CInt32T)就能被正确处理 for stmt in Node.body: if isinstance(stmt, ast.Global): self.Trans.ForHandler._RegisterGlobalNames(stmt.names, Gen) for param, param_name in zip(func.args, ParamNames): param.name = param_name if param_name == '__stop_iter_flag__': Gen._stop_iter_flag_param = param Gen.builder.store(ir.Constant(ir.IntType(1), 0), param) elif param_name.startswith('__nonlocal_') and param_name.endswith('__'): var_name = param_name[len('__nonlocal_'):-2] Gen.variables[var_name] = param else: if isinstance(param.type, ir.PointerType) and isinstance(param.type.pointee, (ir.LiteralStructType, ir.IdentifiedStructType)): var = Gen.builder.alloca(param.type, name=param_name) Gen._store(param, var) Gen.variables[param_name] = var for CN, ST in Gen.structs.items(): if param.type.pointee == ST or (isinstance(param.type.pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and param.type.pointee.name == ST.name): Gen.var_struct_class[param_name] = CN break elif isinstance(param.type, (ir.LiteralStructType, ir.IdentifiedStructType)): var = Gen.builder.alloca(param.type, name=param_name) Gen._store(param, var) Gen.variables[param_name] = var for CN, ST in Gen.structs.items(): if param.type == ST or (isinstance(param.type, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and param.type.name == ST.name): Gen.var_struct_class[param_name] = CN break else: # 所有参数都存入 alloca,确保循环体中对参数的修改能正确反映 var = Gen._allocaEntry(param.type, name=param_name) Gen._store(param, var) Gen.variables[param_name] = var # 为联合类型注解(如 Function | t.CPtr)的参数设置 var_struct_class, # 确保编译器能正确生成 GEP 访问结构体成员(如 func.Blocks、func.Params) for i, arg in enumerate(Node.args.args): if arg.annotation and isinstance(arg.annotation, ast.BinOp) and isinstance(arg.annotation.op, ast.BitOr): param_name: str = ParamNames[i] if i < len(ParamNames) else arg.arg if param_name in Gen.variables: # 若 L1650-1657 已根据 param.type.pointee 匹配到正确的特化名 # (如 ndarray[double]),不覆盖:FindStructNameInAnnotation 对 # 泛型注解 ndarray[t.CDouble] 会构造 ndarray[CDouble](与实际 # ndarray[double] 不匹配),回退到裸模板类名 ndarray(opaque), # 导致方法调用查找 ndarray.sum 而非 ndarray[double].sum。 if param_name in Gen.var_struct_class: _existing_ps: str = Gen.var_struct_class[param_name] # 指针占位名(rawptr / {sha1}.rawptr / rawptr[...])是模块限定 # struct 联合(llvmlite.Function | t.CPtr)被 resolver 退化 # 的产物,必须允许 FindStructNameInAnnotation 短名修正 # (否则 func.IsVarArg → "属性在类 'rawptr' 中找不到")。 if not (_existing_ps == 'rawptr' or '.rawptr' in _existing_ps or _existing_ps.startswith('rawptr[')): continue found_struct: str | None = FindStructNameInAnnotationWithContext( arg.annotation, self.Trans, Gen) if found_struct: Gen.var_struct_class[param_name] = found_struct # 普通类注解形参(非 BinOp 联合):rawptr[X] / t.CPtr[X] / X / t.X # 一律按"声明类"登记 var_struct_class。避免按 param.type.pointee 匹配 # 到泛型父特化(如 class Function(GSListNode[Function]) 的形参 func 被 # 登记成 GSListNode[Function],其 struct 仅含 Next → func.Blocks 访问 # fast-fail "属性 'Blocks' 在类 'GSListNode[Function]' 中找不到")。 # 泛型占位(rawptr[T])的 T 不在 Gen.structs,自动跳过、保留 pointee 匹配。 for i, arg in enumerate(Node.args.args): if arg.annotation is None: continue if isinstance(arg.annotation, ast.BinOp) and isinstance(arg.annotation.op, ast.BitOr): continue # 联合注解由上方循环处理 param_name = ParamNames[i] if i < len(ParamNames) else arg.arg if param_name not in Gen.variables: continue ann = arg.annotation target: str | None = None if isinstance(ann, ast.Name): target = ann.id elif isinstance(ann, ast.Attribute): target = ann.attr elif isinstance(ann, ast.Subscript): subv = ann.value subname = getattr(subv, 'id', None) or getattr(subv, 'attr', '') if subname in ('rawptr', 'CPtr', 'Ptr'): slc = ann.slice if isinstance(slc, ast.Name): target = slc.id elif isinstance(slc, ast.Attribute): target = slc.attr if not target: continue key: str | None = target if target in Gen.structs else None if key is None: _sha_t: str | None = (getattr(Gen, 'class_sha1_map', {}) or {}).get(target) if _sha_t and f'{_sha_t}.{target}' in Gen.structs: key = f'{_sha_t}.{target}' if key: Gen.var_struct_class[param_name] = key if ResolvedClassName and (IsMethod or RawFuncName == '__init__'): self.Trans._CurrentCpythonObjectClass = ResolvedClassName Gen._variadic_info = None if IsVariadic and Node.args.vararg: vararg_name = getattr(Node.args.vararg, 'arg', 'args') last_param_name = ParamNames[-1] if ParamNames else None last_param_ptr = None for param, pn in zip(func.args, ParamNames): if pn == last_param_name: last_param_ptr = param break triple = getattr(Gen, 'module_triple', '') or getattr(Gen.module, 'triple', '') is_windows = 'windows' in triple if triple else False ptr_size = getattr(Gen, 'ptr_size', 8) # va_list 大小取决于 ABI:Windows x64 = __va_list_tag(24字节),Linux x64 = __va_list_tag[1](24字节) # 注意:x86_64-pc-windows-gnu 的 llvm.va_start 写的是 24 字节的 struct __va_list_tag # ({i32 gp_offset, i32 fp_offset, i8* overflow_arg_area, i8* reg_save_area}), # 若只分配 8 字节会向调用者栈帧越界写 16 字节,导致随机栈破坏(历史崩溃根因)。 if ptr_size == 4: va_list_size = 4 if is_windows else 12 va_list_align = 4 else: va_list_size = 24 va_list_align = 16 va_list_type = ir.ArrayType(ir.IntType(8), va_list_size) va_list_alloc = Gen._allocaEntry(va_list_type, name=f"{vararg_name}_va_list", align=va_list_align) va_list_ptr = Gen.builder.bitcast(va_list_alloc, ir.IntType(8).as_pointer(), name=f"{vararg_name}_va_list_i8ptr") Gen._variadic_info = { 'vararg_name': vararg_name, 'va_list_ptr': va_list_ptr, 'last_param_ptr': last_param_ptr, 'va_start_called': False, } if last_param_ptr: last_param_alloc = Gen._allocaEntry(last_param_ptr.type, name="last_param_copy") Gen.builder.store(last_param_ptr, last_param_alloc) Gen.emit_va_start(va_list_ptr) Gen._variadic_info['va_start_called'] = True # 用 _direct_values 注册,Name 解析时直接返回 va_list 指针(i8*), # 不走 variables 的 load 路径(否则会把 i8* 当 char* 加载一个字节) Gen._direct_values[vararg_name] = va_list_ptr # @t.TLS 一次性初始化检查:首次调用执行函数体,后续调用直接返回 if is_tls_func: flag_name: str = f"__tls_init_done_{FuncName}" flag_global = None for gv in Gen.module.global_values: if gv.name == flag_name: flag_global = gv break if flag_global is None: flag_global = ir.GlobalVariable(Gen.module, ir.IntType(1), name=flag_name) flag_global.initializer = ir.Constant(ir.IntType(1), 0) flag_global.linkage = 'internal' flag_val = Gen.builder.load(flag_global, name="tls_flag_check") skip_bb = func.append_basic_block("tls_skip") cont_bb = func.append_basic_block("tls_continue") Gen.builder.cbranch(flag_val, skip_bb, cont_bb) Gen.builder.position_at_end(skip_bb) ActualReturnType = func.function_type.return_type if isinstance(ActualReturnType, ir.VoidType): Gen.builder.ret_void() elif isinstance(ActualReturnType, ir.IntType): Gen.builder.ret(ir.Constant(ActualReturnType, 0)) elif isinstance(ActualReturnType, (ir.FloatType, ir.DoubleType)): Gen.builder.ret(ir.Constant(ActualReturnType, 0.0)) elif isinstance(ActualReturnType, ir.PointerType): Gen.builder.ret(ir.Constant(ActualReturnType, None)) else: Gen.builder.ret(ir.Constant(ActualReturnType, None)) Gen.builder.position_at_end(cont_bb) Gen.builder.store(ir.Constant(ir.IntType(1), 1), flag_global) _saved_class_name = getattr(Gen, '_current_class_name', None) Gen._current_class_name = ClassName # 提取首个裸字符串字面量作为 __doc__ docstring,并跳过该节点避免生成死代码 func_body: list[ast.stmt] = Node.body doc_symbol: str = f"{ClassName}.{Node.name}" if ClassName else Node.name if (func_body and isinstance(func_body[0], ast.Expr) and isinstance(func_body[0].value, ast.Constant) and isinstance(func_body[0].value.value, str)): Gen._create_doc_global(doc_symbol, func_body[0].value.value) func_body = func_body[1:] else: Gen._create_doc_global(doc_symbol, None) try: self.Trans.BodyHandler.HandleBodyLlvm(func_body) except Exception as _body_exc: # 方法体编译失败:确保 block 终止(防止 expected instruction opcode 错误), # 然后重新抛出异常让编译立即终止(不吞掉错误) _fn_name: str = Node.name _cls_name: str = ClassName if ClassName else '' import sys as _sys import traceback as _tb print(f"[FATAL] 方法体编译失败 ({_cls_name}.{_fn_name}): {type(_body_exc).__name__}: {_body_exc}", file=_sys.stderr) _tb.print_exc(file=_sys.stderr) if Gen.builder is not None: try: if not Gen.builder.block.is_terminated: _ret_ty = func.function_type.return_type if isinstance(_ret_ty, ir.VoidType): Gen.builder.ret_void() elif isinstance(_ret_ty, ir.PointerType): Gen.builder.ret(ir.Constant(_ret_ty, None)) elif isinstance(_ret_ty, ir.IntType): Gen.builder.ret(ir.Constant(_ret_ty, 0)) else: Gen.builder.ret(ir.Constant(_ret_ty, None)) except Exception: try: if Gen.builder and not Gen.builder.block.is_terminated: Gen.builder.ret_void() except Exception: pass raise if not Gen.builder.block.is_terminated: if 'naked' in fn_attrs: Gen.builder.unreachable() self.Trans._CurrentCpythonObjectClass = saved_cpython_class return # fail-fast:有非 void 返回类型注解但函数体掉出末尾(无显式 return 覆盖) # → 立即报错,不静默 ret 0(用户隐式返回规则)。 # 判据按**源码层面**函数体末句判断(不依赖 builder 状态——翻译后未 # terminated 可能由其它翻译问题导致,如 HandleExprLlvm 返回 None 静默 # 跳过 ret,不该归类为"掉出末尾"缺陷): # - 末句是显式 return → 有覆盖,正常 # - 末句是控制流(If/Match/While/For/Try/With)→ 掉出合法(隐式返回 # 规则:末句控制流 → unreachable;match/if 合成 after 块机械掉出, # 所有 arm 已 terminated 属正常) # - 末句是普通语句 → 真掉出末尾;-> None / -> t.CVoid 视为 Void 合法, # 无注解 → C 风格过程(ConstZero,保持现状);其余注解报错 _last_stmt = Node.body[-1] if Node.body else None _is_ret_or_ctrl_tail: bool = isinstance(_last_stmt, ( ast.Return, ast.If, ast.Match, ast.While, ast.For, ast.Try, ast.With)) if Node.returns is not None and not _is_ret_or_ctrl_tail: # void(None / t.CVoid,含 | 联合)/ extern|export 声明型辅助符号 # (State / CExport / CExtern)→ 掉出合法,不 fail-fast if not _IsVoidOrDeclAnnotation(Node.returns): raise Exception( f"函数 {Node.name} 声明了返回类型但函数体可能掉出末尾(缺少 return 语句);" f"普通语句掉出末尾 + 有返回注解属于定义缺陷,请补显式 return") Gen._emit_local_heap_frees() if Gen._variadic_info and Gen._variadic_info.get('va_start_called'): va_list_ptr = Gen._variadic_info.get('va_list_ptr') if va_list_ptr: Gen.emit_va_end(va_list_ptr) ActualReturnType = func.function_type.return_type if isinstance(ActualReturnType, ir.VoidType): Gen.builder.ret_void() elif isinstance(ActualReturnType, ir.IntType): Gen.builder.ret(ir.Constant(ActualReturnType, 0)) elif isinstance(ActualReturnType, (ir.FloatType, ir.DoubleType)): Gen.builder.ret(ir.Constant(ActualReturnType, 0.0)) elif isinstance(ActualReturnType, ir.PointerType): Gen.builder.ret(ir.Constant(ActualReturnType, None)) elif isinstance(ActualReturnType, ir.IdentifiedStructType): if ActualReturnType.elements: zero_val = ir.Constant(ActualReturnType, [ir.Constant(et, None) if isinstance(et, (ir.PointerType, ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)) else ir.Constant(et, 0) if isinstance(et, (ir.IntType, ir.FloatType, ir.DoubleType)) else ir.Constant(et, ir.Undefined) for et in ActualReturnType.elements]) else: zero_val = ir.Constant(ActualReturnType, None) Gen.builder.ret(zero_val) elif isinstance(ActualReturnType, ir.ArrayType): 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 Gen.variables = {} Gen.var_signedness = {} Gen._reg_values = {} Gen._direct_values = {} Gen.var_struct_class = {} Gen.var_ptr_element = {} Gen.var_const_flags = {} # const/volatile 的**函数作用域层**随函数出栈清空(模块级层 global_* 与 # 类字段层 field_* 是持久的,不在此清;见 BaseGen 的登记说明)。 Gen.var_volatile_flags = {} Gen.var_pointee_volatile_flags = {} # 恢复保存的 var_type_info Gen.var_type_info = saved_var_type_info Gen.var_type_assignments = saved_var_type_assignments Gen._stop_iter_flag_param = None # 恢复外层作用域的 _local_heap_ptrs / _var_to_heap_ptr Gen._local_heap_ptrs = saved_local_heap_ptrs Gen._var_to_heap_ptr = saved_var_to_heap_ptr # 恢复外层作用域的 var_struct_class / global_struct_class # (内层方法体编译不应污染外层函数的变量-类型映射) Gen.var_struct_class = saved_var_struct_class if hasattr(Gen, 'global_struct_class'): Gen.global_struct_class = saved_global_struct_class Gen._variadic_info = None self.Trans._CurrentCpythonObjectClass = saved_cpython_class self.Trans.CurrentMultiRetTypes = None if self.Trans.VarScopes: self.Trans.VarScopes.pop() self.Trans.FunctionReturnTypes[FuncName] = ReturnTypeInfo if not self.Trans.SymbolTable.has(FuncName): FuncInfo = CTypeInfo() FuncInfo.Name = FuncName FuncInfo.IsFunction = True FuncInfo.MetaList = func_meta if IsInlineFunc: FuncInfo.IsInline = True FuncInfo.InlineBody = Node.body FuncInfo.InlineParams = [arg.arg for arg in Node.args.args] self.Trans.SymbolTable.insert(FuncName, FuncInfo) else: existing = self.Trans.SymbolTable[FuncName] if existing.MetaList == FuncMeta.NONE and func_meta != FuncMeta.NONE: existing.MetaList = func_meta if IsInlineFunc: existing.IsInline = True existing.InlineBody = Node.body existing.InlineParams = [arg.arg for arg in Node.args.args] # property setter/deleter: 在原始 PropKey(不带后缀)下注册 MetaList if FuncMeta.PROPERTY_SETTER in func_meta or FuncMeta.PROPERTY_DELETER in func_meta: BasePropKey = f"{ClassName}.{RawFuncName}" if ClassName else RawFuncName base_existing = self.Trans.SymbolTable.lookup(BasePropKey) if base_existing: if func_meta != FuncMeta.NONE: base_existing.MetaList = base_existing.MetaList | func_meta else: PropInfo = CTypeInfo() PropInfo.Name = BasePropKey PropInfo.IsFunction = True PropInfo.MetaList = func_meta self.Trans.SymbolTable.insert(BasePropKey, PropInfo) return func