198 Commits
Author SHA1 Message Date
TermiNexus 8461a3da47 fix(viperc): typedef 强转补充 stdint/win32base 解析兜底 2026-10-19 19:16:46 +08:00
TermiNexus 08fe5a7b6b fix(viperc): 支持多级模块路径的 typedef 强转(win32.win32base.LPCWSTR) 2026-10-19 19:16:00 +08:00
TermiNexus 82a735c367 refactor(viperc): 完全删除 T1 | T2 类型组合,语法糖改用标记下标 2026-10-18 13:39:38 +08:00
TermiNexus 42b094a575 refactor(viperc): 退役 t/c 模块标记,内建类型改由编译器直接识别 2026-10-18 12:56:57 +08:00
TermiNexus 3242560d02 支持 tls 关键字,全面准备清退 t, c 2026-10-17 23:40:06 +08:00
TermiNexus 15952d3852 fix(asm): 内联汇编/LLVMIR 文本缓冲扩容并将所有超限改为 fail-fast
ASM_TEXT_BUF_SIZE 2048→8192(内核 _do_switch 模板已 2245 字节),c.LLVMIR 模板 512→4096。_asm_append_cstr 不再静默截断:装不下时报 TypeError 并给出已用/待写/容量字节数(此前截断会把模板切成半条 mov,最终以 llc invalid operand 的面目出现)。操作数超过 16、clobber 超过 32、符号改写缓冲溢出同样 fail-fast;约束串/参数串/extractvalue 行缓冲改为按实际操作数与类型文本长度动态分配。
2026-10-17 17:41:11 +08:00
TermiNexus 19feb40e8c fix(call): 实参个数与被调方不符时前端 fail-fast - 不再漏到 LLVM verifier(含 EH 参数扣除与可变参数放行) 2026-10-16 19:26:22 +08:00
TermiNexus d8648176e9 feat(asm): op=/clobber= 支持裸枚举名(CLOBBER_MEMORY) - 等价 ASM_DESCR.XXX 2026-10-16 15:26:17 +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 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 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 ea54d5685d feat(gen): virtual(HasVTable)类豁免「无 def => struct」规则,必须合成 __before_init__/__init__ 且必发 vtable;非泛型构造路径按符号存在性判定调用 2026-10-13 21:29:24 +08:00
TermiNexus 97c0a1c6fd fix(gen): 取消「宽整型 -> bool(i1)」的隐式真值归一化,改为 fail-fast(仅保留编译期常量豁免) 2026-10-13 16:07:43 +08:00
TermiNexus d206abf3e1 chore: 全仓同步 w32→win32 模块改名与 range(int(...)) 显式收窄适配 2026-10-12 20:59:11 +08:00
TermiNexus 3c0d3d13b5 fix(narrow): 清理注解式整数窄化(Converter/TypeGenCType/CallGenLeafKit/ClassGenEnum)
CDefine 查询返回 int64 处按下游用法定型:回传给 int 的用显式 int(...),流入 int64 目标的加宽为 int64;sizet 数组元素赋给 int 的用 int(...)
2026-10-11 09:51:08 +08:00
TermiNexus 77f4a25055 fix(narrow): CallGenFd 的 fd_can 改用 int(len(...)) 消除 64->32 隐式窄化 2026-10-11 09:38:24 +08:00
TermiNexus 948e1855a6 fix(gen): 跨模块 vpi 查询只在加载成功时记"已加载"备忘(修漏检回归)
A2 引入的 lookup_ret_kind_via_vpi 会在 life_of_expr(判右值生命期,可能在极早的翻译阶段)
里触发对方模块 vpi 的按需加载,但它沿用 _vpi_escape_packed 的旧写法:**无论加载成功与否**
都把该模块记入 _vpi_escape_module_loaded 备忘。于是当那个时刻 vpi 还没生成/打不开时,
该模块被毒化成"已加载",之后所有共用这条备忘的跨模块查询(逃逸摘要 esc=、willFree wf=)
都跳过真正的加载 → 缓存恒空 → 判据静默失效。

现场:EscapeXmodTest(跨模块 esc)与 NewLifetimeWillFreeTest(跨模块 wf)双双漏检,
即"应拒绝却通过"。同模块用例不受影响,故更隐蔽。

