TermiNexus
|
508428bbc9
|
fix(viperc): 浮点常量按目标类型/声明宽度直接出 f32,不再先出 double
- 浮点字面量在 f32 目标(float(1.5) / x: float = 1.5 / f32 形参)下直接物化 f32 常量,
负号折叠(-c)同口径;去掉旧的「f64 常量 + fptrunc」
- CDefine 浮点条目记录宽度种类(1=f64 / 2=f32):define PI: float = ... 的使用处
直接出 f32 常量,与 f32 字面量混算不再被提升成 double(现场 33 处 cvtss2sd)
- 本模块注册 / pyi·vpi 跨模块重解析 / xmod 缓存三处都按注解裁决宽度,保持跨模块一致
|
2026-10-15 18:35:48 +08:00 |
|
TermiNexus
|
3a687db0bb
|
feat(viperc): 静态常量算式补上除法/整除/取模折叠(与运行期 sdiv/srem 同口径)
此前纯常量折叠只覆盖 + - * | & ^ << >>,Div/FloorDiv/Mod 一律落到运行期 sdiv/udiv/srem/urem。现按同一维护口径补上:以精确值折叠,再由既有逻辑按结果值自动提升位宽(不无故抬宽,避免把 A/1 这类算式整体抬成 i64)。语义与运行期一致:Div/FloorDiv → sdiv(向零截断)、Mod → srem(余数符号随被除数)——宿主侧 // 与 % 正是这两个语义,无须额外修正;无符号位型常量按规范恒为非负,与运行期 udiv/urem 取值一致。除零不交给宿主(会打挂编译器):先关掉折叠再 fail-fast,诊断文本与 AssignGenMixin 的常量求值器保持一致。
|
2026-10-14 22:28:43 +08:00 |
|
TermiNexus
|
38a277a914
|
feat(viperc): 纯常量折叠补上 / // %,与 + - * 同口径(精确值 + 按值自动提升位宽)
口径与 AssignGenMixin 的常量求值器逐字对齐:①除零先关折叠再 fail-fast(同一条诊断文案,避免交给宿主 Python 打挂编译器);②结果按精确值自动提升位宽,不无故抬宽;③负数语义待定 ⇒ 本轮只折叠两侧都非负的情形(此时 sdiv 与 udiv 结果相同、无歧义),含负操作数的算式不折叠,照旧走运行期 sdiv/udiv/srem/urem。
|
2026-10-14 22:27:55 +08:00 |
|
TermiNexus
|
dc4468593c
|
fix(viperc): CDefine 常量按位宽处理时不再把可容正值翻转成负数,修常量算式折错
现场:Gargantua _start 的 string.memset(fb, 0, GW * GH * 4)(GW=160, GH=90)应折叠为 57600,实际生成 movl \(= -34560)作为 memset 长度 → 从 0x457ca0 写 4GB → 越界写撞到映射区末尾 0x467000,用户态 #PF err=0x7(cr2 与反汇编逐字对上)。根因:define GW = 160 的位宽按值推断为 8(无符号可容),而 _cdefine_bits_value/_normalize_cdefine_bits 无条件 '(value<<56)>>56' 重解释为有符号 → 160 变 -96(=-96*90*4=-34560)。现只在两种解释都装不下时才截断;位型不变(const_int 本就按位宽截断),仅不再翻转可容正值的语义。
|
2026-10-14 22:20:52 +08:00 |
|
TermiNexus
|
a143c2de0c
|
fix(stubgen): 装饰器循环变量改名 ddi,避免与默认值处的注解声明 di 冲突
同一个函数里 di 先被 for 循环绑定为 int(i32),后面又用注解声明为 sizet(i64) 且右值是运行期 i64 值:存储类型 i32 收不下,编译器按 fail-fast 报'带注解重声明冲突'(此前 TPC 是静默丢掉 store,生成的 viperc.exe 在 list[AST*].get 越界读)。装饰器循环改用 ddi,di 保持为首次声明。
|
2026-10-14 21:13:03 +08:00 |
|
TermiNexus
|
7da9d7cb0d
|
fix(viperc): 位宽探测循环改为固定 64 次上界,修主编译器死循环
- 现象:Phase1 编译到 viperlib.vp 时卡死,栈顶停在 ExprGenOps.vp:1362(我新加的位宽探测 while)
- 原因:`while t != 0 { t = t >> 1 }`(t 为 int64)在生成代码里不收敛(疑似 i64 移位/比较被按窄宽度处理)→ 死循环;改为 `while i < 64 and t > 0` 的固定上界写法,两处(ExprGenOps 运行期常量折叠 / AssignGenMixin 静态求值)一起改
- 遗留待查:该 while 为何不收敛(i64 >> / != 0 的代码生成),属同类“最小宽度”问题面
|
2026-10-14 19:54:29 +08:00 |
|
TermiNexus
|
d09b79995d
|
fix(viperc): 运行期纯常量整型算式按精确值折叠并按值定宽,禁止最小宽度回绕
- 现场:`1024 * 1024 * 4` 在表达式侧按最小宽度(i16)运算,1024×1024 先回绕成 0 ⇒ 常量变 0(WINBUF_MAX_BYTES=0 ⇒ 窗口缓冲只剩几字节 ⇒ 内核 memcpy 240KB 越界读 → 三重故障)
- 在 translate_binop 取到操作数类型后加入纯常量折叠:+ - * | & ^ << >> 两侧都是编译期整型常量时按精确值求结果,并按“能精确容纳该值的最小合法宽度(下限取操作数较宽者)”定宽、向上取 8/16/32/64;只有装不下才加宽(与 61f23d9 的静态求值器同口径)
- 与 61f23d9 合起来:静态 define 求值与运行期常量算式都不再按最小宽度回绕
|
2026-10-14 19:39:11 +08:00 |
|
TermiNexus
|
61f23d99a1
|
fix(viperc): 静态常量求值对 + - * << 按结果值加宽,杜绝 define 算式静默回绕
- 现象:Gargantua 的 define V3_POOL_SIZE=8192 / V3_POOL_BYTES=V3_POOL_SIZE*24+512 在运行时变成 512(正好是表达式里的 +512),等价于 8192*24=196608 被按 16 位回绕成 0 → 池只剩 512B → 每像素 trace 立刻 OOM 刷屏
- 根因:extract_cdefine_int_value_bits 的 BinOp 位宽规则只“取较宽”,而 + - * << 会增长结果位宽 → define 物化时按 16 位截断
- 现在:操作数的声明宽度仍保持最小(不提升);基准取较宽者;若精确结果装不进基准宽度,则按结果值加宽(向上取 8/16/32/64)—— 静态计算不再回绕;基准未知(纯字面量算式)时保持“未知”,仍由物化端按值推断
- 顺带:未知 BinOp 算子恢复 fail-fast(重构后原落空分支若留着会静默返回 0)
|
2026-10-14 19:18:52 +08:00 |
|
TermiNexus
|
813b59e25f
|
fix(viperc): 修正 (expr).method() 接收者误入 get_attribute_ptr 导致的 strcmp(_,0x1) 崩溃
- 表达式接收者分支(L1236 设计上可收 BinOp/Subscript/Call)在接收者求值非指针时会调 get_attribute_ptr;该 API 只接受 Attribute,内部直接强转成 ast.Attribute 并读 .attr,对别的节点会命中偏移 9 的字段:BinOp 的 op(OpKind.Sub=1)、Name 的 ctx(ASTCtx.Store=1)等,于是把整数 1 当字符串传给 strcmp → ASan access-violation on 0x1
- 现在仅当接收者确为 ast.Attribute 时才走“取字段地址”,其余节点保持已翻译的接收者值(与旧实现的回退结果一致)
- 现场:Test/OopInheritTest/App/main.vp 的 (a3 * 2.0 - a4).cross(a5),接收者 BinOp 的 op=Sub=1
|
2026-10-14 17:57:01 +08:00 |
|
TermiNexus
|
ee3337f3c4
|
revert(viperc): 回退闭包变量取址的放行,仅保留“实参级报错定位”
- 回退 a060e1d 中 ExprGenOps 的闭包取址改动与 TypeGenErr 的临时打印移除:&_on_submit 仍按级数不符报 CastError(source level 2 -> target level 1),语义不变、不放行
- 保留 CallGenCall._call_method_on_ptr 的实参级 AST 节点透传:方法/构造实参转换失败时报错定位到具体实参表达式,并显示完整两帧(函数定义帧 + 错误点)
|
2026-10-14 17:40:53 +08:00 |
|
TermiNexus
|
a060e1d76e
|
fix(viperc): 闭包变量取址返回闭包指针,并让方法/构造实参转换报错定位到具体实参
- ExprGenOps 取址:嵌套 def 提升出的闭包变量在父函数里是 i8** 槽,&f 原来返回槽地址(二级),传给 callback: t.CPtr 会因级数不符报 CastError(source level 2 -> target level 1);现按闭包名表判定,返回其值 i8*(一级),与“函数名即地址(同 C)”一致
- CallGenCall._call_method_on_ptr:实参逐个转换原来统一传 node=None,失败时只能退回函数定义行(只剩一帧);现按 arg_nodes 带上每个实参自身的 AST 节点(slot 0 是 self),报错可定位到具体实参表达式并显示完整两帧
- TypeGenErr:移除定位用的 [TEMP-DIAG] 临时打印
|
2026-10-14 17:38:50 +08:00 |
|
TermiNexus
|
3c6041c97c
|
fix(viperc/diag): 把“当前实参位置”的记录点下沉到 translate_call_arg(覆盖所有调用路径)
TEMP-DIAG 实测:node=0 curarg=0 trace=1 top=11 —— 节点是合成的(无行号),但“当前实参
位置”压根没被记录,说明该构造器调用没走 CallGenLib 的参数循环,兜底只能退回栈帧(函数定义行)。
改为在**所有调用实参的公共入口** CallGenBase.translate_call_arg 顶部记录(它持有 arg_node),
并移除 CallGenLib 里的重复挂点。这样任何调用路径(含构造器)都能把报错定位到具体实参表达式。
|
2026-10-14 17:13:38 +08:00 |
|
TermiNexus
|
ca81c1185c
|
diag(viperc): 放宽报错位置兜底判据 + 临时打印定位决策输入(定位后删除)
兜底判据改为:只要实参位置有效,且节点行号“不深于”栈最内层帧行号(或栈为空),就用实参
位置 —— 覆盖 FunctionDef 节点被传下来的情形(其行号恰好等于函数定义行、并非真实表达式)。
另加一行 [TEMP-DIAG](node/curarg/trace/top/shown),用于一次看清兜底为何未触发;
定位完成后立即删除该行。
|
2026-10-14 17:08:59 +08:00 |
|
TermiNexus
|
40ea5d6513
|
fix(viperc/diag): 节点行号等于函数定义行时也用实参位置兜底(定位到具体表达式)
上一版只在 lineno==0 时用 CurArg 兜底;实测该报错的节点自带行号且恰好等于当前函数定义行
(节点其实是 FunctionDef 本身,构造器内联路径把它传了下来),于是兜底没触发,错误位置与
栈帧都在定义行、被去重合并,看起来只剩一帧。
现把“节点位置不可信”判据放宽为:lineno==0,**或** lineno 等于最内层栈帧的行号(即函数
定义行)→ 两条都优先用 CurArg,报错精确指向调用处的实参表达式(如 `&_on_submit`)。
|
2026-10-14 17:02:16 +08:00 |
|
TermiNexus
|
4f45b391ea
|
fix(viperc/diag): 保留函数定义帧,不覆盖栈帧位置(补齐“定义帧 + 出错语句帧”两帧)
上一版 B 把最内层栈帧的位置改写成“当前语句”,结果它与错误帧落在同一 file:line,
被去重合并 —— 输出只剩一帧,`_start` 那帧(函数定义)反而没了。
改为:栈帧只记录**被调函数的定义位置**(不随语句推进覆盖);“当前语句/具体表达式”
统一由错误帧给出(CurArg 兜底,见 TypeGenErr)。这样能得到完整两帧:
File "./Apps/HelloWorld/main.vp", line 11 export def _start() -> int: ← 定义帧
File "./Apps/HelloWorld/main.vp", line 36 ... &_on_submit) ← 出错语句帧
同时删除已无调用的 TypeGenBase.update_top_trace_position。
|
2026-10-14 16:51:51 +08:00 |
|
TermiNexus
|
d6b87da063
|
fix(viperc/attr): 不再要求 import c 才认 @__attribute__(否则函数属性被静默丢弃)
ast/parser.vp 的 _DesugarMagicAttribute 会把用户写的 `@__attribute__(...)` 脱糖成
`@c.Attribute(...)`,此处看到的 `c.` 前缀是编译器自己产生的(用户并未写 `@c.Attribute`)。
原先这里要求 is_module_imported(...,"c"),用户没写 `import c` 时整条装饰器被静默丢弃,
stackrealign / always_inline 等函数属性全部失效。现去掉该守卫,与 extract_func_section
(本就没有此守卫)保持一致。
|
2026-10-14 16:42:16 +08:00 |
|
TermiNexus
|
0f2675e794
|
fix(viperc/codegen): Win64 变参提升按实参符号性选择 zext/sext,避免无符号值高位被填脏
变参调用把 <64 位整数提升到 i64 时原先一律 sext:uint8 0x8E 会被填成
0xFFFFFFFFFFFFFF8E,va_arg(i64) 读到脏高位(即 Debugger/VKERNELERR.md 记录的 sext 家族)。
现按实参符号性选择:无符号走 zext、有符号仍走 sext,与
CallGenVa._check_and_promote_variadic_call 同口径(复用 ExprGenOps.should_zext_widen)。
|
2026-10-14 16:41:58 +08:00 |
|
TermiNexus
|
0678cc8c48
|
feat(viperc/diag): 报错定位到具体表达式 + 栈帧跟踪当前语句(方案 A+B)
A:报错节点是合成节点(lineno==0,如构造器内联出的参数赋值)时,优先用“正在翻译的实参
位置”兜底 → 报错精确指向调用处的表达式(如 `&_on_submit`),不再退回函数定义行。
- TypeGenBase 新增 CurArgFile/CurArgLine/CurArgCol 与 set_cur_arg()
- CallGenLib 翻译实参前调用 set_cur_arg(当前文件, arg_node 位置)
- TypeGenErr 兜底顺序改为:节点自身行号 → CurArg → 栈最内层帧
- 语句边界清空 CurArg,避免兜底串味到上一条语句的实参
B:栈帧跟踪“当前语句”位置(Python traceback 口径)
- TypeGenBase.update_top_trace_position():更新最内层帧的 lineno/col
- translate_stmt 每条语句推进时调用 → 报错时栈帧给出的是调用点所在语句,而非函数定义行
配合 A 即可得到“调用点 + 具体表达式”两帧。
|
2026-10-14 16:40:35 +08:00 |
|
TermiNexus
|
70c271d2a4
|
fix(viperc): &func 对函数指针变量应取其值(Ptr(Func) 一级),不再多一层地址
现场:Apps/HelloWorld 里 vpui.Button(..., &_on_submit) 报
CastError: pointer level differs (source level 2 -> target level 1);
source: level 2, pointee !llvm.ptr -> target: level 1, pointee i8
根因:嵌套函数名在符号表里是 Ptr(Func) 变量。ExprGenOps 的取址分支有一条
“变量本身就是那个对象”的规则(结构体指针变量要 load 一次、而非取变量地址),
但该 match 只覆盖了 Ptr(Ptr(Struct)),未覆盖 Ptr(Ptr(Func)) —— 于是 `&f` 落到末尾的
`return v_ao`,给出的是变量地址 Ptr(Ptr(Func))(二级),而不是函数地址 Ptr(Func)(一级)。
修改:在该 match 中补上 Ptr(Ptr(Func)) 分支,load 一次后返回 Ptr(Func),
与结构体指针变量同口径。
|
2026-10-14 16:37:37 +08:00 |
|
TermiNexus
|
9d02a3ac0b
|
improve(viperc/diag): 指针级数不符报错补印“级数 + pointee 类型”
LLVM 不透明指针下 source/target 两边的类型文本都是 !llvm.ptr,看不出差异,现场只剩
一个 “2 -> 1”。现改为同时打印:
source: level N, pointee <T> -> target: level M, pointee <U>
这样一眼能定位是哪个表达式/哪个形参触发的级数不符。
|
2026-10-14 16:01:09 +08:00 |
|
TermiNexus
|
6b180c8f59
|
fix(viperc/life): 进程入口豁免补上 _start(ViperOS 应用入口),消除栈逃逸误报
现象:Apps/HelloWorld/main.vp 报 LifetimeError(`master` frame-local,传给构造器参数会
悬垂)。而 `master = &root` 中 root 是 _start 的帧内 Tk,_start 是进程入口
(@__attribute__(section(".text.startup")),结尾 mainloop/process.exit),本帧返回即进程
结束 —— 与 main 同口径,确无逃逸。
_CurFuncIsEntryMain 此前只认 "main",现把 `_start` 一并视为进程入口。
|
2026-10-14 15:53:28 +08:00 |
|
TermiNexus
|
a23c1bda3e
|
fix(viperc/diag): 调用栈帧与错误点同位置时不再重复打印
现象:`_start` 定义行在 Traceback 里被打印两遍 —— 栈内最内层帧与随后的“错误点帧”
落在同一 file:line(错误的 AST 节点 lineno 为 0 时,错误点位置会回退到栈最内层帧,
于是与栈帧完全重合)。
Diag.emit 增加两条去重规则(DIAG_DIR_UP / DIAG_DIR_DOWN 两个方向都生效):
① 连续两个位置完全相同的栈帧只印一次;
② 与紧随其后的“错误点帧”(emit_current 打印的那一帧)位置相同的栈帧不再重复印。
|
2026-10-14 15:53:05 +08:00 |
|
TermiNexus
|
dc24970af2
|
fix(gen): 修 __before_init__ 字段默认值写入的参数次序(build_store 缺 builder/file 顺序颠倒),修编译期参数缺失报错
|
2026-10-13 21:46:20 +08:00 |
|
TermiNexus
|
ea54d5685d
|
feat(gen): virtual(HasVTable)类豁免「无 def => struct」规则,必须合成 __before_init__/__init__ 且必发 vtable;非泛型构造路径按符号存在性判定调用
|
2026-10-13 21:29:24 +08:00 |
|
TermiNexus
|
99a021ad67
|
fix(gen): 类合成默认构造——有方法但无显式 __init__ 的类合成空 __init__(补 undefined 符号);完全无 def 的类按 struct 处理,不合成 __init__/__before_init__
|
2026-10-13 20:59:41 +08:00 |
|
TermiNexus
|
12da1cbfc1
|
fix(gen): define 复用前置声明时按源码形参名对齐签名参数名,修签名与函数体两套参数名导致 MLIR「region entry argument already in use」
|
2026-10-13 20:33:06 +08:00 |
|
TermiNexus
|
bc1eeb6e38
|
feat(gen): REPL 会话变量的复合赋值下传槽类型作为 target_ty(复用 repl_slot_ty,缺失即 fail-fast),与二元/普通变量路径对齐
|
2026-10-13 20:04:34 +08:00 |
|
TermiNexus
|
c1e5a11962
|
feat(gen): 复合赋值统一二元运算口径(常量无损适配另一侧、不做整数提升、RHS 按左值类型翻译),修 u16 -= 1 误报窄化
|
2026-10-13 20:01:16 +08:00 |
|
TermiNexus
|
d2138678ef
|
feat(gen): 同型聚合值 -> 同型聚合指针 允许隐式值拷贝(调用者帧溢出临时槽后取址),修裸类形参接收聚合值实参报错
|
2026-10-13 18:33:49 +08:00 |
|
TermiNexus
|
1c3cdf3493
|
fix(stub): 消费模块补齐按值返回聚合的具名结构体完整体(_inject_method_declare 补 _ensure_full_value_types、_inject_class_struct_declare 补登完整定义),修 MLIR opaque 报错
|
2026-10-13 17:48:57 +08:00 |
|
TermiNexus
|
377c0db5d3
|
fix(gen): life_of_expr 的构造分支按目标类型判定——目标为同型聚合值时判 LIFE_VALUE(值拷贝),不再误判帧逃逸
|
2026-10-13 17:48:35 +08:00 |
|
TermiNexus
|
6cb1f525d9
|
feat(gen): 常量操作数隐式适配另一侧位宽(仅另一侧非常量时),修 u16 变量 + 字面量被抬到 i32 导致误报窄化
|
2026-10-13 17:01:53 +08:00 |
|
TermiNexus
|
a01e9280cc
|
fix(stub,phase1): 因取消整数提升,模块属性 CDefine 的窄乘法显式加宽为 sizet(修缓冲区尺寸回绕成 0/负值)
|
2026-10-13 16:34:39 +08:00 |
|
TermiNexus
|
14d8c05a2a
|
feat(gen): 二元运算取消 C 式整数提升(任何位宽不再默认提升到 i32),改为按 max(两侧)/目标位宽运算
|
2026-10-13 16:20:02 +08:00 |
|
TermiNexus
|
97c0a1c6fd
|
fix(gen): 取消「宽整型 -> bool(i1)」的隐式真值归一化,改为 fail-fast(仅保留编译期常量豁免)
|
2026-10-13 16:07:43 +08:00 |
|
TermiNexus
|
d7c5af9b80
|
fix(gen): callable[[]] 省略返回类型按 void 注册(作为值使用时报错,不再静默按 int)
|
2026-10-13 13:32:47 +08:00 |
|
TermiNexus
|
cb2dc4cb3a
|
feat(gen): 字节序 bswap 改为按目标端序判断(BigEndian/LittleEndian 都相对目标),原语改名 apply_byte_order_bswap
|
2026-10-13 13:29:03 +08:00 |
|
TermiNexus
|
444e87dd7d
|
fix(gen): callable[[]](省略返回类型)按默认 int(i32) 注册函数指针签名,修间接调用签名缺失 fail-fast
|
2026-10-13 13:26:51 +08:00 |
|
TermiNexus
|
d3997e0746
|
fix(gen): 函数指针变量别名(f2: rawptr = f)继承已注册的返回类型签名,修 rawptr 间接调用的签名缺失 fail-fast
|
2026-10-13 13:26:11 +08:00 |
|
TermiNexus
|
32599a08c1
|
fix(stub): .vpi 读取侧复刻字段标记判定(volatile/pointee-volatile/const/字节序),跨模块不再丢字段标记
|
2026-10-13 12:30:23 +08:00 |
|
TermiNexus
|
37c4b0da3b
|
feat(gen): 字节序 bswap 代码生成——字段/局部变量/数组元素读写处成对 llvm.bswap(仅 BigEndian 且 16/32/64 位整数)
|
2026-10-13 12:30:05 +08:00 |
|
TermiNexus
|
5d15d01e21
|
feat(gen): 支持 t.BigEndian / t.LittleEndian 字节序描述符(注解识别 X|marker 并把字节序登记到 FieldEntry.ByteOrder,暂不生成 bswap)
|
2026-10-13 12:17:02 +08:00 |
|
TermiNexus
|
3ca2165fd9
|
feat(gen): 指向同型聚合的指针→同型聚合值允许隐式值拷贝(裸类形参 T* ABI 的直接赋值仍按值拷贝)
|
2026-10-13 10:30:15 +08:00 |
|
TermiNexus
|
b859f8a136
|
fix(gen): CDefine 常量(含 mod.N 属性形态)拓宽方向单独判定——负值 sext、非负 zext,修 zlib 窗口尺寸被 sext 成负数与 Z_DEFAULT_COMPRESSION->255
|
2026-10-12 21:48:05 +08:00 |
|
TermiNexus
|
22475e0fda
|
fix(gen): 逃逸检查把模块级(根 scope)变量判为 LIFE_STATIC,修模块级数组 return 误判帧逃逸(pyzlib_error_msg)
|
2026-10-12 21:23:23 +08:00 |
|
TermiNexus
|
c0ff5c9d96
|
fix(gen): 复合赋值取消「右值有符号 vs 左值无符号」拦截,与二元 x = x op y 口径一致(修 sizet += int 误报)
|
2026-10-12 21:16:50 +08:00 |
|
TermiNexus
|
c9562a6e04
|
feat(gen): 一元 +/-/~ 按符号性提升——u 类不提升(保持原位宽),i 类提升到 i32 防负数陷阱
|
2026-10-12 21:10:06 +08:00 |
|
TermiNexus
|
d206abf3e1
|
chore: 全仓同步 w32→win32 模块改名与 range(int(...)) 显式收窄适配
|
2026-10-12 20:59:11 +08:00 |
|
TermiNexus
|
ea2af739dd
|
feat(gen): range 边界与循环变量统一提升到至少 i32(取消 u8/u16 循环变量档),u64 边界保持 i64
|
2026-10-12 20:57:12 +08:00 |
|
TermiNexus
|
00bf7ebf38
|
fix(gen): 非负 define 常量按最小位宽的无符号位模式参与宽化/比较(修 range(50000) 迭代 0 次)
|
2026-10-12 20:52:52 +08:00 |
|