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:
@@ -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) {
|
||||
|
||||
@@ -949,6 +949,7 @@ pub fn monomorphizePackFn(
|
||||
const name_id = self.module.types.internString(owned_name);
|
||||
_ = self.builder.beginFunction(name_id, params.items, ret_ty);
|
||||
self.builder.currentFunc().has_implicit_ctx = wants_ctx;
|
||||
self.builder.currentFunc().is_pure = (fd.abi == .pure);
|
||||
|
||||
const entry_name = self.module.types.internString("entry");
|
||||
const entry = self.builder.appendBlock(entry_name, &.{});
|
||||
@@ -1038,7 +1039,13 @@ pub fn monomorphizePackFn(
|
||||
defer self.setCurrentSourceFile(saved_source);
|
||||
if (fd.body.source_file) |src| self.setCurrentSourceFile(src);
|
||||
|
||||
if (ret_ty != .void) {
|
||||
if (self.builder.currentFunc().is_pure) {
|
||||
// `abi(.pure)`: asm-only body that rets itself — no sx value return.
|
||||
// Lower 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();
|
||||
} else if (ret_ty != .void) {
|
||||
const body_val = self.lowerBlockValue(fd.body);
|
||||
if (!self.currentBlockHasTerminator()) {
|
||||
if (body_val) |val| {
|
||||
|
||||
Reference in New Issue
Block a user