Files
TransPyC/lib/core/Handles/HandlesFunctions.py
T
TermiNexus 88645fe7da fix(func): extern/export 声明跳过掉出末尾检查
FunctionDef.Extern/Export 为真时视为声明型函数,不再要求显式 return。
2026-10-18 20:18:36 +08:00

2207 lines
131 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 FindAutoAddrMode
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
from lib.core import TypeSystem
from lib.core.TypeSystem import CTypeRegistry
# 内建存储类标记装饰器名称集合
_T_STORAGE_DECORATORS = frozenset({'CExport', 'CExtern', 'CStatic', 'State', 'CInline', 'TLS'})
# `@CReturn` 装饰器已移除;任何地方遇到都必须 fail-fast,不得静默忽略或改写。
_CRETURN_REMOVED_HINT: str = (
"`@CReturn` 已移除:请改用返回注解 `-> tuple[ty1, ty2, ...]`(多返回值打包为 struct)"
)
def _RejectCReturnDecorator(node: ast.AST, decorators: list[ast.AST]) -> None:
"""扫到 `@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', '<unknown>')
raise SyntaxError(f"函数 '{func_name}':{_CRETURN_REMOVED_HINT}")
def _RejectRefReturnAnnotation(node: ast.AST) -> None:
"""返回注解出现值引用标记(`&T` / `&temp T`)即 fail-fast。
值引用仅用于函数参数位;返回位一律拒绝,禁止静默按指针降级。
"""
if getattr(node, 'returns', None) is None:
return
if FindAutoAddrMode(node.returns) is not None:
from lib.core.LLVMCG.FuncGen import FailFastError
func_name: str = getattr(node, 'name', '<unknown>')
raise FailFastError(
f"返回注解不支持值引用 `&T` / `&temp T`(函数 '{func_name}'):"
f"值引用仅用于函数参数位;返回位请改用显式指针类型(如 `T*`)。")
def _IsVoidOrDeclAnnotation(Annot: ast.AST) -> bool:
"""判断函数返回注解是否为 void 或 extern/export 声明型辅助符号。
void:None / CVoid。
声明型辅助符号:State(extern)/ CExport(export)/ CExtern——
此类函数 body 为空(extern 声明),掉出末尾是正常形态,必须豁免 fail-fast。
"""
if isinstance(Annot, ast.BinOp) and isinstance(Annot.op, ast.BitOr):
Line: int = getattr(Annot, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
# 新表示:修饰词写入注解节点的 Markers(State/CExport/CExtern -> state/export/extern)。
Markers: tuple[str, ...] = getattr(Annot, 'Markers', None) or ()
if 'state' in Markers or 'export' in Markers or 'extern' in Markers:
return True
if isinstance(Annot, ast.Constant):
return Annot.value is None
if isinstance(Annot, ast.Subscript):
return _IsVoidOrDeclAnnotation(Annot.value)
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]:
"""从装饰器列表中提取内建存储类标记
支持 @CExport, @CExtern, @CStatic, @State, @CInline
内建标记按裸名书写,如 @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
# 内建标记按裸名书写(@CExport / @CStatic / ...)
if isinstance(decorator, ast.Name):
cls: type | None = getattr(TypeSystem, decorator.id, None)
if cls is None and hasattr(symtab, '_builtin_type_symbols'):
cls = symtab._builtin_type_symbols.get(decorator.id)
if cls is not None and isinstance(cls, type) and issubclass(cls, TypeSystem.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:
"""检查装饰器是否是内建存储类标记(用于排除 behavior_decorators)"""
attr_name: str | None = None
if isinstance(decorator, ast.Name):
cls: type | None = getattr(TypeSystem, decorator.id, None)
if cls is None and hasattr(symtab, '_builtin_type_symbols'):
cls = symtab._builtin_type_symbols.get(decorator.id)
if cls is not None and isinstance(cls, type) and issubclass(cls, TypeSystem.CType):
attr_name = cls.__name__
elif decorator.id in _T_STORAGE_DECORATORS and hasattr(TypeSystem, 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] = []
for raw_attr in getattr(node, 'Attributes', None) or ():
attr_name: str = str(raw_attr).split('(', 1)[0].strip()
if attr_name in self._LLVM_ATTR_NAMES:
attrs.append(attr_name)
if isinstance(node, ast.Attribute):
resolved: str | None = self._GetAttrLLVMName(node)
if resolved:
attrs.append(resolved)
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.Name) or inner.id != 'attr':
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('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)
_RejectRefReturnAnnotation(Node)
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 = TypeSystem.CVoid()
else:
try:
if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr):
Line: int = getattr(Node.returns, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
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] / 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 = TypeSystem.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, TypeSystem.CVoid)):
pass
else:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CVoid()
if ReturnTypeInfo is None:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CVoid()
# 仅指针层数 <=1 才算裸 str/bytes(i8*)。
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,不能压平。
if is_str_type or (ReturnTypeInfo.IsStr and ReturnTypeInfo.PtrCount <= 1):
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CChar()
ReturnTypeInfo.PtrCount = 1
# 检查泛型类返回类型 (如 list[str])
# 注意:_from_node_subscript 对未识别的泛型下标(如 list[str])返回空 CTypeInfo(BaseType=None),
# 此时 IsVoid 为 False(因为 IsVoid 仅检查 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。
try:
spec_name2: str | None = self.Trans.ClassHandler._specialize_generic_class(
ret_class, ret_type_args, Gen, type_names=ret_type_names, declare_only=True)
except Exception as _spec_err:
# 不静默吞特化异常:记录到 Gen._generic_spec_error 后再
# 交给外层返回类型回退(否则只剩一个错误的 CInt 返回类型)。
Gen._generic_spec_error = f'{type(_spec_err).__name__}: {_spec_err}'
raise
if spec_name2 and spec_name2 in Gen.structs:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.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 = TypeSystem.CInt()
except TypeError:
raise
except Exception: # 回退:设置默认返回类型为 CInt
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CInt()
else:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.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]]` / `-> CPtr[CPtr[X]]`)
# 与泛型特化方法返回(`list[X**]` 的 get/pop/__getitem__/__next__)少算一层,
# 与同函数的形参(`append(item: T)` 保留 `X**`)、声明端
# DeclarationGenerator._get_type_str 的指针下标分支(同样不压层,见
# '_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*)。
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,不能压平。
if ReturnTypeInfo and ReturnTypeInfo.IsStr and ReturnTypeInfo.PtrCount <= 1:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CChar()
ReturnTypeInfo.PtrCount = 1
if ReturnTypeInfo is None:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.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 = TypeSystem.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)。
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,
# 不能压平,否则形参类型错误导致 _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 = TypeSystem.CChar()
ParamTypeInfo.PtrCount = 1
IsPtr = True
# C 语言中数组参数退化为指针:CArray[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"请使用有效的 VPC 类型(如 CPtr、ast.AST 或已注册的结构体)。"
)
ParamTypeStr: Any = ParamTypeInfo
except SyntaxError:
raise
except Exception as e:
ParamType = ir.IntType(32)
ParamTypeStr = CTypeInfo()
ParamTypeStr.BaseType = TypeSystem.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 = TypeSystem.CInt()
ParamTypes.append(ParamType)
ParamNames.append(Arg.arg)
ParamTypeStrs.append(ParamTypeStr)
# 自动取址模式(由注解读出,不依赖 BaseType 类型):
# 'ref' = &T、'temp' = &temp T(合成下标 CRef[T] / CTempRef[T]),
# 'always' = CAutoPtr。经 Gen._auto_addr_params 供调用点分流。
auto_mode: str | None = FindAutoAddrMode(Arg.annotation)
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}")
auto_addr_modes.insert(0, None)
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):
Line: int = getattr(node, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
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 名称如 '<sha1>.AST*' 需要还原为 `CPtr[<sha1>.AST]` 下标结构,
否则类型解析会丢失 PtrCount 信息。
含点号的名称(如 '<sha1>.AST')需解析为 ast.Attribute 链。
下标形态('rawptr[ast.AST]' / 'list[AST]' 等)必须整体解析为 Subscript:
_make_name_node 只按 '.' 切分会把 'rawptr[ast.AST]' 拆成
Name('rawptr[ast') + Attribute('AST]'),两段都不是有效类型名 →
参数/返回注解解析为空 → VoidType → "无法识别的参数类型注解"。
指针下标统一保持 Subscript 形态(rawptr[T] / CPtr[T] / CRef[T] / ...)。
内层为已混淆名(数字开头,如 'rawptr[7565e081d88517ac.AST]')时
ast.parse 无法解析(数字开头的令牌),改用手工拆 base/slice(同 VPC
TypeGenResolve._parse_type_string 的数字开头手工拆分分支)。
尾部 '*'(泛型实参 '<sha1>.Node*' / '<sha1>.Node**',来自 rawptr[T] /
CPtr 的逐层 mangling)逐层还原为嵌套 `CPtr[...]` → 对应
层数指针;只剥一层会把 'Node*' 当结构体名建出 phantom opaque
(item 类型与特化名 '<sha1>.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*)在源码侧写作 CPtr;再叠加 StarCount-1 层
base_node = ast.Name(id='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.Subscript(
value=ast.Name(id='CPtr', ctx=ast.Load()),
slice=node,
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.Subscript(
value=ast.Name(id='CPtr', ctx=ast.Load()),
slice=node,
ctx=ast.Load(),
)
return node
if '[' in replacement:
SubNode: ast.AST | None = None
try:
SubNode = ast.parse(replacement, '<stub:type_expr>', mode='eval').body
except Exception:
SubNode = None
if not isinstance(SubNode, ast.Subscript):
SubNode = self._parse_subscript_manually(replacement)
if isinstance(SubNode, ast.Subscript):
return SubNode
return self._make_name_node(replacement)
def _parse_subscript_manually(self, replacement: str) -> ast.AST | None:
"""手工拆分单实参下标字符串(ast.parse 因数字开头标识符失败时使用)。
处理 `<base>[<inner>]`(整体以 ']' 结尾、单实参、无逗号;内层可为嵌套
单实参下标):'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[<sha1>.CLS]]、
# <sha1>.list[<sha1>.X*]):递归按同一还原规则拆解
slice_node = self._make_replacement_node(inner_name)
else:
try:
slice_node = ast.parse(inner_name, '<stub:type_expr>', 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 处理含点号的类型名(如 '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[CPtr[AST]] 中的 T):表达式里 T 的唯一
# 用法是 `T.__sizeof__()`,指针大小恒为 8。替换成**裸 CPtr**
# (而不是 CPtr[<mangled 串>]):mangled 串含 '.'/'*',既不是
# 合法 Name,也会让 __sizeof__ 的 Subscript 分支(只认泛型切片)
# 落空后把 CPtr 当变量求值 → "未定义名称: 'CPtr'"。
if cptr_params and node.func.value.id in cptr_params:
node.func.value = ast.Name(id='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)
elif isinstance(node.func, ast.Subscript):
# `T*(expr)` / `list[T](...)`:被调者/转换目标的切片也要替换。
self._apply_type_map_to_expr(node.func, 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:
# 同上:指针类型参数的表达式用法(T.__sizeof__ 等)只需
# "指针语义",裸 CPtr 即指针大小 8;不要拼 mangled 串。
node.value = ast.Name(id='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)
# `T*(expr)` 的指针转换在 AST 里是 Call(func=Subscript(CPtr, T)):
# 切片上的 T 必须整体替换成 `_make_replacement_node` 的产物(如
# CPtr[<sha1>.AST]),不能走 Name 分支直接改 id(mangled 串含 '.'/'*'
# 不是合法标识符),否则会留下裸 T → 生成幻影结构体 %"<sha1>.T"。
if isinstance(node.slice, ast.Name) and node.slice.id in type_map:
node.slice = self._make_replacement_node(type_map[node.slice.id])
else:
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 = CTypeInfo.FromNode(Node.returns, self.Trans.SymbolTable)
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, TypeSystem.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, TypeSystem.CExport) and not RetTypeInfo.IsState:
Gen._export_funcs.add(FuncName)
IsUserMarkedExport = True
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, TypeSystem.CExtern):
Gen._export_funcs.add(FuncName)
IsUserMarkedExport = True
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.IsState:
Gen._export_funcs.add(FuncName) # State 标记的函数必须保持原始名称,以便链接器解析
IsUserMarkedExport = True
except Exception as _e:
if _config_mode == "strict":
self.Trans.LogWarning(f"异常被忽略: {_e}")
# 装饰器形式的存储类标记(@CExport / @CExtern / @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)
# 自动取址模式:查表侧统一按**真实发射名**(func.name,即 MangledName)查
# (FuncGen._adjust_args)。签名阶段(_GetFunctionSignatureLlvm)只能按逻辑名
# (FuncName)登记,故在此把该逻辑名下的模式复制到真实名下——否则同模块
# "先调用、后定义"的 &T / &temp T 会在前向声明路径上静默丢失取址。
_aam_fwd: list[str | None] | None = Gen._auto_addr_params.get(FuncName)
if _aam_fwd:
Gen._auto_addr_params[MangledName] = _aam_fwd
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:
# 统一走幂等入口:module.globals 已有同名函数时复用(并补登记
# Gen.functions),签名冲突则 fail-fast —— 绝不直接新建同名
# ir.Function(llvmlite NameScope 按名去重,必抛 DuplicatedNameError;
# 现场:5d84ea579d83ef73.CallGenFd._translate_fakeduck_call 被此路径新建,
# 而 BaseGen._get_or_declare_function 已建过同名声明却未登记
# Gen.functions ⇒ need_new 误判为真)。
func: ir.Function = Gen._CreateOrReuseFuncDecl(MangledName, FuncType)
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:
from lib.core.LLVMCG.FuncGen import FailFastError
if isinstance(_e, FailFastError):
# 签名冲突 = declare/define 分裂,必须终止(不吞)
raise
# 其余异常同样必须终止:本 try 块内只有「创建/复用声明 + 挂属性」,
# 失败即该声明不可用(调用点会按错签名传参)。原实现非严格模式静默
# `pass`、严格模式仅 LogWarning —— 正是它把 llvmlite 的 AssertionError
# (形参类型不是 types.Type 时 `Argument(...)` 断言失败,见
# BaseGen._CreateOrReuseFuncDecl 的创建前自检注释)吞成"名字半注册":
# 名字已进 module.scope、未进 module.globals,直到定义阶段才以
# DuplicatedNameError(报文只有名字)暴露,真因与现场彻底脱节。
raise FailFastError(
f"函数前置声明创建失败:'{MangledName}'"
f"\n · 本次签名: {FuncType}"
f"\n · 原始异常: {type(_e).__name__}: {_e}"
+ Gen._get_node_info())
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:
# fail-fast 一律上抛(本仓既定口径):吞掉它 = 声明静默缺失 +
# 半注册名字留给下一轮,真因与现场脱节。
from lib.core.LLVMCG.FuncGen import FailFastError as _FFE
if isinstance(_e, _FFE):
raise
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:
# 走唯一幂等入口:名字可能已存在于 module.globals 但未登记进 Gen.functions
# (别的路径先建过声明)——直接 ir.Function 必抛裸 DuplicatedNameError,
# 入口则同名同类型复用、异类型带两侧签名 fail-fast。
return Gen._CreateOrReuseFuncDecl(MangledName, NewFuncType)
except Exception as _e: # 回退:函数已存在时返回旧函数
from lib.core.LLVMCG.FuncGen import FailFastError as _FFE
if isinstance(_e, _FFE):
# 创建中途失败(如形参/返回类型不是 llvmlite Type)由 BaseGen 的
# Function 守卫转成 fail-fast:必须上抛,原实现会 `return old_func`
# (此处 old_func 必为 None)⇒ 调用点把 None 当声明用。
raise
return old_func
try:
old_name: str = old_func.name
# 必须同时清 old_name(对象真名)与 MangledName(字典键 / 目标名):
# 别名场景下二者不同,只清真名会让 MangledName 仍占住 module.scope
# (llvmlite 按名字去重)→ 重建抛 DuplicatedNameError。
module_scope: Any = getattr(Gen.module, 'scope', None)
for _stale_name in {old_name, MangledName}:
_stale: Any = Gen.module.globals.get(_stale_name)
if isinstance(_stale, ir.Function):
del Gen.module.globals[_stale_name]
if getattr(module_scope, '_useset', None):
module_scope._useset.discard(_stale_name)
if getattr(Gen.module, '_guessed_names', None):
Gen.module._guessed_names.discard(FuncName)
new_func: ir.Function = Gen._CreateOrReuseFuncDecl(MangledName, NewFuncType)
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:
from lib.core.LLVMCG.FuncGen import FailFastError
if isinstance(ex, FailFastError):
# 同名符号冲突(函数签名分裂 / 名字被非函数 global 占住):必须终止,
# 不能回退成"复用旧声明"——那正是 declare/define 分裂的现场。
raise
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)
_RejectRefReturnAnnotation(Node)
# 保存父级 _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 = []
# 内置装饰器名称,这些由编译器特殊处理,不作为行为装饰器
# 另含**编译期生命期标注**(P2):@life(willFree(...)) 与 @willFree(...) 是纯标注,
# 没有运行时装饰器函数;不排除会生成 wrapper 去调用不存在的 @life/@willFree,
# 并把被装饰的 extern def(如 stdlib.free)变成本模块 internal 声明(llc 报 linkage 错)。
_BUILTIN_DECORATORS = {'staticmethod', 'property', 'classmethod', 'life', 'willFree', 'Attribute'}
_symtab: object = self.Trans.SymbolTable
if Node.decorator_list:
for decorator in Node.decorator_list:
# 跳过内建存储类标记装饰器(@CExport / @CStatic 等)
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):
if isinstance(decorator.func, ast.Attribute) and decorator.func.attr == 'CReturn':
_RejectCReturnDecorator(Node, [decorator])
elif isinstance(decorator.func, ast.Name) and decorator.func.id == 'Attribute':
for arg in decorator.args:
if isinstance(arg, ast.Call) and isinstance(arg.func, ast.Attribute):
if isinstance(arg.func.value, ast.Name) and arg.func.value.id == '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.Name) and arg.func.value.value.id == 'attr'):
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.Name) and arg.value.id == '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.Name) and arg.value.value.id == 'attr'):
llvm_attr_name = arg.attr
if llvm_attr_name in self._LLVM_ATTR_NAMES:
fn_attrs[f'llvm.{llvm_attr_name}'] = True
# 检查 @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 decorator.attr == 'TLS':
is_tls_func = True
break
elif isinstance(decorator, ast.Name) and decorator.id == 'TLS' and hasattr(TypeSystem, '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*)。
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,
# 不能压平,否则返回类型错误。
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 = TypeSystem.CChar()
ReturnTypeInfo.PtrCount = 1
elif Node.returns:
if MultiRetTypes:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CVoid()
else:
try:
if isinstance(Node.returns, ast.BinOp) and isinstance(Node.returns.op, ast.BitOr):
Line: int = getattr(Node.returns, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
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] / 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 = TypeSystem.CInt()
if not hasattr(self, '_cdefine_funcs'):
self._cdefine_funcs = set()
self._cdefine_funcs.add(FuncName)
elif ReturnTypeInfo and ReturnTypeInfo.IsState:
pass # State is a modifier, preserve the actual return type
if ReturnTypeInfo is None:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CVoid()
# 仅指针层数 <=1 才算裸 str/bytes(i8*)。
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,不能压平。
if is_str_type or (ReturnTypeInfo.IsStr and ReturnTypeInfo.PtrCount <= 1):
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CChar()
ReturnTypeInfo.PtrCount = 1
# 检查泛型类返回类型 (如 list[str])
# 注意:_from_node_subscript 对未识别的泛型下标(如 list[str])返回空 CTypeInfo(BaseType=None),
# 此时 IsVoid 为 False(因为 IsVoid 仅检查 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 块未终止)。
try:
spec_name2: str | None = self.Trans.ClassHandler._specialize_generic_class(
ret_class, ret_type_args, Gen, type_names=ret_type_names, declare_only=True)
except Exception as _spec_err:
# 不静默吞特化异常:记录到 Gen._generic_spec_error 后再
# 交给外层返回类型回退(否则只剩一个错误的 CInt 返回类型)。
Gen._generic_spec_error = f'{type(_spec_err).__name__}: {_spec_err}'
raise
if spec_name2 and spec_name2 in Gen.structs:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.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 = TypeSystem.CInt()
except TypeError:
raise
except Exception: # 回退:设置默认返回类型为 CInt
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CInt()
else:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.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 = TypeSystem.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)。
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,
# 不能压平,否则形参类型错误导致 _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 = TypeSystem.CChar()
ParamTypeInfo.PtrCount = 1
IsPtr = True
# C 语言中数组参数退化为指针:CArray[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"请使用有效的 VPC 类型(如 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 = TypeSystem.CInt()
else:
ParamType = ir.IntType(32)
ParamTypeInfo = CTypeInfo()
ParamTypeInfo.BaseType = TypeSystem.CInt()
ParamTypes.append(ParamType)
ParamNames.append(Arg.arg)
ParamTypeStrs.append(ParamTypeInfo)
# 自动取址模式(由注解读出):'ref' = &T、'temp' = &temp T、'always' = CAutoPtr
auto_mode_emit: str | None = FindAutoAddrMode(Arg.annotation)
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 与 ViperC 侧同口径。
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*)。
# `CPtr[str]` 是两层指针(i8**,如 argv 数组),IsStr=True 但 PtrCount=2,不能压平。
if ReturnTypeInfo and ReturnTypeInfo.IsStr and ReturnTypeInfo.PtrCount <= 1:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CChar()
ReturnTypeInfo.PtrCount = 1
if ReturnTypeInfo is None:
ReturnTypeInfo = CTypeInfo()
ReturnTypeInfo.BaseType = TypeSystem.CInt()
RetType = Gen._ctype_to_llvm(ReturnTypeInfo)
MultiRetLlvmTypes.append(RetType)
ReturnType = ir.LiteralStructType(MultiRetLlvmTypes)
self.Trans.CurrentMultiRetTypes = MultiRetTypes
else:
self.Trans.CurrentMultiRetTypes = None
if self._apply_struct_self_cls_types(ParamTypes, ParamNames, IsMethod, IsClassMethod, ResolvedClassName, Gen):
auto_addr_modes_emit.insert(0, None)
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)
# 逻辑名(FuncName = 裸名 / "类名.方法")登记:真身定义路径下它是真实发射名的
# 别名,保留以便按逻辑名查表;真实发射名(func.name)的登记在下方 func 就绪后
# 进行(查表侧 FuncGen._adjust_args 统一按 func.name 查)。
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, TypeSystem.CInline):
IsInlineFunc = True
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, TypeSystem.CExport) and not RetTypeInfo.IsState:
Gen._export_funcs.add(FuncName)
IsUserMarkedExport = True
if isinstance(RetTypeInfo, CTypeInfo) and RetTypeInfo.Storage and isinstance(RetTypeInfo.Storage, TypeSystem.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}")
# 装饰器形式的存储类标记(@CExport / @CExtern / @CStatic / @State / @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)
# 补登记:module.globals 已有同名函数(stub 声明 / 调用点先建)但未登记到
# Gen.functions 时,先登记再走下方判定 —— 否则 1750 分支裸建 ir.Function
# 会抛 llvmlite DuplicatedNameError(报文只有名字,不含冲突双方)。
_g_existing_fn: Any = Gen.module.globals.get(MangledName)
if MangledName not in Gen.functions and isinstance(_g_existing_fn, ir.Function):
Gen.functions[MangledName] = _g_existing_fn
if MangledName in Gen.functions:
func = Gen.functions[MangledName]
if getattr(func, 'name', MangledName) != MangledName:
func = Gen._CreateOrReuseFuncDecl(MangledName, FuncType)
else:
existing_type = getattr(func, 'ftype', None)
if existing_type and existing_type != FuncType:
func = self._replace_function_decl(Gen, FuncName, FuncType)
else:
func = Gen._CreateOrReuseFuncDecl(MangledName, FuncType)
if MangledName == FuncName or FuncName not in Gen._export_extern_funcs:
Gen.functions[FuncName] = func
# 自动取址模式(ref/temp/always)的**主键**必须是真实发射出的函数名 func.name,
# 与查表侧 FuncGen._adjust_args 的 func.name 逐字一致;FuncName(上方已登记)作别名。
_auto_addr_real_name: str | None = getattr(func, 'name', None)
if _auto_addr_real_name:
Gen._auto_addr_params[_auto_addr_real_name] = auto_addr_modes_emit
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 = 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
# 类注释形参:rawptr[X] / CPtr[X] / 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):
Line: int = getattr(arg.annotation, 'lineno', 0) or 0
raise TypeError(
f"[TPC] 不支持类型联合 'T1 | T2'(第 {Line} 行);"
f"类型注解只能是单一类型:指针请写 CPtr[T],修饰符请用关键字")
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', 'CRef', 'CTempRef', 'CArrayPtr', 'CAutoPtr'):
slc = ann.slice
while isinstance(slc, ast.Subscript):
slc = slc.value
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
# @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
# 失败路径也要复位「当前方法」上下文(成功路径的复位在函数末尾,异常
# 直接 re-raise 会跳过它)。上层有吞掉异常的调用点(如泛型特化按需补全
# _try_complete_generic_specialization、类按需实例化),它们让外层方法
# 继续编译;若此时 _CurrentCpythonObjectClass / var_struct_class 仍指向
# 内层特化类,外层方法的 `self.X` 会被按内层类解析(典型现象:
# ExprGenFstr.translate_joined_str 的 `self.Gen` 被按
# `list[cfc4ca8da95a30e1.AST*]` 解析 → "属性 'Gen' 在类中找不到")。
Gen._current_class_name = _saved_class_name
self.Trans._CurrentCpythonObjectClass = saved_cpython_class
Gen.var_struct_class = saved_var_struct_class
if hasattr(Gen, 'global_struct_class'):
Gen.global_struct_class = saved_global_struct_class
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 / -> 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 / CVoid)/ extern|export 声明型辅助符号
# (State / CExport / CExtern)→ 掉出合法,不 fail-fast
_DeclMarkers: tuple[str, ...] = (
tuple(getattr(Node, 'Markers', None) or ())
+ tuple(getattr(Node.returns, 'Markers', None) or ()))
_IsDecl: bool = (any(m in ('state', 'export', 'extern') for m in _DeclMarkers)
or bool(getattr(Node, 'Extern', False))
or bool(getattr(Node, 'Export', False)))
if not _IsDecl and 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 = {}
# 注解声明类台账是**函数作用域**的(局部变量的声明随函数出栈失效),
# 与 var_struct_class 同处清空 —— 否则同名变量会在别的函数里被误判为
# "已由注解声明",从而挡住右值推出类的正常登记。
Gen.var_annotated_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