diff --git a/App/lib/Projectrans/Config.vp b/App/lib/Projectrans/Config.vp index dc1e852..6a53baa 100644 --- a/App/lib/Projectrans/Config.vp +++ b/App/lib/Projectrans/Config.vp @@ -337,9 +337,22 @@ def _normalize_path(path: str) -> str: # 单段 ".":跳过 if seg_len == 1 and path[seg_start] == '.': pass - # 单段 "..":弹出上一段(无段可弹时保留,如 ../includes) + # 单段 "..":弹出上一段;但**前导 ".." 不可弹**,必须保留。 + # 旧实现只判 out_len > 0 就回退,于是 "无段可弹时保留" 的那一个 + # 前导 ".." 会被下一个 ".." 当成普通段吃掉: + # ./VKernel/../../../includes → 缓冲反复清空 → "./includes" + # (cwd 在项目目录时,语义应得 "../../includes")。这正是 + # ViperOS 各子工程 import 找不到模块的根因。 + # 与 Python os.path.normpath / TPC 的行为对齐。 elif seg_len == 2 and path[seg_start] == '.' and path[seg_start + 1] == '.': - if out_len > 0: + # 末段是否已经是前导 ".."(独立一段:要么是开头,要么前面是分隔符) + last_is_dotdot: int = 0 + if out_len >= 2 and out[out_len - 1] == '.' and out[out_len - 2] == '.': + if out_len == 2: + last_is_dotdot = 1 + elif out[out_len - 3] == '/' or out[out_len - 3] == '\\': + last_is_dotdot = 1 + if out_len > 0 and last_is_dotdot == 0: # 回退到上一个分隔符 k: t.CSizeT = out_len while k > 0 and out[k - 1] != '/' and out[k - 1] != '\\': @@ -354,10 +367,13 @@ def _normalize_path(path: str) -> str: else: has_seg = 0 else: - # 无段可弹:保留 .. - out[0] = '.' - out[1] = '.' - out_len = 2 + # 没有普通段可弹:把 ".." 当普通段追加(前导 .. 累积保留) + if has_seg > 0: + out[out_len] = '/' + out_len += 1 + out[out_len] = '.' + out[out_len + 1] = '.' + out_len += 2 has_seg = 1 else: # 普通段:追加分隔符 + 段 diff --git a/App/lib/Stub/StubGen/Converter.vp b/App/lib/Stub/StubGen/Converter.vp index 418e60b..c95b62c 100644 --- a/App/lib/Stub/StubGen/Converter.vp +++ b/App/lib/Stub/StubGen/Converter.vp @@ -914,6 +914,14 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr, if ca_cv.const_kind == ast.CONST_INT and num_buf_c is not None: viperlib.snprintf(num_buf_c, 32, " = %lld", ca_cv.int_val) pos = _PyiEmit(buf, buf_size, pos, num_buf_c) + elif ca_cv.const_kind == ast.CONST_FLOAT: + # Call 包装的浮点常量(如 PI: t.CDefine = float(3.14159...)): + # stub 必须输出值,否则读回端 vpi 无值 → 退化 0.0。 + # %.17g 保证 double 全精度往返(与上方 CONST_FLOAT 分支一致)。 + fbuf_cc: bytes = mb.alloc(64) + if fbuf_cc is not None: + viperlib.snprintf(fbuf_cc, 64, " = %.17g", ca_cv.float_val) + pos = _PyiEmit(buf, buf_size, pos, fbuf_cc) elif arg_kind == ast.ASTKind.UnaryOp: uop_ca: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(first_arg) num_buf_cu: bytes = mb.alloc(32) @@ -924,6 +932,14 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr, neg_c_val: t.CInt64T = -uoc.int_val viperlib.snprintf(num_buf_cu, 32, " = %lld", neg_c_val) pos = _PyiEmit(buf, buf_size, pos, num_buf_cu) + elif uoc.const_kind == ast.CONST_FLOAT: + # 负浮点 Call 包装(如 t.CDefine = float(-1.5)): + # 同 CONST_FLOAT,%.17g 全精度往返 + neg_cf: double = -uoc.float_val + fbuf_cu: bytes = mb.alloc(64) + if fbuf_cu is not None: + viperlib.snprintf(fbuf_cu, 64, " = %.17g", neg_cf) + pos = _PyiEmit(buf, buf_size, pos, fbuf_cu) elif arg_kind == ast.ASTKind.BinOp: # Call 内部的 BinOp(如 t.CUnsignedLong(A | B)) # 递归计算 BinOp 值 diff --git a/App/lib/core/Gen/AssignGenMixin.vp b/App/lib/core/Gen/AssignGenMixin.vp index c2a7097..5be5d97 100644 --- a/App/lib/core/Gen/AssignGenMixin.vp +++ b/App/lib/core/Gen/AssignGenMixin.vp @@ -297,6 +297,22 @@ class AssignGenMixin: eq += 1 while eq < line_start + line_len and buf[eq] == ' ': eq += 1 + # Call 包装的浮点常量(如 PI: t.CDefine = float(3.14159...) / + # t.CDouble(1.0)):值的 token 是整段 "float(3.14159...)"。 + # atof 只认数字/符号/'.',首字符 'f' → 恒得 0.0,导致浮点 CDefine + # 被注册为 0(gfx.vp PI 编成 0.0 的直接根因)。此处跳过 "float(" + # 之类前缀,从括号内首个数字/符号/'.' 起取值。 + # 裸字面量(3.14 / -1.5,首字符已是数字/符号/'.')不受影响。 + if eq < line_start + line_len: + c0_rf: t.CChar = buf[eq] + if not ((c0_rf >= '0' and c0_rf <= '9') or c0_rf == '-' or c0_rf == '+' or c0_rf == '.'): + pfx_rf: t.CSizeT = eq + while pfx_rf < line_start + line_len: + cp_rf: t.CChar = buf[pfx_rf] + if (cp_rf >= '0' and cp_rf <= '9') or cp_rf == '.' or cp_rf == '-' or cp_rf == '+': + eq = pfx_rf + break + pfx_rf += 1 val_start: t.CSizeT = eq while eq < line_start + line_len and buf[eq] != ' ' and buf[eq] != '\t' \ and buf[eq] != '#' and buf[eq] != '\r' and buf[eq] != '\n': @@ -623,11 +639,13 @@ class AssignGenMixin: if arr_ty is None: return 1 - # 匹配数组类型获取元素类型 + # 匹配数组类型获取元素类型与声明长度 elem_ty: llvmlite.LLVMType | t.CPtr = None + arr_count: int = 0 match arr_ty: - case llvmlite.LLVMType.Array(et, _): + case llvmlite.LLVMType.Array(et, cnt): elem_ty = et + arr_count = cnt if elem_ty is None: return 1 @@ -638,6 +656,42 @@ class AssignGenMixin: elts: list[ast.AST | t.CPtr] | t.CPtr = lst.elts elts_count: t.CSizeT = len(elts) + # 特例:单个字符串字面量初始化字符数组([N x i8],N = strlen+1) + # 逐字节写入字符串内容;调用方已先 store zeroinitializer,末字节 NUL 由零保持。 + if self.Gen.ExprGenBase.get_llvm_type_bits(elem_ty) == 8 and elts_count == 1 and arr_count >= 1: + e0_s: ast.AST | t.CPtr = elts.get(0) + if e0_s is not None and e0_s.kind() == ast.ASTKind.Constant: + c0_s: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(e0_s) + if c0_s.const_kind == ast.CONST_STR: + sv_s: str = ast.constant_get_str_val(c0_s) + if sv_s is not None: + n_s: t.CSizeT = string.strlen(sv_s) + if t.CSizeT(arr_count) < n_s: + self.Gen.TypeGenErr.fatal_error( + list_node, + f"字符串字面量长度 {n_s} 超过字符数组声明长度 {arr_count},不允许越界写入", + "OverflowError") + bi_s: t.CSizeT = 0 + while bi_s < n_s: + bidx_s: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, bi_s) + bp_s: llvmlite.Value | t.CPtr = llvmlite.build_gep_array( + builder, arr_ty, elem_ty, array_alloca, bidx_s) + if bp_s is None: + break + bvv: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, sv_s[bi_s]) + bsv: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type( + builder, bvv, elem_ty, e0_s) + llvmlite.build_store(builder, bsv, bp_s) + bi_s += 1 + return 0 + + # 元素数超过声明长度 → fail-fast(否则会生成 idx>=N 的越界 GEP 写) + if arr_count > 0 and t.CSizeT(arr_count) < elts_count: + self.Gen.TypeGenErr.fatal_error( + list_node, + f"数组初始化元素数 {elts_count} 超过数组声明长度 {arr_count},不允许越界写入", + "OverflowError") + # 为每个元素生成 GEP + store for i in range(elts_count): elem_node: ast.AST | t.CPtr = elts.get(i) @@ -721,16 +775,30 @@ class AssignGenMixin: # 整数运算:类型提升 if lhs_bits > rhs_bits and rhs_bits > 0: - rhs = self.Gen.ExprGenBase.coerce_to_type(builder, rhs, lhs.Ty, node) + rhs = self.Gen.ExprGenBase.coerce_to_type(builder, rhs, lhs.Ty, node, trans) elif rhs_bits > lhs_bits and lhs_bits > 0: - lhs = self.Gen.ExprGenBase.coerce_to_type(builder, lhs, rhs.Ty, node) + lhs = self.Gen.ExprGenBase.coerce_to_type(builder, lhs, rhs.Ty, node, trans) + + # 无符号操作数(如 u_num_l: t.CUInt64T 的 //= / %=)→ udiv/urem。 + # 此前一律 sdiv/srem(translate_binop 的 Div/Mod 已修,但 AugAssign 走本 + # 函数独立发射 → viperlib %lu/%lx 的 //= 仍为 sdiv,T3 未覆盖根因)。 + aug_unsigned: int = 0 + if lhs_node is not None: + if self.Gen.ExprGenOps._node_type_unsigned(pool, lhs_node, trans) != 0: + aug_unsigned = 1 if op == ast.OpKind.Add: return llvmlite.build_add(builder, lhs, rhs) elif op == ast.OpKind.Sub: return llvmlite.build_sub(builder, lhs, rhs) elif op == ast.OpKind.Mult: return llvmlite.build_mul(builder, lhs, rhs) - elif op == ast.OpKind.Div: return llvmlite.build_sdiv(builder, lhs, rhs) - elif op == ast.OpKind.FloorDiv: return llvmlite.build_sdiv(builder, lhs, rhs) - elif op == ast.OpKind.Mod: return llvmlite.build_srem(builder, lhs, rhs) + elif op == ast.OpKind.Div: + if aug_unsigned != 0: return llvmlite.build_udiv(builder, lhs, rhs) + return llvmlite.build_sdiv(builder, lhs, rhs) + elif op == ast.OpKind.FloorDiv: + if aug_unsigned != 0: return llvmlite.build_udiv(builder, lhs, rhs) + return llvmlite.build_sdiv(builder, lhs, rhs) + elif op == ast.OpKind.Mod: + if aug_unsigned != 0: return llvmlite.build_urem(builder, lhs, rhs) + return llvmlite.build_srem(builder, lhs, rhs) elif op == ast.OpKind.BitAnd: return llvmlite.build_and(builder, lhs, rhs) elif op == ast.OpKind.BitOr: return llvmlite.build_or(builder, lhs, rhs) elif op == ast.OpKind.BitXor: return llvmlite.build_xor(builder, lhs, rhs) @@ -1041,6 +1109,17 @@ class AssignGenMixin: cnt_arr: int = 0 if lst_arr.elts is not None: cnt_arr = len(lst_arr.elts) + # 特例:单个字符串字面量(如 hex_digits: t.CArray[t.CChar, None] = ["0123.."]) + # 语义是"以字符串内容初始化字符数组",长度应取 strlen+1(含结尾 NUL), + # 而不是列表元素个数 1——否则 alloca [1 x i8] 且只写首字节 → 下标 0..15 越界读。 + if elem_ty_arr is not None and cnt_arr == 1 and lst_arr.elts is not None: + e0_arr: ast.AST | t.CPtr = lst_arr.elts.get(0) + if e0_arr is not None and e0_arr.kind() == ast.ASTKind.Constant: + c0_arr: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(e0_arr) + if c0_arr.const_kind == ast.CONST_STR: + sv0_arr: str = ast.constant_get_str_val(c0_arr) + if sv0_arr is not None and self.Gen.ExprGenBase.get_llvm_type_bits(elem_ty_arr) == 8: + return llvmlite.Array(pool, elem_ty_arr, int(string.strlen(sv0_arr)) + 1) if elem_ty_arr is not None and cnt_arr > 0: return llvmlite.Array(pool, elem_ty_arr, cnt_arr) return resolved_ty @@ -1145,26 +1224,38 @@ class AssignGenMixin: var_ty: llvmlite.LLVMType | t.CPtr = None annot: ast.AST | t.CPtr = aa.annotation if annot is not None: + # 泛型特化补救(在解析之前无条件执行,_specialize_generic_class 幂等): + # 注解可能是 list[X](Subscript)或 list[X] | t.CPtr(含 CPtr 的 BinOp)。 + # 若泛型类尚未特化,resolve_annotation_type 会把 list[X] 退化为不透明 + # 基类 list*(丢掉元素类型)——PreScan 预建的 alloca 因此变成 list*, + # 之后 body_list.get(i) 会分派到默认 list[int] 特化(返回 i32)→ + # inttoptr i32→AST* 截断指针 → StmtGenMixin._translate_stmt_impl + # 虚调用读 vtable 崩溃。故先提取 Subscript 一侧主动特化再解析,保证 + # PreScan 与 Handle 两处解析结果一致。 + spec_annot: ast.Subscript | t.CPtr = None + if annot.kind() == ast.ASTKind.Subscript: + spec_annot = (ast.Subscript | t.CPtr)(annot) + elif annot.kind() == ast.ASTKind.BinOp: + bop_ps: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot) + if bop_ps.op == ast.OpKind.BitOr: + if bop_ps.left is not None and bop_ps.left.kind() == ast.ASTKind.Subscript: + spec_annot = (ast.Subscript | t.CPtr)(bop_ps.left) + elif bop_ps.right is not None and bop_ps.right.kind() == ast.ASTKind.Subscript: + spec_annot = (ast.Subscript | t.CPtr)(bop_ps.right) + if spec_annot is not None: + sv_ps: ast.AST | t.CPtr = spec_annot.value + if sv_ps is not None and sv_ps.kind() == ast.ASTKind.Name: + sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sv_ps) + if sub_nm.id is not None: + template_cd: ast.ClassDef | t.CPtr = self.Gen.ClassGenGeneric._find_generic_template(sub_nm.id) + if template_cd is not None: + type_args_ps: list[str] | t.CPtr = self.Gen.CallGenCtor._extract_type_args_from_slice( + pool, spec_annot.slice, trans._from_imports) + if type_args_ps is not None and len(type_args_ps) > 0: + self.Gen.ClassGenGeneric._specialize_generic_class( + trans, sub_nm.id, type_args_ps) resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type( pool, annot, trans._imported_modules, trans._from_imports, trans, 0) - if resolved is None: - # 尝试特化泛型类注解(如 list[str]) - # resolve_annotation_type 返回 None 可能是因为泛型类未特化 - if annot.kind() == ast.ASTKind.Subscript: - sub_annot: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot) - if sub_annot.value is not None and sub_annot.value.kind() == ast.ASTKind.Name: - sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_annot.value) - if sub_nm.id is not None: - template_cd: ast.ClassDef | t.CPtr = self.Gen.ClassGenGeneric._find_generic_template(sub_nm.id) - spec_name_ps: str = None - if template_cd is not None: - type_args_ps: list[str] | t.CPtr = self.Gen.CallGenCtor._extract_type_args_from_slice(pool, sub_annot.slice, trans._from_imports) - if type_args_ps is not None and len(type_args_ps) > 0: - spec_name_ps = self.Gen.ClassGenGeneric._specialize_generic_class( - trans, sub_nm.id, type_args_ps) - if spec_name_ps is not None: - resolved = self.Gen.TypeGenResolve.resolve_annotation_type( - pool, annot, trans._imported_modules, trans._from_imports, trans, 0) if resolved is not None: var_ty = resolved # 单参 t.CArray[elem_ty] + 列表字面量 → 静态数组(与 Handle 推断一致)。 diff --git a/App/lib/core/Gen/Call/CallGenBase.vp b/App/lib/core/Gen/Call/CallGenBase.vp index cdab94c..8b11657 100644 --- a/App/lib/core/Gen/Call/CallGenBase.vp +++ b/App/lib/core/Gen/Call/CallGenBase.vp @@ -692,6 +692,10 @@ class CallGenBase: # {sha1}.{cls}.{method} 查 vpi 参数注解缓存取定义侧类型:仅当实参与 # 定义都是整数且定义更宽时采用定义宽度(指针/联合保持实参类型,避免 # 字符串路径把 list*/Struct* 降级为 i8*)。 + # 注:反方向(定义侧更窄,如 su8250.putchar 定义 (i16,i8) 而字面量 + # 1016=i32)由调用点 CallGenLib._coerce_args_to_def_params 先把实参 + # 窄化到定义宽度,本处依 param_head 建 declare 即已对齐(此块做补强, + # 对已窄化的实参不再触发)。 sha1_d: str = None cls_d: str = None meth_d: str = None diff --git a/App/lib/core/Gen/Call/CallGenCBuiltin.vp b/App/lib/core/Gen/Call/CallGenCBuiltin.vp index 0d5f6d5..d671abc 100644 --- a/App/lib/core/Gen/Call/CallGenCBuiltin.vp +++ b/App/lib/core/Gen/Call/CallGenCBuiltin.vp @@ -241,11 +241,40 @@ class CallGenCBuiltin(CallGenBase.CallGenBase): ptr_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value( builder, pool, mod, d_args.get(0), None, 0, trans) if ptr_val is not None: - val_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, b_val.Ty) - casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, ptr_val, val_ptr_ty) - if casted_ptr is not None: - llvmlite.build_store(builder, b_val, casted_ptr) + # 写入宽度以「左值指针自身的元素类型」为准: + # c.Set(c.Deref((p)), v) 应先把 v 转换到 T,再按 T 宽度写入。 + # 此前用 Ptr(b_val.Ty) 重解释指针并按 RHS 宽度 store,导致 + # c.Deref(uint16(p)) 被 i32 字面量写成 4 字节(越界 2 字节)、 + # c.Deref(uint32(p)) 被 0xFFFFFFFF(i64) 写成 8 字节(越界 4 字节)。 + # 无类型指针(元素为 i8,如 t.CPtr/i8* 形参)维持原行为: + # 按 RHS 类型重解释指针 store(如 paging save_count 写 i32)。 + store_ptr: llvmlite.Value | t.CPtr = ptr_val + store_val: llvmlite.Value | t.CPtr = b_val + typed_elem: int = 0 + elem_ty: llvmlite.LLVMType | t.CPtr = None + if ptr_val.Ty is not None: + elem_ty = ptr_val.Ty.Pointee + if elem_ty is not None: + eb: int = self.Gen.ExprGenBase.get_llvm_type_bits(elem_ty) + if eb != 0 and eb != 8: + typed_elem = 1 + elif self.Gen.ExprGenBase.get_llvm_float_bits(elem_ty) != 0: + typed_elem = 1 + elif self.Gen.ExprGenBase.is_ptr_type(elem_ty) != 0: + typed_elem = 1 + elif self.Gen.ExprGenBase.is_array_type(elem_ty) != 0: + typed_elem = 1 + if typed_elem != 0: + store_val = self.Gen.ExprGenBase.coerce_to_type( + builder, b_val, elem_ty, a_node) + else: + val_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, b_val.Ty) + casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, ptr_val, val_ptr_ty) + if casted_ptr is not None: + store_ptr = casted_ptr + if store_ptr is not None and store_val is not None: + llvmlite.build_store(builder, store_val, store_ptr) return b_val # 其他 Call 形态不可作左值 return b_val diff --git a/App/lib/core/Gen/Call/CallGenCall.vp b/App/lib/core/Gen/Call/CallGenCall.vp index 4a3d17e..c8334dc 100644 --- a/App/lib/core/Gen/Call/CallGenCall.vp +++ b/App/lib/core/Gen/Call/CallGenCall.vp @@ -1644,6 +1644,9 @@ class CallGenCall(CallGenBase.CallGenBase): obj_ptr) # 跨模块调用:创建 declare 声明,避免 llc 报 undefined value + # 先按 vpi 定义侧形参 coerce 实参(宽度对齐),再建 declare(ABI 通用化) + head = self.Gen.CallGenLib._coerce_args_to_def_params( + pool, builder, call_name, head, total_count) self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count) # 检查变长函数 + C ABI 提升(cargs 是实参 AST,self_offset=1 跳过 self) is_variadic_3441: int = self.Gen.CallGenVa._check_and_promote_variadic_call( @@ -2136,6 +2139,9 @@ class CallGenCall(CallGenBase.CallGenBase): match entry.Ty: case llvmlite.LLVMType.Struct(fields, fcount, name): offset_fb: int = 0 + # packed(@c.Attribute(t.attr.packed))结构体无字段填充: + # 偏移 = 前序字段尺寸之和(LLVM packed struct 布局)。 + is_packed_fb: int = entry.IsPacked cur_fb: llvmlite.ParamNode | t.CPtr = fields i_fb: int = 0 while cur_fb is not None and i_fb < field_index: @@ -2143,7 +2149,7 @@ class CallGenCall(CallGenBase.CallGenBase): fty_fb: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur_fb.Ty) fsize_fb: int = self.Gen.ClassGenEnum._get_type_size(fty_fb) falign_fb: int = self.Gen.ClassGenEnum._get_type_align(fty_fb) - if falign_fb > 1: + if is_packed_fb == 0 and falign_fb > 1: rem_fb: int = offset_fb % falign_fb if rem_fb != 0: offset_fb += falign_fb - rem_fb @@ -2154,7 +2160,7 @@ class CallGenCall(CallGenBase.CallGenBase): if cur_fb is not None and cur_fb.Ty is not None: fty2_fb: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur_fb.Ty) falign2_fb: int = self.Gen.ClassGenEnum._get_type_align(fty2_fb) - if falign2_fb > 1: + if is_packed_fb == 0 and falign2_fb > 1: rem2_fb: int = offset_fb % falign2_fb if rem2_fb != 0: offset_fb += falign2_fb - rem2_fb diff --git a/App/lib/core/Gen/Call/CallGenCtor.vp b/App/lib/core/Gen/Call/CallGenCtor.vp index 115331d..a85e783 100644 --- a/App/lib/core/Gen/Call/CallGenCtor.vp +++ b/App/lib/core/Gen/Call/CallGenCtor.vp @@ -122,7 +122,7 @@ class CallGenCtor(CallGenBase.CallGenBase): # 创建临时 alloca # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, struct_ty) - tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) + tmp: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry(builder, struct_ty) if tmp is None: return llvmlite.ConstZero(pool, struct_ty) # 诊断节点:取第一个构造实参(有行号),供 _call_method_on_ptr 的 @@ -397,7 +397,7 @@ class CallGenCtor(CallGenBase.CallGenBase): # alloca REnum 类型 # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, renum_ty) - tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, renum_ty) + tmp: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry(builder, renum_ty) if tmp is None: return llvmlite.ConstZero(pool, renum_ty) @@ -476,7 +476,7 @@ class CallGenCtor(CallGenBase.CallGenBase): # 创建临时 alloca # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, struct_ty) - tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) + tmp: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry(builder, struct_ty) if tmp is None: return llvmlite.ConstZero(pool, struct_ty) # 诊断节点:取第一个构造实参(有行号),供 _call_method_on_ptr 的 @@ -928,7 +928,7 @@ class CallGenCtor(CallGenBase.CallGenBase): self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, struct_ty) # alloca tmp(self 指针) - tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) + tmp: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry(builder, struct_ty) if tmp is None: return None diff --git a/App/lib/core/Gen/Call/CallGenDispatch.vp b/App/lib/core/Gen/Call/CallGenDispatch.vp index 852c30f..ff8dfdd 100644 --- a/App/lib/core/Gen/Call/CallGenDispatch.vp +++ b/App/lib/core/Gen/Call/CallGenDispatch.vp @@ -1432,6 +1432,9 @@ class CallGenDispatch(CallGenBase.CallGenBase): # 依赖未就绪:保持默认 i32(build_call(Void) # 返回 None 破坏表达式翻译;本遍不写盘) ret_ty3 = llvmlite.Int32(pool) + # 先按 vpi 定义侧形参 coerce 实参(宽度对齐),再建 declare + head3 = self.Gen.CallGenLib._coerce_args_to_def_params( + pool, builder, mangled3, head3, total3) self._ensure_method_declare(pool, mod, mangled3, ret_ty3, head3, total3) return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0) else: diff --git a/App/lib/core/Gen/Call/CallGenLeafKit.vp b/App/lib/core/Gen/Call/CallGenLeafKit.vp index a3b7108..1814630 100644 --- a/App/lib/core/Gen/Call/CallGenLeafKit.vp +++ b/App/lib/core/Gen/Call/CallGenLeafKit.vp @@ -121,8 +121,8 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin): msg_ptr = trans._eh_msg_out_param code_ptr = trans._eh_code_out_param if msg_ptr is None: - msg_ptr = llvmlite.build_alloca(builder, i8_ptr_ty_g) - code_ptr = llvmlite.build_alloca(builder, i32_ty_g) + msg_ptr = self.Gen.VarGen._alloca_at_entry(builder, i8_ptr_ty_g) + code_ptr = self.Gen.VarGen._alloca_at_entry(builder, i32_ty_g) # ---- 2. 调用前清零 ---- null_msg_g: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, i8_ptr_ty_g, "null") zero_code_g: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) @@ -1182,8 +1182,14 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin): return 1 if self._init_global_defaults_table() == 0: return 1 - # 已存在则跳过 - if self.find_func_defaults(name) is not None: + # 当前模块 SHA1 作为限定键:同一函数名在不同模块各存一条, + # 查询时按「名 + 定义模块」精确匹配,消除跨模块同名串味 + # (usb.uhci.init 1 参误命中 mm.init 5 参/2 默认值根因)。 + cur_sha: str = None + if self.Gen is not None and self.Gen.TypeGenBase is not None: + cur_sha = self.Gen.TypeGenBase.CurrentModuleSha1 + # 同模块同名已存在则跳过 + if self.find_func_defaults(name, cur_sha) is not None: return 0 if self.GlobalDefaultsCount >= GLOBAL_DEFAULTS_MAX: return 1 @@ -1197,6 +1203,13 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin): return 1 string.strcpy(nm_copy, name) entry.Name = nm_copy + entry.ModuleSha1 = None + if cur_sha is not None: + sh_len: t.CSizeT = string.strlen(cur_sha) + sh_copy: str = CompilerFactory.factory.PermPool.alloc(sh_len + 1) + if sh_copy is not None: + string.strcpy(sh_copy, cur_sha) + entry.ModuleSha1 = sh_copy entry.Defaults = defaults entry.DefaultCount = default_count entry.ParamCount = param_count @@ -1269,17 +1282,29 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin): return 0 - def find_func_defaults(self, name: str) -> GenTypes.FuncDefaultsEntry | t.CPtr: - """按函数名查找默认参数信息,返回 FuncDefaultsEntry 或 None""" + def find_func_defaults(self, name: str, + module_sha1: str = None) -> GenTypes.FuncDefaultsEntry | t.CPtr: + """按函数名(可选按定义模块 SHA1)查找默认参数信息,返回 FuncDefaultsEntry 或 None + + module_sha1 非 None 时要求条目定义模块完全一致(限定名匹配,消除跨模块同名串味); + 为 None 时退化为按名匹配(兼容旧调用点)。 + """ if name is None or self.GlobalDefaults is None: return None entry_size: t.CSizeT = GenTypes.FuncDefaultsEntry.__sizeof__() for i in range(self.GlobalDefaultsCount): entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalDefaults) + i * entry_size entry: GenTypes.FuncDefaultsEntry | t.CPtr = (GenTypes.FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr)) - if entry.Name is not None: - if string.strcmp(entry.Name, name) == 0: - return entry + if entry.Name is None: + continue + if string.strcmp(entry.Name, name) != 0: + continue + if module_sha1 is not None: + if entry.ModuleSha1 is None: + continue + if string.strcmp(entry.ModuleSha1, module_sha1) != 0: + continue + return entry return None diff --git a/App/lib/core/Gen/Call/CallGenLib.vp b/App/lib/core/Gen/Call/CallGenLib.vp index 4168489..5790064 100644 --- a/App/lib/core/Gen/Call/CallGenLib.vp +++ b/App/lib/core/Gen/Call/CallGenLib.vp @@ -4,6 +4,7 @@ import ast import llvmlite import memhub import string +import stdlib import lib.core.Gen.Translator as HT from . import CallGenBase @@ -130,21 +131,25 @@ class CallGenLib(CallGenBase.CallGenBase): # 仅裸名(无 '.' 分隔 → 无 sha1 前缀);带前缀走 vpi 定义侧解析 if string.strchr(call_name, 46) is not None: return head - # 白名单:第三参 size_t(i64) 的函数(与 _ensure_c_lib_declare 一致) - is_3rd_i64: int = 0 - if string.strcmp(call_name, "memset") == 0: is_3rd_i64 = 1 - elif string.strcmp(call_name, "memcpy") == 0: is_3rd_i64 = 1 - elif string.strcmp(call_name, "memmove") == 0: is_3rd_i64 = 1 - elif string.strcmp(call_name, "memcmp") == 0: is_3rd_i64 = 1 - elif string.strcmp(call_name, "strncmp") == 0: is_3rd_i64 = 1 - elif string.strcmp(call_name, "strncpy") == 0: is_3rd_i64 = 1 - elif string.strcmp(call_name, "strncat") == 0: is_3rd_i64 = 1 - if is_3rd_i64 == 0 or count < 3: + # 白名单:size_t(i64) 长度参数所在下标(与 _ensure_c_lib_declare 一致)。 + # vsnprintf 非变参(第二参即 t.CSizeT 长度)——viperlib.vp `export def + # vsnprintf(buf, size: t.CSizeT, fmt, ap)`,跨模块裸名调用时字面量 1024 + # 固化 i32 vs 定义 i64,与 memset 同族。 + size_idx: int = -1 + if string.strcmp(call_name, "memset") == 0: size_idx = 2 + elif string.strcmp(call_name, "memcpy") == 0: size_idx = 2 + elif string.strcmp(call_name, "memmove") == 0: size_idx = 2 + elif string.strcmp(call_name, "memcmp") == 0: size_idx = 2 + elif string.strcmp(call_name, "strncmp") == 0: size_idx = 2 + elif string.strcmp(call_name, "strncpy") == 0: size_idx = 2 + elif string.strcmp(call_name, "strncat") == 0: size_idx = 2 + elif string.strcmp(call_name, "vsnprintf") == 0: size_idx = 1 + if size_idx < 0 or count <= size_idx: return head - # 定位第三参(index 2) + # 定位长度参数(index size_idx) cur: llvmlite.Value | t.CPtr = head idx: int = 0 - while cur is not None and idx < 2: + while cur is not None and idx < size_idx: cur = cur.Next idx += 1 if cur is None or cur.Ty is None: @@ -165,14 +170,14 @@ class CallGenLib(CallGenBase.CallGenBase): return head if promoted is None: return head - # 重建实参链表:index 2 替换为提升后的值 + # 重建实参链表:index size_idx 替换为提升后的值 new_head: llvmlite.Value | t.CPtr = None new_tail: llvmlite.Value | t.CPtr = None cur2: llvmlite.Value | t.CPtr = head i2: int = 0 while cur2 is not None: node_v: llvmlite.Value | t.CPtr = cur2 - if i2 == 2: + if i2 == size_idx: node_v = promoted if new_head is None: new_head = node_v @@ -183,6 +188,146 @@ class CallGenLib(CallGenBase.CallGenBase): i2 += 1 return new_head + # ============================================================ + # _coerce_args_to_def_params - 跨模块调用实参按定义侧形参类型 coerce + # + # B3 同族通用化:_ensure_method_declare 用调用点实参类型建 declare,字面量 + # 实参(i32 0/1016/512)把定义侧窄整型形参(i8/i16)固化宽(或把宽形参固化 + # 窄)→ declare 与 define 宽度不一致(跨模块 IR/ABI 失配,x86-64 下侥幸正确: + # 调用侧写 32 位寄存器清高 32 位,callee 按 i64 读高位是 0)。本函数在调用点 + # 按定义侧(vpi 参数注解)重建/转换实参,随后 _ensure_method_declare 依 head + # 建 declare → call/declare/define 三者一致。 + # + # 仅处理"带 sha1 前缀的模块级函数调用"({sha1}.{func},2 段):该形态下实参 + # 下标与 vpi 参数注解段下标一一对应(段 0 即首参,无 self 占位)。类方法 + # ({sha1}.{cls}.{method},3 段)含 self 偏移,交由既有路径(CallGenCall/stub + # 注入)处理,不在本条通用化范围内。裸名 C 库函数由 _promote_clib_call_args + # 与 _ensure_c_lib_declare 标准签名处理。未命中/不可解原样保留(不兜底改型)。 + # ============================================================ + def _coerce_args_to_def_params(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + call_name: str, + head: llvmlite.Value | t.CPtr, + count: int) -> llvmlite.Value | t.CPtr: + """把跨模块模块级函数实参 coerce 到 vpi 定义侧形参类型,返回重建的实参链""" + if pool is None or builder is None or call_name is None or head is None: + return head + # 函数内懒 import:与 _lookup_method_ret_ty_via_vpi 同源,规避顶层循环依赖 + import lib.Stub.StubGen.VpiReader as VpiReader + if self._is_sha1_mangled_call(call_name) == 0: + return head + # 仅 {sha1}.{func}(2 段);3 段(含类名/self)跳过 + rest: str = call_name + 17 + if string.strchr(rest, 46) is not None: + return head + meth_nm: str = rest + if meth_nm is None or meth_nm[0] == '\0': + return head + sha1_buf: bytes = stdlib.malloc(17) + if sha1_buf is None: + return head + string.strncpy(sha1_buf, call_name, 16) + sha1_buf[16] = '\0' + # 注意:不能用 self._vpi_method_param_annot —— 其形参校验含 + # `cls_name is None → return None`,而模块级函数必传 cls_name=None, + # 于是恒返回 None → 本函数永不生效(ABI 收敛首轮/二轮均未生效的根因)。 + # 改为直接 ensure 加载 + 直查缓存(键 {sha1}.{func},与 cls_name=None 匹配)。 + if self.Gen.CallGenBase.TempDir is not None and self.Gen.CallGenBase.TempDirLen > 0: + VpiReader._ensure_vpi_param_annot_loaded(sha1_buf, self.Gen.CallGenBase.TempDir) + prm_annots: str = VpiReader._lookup_vpi_param_annots(sha1_buf, None, meth_nm) + if prm_annots is None: + stdlib.free(sha1_buf) + return head + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + new_head: llvmlite.Value | t.CPtr = None + new_tail: llvmlite.Value | t.CPtr = None + cur: llvmlite.Value | t.CPtr = head + idx: int = 0 + while cur is not None and idx < count: + node_v: llvmlite.Value | t.CPtr = cur + tgt_ty: llvmlite.LLVMType | t.CPtr = VpiReader._resolve_vpi_param_annot_seg( + pool, sha1_buf, None, meth_nm, idx, i32_ty, i8_ptr_ty) + if tgt_ty is not None and cur.Ty is not None: + node_v = self._coerce_arg_value_to_ty(pool, builder, cur, tgt_ty) + if new_head is None: + new_head = node_v + else: + new_tail.Next = node_v + new_tail = node_v + cur = cur.Next + idx += 1 + stdlib.free(sha1_buf) + return new_head + + # ============================================================ + # _coerce_arg_value_to_ty - 单个实参 Value 转换到目标形参类型 + # + # 整型: + # - 同宽 → 原样; + # - 窄化(目标更窄,本簇主场景 i32→i8/i16)→ 常量按目标宽度重建常量, + # SSA 用 trunc(trunc 与符号无关,窄化安全); + # - 扩宽交由 _ensure_method_declare 既有"定义侧更宽才采用"逻辑 + 下遍 + # 收敛时按形参 coerce(需 AST 判定符号性,本函数无 AST,不越权处理)。 + # 指针:实参与目标皆指针且"泛型 i8* 性"不同时 bitcast(如 i32*→i8*), + # 使 declare 指针类型与 define 一致;同为 i8* 或同为具体 struct 指针 + # 则原样保留(避免把 list*/Struct* 无谓降级为 i8* 的 IR 噪声)。 + # 其它(结构体值/void 等)→ 原样保留。不可转换亦原样返回(不兜底改型)。 + # ============================================================ + def _coerce_arg_value_to_ty(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + val: llvmlite.Value | t.CPtr, + tgt_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.Value | t.CPtr: + """把单个实参 Value 转换到目标形参类型,无法安全转换时原样返回""" + if pool is None or builder is None or val is None or tgt_ty is None or val.Ty is None: + return val + match val.Ty: + case llvmlite.LLVMType.Int(bits_a): + match tgt_ty: + case llvmlite.LLVMType.Int(bits_b): + if bits_b == bits_a: + return val + if bits_b < bits_a: + if val.IsConst != 0: + nv_c: llvmlite.Value | t.CPtr = llvmlite.const_int( + pool, bits_b, val.IntVal) + if nv_c is not None: + return nv_c + else: + nv_t: llvmlite.Value | t.CPtr = llvmlite.build_trunc( + builder, val, tgt_ty) + if nv_t is not None: + return nv_t + case _: + pass + case llvmlite.LLVMType.Ptr(pointee_a): + match tgt_ty: + case llvmlite.LLVMType.Ptr(pointee_b): + ia: int = 0 + match pointee_a: + case llvmlite.LLVMType.Int(pa_bits): + if pa_bits == 8: + ia = 1 + case _: + pass + ib: int = 0 + match pointee_b: + case llvmlite.LLVMType.Int(pb_bits): + if pb_bits == 8: + ib = 1 + case _: + pass + if ia != ib: + nv_p: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, val, tgt_ty) + if nv_p is not None: + return nv_p + case _: + pass + case _: + pass + return val + def _infer_external_func_ret_ty(self, pool: memhub.MemBuddy | t.CPtr, func_name: str, node: ast.AST | t.CPtr, diff --git a/App/lib/core/Gen/Call/CallGenMixin.vp b/App/lib/core/Gen/Call/CallGenMixin.vp index 08fda1e..599d19a 100644 --- a/App/lib/core/Gen/Call/CallGenMixin.vp +++ b/App/lib/core/Gen/Call/CallGenMixin.vp @@ -947,7 +947,7 @@ class CallGenMixin(CallGenBase.CallGenBase): # alloca 暂存 i8_ty_nl: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) i8_ptr_ty_nl: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_nl) - tmp_alloca_nl: llvmlite.Value | t.CPtr = llvmlite.build_alloca( + tmp_alloca_nl: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry( builder, i8_ptr_ty_nl) if tmp_alloca_nl is not None: llvmlite.build_store(builder, fp_alloca, tmp_alloca_nl) @@ -1104,11 +1104,42 @@ class CallGenMixin(CallGenBase.CallGenBase): # 快照才是跨文件永久存活。同模块命中时 gd_entry 也必须已赋值, # 否则下方 _build_const_from_snapshot 读到未初始化栈垃圾指针崩溃。 # 与 _translate_method_call 的 mdf_gd 无条件查询(L2677)保持一致。 - gd_entry: GenTypes.FuncDefaultsEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_defaults(func_name) + # 计算被调模块 SHA1 作限定键(消除跨模块同名函数串味): + # module.func(...) → 该 module 的 SHA1;裸名调用 → 当前模块 SHA1。 + # 全局默认参数表按「名 + 定义模块 SHA1」精确匹配,避免 usb.uhci.init(1 参) + # 误命中 mm.init(5 参/2 默认值) 而补出多余实参。 + dfx_callee_sha: str = None + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + dfx_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if dfx_at.value is not None and dfx_at.value.kind() == ast.ASTKind.Name: + dfx_mn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(dfx_at.value) + if dfx_mn.id is not None: + dfx_callee_sha = self._lookup_module_sha1(dfx_mn.id) + if dfx_callee_sha is None and self.Gen.TypeGenBase is not None: + dfx_callee_sha = self.Gen.TypeGenBase.CurrentModuleSha1 + gd_entry: GenTypes.FuncDefaultsEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_defaults(func_name, dfx_callee_sha) if df_defaults is None and gd_entry is not None: df_defaults = gd_entry.Defaults df_default_count = gd_entry.DefaultCount df_param_count = gd_entry.ParamCount + # 交叉校验:全局默认参数表按「裸函数名」登记/查询,跨模块同名函数会串味 + # (如 usb.uhci.init 只有 1 形参,却命中 mm.init 的 5 形参/2 默认值记录 + # → 被补 2 个 i32 0 → call 3 实参 vs declare 1 形参 → ABI 错位)。 + # 若被调声明(found_func)的实际形参数与表记录 ParamCount 不符,则丢弃该表, + # 交由下方 `elif found_func is not None` 分支按真实形参数零值兜底。 + if found_func is not None and df_default_count > 0: + dfx_cnt: int = 0 + dfx_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + while dfx_p is not None: + dfx_nm: str = llvmlite.param_get_name(dfx_p) + if dfx_nm is None or (string.strcmp(dfx_nm, "%__eh_msg_out__") != 0 + and string.strcmp(dfx_nm, "%__eh_code_out__") != 0): + dfx_cnt += 1 + dfx_p = llvmlite.param_get_next(dfx_p) + if dfx_cnt > 0 and dfx_cnt != df_param_count: + df_defaults = None + df_default_count = 0 + df_param_count = 0 # 填充缺失参数 if df_defaults is not None and df_default_count > 0 and can < df_param_count: df_offset: int = df_param_count - df_default_count @@ -1561,6 +1592,12 @@ class CallGenMixin(CallGenBase.CallGenBase): # declare/定义宽度一致(B3:process 固化 i32 vs 定义 t.CSizeT=i64)。 head = self.Gen.CallGenLib._promote_clib_call_args( pool, builder, mod, call_name, head, can) + # 跨模块模块级调用({sha1}.{func}):实参按 vpi 定义侧形参类型 coerce + # (整型宽度精确对齐,i32 字面量 → 定义侧 i8/i16),再建 declare → + # call 实参 / declare / define 三者宽度一致(B3 同族通用化;反例: + # su8250.putchar 定义 (i16,i8) 而调用点字面量 1016=i32 固化宽)。 + head = self.Gen.CallGenLib._coerce_args_to_def_params( + pool, builder, call_name, head, can) # 跨模块调用:创建 declare 声明,避免 llc 报 undefined value self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, can) # 检查被调用函数是否为变长函数(*args),若是则对变长参数进行 C ABI 提升 diff --git a/App/lib/core/Gen/Call/CallGenProp.vp b/App/lib/core/Gen/Call/CallGenProp.vp index 0bd1146..6463db4 100644 --- a/App/lib/core/Gen/Call/CallGenProp.vp +++ b/App/lib/core/Gen/Call/CallGenProp.vp @@ -342,7 +342,7 @@ class CallGenProp(CallGenBase.CallGenBase): struct_ty_cc: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type(class_name) if struct_ty_cc is None: return None - cls_ptr: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty_cc) + cls_ptr: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry(builder, struct_ty_cc) if cls_ptr is None: return None llvmlite.value_set_next(cls_ptr, None) diff --git a/App/lib/core/Gen/Class/ClassGenEnum.vp b/App/lib/core/Gen/Class/ClassGenEnum.vp index 29b0af7..ac64956 100644 --- a/App/lib/core/Gen/Class/ClassGenEnum.vp +++ b/App/lib/core/Gen/Class/ClassGenEnum.vp @@ -308,6 +308,9 @@ class ClassGenEnum(ClassGenBase.ClassGenBase): # 规则: 每个字段的对齐 = 该字段类型的自然对齐 # 指针/i64 → 8, i32 → 4, i16 → 2, i8 → 1 # 结构体总大小需对齐到最大字段对齐的倍数 + # packed(@c.Attribute(t.attr.packed))结构体无字段填充: + # 大小 = 字段尺寸之和(LLVM packed struct 语义)。 + is_packed: int = self.Gen.StructGen.struct_type_is_packed(ty) total: int = 0 max_align: int = 1 cur: llvmlite.ParamNode | t.CPtr = fields @@ -317,17 +320,19 @@ class ClassGenEnum(ClassGenBase.ClassGenBase): fty: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur.Ty) fsize: int = self._get_type_size(fty) falign: int = self._get_type_align(fty) - # 对齐当前偏移到字段对齐边界 - if falign > 0: + # 对齐当前偏移到字段对齐边界(packed 不插填充) + if is_packed == 0 and falign > 0: rem: int = total % falign if rem != 0: total += falign - rem total += fsize - if falign > max_align: + if is_packed == 0 and falign > max_align: max_align = falign cur = cur.Next i += 1 - # 结构体总大小对齐到最大字段对齐的倍数 + # packed 无尾部对齐;非 packed 总大小对齐到最大字段对齐的倍数 + if is_packed != 0: + return total rem2: int = total % max_align if rem2 != 0: total += max_align - rem2 @@ -358,6 +363,9 @@ class ClassGenEnum(ClassGenBase.ClassGenBase): case llvmlite.LLVMType.Array(elem_ty, count): return self._get_type_align(elem_ty) case llvmlite.LLVMType.Struct(fields, fcount, name): + # packed 结构体整体按字节对齐(对齐 1,无填充) + if self.Gen.StructGen.struct_type_is_packed(ty) != 0: + return 1 # 结构体的对齐 = 最大字段对齐 max_align: int = 1 cur: llvmlite.ParamNode | t.CPtr = fields diff --git a/App/lib/core/Gen/Expr/ExprGenBase.vp b/App/lib/core/Gen/Expr/ExprGenBase.vp index 545774e..5b58644 100644 --- a/App/lib/core/Gen/Expr/ExprGenBase.vp +++ b/App/lib/core/Gen/Expr/ExprGenBase.vp @@ -439,7 +439,10 @@ class ExprGenBase: # 此前一律 sext(i1 除外)→ t.CUInt32T 等无符号值赋值/传参被符号 # 扩展(高位置 1,如 0xFFFFFFFF 变 0xFFFFFFFFFFFFFFFF),与比较路径 # should_zext_widen(i8 默认 zext)规则相反 → 隐蔽数据损坏。 - if self._zext_or_sext_val(pool, val, node) != 0: + # trans 必须下传:_node_type_unsigned 对 Name/Subscript 形态需经 + # trans.SymTab 查变量注解(uint16/sec:uint32 等)才能判定无符号, + # 否则返回未知 → 退回 sext(无符号扩展缺陷根因)。 + if self._zext_or_sext_val(pool, val, node, trans) != 0: return llvmlite.build_zext(builder, val, target_ty) return llvmlite.build_sext(builder, val, target_ty) # 窄化截断诊断(_Type.md 问题 8):宽→窄 trunc 静默丢位。 @@ -488,7 +491,8 @@ class ExprGenBase: def _zext_or_sext_val(self, pool: memhub.MemBuddy | t.CPtr, val: llvmlite.Value | t.CPtr, - node: ast.AST | t.CPtr = None) -> int: + node: ast.AST | t.CPtr = None, + trans: HT.Translator | t.CPtr = None) -> int: """统一整数拓宽方向:1=zext(无符号语义),0=sext 规则(对齐 ExprGenOps.should_zext_widen / _node_type_unsigned): @@ -496,6 +500,9 @@ class ExprGenBase: 2. i8 → zext(系统编程中 i8 几乎总是无符号字节) 3. AST 节点解析为无符号类型(t.CUIntXXT 强转/无符号类型名/BYTE 等)→ zext 4. 否则 sext + + trans 供 _node_type_unsigned 经 SymTab 解析变量注解的符号性(Name/ + Subscript 形态必需);省略则仅能识别显式 t.CUIntXXT 强转。 """ if val is None or val.Ty is None: return 0 @@ -505,7 +512,7 @@ class ExprGenBase: if bits == 8: return 1 if node is not None: - if self.Gen.ExprGenOps._node_type_unsigned(pool, node) != 0: + if self.Gen.ExprGenOps._node_type_unsigned(pool, node, trans) != 0: return 1 return 0 diff --git a/App/lib/core/Gen/Expr/ExprGenConst.vp b/App/lib/core/Gen/Expr/ExprGenConst.vp index 6b48ffe..b896d19 100644 --- a/App/lib/core/Gen/Expr/ExprGenConst.vp +++ b/App/lib/core/Gen/Expr/ExprGenConst.vp @@ -336,7 +336,7 @@ class ExprGenConst(ExprGenBase.ExprGenBase): # alloca 临时 list 空间 # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, struct_ty) - tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) + tmp: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry(builder, struct_ty) if tmp is None: return None diff --git a/App/lib/core/Gen/Expr/ExprGenFstr.vp b/App/lib/core/Gen/Expr/ExprGenFstr.vp index 6718760..93148a9 100644 --- a/App/lib/core/Gen/Expr/ExprGenFstr.vp +++ b/App/lib/core/Gen/Expr/ExprGenFstr.vp @@ -172,7 +172,7 @@ class ExprGenFstr(ExprGenBase.ExprGenBase): return None # 固定栈缓冲 [FSTR_BUF_SIZE x i8],GEP(0,0) 取 i8* buf_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, i8_ty, FSTR_BUF_SIZE) - buf_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, buf_ty) + buf_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry(builder, buf_ty) if buf_alloca is None: return None zero_i32: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) diff --git a/App/lib/core/Gen/Expr/ExprGenOps.vp b/App/lib/core/Gen/Expr/ExprGenOps.vp index 5412928..968f149 100644 --- a/App/lib/core/Gen/Expr/ExprGenOps.vp +++ b/App/lib/core/Gen/Expr/ExprGenOps.vp @@ -190,8 +190,11 @@ class ExprGenOps(ExprGenBase.ExprGenBase): if wide_val.IntVal > signed_max: return 1 # 窄侧 AST 节点解析为无符号类型(如 t.CUIntXXT 字面量/强转) + # trans 必须下沉:Name/Subscript 形态靠 trans.SymTab 查变量/数组元素 + # 注解的无符号性,缺 trans 时恒返回 0 → 无符号值被误用 sext 扩展 + # (ide.vp identify_data[60] / timer.vp sec 的 uint16/uint32→更宽 根因) if narrow_node is not None: - if self._node_type_unsigned(pool, narrow_node) != 0: + if self._node_type_unsigned(pool, narrow_node, trans) != 0: return 1 # 窄侧是高位比特置位的 CDefine 常量(0x80000000..0xFFFFFFFF)→ zext。 # CDefine 常量是编译期值而非变量,_node_type_unsigned 查不到类型注解; @@ -272,6 +275,46 @@ class ExprGenOps(ExprGenBase.ExprGenBase): if self._annot_str_unsigned(ve_su.AnnotClassName) != 0: return 1 return 0 + if k == ast.ASTKind.Attribute: + # 结构体字段(如 viperio.Buf 的 self.capacity/length: t.CSizeT): + # 经接收者变量的 AnnotClassName 取类名,再按类名+字段名查字段注解, + # 判定无符号(CSizeT/uint*)。此前 Attribute 落到末尾 return 0 → + # `self.capacity > 0` / `self.length < self.capacity` 生成 icmp sgt/slt + # (viperio 字段比较误用有符号,T1 残留根因)。 + # 注意:本函数在 translate_binop 对每个操作数调用,必须**只读失败返回 0**; + # 故不走 lookup_field_by_class(其模块限定名分支会 fatal_error), + # 改用 find_struct + 自遍历字段(未命中一律返回 0)。 + at_u: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at_u.value is not None and at_u.attr is not None and trans is not None: + cls_nm_u: str = None + if at_u.value.kind() == ast.ASTKind.Name: + vn_u: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_u.value) + if vn_u.id is not None: + ve_u: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry( + trans.SymTab, vn_u.id) + if ve_u is not None: + cls_nm_u = ve_u.AnnotClassName + if cls_nm_u is not None: + # 取裸类名(点前部分):只做裸名结构体查找,避免模块限定名解析 + bare_u: str = cls_nm_u + dot_u: str = self.Gen.StructGen._last_dot_outside_brackets(cls_nm_u) + if dot_u is not None: + bare_u = dot_u + 1 + if bare_u is not None: + st_u: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(bare_u) + if st_u is not None: + fi_u: int = 0 + while fi_u < st_u.FieldCount: + fe_u: GenTypes.FieldEntry | t.CPtr = \ + self.Gen.StructGen._get_field_entry(st_u, fi_u) + if fe_u is not None and fe_u.Name is not None \ + and string.strcmp(fe_u.Name, at_u.attr) == 0: + if fe_u.AnnotClassName is not None: + if self._annot_str_unsigned(fe_u.AnnotClassName) != 0: + return 1 + break + fi_u += 1 + return 0 return 0 def _type_name_unsigned(self, type_name: str) -> int: """类型名是否为无符号整数类型(精确匹配,避免子串误伤如 nUIntCount)""" @@ -282,6 +325,12 @@ class ExprGenOps(ExprGenBase.ExprGenBase): if string.strcmp(type_name, "CUInt16T") == 0: return 1 if string.strcmp(type_name, "CUInt32T") == 0: return 1 if string.strcmp(type_name, "CUInt64T") == 0: return 1 + # 内建无符号别名(非 CTypedef,动态兜底查不到 → 必须显式登记)。 + # CSizeT 此前缺失 → viperio.Buf.write 的 capacity/length 比较生成 + # icmp sgt/sle/slt(应 ult/ule/ult),A5 同族残留根因。 + if string.strcmp(type_name, "CSizeT") == 0: return 1 + if string.strcmp(type_name, "SSizeT") == 0: return 1 + if string.strcmp(type_name, "CUIntPtrT") == 0: return 1 # stdint 裸别名(from stdint import *) if string.strcmp(type_name, "UInt8T") == 0: return 1 if string.strcmp(type_name, "UInt16T") == 0: return 1 @@ -318,6 +367,17 @@ class ExprGenOps(ExprGenBase.ExprGenBase): if string.strstr(annot, "CUInt16T") is not None: return 1 if string.strstr(annot, "CUInt32T") is not None: return 1 if string.strstr(annot, "CUInt64T") is not None: return 1 + # 内建无符号别名(同 _type_name_unsigned) + if string.strstr(annot, "CSizeT") is not None: return 1 + if string.strstr(annot, "CUIntPtrT") is not None: return 1 + # 小写 stdint 别名(uint16/uint32/uint64/uint8):复合注解如 + # t.CArray[uint16, 256] 的注解串用大写规则扫不到,需显式识别小写 + # (ide.vp identify_data: t.CArray[uint16,256] 的 word60 误 sext 根因)。 + # 注意不含 "size_t":ssize_t(有符号)包含该子串会误判。 + if string.strstr(annot, "uint8") is not None: return 1 + if string.strstr(annot, "uint16") is not None: return 1 + if string.strstr(annot, "uint32") is not None: return 1 + if string.strstr(annot, "uint64") is not None: return 1 if string.strstr(annot, "CUnsigned") is not None: return 1 if string.strstr(annot, "BYTE") is not None: return 1 if string.strstr(annot, "UCHAR") is not None: return 1 @@ -1279,16 +1339,26 @@ class ExprGenOps(ExprGenBase.ExprGenBase): if op == ast.OpKind.Sub and lhs_bits == 0: return self.translate_ptr_arith(pool, builder, lhs, rhs, op) + # 拓宽方向(zext/sext)与后续除/模谓词都需要"操作数是否无符号", + # 统一在此求值一次并下沉 trans(Name/Subscript 靠 SymTab 注解判定)。 + binop_unsigned: int = 0 + if lhs_node is not None: + if self._node_type_unsigned(pool, lhs_node, trans) != 0: + binop_unsigned = 1 + if binop_unsigned == 0 and rhs_node is not None: + if self._node_type_unsigned(pool, rhs_node, trans) != 0: + binop_unsigned = 1 + if lhs_bits > rhs_bits: - if self.should_zext_widen(pool, rhs, lhs, rhs_node) != 0: + if self.should_zext_widen(pool, rhs, lhs, rhs_node, trans) != 0: rhs = llvmlite.build_zext(builder, rhs, lhs.Ty) else: - rhs = self.coerce_to_type(builder, rhs, lhs.Ty, node) + rhs = self.coerce_to_type(builder, rhs, lhs.Ty, node, trans) elif rhs_bits > lhs_bits: - if self.should_zext_widen(pool, lhs, rhs, lhs_node) != 0: + if self.should_zext_widen(pool, lhs, rhs, lhs_node, trans) != 0: lhs = llvmlite.build_zext(builder, lhs, rhs.Ty) else: - lhs = self.coerce_to_type(builder, lhs, rhs.Ty, node) + lhs = self.coerce_to_type(builder, lhs, rhs.Ty, node, trans) # 位运算类型安全检查:两边都是指针(lhs_bits==0 and rhs_bits==0)时, # 位运算(BitOr/BitAnd/BitXor/LShift/RShift)非法,LLVM 要求整数操作数。 @@ -1308,10 +1378,20 @@ class ExprGenOps(ExprGenBase.ExprGenBase): elif op == ast.OpKind.Mult: return llvmlite.build_mul(builder, lhs, rhs) elif op == ast.OpKind.Div: + # 无符号操作数 → udiv(binop_unsigned 经 _node_type_unsigned 判定, + # 覆盖 t.CSizeT/t.CUInt64T 及变量/数组元素的注解无符号性)。 + # 此前一律 sdiv → 无符号值 ≥ 2^63 时结果错误(viperlib %lu/%lx、 + # fat32_mkfs 扇区运算等根因)。 + if binop_unsigned != 0: + return llvmlite.build_udiv(builder, lhs, rhs) return llvmlite.build_sdiv(builder, lhs, rhs) elif op == ast.OpKind.FloorDiv: + if binop_unsigned != 0: + return llvmlite.build_udiv(builder, lhs, rhs) return llvmlite.build_sdiv(builder, lhs, rhs) elif op == ast.OpKind.Mod: + if binop_unsigned != 0: + return llvmlite.build_urem(builder, lhs, rhs) return llvmlite.build_srem(builder, lhs, rhs) elif op == ast.OpKind.BitAnd: return llvmlite.build_and(builder, lhs, rhs) diff --git a/App/lib/core/Gen/Func/FuncGenMixin.vp b/App/lib/core/Gen/Func/FuncGenMixin.vp index 8ff4327..fdd6d60 100644 --- a/App/lib/core/Gen/Func/FuncGenMixin.vp +++ b/App/lib/core/Gen/Func/FuncGenMixin.vp @@ -459,7 +459,7 @@ class FuncGenMixin(CallGenBase.CallGenBase): llvmlite.build_store(parent_builder, null_val, env_slot) # 13e. 将闭包指针存储到父函数的局部变量 {func_name} - closure_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(parent_builder, i8_ptr_ty) + closure_alloca: llvmlite.Value | t.CPtr = self.Gen.VarGen._alloca_at_entry(parent_builder, i8_ptr_ty) if closure_alloca is not None: llvmlite.build_store(parent_builder, closure_ptr, closure_alloca) self.Gen.VarGen.define_var(trans.SymTab, func_name, closure_alloca) diff --git a/App/lib/core/Gen/GenTypes.vp b/App/lib/core/Gen/GenTypes.vp index b5c98a1..494694c 100644 --- a/App/lib/core/Gen/GenTypes.vp +++ b/App/lib/core/Gen/GenTypes.vp @@ -184,6 +184,7 @@ class FuncEntry: class FuncDefaultsEntry: """默认参数表条目""" Name: str + ModuleSha1: str # 定义该函数的模块 SHA1(限定名去重,避免跨模块同名串味) Defaults: t.CVoid | t.CPtr # defaults 列表节点指针 (list[AST | CPtr])(pool 内,可能被 reset) DefaultCount: int ParamCount: int # 形参数量(不含 self) diff --git a/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp b/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp index aa0a41f..6aea00f 100644 --- a/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp +++ b/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp @@ -659,7 +659,9 @@ class StmtGenCifMixin: if val_bits == 1 and val_bits < ret_bits: val = llvmlite.build_zext(builder, val, ret_ty_rt) else: - val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node) + # 传 trans:无符号源类型(uint16/uint32/CSizeT 等)扩展用 zext, + # 缺 trans 时 _node_type_unsigned 查不到变量注解 → 误 sext + val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node, trans) llvmlite.build_ret(builder, val) return 0 @@ -1238,6 +1240,48 @@ class StmtGenCifMixin: if skc_r.int_val < 0: step_neg_const = 1 + # 3.5 循环变量存储位宽:随 range 参数类型(uint64→i64 / uint16→i16 / + # uint8→i8 / 其余→i32),不固定 i32。此前固定 i32 alloca,使 + # uint64 上界的循环变量被截断(syscall MMAP 的 + # range(heap_end, new_end, 4096) 生成 alloca i32 + trunc i64→i32 + # → 高 32 位丢失 → 映射地址错误)。仅当循环变量尚未声明时生效; + # 已声明变量沿用其 alloca 元素类型(见下方 loop_var_ty 解引用)。 + loop_store_ty: llvmlite.LLVMType | t.CPtr = i32_ty + range_arg_bits: int = 0 + if arg_count == 1: + if stop_val is not None and stop_val.Ty is not None: + range_arg_bits = self.Gen.ExprGenBase.get_llvm_type_bits(stop_val.Ty) + else: + start_bits_rt: int = 0 + stop_bits_rt: int = 0 + if start_val is not None and start_val.Ty is not None: + start_bits_rt = self.Gen.ExprGenBase.get_llvm_type_bits(start_val.Ty) + if stop_val is not None and stop_val.Ty is not None: + stop_bits_rt = self.Gen.ExprGenBase.get_llvm_type_bits(stop_val.Ty) + range_arg_bits = start_bits_rt if start_bits_rt > stop_bits_rt else stop_bits_rt + if range_arg_bits == 64: + loop_store_ty = llvmlite.Int64(pool) + elif range_arg_bits == 16: + loop_store_ty = llvmlite.Int16(pool) + elif range_arg_bits == 8: + loop_store_ty = llvmlite.Int8(pool) + + # 3.6 循环无符号性:循环变量注解或任一 range 边界为无符号整型 → + # icmp ult/ugt 而非 slt/sgt(复用 ExprGenOps._node_type_unsigned: + # Name 查 SymTab 注解 / Call 转换目标 / Subscript 元素 / BinOp 递归)。 + # syscall 的 va 未声明,靠边界 heap_end/new_end(uint64)判定; + # fat32 的 i/s 已声明 uint32/uint8,靠循环变量注解判定。 + loop_unsigned: int = 0 + if tk == ast.ASTKind.Name: + if self.Gen.ExprGenOps._node_type_unsigned(pool, target, trans) != 0: + loop_unsigned = 1 + if loop_unsigned == 0: + args_u: t.CSizeT + for args_u in range(arg_count): + if self.Gen.ExprGenOps._node_type_unsigned(pool, args.get(args_u), trans) != 0: + loop_unsigned = 1 + break + # 4. 创建/查找循环变量 alloca # 必须用 lookup_current(仅当前作用域):闭包内 lookup_var 会跨函数 # 命中父函数同名变量(如父函数自己的循环计数器 i)→ 循环计数写到 @@ -1253,7 +1297,9 @@ class StmtGenCifMixin: # uses!",Terminal _cmd_cd 的 for i in range(1,64) 根因)。 # 闭包跨函数命中父函数变量的根因已由 lookup_current 修复, # 故 entry 插入路径安全。 - var_alloca = self.Gen.VarGen._alloca_at_entry(builder, i32_ty) + # 位宽随 range 参数类型(loop_store_ty),不再固定 i32: + # uint64 上界 → i64 alloca,避免 trunc i64→i32 丢失高位。 + var_alloca = self.Gen.VarGen._alloca_at_entry(builder, loop_store_ty) if self.Gen.VarGen.define_var( trans.SymTab, var_name, var_alloca) == 0: new_vars = 1 @@ -1320,10 +1366,16 @@ class StmtGenCifMixin: # "invalid cast opcode for cast from 'i32' to 'i64'" # (VpiReader.vp range(arg_count) 追加86 根因)。 cmp_lhs = llvmlite.build_trunc(builder, cur_i, stop_val.Ty) - # step 为负时条件反转:i > stop(ICMP_SGT);正/缺省 step 保持 i < stop + # 有符号基准谓词:step 为负时条件反转(i > stop,SGT);正/缺省 i < stop(SLT) range_cmp_op: int = llvmlite.ICMP_SLT if step_neg_const != 0: range_cmp_op = llvmlite.ICMP_SGT + # 无符号循环:改用无符号谓词(正步长 ult / 负步长 ugt) + if loop_unsigned != 0: + if step_neg_const != 0: + range_cmp_op = llvmlite.ICMP_UGT + else: + range_cmp_op = llvmlite.ICMP_ULT cond_i1: llvmlite.Value | t.CPtr = llvmlite.build_icmp( builder, range_cmp_op, cmp_lhs, cmp_rhs) llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb) diff --git a/App/lib/core/Gen/StructGenMixin.vp b/App/lib/core/Gen/StructGenMixin.vp index 8ba17db..f18b187 100644 --- a/App/lib/core/Gen/StructGenMixin.vp +++ b/App/lib/core/Gen/StructGenMixin.vp @@ -286,6 +286,7 @@ class StructGenMixin: entry.FieldCount = src_entry.FieldCount entry.Fields = src_entry.Fields entry.IsUnion = src_entry.IsUnion + entry.IsPacked = src_entry.IsPacked entry.IsOOP = src_entry.IsOOP entry.HasInit = src_entry.HasInit entry.HasNew = src_entry.HasNew @@ -720,6 +721,26 @@ class StructGenMixin: return entry return None + def struct_type_is_packed(self, struct_ty: llvmlite.LLVMType | t.CPtr) -> int: + """判断命名结构体是否 packed(@c.Attribute(t.attr.packed)),返回 1/0 + + 先按类型指针身份匹配(find_struct_by_type,跨模块 deep copy 后仍 + 指向同一 entry.Ty)、miss 时按结构体名回退(等价类型实例),最终读 + StructEntry.IsPacked(B5 在定义侧/stub 注入侧写入)。供 __sizeof__ + 尺寸与字段偏移计算:packed 结构体无字段填充,大小=字段尺寸之和。 + """ + if struct_ty is None: + return 0 + sname: str = llvmlite.get_struct_name(struct_ty) + if sname is None: + return 0 + entry: GenTypes.StructEntry | t.CPtr = self.find_struct_by_type(struct_ty) + if entry is None: + entry = self.find_struct(sname) + if entry is None: + return 0 + return entry.IsPacked + def lookup_field(self, struct_ty: llvmlite.LLVMType | t.CPtr, field_name: str) -> GenTypes.FieldEntry | t.CPtr: """按结构体类型和字段名查找字段信息 diff --git a/App/lib/core/Gen/TranslatorGenMixin.vp b/App/lib/core/Gen/TranslatorGenMixin.vp index c0ccc04..72c275b 100644 --- a/App/lib/core/Gen/TranslatorGenMixin.vp +++ b/App/lib/core/Gen/TranslatorGenMixin.vp @@ -245,6 +245,16 @@ class TranslatorGenMixin: return None elts_count: t.CSizeT = len(elts) + # 元素数超过声明长度 → fail-fast(此前在下方循环中按声明长度截断、静默丢弃 + # 多余元素:apic._trampoline_bin 声明 [128 x i8] 却给出 138 个字节 → 末尾 + # mov rax,[0x7F28]; jmp rax 被丢弃,AP trampoline 失效)。 + if t.CSizeT(arr_count) < elts_count: + self.Gen.TypeGenErr.fatal_error( + list_node, + f"数组初始化元素数 {elts_count} 超过数组声明长度 {arr_count},不允许静默截断", + "OverflowError") + return None + # 非整数元素类型(struct/指针等聚合):不存在 "%s %lld" 文本展开。 # 仅当列表全零(元素缺失按零填充)时返回整体 "zeroinitializer"—— # 对任意聚合类型合法(devfs.directories: t.CArray[devfs_directory, N] @@ -363,6 +373,16 @@ class TranslatorGenMixin: # 0(128 字节 PS/2 扫描码表全 0 → 键盘输入失效根因)。 if ec is not None and (ec.const_kind == ast.CONST_INT or ec.const_kind == ast.CONST_CHAR): elem_val = ec.int_val + # CONST_STR 单字符(双引号如 "'" / '"'):parser 把双引号 + # 一律判为 CONST_STR(见 ast/parser.vp 字符串常量判定), + # 此前只认 CONST_INT/CONST_CHAR → 双引号单字符元素被编成 0 + # (keyboard.vp scancode_set1[40]='\'' 、scancode_set1_shift[40] + # ='"' 丢失根因;A2 的修复只覆盖了单引号字符)。 + # strlen == 1 时取首字符码;多字符字符串无法表达为整型元素 + # → 保持 0(由下方按声明长度补零)。 + elif ec is not None and ec.const_kind == ast.CONST_STR: + if ec.str_val is not None and string.strlen(ec.str_val) == 1: + elem_val = t.CInt64T(ec.str_val[0]) elif ek == ast.ASTKind.UnaryOp: # 负数: UnaryOp(USub, Constant) elem_val = self.Gen.AssignGen.extract_cdefine_int_value(elem_node) @@ -659,6 +679,14 @@ class TranslatorGenMixin: elif val_kind2 == ast.ASTKind.List: init_list_node = (ast.List | t.CPtr)(asgn.value) init_kind = 2 + elif val_kind2 == ast.ASTKind.Attribute: + # 模块级 re-export 别名(如 fat32_core.vp `_read32 = types._read32`、 + # fat32_dir.vp/fat32_file.vp 的同型 shim):RHS 是函数/实体引用, + # 无值语义可落入 LLVM 全局。此前未识别 → var_ty 默认 i32 → + # 生成假符号 `global i32 zeroinitializer`(被引用即调用地址 0)。 + # 与 __all__ 同类:别名/元数据实体不产出 LLVM 全局(详见 L693)。 + # 真正的函数别名机制(可调用 + 可 re-export)属独立特性,待后续实现。 + return 0 if var_name is None: return 0 diff --git a/_commit_msg.tmp b/_commit_msg.tmp deleted file mode 100644 index f16400b..0000000 --- a/_commit_msg.tmp +++ /dev/null @@ -1,15 +0,0 @@ -fix(tpv-call): 裸名调用同模块优先,修复跨模块同名 stub 抢占致 _advance 误绑 - -根因:LoadDepVpiIntoModule 在 forward_declare_functions 之前把依赖模块 -(lexer)函数以裸名注册进本文件 _funcs(槽位在前),find_func_in_table -与 find_func_in_module 后缀扫描均先命中跨模块 stub declare → parser.vp -内部 163 处 _advance(ps) 全部绑成 lexer._advance,并以 Parser→Lexer** -bitcast 传参(运行期游标永不推进,AstTest 无限 SyntaxError 至 pool 耗尽)。 - -修复:find_func_in_table / find_func_in_module 增加 owner_sha1(当前模块) -前缀优先遍,仅接受恰为 "{sha1}.{name}" 的本模块函数(declare/define 均可, -前向 declare 未激活时同样命中);translate_call 裸名分支传 trans.ModuleSha1。 -本模块无同名定义(纯 from-import/外部 stub)时回落原语义,不改变 CExport/ -方法拒绝/装饰器分支行为。 - -附带同批入库:list 内置方法内联分派与裸名模块表匹配等本会话修复。