fix(cif): 平台宏按目标 triple 求值,属性形式不再依赖跨模块 define

- _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

注:本文件含此前未提交的既有改动,按整文件一并提交。
This commit is contained in:
TermiNexus committed 2026-10-25 13:05:51 +08:00
1 parent 3febb87abf
commit da636a5422
1 file changed
+22 -9
+22 -9
View File
@@ -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")