修法:两处加载点都改为 _ensure_vpi_ret_annot_loaded 返回非 0(= 真加载/已缓存)才
_vpi_escape_mark_module;失败直接返回 0,留给后续查询重试。
- lookup_ret_kind_via_vpi(新代码,回归根源)
- _vpi_escape_packed(既有同款隐患,一并修)。
2026-10-10 11:25:43 +08:00
TermiNexus 6da8e2e095 feat(gen): 落地 @life(ret(...)) 返回值生命期契约(A2)
- GenApi:新增 compute_life_anno / _RetKindFromTag 与 RET_KIND_* 编码,
  提供 get_ret_kind / get_ret_kind_method / lookup_ret_kind_via_vpi;
  _WillFreeMergeTag 不再拦截 ret(改由 compute_life_anno 收集校验)。
- StructGenMixin:EscDirTable 由 3 槽扩到 4 槽(新增 ret_kind 列),
  compute_escape_summary 把契约落在 box[5] 并登记。
- Stub:.vpi 行尾新增 escr=<ret_kind>(Converter 写、VpiReader 读 _g_vpi_esd_r)。
- AssignGenMixin.life_of_expr(Call):@life(ret(...)) 声明优先于任何推断;
  frame/heap/static/borrows=none 直接映射,borrows=x 取对应实参生命期,
  方法调用按接收者静态类型解析类名。
- StmtGenCifMixin:同批移除定义端 return <本帧地址> 的 fail-fast,
  返回值去向改由调用点按被调者契约判定。
2026-10-09 22:58:33 +08:00
TermiNexus 4907e64714 feat(lifetime): _g_new_life 透传——new stack/slife 的构造也算 FRAME(参与构造器同命裁剪)
新增模块级 _g_new_life 与 _g_new_storage 同步维护(set/restore 支持嵌套 ctor),口径与 life_of_expr 的
New 分支一致:stack(含 stack slife)/slife → LIFE_FRAME;heap·memgr + 缺省/hlife → LIFE_HEAP;-1 = 未知。
_translate_struct_ctor 两份副本的 recv_life_ct 改为:裸 T() → FRAME;有 new → 取 _g_new_life。
于是 new stack S(&l) / new heap slife S(&l) 不再误报,new heap hlife S(&l) 仍报。
2026-10-09 22:43:43 +08:00
TermiNexus 953c829e9f feat(lifetime): 构造器路径填 recv_life——裸 T() 构造(入口块 alloca)算 FRAME
_translate_struct_ctor 两份副本都算 recv_life_ct:_g_new_storage == None(无 new 描述符提供存储)→
裸 T() 的存储是入口块 alloca → LIFE_FRAME(参与构造器同命裁剪);非空(存储来自 new …)→ -1 不裁剪。
两处 __init__ 调用点(:171 / :675)均传入。覆盖 CtorHolder(&l) / BoxCtor(&l) 这类裸构造误报。
2026-10-09 22:40:30 +08:00
TermiNexus 357a8bba05 feat(lifetime): 构造器路径同命裁剪的透传管道(recv_life,默认 -1 = 现状不变)
_call_method_on_ptr 新增 recv_life: int = -1(被构造对象的生命期,由调用方 CallGenCtor 算出);
构造器分支在指令最终裁决之后,若 recv_life ∈ {FRAME, VALUE} 则复用 _FrameArgsEscapeClearsMethod
(recv_node=None,接收者已由 recv_life 判定)清"写进形参对象字段"那类位。
下一轮只需在 3 个 __init__ 调用点(CallGenCtor:171/665、ExprGenConst:257)填 recv_life;未填 = 完全现状。
2026-10-09 22:36:09 +08:00
TermiNexus bf5ecd7668 fix(lifetime): 方法路径补上"同命裁剪"(此前缺失)—— h.set_q(l) 不该报
现场:h: S* = new heap slife S()(生命期本就是 FRAME:作用域出口释放)+ l 是栈数组;
h.set_q(l) 却报"escaping method parameter"。根因:同命裁剪只做在模块级函数路径,方法路径一直没接
(此前已明确告知"还差一半")。

新增 CallGenMixin._FrameArgsEscapeClearsMethod:位 0 = 接收者(self)、位 (i+1) = 用户第 i 个实参;
某位可清 ⇔ 该位对应实参是 FRAME/VALUE 且其余全部实参(含接收者)也在本帧。
CallGenCall 方法路径在 refine 之后、指令最终裁决之前套用;硬位仍用 get_param_escapes_hard_method 排除。
构造器路径暂未接(__init__ 的 self 是"正在构造的对象",此处拿不到接收者 AST 变量)。
2026-10-09 22:30:35 +08:00
TermiNexus 71730d920c chore(dbg): 删除 NLL 临时诊断(§13 已在 EscapeTest 上验证通过)
实测:var=h confined=1,g(l,h) 不再报错;报错前移到真正的泄漏点 `if 1==0 or a == 1: return l`(where=a return value)。
2026-10-09 21:59:48 +08:00
TermiNexus e82e2ac768 chore(dbg): 加 NLL 判定链临时诊断([NLL-DBG]),定位后删除 2026-10-09 21:05:31 +08:00
TermiNexus d0ffb094c2 feat(lifetime): §13 NLL——默认生命期的 new heap 证明帧内封闭时降级为帧对象
StructGenMixin: 新增 NllFrameConfined 及遍历器(_NllStmts/_NllExprUnsafe/_NllMentions/_NllInSet/_NllAdd/_NllCalleeEscMask)+
has_param_escapes(区分"有记录=权威不逃逸"与"无记录=判不定");别名集只增不减故单遍即可,if/while/for 全走、
不进嵌套 def/class;认不出的语句"不提及别名才放行";取址/实参位逃逸/return/长命目标一律按外泄拒绝。

CallGenCtor._new_is_nll_demotable:只降级"堆且未显式指定生命期"的 new;AssignGenMixin.propagate_life
判据成立则 life=FRAME(于是调用点同命裁剪放过 g(l,h)),_slife_note_assign 接 target_name、判据成立按托管堆
对象登记 → 复用 slife 的作用域出口释放(手动 free/del 也会被既有检查挡住)。

三条函数体翻译入口记录 NllCurFunc(谓词要遍历当前函数体),与 traceback 推帧同一处。

注:谓词按 §13.2 保守优先,判不定一律维持 HEAP;本提交未编译验证。
2026-10-09 20:49:21 +08:00
TermiNexus 79299ec47d feat(lifetime): 声明式指令契约落 .vpi(esce=/escn=),跨模块调用点也能最终裁决
写侧 Converter:读 compute_escape_summary 落在 box[3]/box[4] 的契约掩码,随函数头行尾写 esce=<强制逃逸位> / escn=<强制不逃逸位>;
只有指令(既无 esc/ret 也无 wf)时也补一个 "# esc=0 ret=0" 注释段——读侧是"见 # 才解析"。

读侧 VpiReader:_cache_vpi_esc_clears_text 同一次行扫描里顺带收 esce=/escn= 进 _g_vpi_esd_*(与 escg 同键 sha1[.Cls].func);
新增 _lookup_vpi_escape_dir(.., noescape);CallGenBase.lookup_escape_dir_via_vpi 包装。

调用点:模块级函数 / 方法 / 构造器三条路径在本文件指令表为空(= 跨模块)时改查对方 .vpi,
仍放在所有推断/回退之后最后套用:esc_mask = (esc_mask | esce) & ~escn。
2026-10-09 20:40:30 +08:00
TermiNexus 2bd37e80e3 feat(lifetime): 方法/构造器调用点也接 @life(escape/noescape) 最终裁决
StructGenMixin: 新增 _DirForceOf / _DirForceMethod(查 "Class.method" 并沿 MRO 回退)与
get_param_escape_force_method / get_param_noescape_force_method;GenApi 加同名委托。

CallGenCall: 构造器分支(esc_mask_ci)与方法分支(esc_mask_mc)在跨模块回退、常量特化之后
最后套用一次 esc_mask = (esc_mask | escape_force) & ~noescape_force,与模块级函数那条口径一致。
2026-10-09 20:34:34 +08:00
TermiNexus fc7c5d5560 feat(lifetime): @life(escape/noescape) 升为调用点最终裁决(契约不可被推断推翻)
StructGenMixin: 新增 EscDirTable(3 槽/项:[名哈希, 强制逃逸位, 强制不逃逸位]),
_RegisterFuncEscapeSummary 把 compute_escape_summary 落在 box[3]/box[4] 的指令掩码单独落表
(与 EscTable 的"推断结果"分开);新增 _DirLookup / get_param_escape_force / get_param_noescape_force。
compute_escape_summary 的指令输出缓冲由 g+68 改为 box[3](同一内存,语义显式化)。

CallGenMixin: 在常量特化、同命裁剪、跨模块回退**全部做完之后**,最后套用一次指令:
esc_mask = (esc_mask | escape_force) & ~noescape_force。这样 escape(...) 不会被"死分支/同命"折掉,
noescape(...) 也不会被任何上游路径重新解释成"逃逸"。
2026-10-09 20:30:03 +08:00
TermiNexus 8881dea2e2 fix(diag): 泄漏点采集改为"确认报错后才跑",并保存/恢复扫描期状态
原先在调用点的位循环里就调 escape_leak_line:该函数会重扫被调者函数体并改 EscConstEnv/EscIndCount,
而循环里可能紧接着发现"该实参其实不是帧生命期"从而不报错 —— 等于白白跑一遍扫描、还留下脏状态。
现在改成把 (被调者, 形参位) 传给检查方,过了 LIFE_FRAME 判定才采集;escape_leak_line 内部
把 EscConstEnv/EscIndCount/EscLeakWant 先存后还。
2026-10-09 19:50:31 +08:00
TermiNexus 2353dca8ec feat(diag): 逃逸类 LifetimeError 追加 File lifetime leak 帧,标出泄漏点
StructGenMixin: 新增 escape_leak_line——错误路径重扫被调者函数体,取指定形参的**首个逃逸点**行号;
_NoteLeak 在三处置位来源采集(字段/全局写、return 形参、传递闭包调用),新增 EscLeakWant/EscLeakLine。

Diag: DiagEntry 增加 LeakFileName/LeakLine + set_leak + emit_leak_frame(标签 File lifetime leak),
打印顺序 = 调用链 → 错误点 → 泄漏点 → 类别: 消息。

TypeGenErr.fatal_error / GenApi.fail_if_stack_addr_escape 增加 leak_file/leak_line 透传;
CallGenMixin 调用点按失败实参位取行号。**仅同模块**:跨模块 EscFuncTable 无 AST → 返回 0,不打该帧。
2026-10-09 19:32:54 +08:00
TermiNexus c98730f717 refactor(diag): 精简 LifetimeError 报错词,去掉冗长从句
逃逸主报文由三段长从句压缩为「frame-local + 悬垂 + 修法」两句:
  stack address escapes: `&x` is frame-local; using it at {where} hands out a dangling pointer
  once this frame returns. Copy the value, or allocate on the heap (`new heap hlife ...`).

同步缩短 where 短语(return value / escaping callee|method parameter / constructor parameter stored
into a field / longer-lived field-element / module-level global)

其余冗长报文一并精简:willFree 失效、slife 手动 free/del、async slife、stack+hlife 矛盾、三处容量上限、
@life 标签实参缺失

测试只断言关键字 LifetimeError,不受文案影响(Test/*.py 已确认)。
2026-10-09 19:22:04 +08:00
TermiNexus c791bd5e46 feat(new): new 支持标量/数组与前导 [N]T;类名解析不出时回落基本类型路径
- CallGenCtor._translate_new_primitive:认 Array 元素类型,返回值退化为首元素指针,零初始化按整体类型写
2026-10-09 18:45:01 +08:00
TermiNexus fc797da542 feat(lifetime): @life(escape/noescape) 多形参、硬逃逸位同命精化、归纳变量区间与跨模块常量特化
- GenApi:escape/noescape 标签支持多实参;新增 compute_escape_directives 与若干委托

- StructGenMixin:硬逃逸位(box[2])、常量与归纳变量区间折叠、_PackEscapeClear/compute_escape_clears

- Call 系:调用点同命裁剪(_FrameArgsEscapeClears)+ 跨模块 escg= 查询;写侧 Converter、读侧 VpiReader

- AssignGenMixin:裸 T()(无 new、无 __new__)判为帧生命期
2026-10-09 18:44:51 +08:00
TermiNexus 14a8dcb98b feat(gen): new 支持基本类型 + 跨过程常量特化重算逃逸摘要
- CallGenCtor._translate_new_primitive:
ew [stack|heap|memgr(x)] T(T 为标量)取存储 + 零初始化 → T*;stack 走入口块 alloca、heap 走 malloc、memgr 复用既有通道;标量带实参 fail-fast,不引入第二套标量构造语义

- StructGenMixin:新增 EscFuncTable / EscRefineScratch / EscConstEnv 与常量求值器 _EvalConstInt / _EvalConstCond;_ScanEscapes 的 if 分支按形参常量折叠只扫被走到的分支(死分支里的写不记为逃逸)

- 调用点(普通函数 + 方法,方法沿 MRO 回退)在逃逸检查前用常量实参重算摘要;跨模块拿不到函数体仍保守返回原掩码

- 折叠只会减少逃逸位,不引入新的误报
2026-10-09 14:55:28 +08:00
TermiNexus aeb396831a chore(dbg): 清除 CallGenMixin 残留的 call.enter 探针 2026-10-09 12:43:28 +08:00
TermiNexus 5f92abb7bc fix(gen): 补回 CallGenMixin 的 _FreedMark(修行尾时被 checkout 回滚)
TPC 报 MemberLookupFailFast: 属性 Freed 在 VarEntry 中找不到 —— 该文件的行尾修复用 git checkout 恢复过,把未提交的 _FreedMark 改动一并回滚了,残留 ent_wf.Freed = 1。
2026-10-09 12:03:23 +08:00
TermiNexus dd24dc670f fix(gen): P2 失效状态改存独立槽表,不再给 VarEntry 加字段
现象:任何工程编译都在函数形参注册刚结束处 access-violation(pc=0,逐字节可复现)。定位:逐层探针把崩点压到 FuncGenDef 的 pre_scan 段,而该段对 Check(body 仅 if+return)应为空操作,唯一变量是 VarEntry 这个热结构被加了 Freed 字段。修法:撤销 VarEntry.Freed,改用 VarGenMixin 的独立失效槽表 _g_freed_slots(键 = 变量槽 alloca,整次翻译内唯一,故全局累积、无需按函数 reset/restore);_FreedMark/_FreedCheck/_FreedClearSlot 三个 API 替换字段读写,P2 语义不变。同时清除全部 TEMP 探针。
2026-10-09 11:51:11 +08:00
TermiNexus 20e3f3694f chore(dbg): 补语句级与调用级探针(stmt.kind / call.enter fn)
崩点已收窄到 Check 函数体内的翻译,这两个探针把范围压到具体语句与具体被调者。均为 TEMP,定位后移除。
2026-10-09 10:39:24 +08:00
TermiNexus 2b5ff215c7 fix(gen): 跨模块裸名 CExport/State 函数不再被误清,关键字实参不解析时 fail-fast
现象:stdlib.free(p = p) 生成 llvm.call @free()(零实参),mlir-opt 报 incorrect number of operands (0) for callee。根因:跨模块检查要求函数名前 16 字符等于模块 sha1,而 CExport/t.State 型函数(stdlib.free 等)本来就以裸名定义与声明,于是 found_func 被清成 None → 关键字实参路径整体跳过 → 位置实参循环一个也不翻译。修两处:1) 该检查对 is_cexport_func / _is_state_func_from_vpi 命中的函数放行;2) 带关键字实参却解析不出签名时 fail-fast,不再静默丢弃实参。
2026-10-08 22:38:28 +08:00
TermiNexus 8fb0e38f4c fix(gen): 泛型类构造只在真有 __init__ 时才调 __before_init__/__init__
无方法的泛型类(如 NewTest 的 Box[T])没有 __init__,ClassGenVTable 也就不会生成 __before_init__,但 _translate_generic_ctor_call 无条件发射这两个调用,导致链接期 undefined symbol(1cf2df6387df0bbf.Box[int].__before_init__ / .__init__)。改为与非泛型 _translate_struct_ctor 同判据:有 __init__ 才走 __before_init__ + __init__,否则按字段顺序逐字段 store。
2026-10-08 22:16:23 +08:00
TermiNexus b60ce06335 feat(gen): willFree 覆盖关键字实参、方法调用与取地址三条路径
关键字/混合实参:CallGenMixin._MarkWillFreeKwargs 按形参序(位置实参占前 can 个形参,其余按关键字名匹配)标记。方法调用:CallGenCall._translate_method_call 的 kwargs 与位置两条循环,实参链含 self 故用户第 ai 个实参对应 bit (ai+1);新增 GenApi/StructGenMixin.get_param_willfree_method(查 Class.method 并沿 MRO 回退)。取地址:ExprGenOps 的 AddrOf 分支对已失效变量 fail-fast。
2026-10-08 21:39:53 +08:00
TermiNexus 97313e9e55 feat(gen): P2 生命期标注 @life(willFree(...)) 驱动释放后使用与二次释放检查
标注面:@life(willFree(<形参名|0起序号>)),兼容叠加式 @willFree(...),可混用累加;序号按形参表下标、self/cls 计入。GenApi.compute_willfree_mask 解析标注并对非法标注 fail-fast。本文件表 StructGenMixin.WfTable + 跨模块 .vpi 行尾 wf=<mask>(Converter 写 / VpiReader 读 / CallGenBase 查)。调用点在实参全部翻译之后把对应实参变量槽置 VarEntry.Freed;其后的读取路径报 LifetimeError。重新赋值清除失效态。
2026-10-08 21:28:49 +08:00
TermiNexus 9ff5a3a03e fix(gen): 泛型类构造复用 new 描述符存储,并支持泛型下标 callee
- _translate_generic_ctor_call 之前一律 _alloca_at_entry:new memgr(pool) hlife list[int](...) 会忽略描述符给的内存、把对象构造到栈上、返回栈地址(静默悬垂)。改为与 _translate_struct_ctor 同款:tmp = _g_new_storage,为空才回落 alloca。

- _translate_new_expr 支持泛型下标 callee(Box[int]):新增 _specialize_new_generic_class 先特化模板拿具体类名,再走同一条取存储路径。
2026-10-08 21:04:41 +08:00
TermiNexus 70390858d8 feat(gen): 协程体里的 new heap slife fail-fast(释放点无法确定)
AsyncGenMixin 的状态机会把协程 body 拆成多个 state 块并多次转译,编译器无法确定 slife 的释放点;此前是静默漏释放。新增锚点 trans._coro_body_func(Translator 字段 + init 置 None),只在 body 翻译期间由 translate_async_function 设置并保存/恢复旧值;_translate_new_expr 以**函数对象同一性**(_coro_body_func == _cur_func)判定并 fatal_error(LifetimeError)。嵌套普通函数会换掉 _cur_func 故不误报;new stack 与 hlife 不受影响。
2026-10-08 20:42:09 +08:00
TermiNexus 78b2052445 feat(gen): 接线 M3 owned slife 的 RAII 出口释放(函数级 scope guard)
- 所有权影子标志(i8,登记时入口块置 0)+ free(select(影子!=0, load 槽, null)) 保护式释放:赋值在分支/循环里而未执行 → free(NULL);槽里写入外来指针或别名 → 清影子,绝不 free 外来指针;循环反复 new → 赋值前覆盖释放上一轮,不累积。

- 三条函数体转译路径(FuncGenDef 主路径 / FuncGenMixin 嵌套函数提升为 __closure_* / ClassGenVTable 方法体)各自抬升与弹回登记区间;修两处漏 reset 导致内层出口 free 外层对象再被外层 free 一次 = double free(Windows STATUS_HEAP_CORRUPTION)。出口按槽去重做兜底。

- free 由模块前言统一声明(Translator.vp,紧挨 malloc);释放点只查表 + fail-fast,绝不吐指向未声明符号的 llvm.call。

- 赋值处记账:new heap slife → 登记 + 覆盖释放 + 影子置 1;其它 RHS(new stack / hlife / 别名 / 外来指针 / None)→ 已登记则交还所有权。手动 free slife 对象 → LifetimeError。
2026-10-08 20:03:54 +08:00
TermiNexus 09b5bf5ac3 docs(gen): _translate_new_expr 注明缺省规则(stack 默认 slife)
缺省规则(§3.2 / D3):来源缺省 = heap;生命期缺省由来源决定——stack → slife(故 new stack T(...) 不写 slife 也等效),heap/memgr → hlife。生命期在 life_of_expr 按同一张表落地(LIFE_FRAME / LIFE_HEAP)。
2026-10-08 18:21:00 +08:00
TermiNexus 8a98051759 fix(gen): new 的分配尺寸常量改用 const_int64,修 mlir-opt 校验失败
ConstInt 的第 4 个参数是常量在 IR 里的文本(不是注释/名字),此前传 "newsize" 会打印成 llvm.mlir.constant(newsize : i64),mlir-opt 报 expected attribute value。已改用项目通用的 mlirlite.const_int64(pool, size_bytes)。
2026-10-08 18:18:03 +08:00
TermiNexus c77d38e923 fix(gen): new heap/memgr 的尺寸改用 ClassGenEnum._get_type_size,修结构体报 cannot determine the size
原先调用 TypeGenResolve.get_type_size_bytes,它只解析 typedef/标量,结构体一律返回 0,于是 new heap Point(3,4) 在语义期 fail-fast。

改用语言级 T.__sizeof__() 的同一实现 ClassGenEnum._get_type_size(struct_ty),保证 new 分配的尺寸与源码手写 __sizeof__() 完全一致(含对齐/填充)。
2026-10-08 18:07:28 +08:00