fibers B1.0a: close generic/pack is_pure gap (review)

Adversarial review of dd363ca found is_pure was set only at the two
declareFunction decl sites. Generic monomorphization (generic.zig) and
pack expansion (pack.zig) create the IR Function via a different path
and left is_pure false, so a generic abi(.pure) instance bypassed the
emit bail and silently shipped a framed body — it returned 42 but
leaked the prologue's stack adjustment (the exact SP-in != SP-out
corruption the lock exists to prevent).

Both paths now set is_pure and route .pure bodies through the asm-only
+ unreachable cap, mirroring the decl path. Locked by
examples/1801-concurrency-pure-generic-bail.sx (generic .pure reaches
the loud bail).

The review's other CRITICAL (a .pure lambda) is a false positive:
isLambda's return-type scan (parser.zig:3652) breaks on the abi
keyword, so a .pure lambda is unparseable and parseLambda's abi
handling is never reached. Latent isLambda/parseLambda inconsistency,
not a B1 concern.

Suite green (723/0).
This commit is contained in:
agra
2026-06-20 14:45:29 +03:00
parent dd363ca877
commit 40424df1b8
8 changed files with 65 additions and 6 deletions

View File

@@ -115,6 +115,7 @@ pub fn monomorphizeFunction(self: *Lowering, fd: *const ast.FnDecl, mangled_name
const func_id = self.builder.beginFunction(name_id, params.items, ret_ty);
_ = func_id;
self.builder.currentFunc().has_implicit_ctx = wants_ctx;
self.builder.currentFunc().is_pure = (fd.abi == .pure);
// Create entry block
const entry_name = self.module.types.internString("entry");
@@ -151,6 +152,13 @@ pub fn monomorphizeFunction(self: *Lowering, fd: *const ast.FnDecl, mangled_name
self.ensureTerminator(ret_ty);
}
self.builder.finalize();
} else if (self.builder.currentFunc().is_pure) {
// `abi(.pure)`: asm-only body that rets itself — no sx value return.
// Lower the statements + cap with `unreachable` (mirrors the decl path).
// emit_llvm bails on `is_pure` until B1.0b implements `naked` emission.
self.lowerBlock(fd.body);
if (!self.currentBlockHasTerminator()) self.builder.emitUnreachable();
self.builder.finalize();
} else {
// Lower the function body
if (ret_ty != .void) {