From da636a5422b0f1edd6ccb517ccfc98ce516b43a2 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Sun, 25 Oct 2026 13:05:51 +0800 Subject: [PATCH] =?UTF-8?q?fix(cif):=20=E5=B9=B3=E5=8F=B0=E5=AE=8F?= =?UTF-8?q?=E6=8C=89=E7=9B=AE=E6=A0=87=20triple=20=E6=B1=82=E5=80=BC?= =?UTF-8?q?=EF=BC=8C=E5=B1=9E=E6=80=A7=E5=BD=A2=E5=BC=8F=E4=B8=8D=E5=86=8D?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=E8=B7=A8=E6=A8=A1=E5=9D=97=20define?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - _cif_attr_value 先查平台内建宏(triple 是唯一真相源),再查本地/跨模块 DefineT: 跨模块查不到时会静默得到 0,曾把 platmacro.IS_WINDOWS 判成 0, 导致 Windows 构建误走非 Windows 分支(_io 选了 posix.fileio) - _get_platform_macro_value 补齐 platmacro 的平台名:IS_WINDOWS/IS_WIN64/IS_LINUX/ IS_MACOS/IS_X86_64/IS_ARM64 注:本文件含此前未提交的既有改动,按整文件一并提交。 --- App/lib/core/Gen/Stmt/StmtGenCifMixin.vp | 31 +++++++++++++++++------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp b/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp index 9f5e6f2..889cf74 100644 --- a/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp +++ b/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp @@ -88,10 +88,18 @@ novirtual class StmtGenCifMixin: if string.strcmp(name, "SIZEOF_VOID_P") == 0: self.CifEvalOk = 1; return 8 if is_x64 else 4 if string.strcmp(name, "__SIZEOF_POINTER__") == 0: self.CifEvalOk = 1; return 8 if is_x64 else 4 if string.strcmp(name, "NDEBUG") == 0: self.CifEvalOk = 1; return 0 + # platmacro.vp 的平台名(它是 includes/platmacro.vp 的手写镜像;cif 直接按 triple 求值, + # 不依赖跨模块 define 解析——曾因跨模块查不到而静默取 0,误选了非 Windows 分支)。 + if string.strcmp(name, "IS_WINDOWS") == 0: self.CifEvalOk = 1; return is_win + if string.strcmp(name, "IS_WIN64") == 0: self.CifEvalOk = 1; return is_win if is_x64 else 0 + if string.strcmp(name, "IS_LINUX") == 0: self.CifEvalOk = 1; return is_linux + if string.strcmp(name, "IS_MACOS") == 0: self.CifEvalOk = 1; return 0 + if string.strcmp(name, "IS_X86_64") == 0: self.CifEvalOk = 1; return is_x64 + if string.strcmp(name, "IS_ARM64") == 0: self.CifEvalOk = 1; return 0 return 0 def _cif_name_value(self, pool: memhub.MemBuddy*, trans: HT.Translator*, name: str) -> int: - """Resolve a macro name via local CDefine, cross-module CDefine, then platform macro.""" + """Resolve a macro name via local DefineT, cross-module DefineT, then platform macro.""" self.CifEvalOk = 0 if name is None or trans is None: return 0 v: int = int(self.Gen.TypeGenCDef.lookup_cdefine_constant(name)) @@ -107,12 +115,17 @@ novirtual class StmtGenCifMixin: return 0 def _cif_attr_value(self, pool: memhub.MemBuddy*, trans: HT.Translator*, at: ast.Attribute*) -> int: - """Resolve an attribute macro via platform macro, local CDefine, then cross-module CDefine.""" + """Resolve an attribute macro via platform macro, local DefineT, then cross-module DefineT.""" self.CifEvalOk = 0 if at is None or at.attr is None or at.value is None or trans is None: return 0 if at.value.kind() != ast.ASTKind.Name: return 0 vn: ast.Name* = ast.Name*(at.value) if vn.id is None: return 0 + # 平台内建宏优先:目标 triple 是唯一真相源(platmacro 只是它的手写照)。 + # 必须排在跨模块 define 之前——跨模块查不到时这里会静默拿到 0(曾把 + # platmacro.IS_WINDOWS 判成 0,导致 Windows 构建误选非 Windows 分支)。 + pv_at: int = self._get_platform_macro_value(at.attr) + if self.CifEvalOk != 0: return pv_at v: int = int(self.Gen.TypeGenCDef.lookup_cdefine_constant(at.attr)) if self.Gen.TypeGenCDef.is_cdefine_found() != 0: self.CifEvalOk = 1 @@ -274,7 +287,7 @@ novirtual class StmtGenCifMixin: """Evaluate the defined(NAME) compile-time predicate (1 = macro defined, 0 = not). defined() is always evaluable: an unknown name yields 0. A wrong argument shape is fail-fast. - The macro name resolves through the same CDefine / cross-module / platform-macro paths as a + The macro name resolves through the same DefineT / cross-module / platform-macro paths as a bare name in a cif condition. """ cargs: list[ast.AST*]* = cl.args @@ -407,7 +420,7 @@ novirtual class StmtGenCifMixin: if self.CifEvalOk == 0: self.Gen.TypeGenErr.fatal_error(test, f"the cif/celif condition is not a compile-time constant (line {test.lineno}):" - " cif/celif accept only CDefine constants, integer literals, defined(NAME), and their" + " cif/celif accept only DefineT constants, integer literals, defined(NAME), and their" " constant arithmetic/comparison/boolean/bitwise combinations", "TypeError") return v @@ -505,13 +518,13 @@ novirtual class StmtGenCifMixin: if cur_func_rv is not None: ret_val_ty = mlirlite.function_get_ret_ty(cur_func_rv) # `return <闭包变量>` 且返回注解是 t.Callable:闭包对象是 {fn_ptr, env_ptr}, # 不是裸函数指针。调用方把结果存进 t.Callable 变量后 `f()` 会按裸函数指针直调, - # 跳到堆地址崩溃(ClosureCallTest 现场)。这里明确 fail-fast,要求用 rawptr/t.CPtr。 + # 跳到堆地址崩溃(ClosureCallTest 现场)。这里明确 fail-fast,要求用 rawptr。 if rt.value.kind() == ast.ASTKind.Name and trans is not None and trans.CurFuncRetAnnot is not None: clo_nm_rv: ast.Name* = ast.Name*(rt.value) if clo_nm_rv.id is not None and self.Gen.CallGenLeafKit.is_closure_name(clo_nm_rv.id) != 0: clo_ret_rv: mlirlite.LLVMType* = self.Gen.TypeGenErr.try_extract_callable_ret(pool, trans.CurFuncRetAnnot, trans._imported_modules, trans._from_imports, trans) if clo_ret_rv is not None: - self.Gen.TypeGenErr.fatal_error(rt, f"the return annotation is t.Callable (a bare function pointer) but the returned value is the closure variable '{clo_nm_rv.id}'. A closure is a (fn_ptr, env_ptr) object; storing it where a t.Callable is expected makes the caller jump into heap data. Annotate the return as rawptr / t.CPtr instead", "TypeError") + self.Gen.TypeGenErr.fatal_error(rt, f"the return annotation is t.Callable (a bare function pointer) but the returned value is the closure variable '{clo_nm_rv.id}'. A closure is a (fn_ptr, env_ptr) object; storing it where a t.Callable is expected makes the caller jump into heap data. Annotate the return as rawptr instead", "TypeError") # [C1] return-annotation context: record this return's direct value node so a bare # generic ctor (`return Stack()` in `-> Stack[int]`) specializes via CurFuncRetAnnot. trans.CurRetNode = rt.value @@ -1063,7 +1076,7 @@ novirtual class StmtGenCifMixin: cn_ik: ast.Constant* = ast.Constant*(iter_node) if cn_ik.const_kind != ast.CONST_STR: self.Gen.TypeGenErr.fatal_error(iter_node, "for iteration does not support this constant (only strings, arrays, list literals, range())") elif ik == ast.ASTKind.Dict or ik == ast.ASTKind.Set or ik == ast.ASTKind.Tuple or ik == ast.ASTKind.SetComp or ik == ast.ASTKind.DictComp: - self.Gen.TypeGenErr.fatal_error(iter_node, "for iteration does not support dict/set/tuple literals; use range(), a t.CArray array, or a list literal") + self.Gen.TypeGenErr.fatal_error(iter_node, "for iteration does not support dict/set/tuple literals; use range(), a t.ArrayT array, or a list literal") return self._handle_ptr_iter(trans, for_node, var_name) call: ast.Call* = ast.Call*(iter_node) @@ -1675,7 +1688,7 @@ novirtual class StmtGenCifMixin: elem_ty: mlirlite.LLVMType* = ptr_val.Ty.Pointee if elem_ty is None: self.Gen.TypeGenErr.fatal_error(for_node, "pointer iteration: failed to get the element type") - # element type is an array (Ptr([N x T]), e.g. a decayed t.CArray): load it and iterate by length (no null terminator) + # element type is an array (Ptr([N x T]), e.g. a decayed t.ArrayT): load it and iterate by length (no null terminator) if self.Gen.ExprGenBase.is_array_type(elem_ty) != 0: arr_v2: mlirlite.Value* = mlirlite.build_load(builder, elem_ty, ptr_val) if arr_v2 is not None: return self._handle_array_iter(trans, for_node, var_name, arr_v2) @@ -1926,7 +1939,7 @@ novirtual class StmtGenCifMixin: # element count above the actual fill means a bare 0 slot, i.e. an empty AST element upstream. if first_el is None: self.Gen.TypeGenErr.fatal_error(for_node, f"list literal iteration encountered an empty AST element: element 0 is a bare null pointer (0), " f"but the element count is {elts_count} (element and count mismatch); something upstream produced an empty AST element, compilation aborted.", "ValueError") - # validate the object (vptr non-zero, see AssignGenMixin.vp:1174-1183): for @t.CVTable class + # validate the object (vptr non-zero, see AssignGenMixin.vp:1174-1183): for @t.VTableT class # objects the first word is the vptr; if 0, any later virtual call reads address 0. if *((uint64*)(first_el)) == 0: self.Gen.TypeGenErr.fatal_error(for_node, f"list literal iteration encountered an [INVALID OBJECT] AST element (vptr is 0): element 0 pointer is nonzero" f"(address {uint64(first_el)}) but the first word of its object (vtable pointer) is 0, element count {elts_count};" f"something upstream produced an [uninitialized vptr AST node] (typical source: a deep copy that moved fields but not the vptr), compilation aborted.", "ValueError")