diff --git a/App/lib/Projectrans/Config.vp b/App/lib/Projectrans/Config.vp index f04c2e9..1dedb5b 100644 --- a/App/lib/Projectrans/Config.vp +++ b/App/lib/Projectrans/Config.vp @@ -19,23 +19,26 @@ import w32.fileio as fileio _mbuddy: memhub.MemManager | t.CPtr # 配置值(从 project.vpj 加载) -SourceDir: str -BuildDir: str -TempDir: str # = {BuildDir}/temp(自动计算) -OutputDir: str # = {BuildDir}/output(自动计算) -ProjectName: str -ProjectVersion: str -CompilerCmd: str -CompilerFlags: str # 编译器参数(空格分隔,从 compiler.flags 数组拼接) -LinkerCmd: str -LinkerFlags: str # 链接器参数(空格分隔,从 linker.flags 数组拼接) -LinkerOutput: str -TargetTriple: str -TargetDataLayout: str -Sha1SliceLevel: t.CInt # SHA1 切片层数(目录分散等级) -StrictMode: t.CInt -IncludesDir: str # includes 目录路径(从 includes 数组首元素,兼容单目录场景) -IncludesDirs: str # 全部 includes 目录(空格分隔,多 includes 目录支持) +# 默认 None/0:未加载 project.vpj 时字段为 null,调用方 is not None +# 检查才能正确兜底(否则垃圾指针通过检查 → 用非法路径 → 崩溃, +# 尤其非工作区执行无配置时)。 +SourceDir: str = None +BuildDir: str = None +TempDir: str = None # = {BuildDir}/temp(自动计算) +OutputDir: str = None # = {BuildDir}/output(自动计算) +ProjectName: str = None +ProjectVersion: str = None +CompilerCmd: str = None +CompilerFlags: str = None # 编译器参数(空格分隔,从 compiler.flags 数组拼接) +LinkerCmd: str = None +LinkerFlags: str = None # 链接器参数(空格分隔,从 linker.flags 数组拼接) +LinkerOutput: str = None +TargetTriple: str = None +TargetDataLayout: str = None +Sha1SliceLevel: t.CInt = 0 # SHA1 切片层数(目录分散等级) +StrictMode: t.CInt = 0 +IncludesDir: str = None # includes 目录路径(从 includes 数组首元素,兼容单目录场景) +IncludesDirs: str = None # 全部 includes 目录(空格分隔,多 includes 目录支持) def Load_project_config(path: str) -> int: diff --git a/App/lib/core/Gen/CallGenMixin.vp b/App/lib/core/Gen/CallGenMixin.vp index 66e75c2..6f9ee1b 100644 --- a/App/lib/core/Gen/CallGenMixin.vp +++ b/App/lib/core/Gen/CallGenMixin.vp @@ -6291,45 +6291,59 @@ class CallGenMixin: string.strncpy(cf_sha1, call_name, 16) cf_sha1[16] = '\0' string.strcpy(cf_bare, cf_last + 1) - cf_ret: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( - pool, cf_sha1, None, cf_bare, 1) - if cf_ret is not None: - call_ret_ty = cf_ret + # 本模块自身函数(泛型特化等):从当前 IR 已声明的函数 + # 取返回类型;不走跨模块 text.ll 查找——自己的 text.ll + # 在 Phase A 翻译中尚未生成,直接查会误报"依赖未生成" + # 并保持默认类型(GenericTest 泛型 add/combine 等警告 + # 根因)。未命中(特化尚未声明)保持默认推断。 + is_local_mod: int = 0 + if trans is not None and trans.ModuleSha1 is not None: + if string.strncmp(cf_sha1, trans.ModuleSha1, 16) == 0: + is_local_mod = 1 + if is_local_mod != 0: + local_fn: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name) + if local_fn is not None and local_fn.RetTy is not None: + call_ret_ty = local_fn.RetTy else: - cf_vpi: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi( - pool, cf_sha1, None, cf_bare) - if cf_vpi is not None: - call_ret_ty = cf_vpi + cf_ret: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( + pool, cf_sha1, None, cf_bare, 1) + if cf_ret is not None: + call_ret_ty = cf_ret else: - # 区分两种失败场景: - # 1. 依赖模块 text.ll 存在但函数未命中 → 真错误,fail-fast - # 2. 依赖模块 text.ll 不存在(模块尚未翻译)→ Phase A 按 - # 文件顺序翻译,main.vp 先于其 import 的 mbuddytest.vp - # (同项目多源文件)。此时标记 trans._deps_pending=1, - # 保持白名单类型继续,Phase A 多遍循环下遍重译—— - # 届时依赖已生成 text.ll,可精确解析(治本:依赖先翻译)。 - if self._dep_text_ll_exists(pool, cf_sha1) != 0: - cf_err: t.CChar | t.CPtr = VLogger.fmt_buf() - if cf_err is not None: - viperlib.snprintf( - cf_err, 1024, - "跨模块函数 '%s' 返回类型无法精确获取(text.ll/vpi 均未命中)," - "默认 i32 会截断指针/i64,请检查依赖模块是否已编译/注册", call_name) - VLogger.error(cf_err, "HandlesExprCall") - HandlesType.fatal_error( - node, - f"跨模块函数返回类型无法精确获取(text.ll/vpi 均未命中),默认 i32 会截断指针: {call_name}", - "TypeError") + cf_vpi: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi( + pool, cf_sha1, None, cf_bare) + if cf_vpi is not None: + call_ret_ty = cf_vpi else: - if trans is not None: - trans._deps_pending = 1 - cf_dbg: t.CChar | t.CPtr = VLogger.fmt_buf() - if cf_dbg is not None: - viperlib.snprintf( - cf_dbg, 1024, - "跨模块函数 '%s' 依赖模块 text.ll 尚未生成(Phase A 顺序)," - "标记重试,本遍保持默认类型", call_name) - VLogger.warning(cf_dbg, "HandlesExprCall") + # 区分两种失败场景: + # 1. 依赖模块 text.ll 存在但函数未命中 → 真错误,fail-fast + # 2. 依赖模块 text.ll 不存在(模块尚未翻译)→ Phase A 按 + # 文件顺序翻译,main.vp 先于其 import 的 mbuddytest.vp + # (同项目多源文件)。此时标记 trans._deps_pending=1, + # 保持白名单类型继续,Phase A 多遍循环下遍重译—— + # 届时依赖已生成 text.ll,可精确解析(治本:依赖先翻译)。 + if self._dep_text_ll_exists(pool, cf_sha1) != 0: + cf_err: t.CChar | t.CPtr = VLogger.fmt_buf() + if cf_err is not None: + viperlib.snprintf( + cf_err, 1024, + "跨模块函数 '%s' 返回类型无法精确获取(text.ll/vpi 均未命中)," + "默认 i32 会截断指针/i64,请检查依赖模块是否已编译/注册", call_name) + VLogger.error(cf_err, "HandlesExprCall") + HandlesType.fatal_error( + node, + f"跨模块函数返回类型无法精确获取(text.ll/vpi 均未命中),默认 i32 会截断指针: {call_name}", + "TypeError") + else: + if trans is not None: + trans._deps_pending = 1 + cf_dbg: t.CChar | t.CPtr = VLogger.fmt_buf() + if cf_dbg is not None: + viperlib.snprintf( + cf_dbg, 1024, + "跨模块函数 '%s' 依赖模块 text.ll 尚未生成(Phase A 顺序)," + "标记重试,本遍保持默认类型", call_name) + VLogger.warning(cf_dbg, "HandlesExprCall") stdlib.free(cf_sha1) stdlib.free(cf_bare) # 跨模块调用:创建 declare 声明,避免 llc 报 undefined value diff --git a/App/lib/core/Handles/HandlesFor.vp b/App/lib/core/Handles/HandlesFor.vp index c31ecff..b54d08f 100644 --- a/App/lib/core/Handles/HandlesFor.vp +++ b/App/lib/core/Handles/HandlesFor.vp @@ -396,6 +396,13 @@ class ForHandle(HandlesBase.Mixin): if elem_ty is None: HandlesType.fatal_error(for_node, "指针迭代: 无法获取元素类型") + # 元素类型是数组(Ptr([N x T]),如 t.CArray 变量退化指针): + # load 出数组值后走数组迭代(按长度,非 null 终止) + if HandlesExpr.is_array_type(elem_ty) != 0: + arr_v2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, ptr_val) + if arr_v2 is not None: + return self._handle_array_iter(for_node, var_name, arr_v2) + # 元素类型必须是整数(用于 icmp eq 0 检查 null 终止符) elem_bits: int = HandlesExpr.get_llvm_type_bits(elem_ty) if elem_bits == 0: diff --git a/App/main.vp b/App/main.vp index 242fd1c..9536f02 100644 --- a/App/main.vp +++ b/App/main.vp @@ -369,6 +369,16 @@ def main() -> int: # AST 解析:如果指定了 --src 或 --project,读取文件并解析为 AST 树 src_path: str = args.get_str("src") + # 无 project 配置且未指定 --src:无法构建,fail-fast 退出。 + # (非工作区执行时 CWD 无 project.vpj,proj_loaded=0;若继续执行, + # 未初始化的 Config 字段可能为垃圾指针 → is not None 检查通过 → + # 用非法路径 → 崩溃且 ASan 堆栈来不及输出) + if proj_loaded == 0 and src_path is None: + if log is not None: + log.error("未找到 project.vpj(当前目录/上级目录)且未指定 --src,无法构建", "config") + argparse.release(args) + return 1 + # === 多文件项目模式 === # 当 --project 指定但 --src 未指定时,扫描 source_dir 下所有 .vp/.py 文件编译 if src_path is None and project is not None and Config.SourceDir is not None: