ERR/E4.1 (slice 1): log + is_comptime + process.exit/assert (+ noreturn codegen)
Stdlib slice of Phase E4, plus the noreturn codegen fix that enables it. noreturn codegen (the enabling bug): E1.4c made `noreturn` type-system-only; this is its first backend consumer and it crashed LLVM verification. Fixed: - lower.zig: a `-> noreturn` body lowers as statements ending in `unreachable` (ensureTerminator emits unreachable; the two body-lowering sites no longer treat the last expr as a `ret`). - emit_llvm.zig: a `void`/`noreturn` call result stays unnamed (direct + foreign call sites) — LLVM rejects a named void value. - finishCatchHandler: a `noreturn` value-carrying catch body (which is not an IR terminator) closes the handler with `unreachable` instead of feeding a bad value into the merge phi. Shared by lowerCatch + lowerCatchOverChain. is_comptime(): new nullary `.is_comptime` IR op (inst/print/interp/emit_llvm) — interp evaluates true, emit_llvm emits constant false, so `if is_comptime()` dead-codes out of compiled binaries. Recognized by name in tryLowerReflectionCall + inferExprType (no std.sx decl, which would emit a spurious `declare @is_comptime` into every module). library/modules/log.sx: warn/info/debug/err — interpolate like print, write `LEVEL: <msg>` to stderr. (`error` is reserved → the level is `log.err`.) process.exit(code) -> noreturn + assert(cond, msg) in process.sx. `exit` is POSIX `_exit(2)` (immediate, no cleanup; sx print is unbuffered so nothing is lost), bound to "_exit" which also avoids a link-level clash with the sx `exit` function's own name. examples 248 (exit 0), 249 (exit 42), 250 (exit 1). #caller_location, the comptime-exit diagnostic flush, and trace.print_interpreter_frames deferred to E4.1b.
This commit is contained in:
@@ -1658,6 +1658,11 @@ pub const LLVMEmitter = struct {
|
||||
const llvm_val = c.LLVMConstInt(self.cached_i1, @intFromBool(val), 0);
|
||||
self.mapRef(llvm_val);
|
||||
},
|
||||
.is_comptime => {
|
||||
// Compiled code is never the comptime interpreter → constant
|
||||
// `false`. A `if is_comptime() { … }` branch becomes dead.
|
||||
self.mapRef(c.LLVMConstInt(self.cached_i1, 0, 0));
|
||||
},
|
||||
.const_string => |str_id| {
|
||||
const str = self.ir_mod.types.getString(str_id);
|
||||
const llvm_val = self.emitStringConstant(str);
|
||||
@@ -2343,7 +2348,10 @@ pub const LLVMEmitter = struct {
|
||||
args[j] = self.coerceArg(args[j], param_types[j]);
|
||||
}
|
||||
}
|
||||
const call_label: [*:0]const u8 = if (instruction.ty == .void or callee_uses_sret) "" else "call";
|
||||
// A `void`/`noreturn` call has no value, so it must stay
|
||||
// unnamed (LLVM rejects a named void result).
|
||||
const call_is_void_like = instruction.ty == .void or instruction.ty == .noreturn;
|
||||
const call_label: [*:0]const u8 = if (call_is_void_like or callee_uses_sret) "" else "call";
|
||||
var result = c.LLVMBuildCall2(self.builder, fn_ty, callee, args.ptr, arg_count, call_label);
|
||||
if (callee_uses_sret) {
|
||||
// Mirror the function-decl `sret(<T>)` attribute on the call site so the
|
||||
@@ -2354,7 +2362,7 @@ pub const LLVMEmitter = struct {
|
||||
c.LLVMAddCallSiteAttribute(result, param1_idx, sret_attr);
|
||||
// Load the actual struct value the callee wrote into the slot.
|
||||
result = c.LLVMBuildLoad2(self.builder, callee_raw_ret, sret_slot, "sret.load");
|
||||
} else if (instruction.ty != .void and callee_func.is_extern) {
|
||||
} else if (!call_is_void_like and callee_func.is_extern) {
|
||||
// Coerce ABI return value (e.g. i64 / [2 x i64]) back to IR struct type if needed
|
||||
const expected_ty = self.toLLVMType(instruction.ty);
|
||||
result = self.coerceArg(result, expected_ty);
|
||||
@@ -2455,11 +2463,12 @@ pub const LLVMEmitter = struct {
|
||||
}
|
||||
}
|
||||
const fn_ty = c.LLVMFunctionType(ret_ty, param_tys.ptr, arg_count, 0);
|
||||
var result = c.LLVMBuildCall2(self.builder, fn_ty, callee, args.ptr, arg_count, if (instruction.ty == .void) "" else "icall");
|
||||
const icall_void_like = instruction.ty == .void or instruction.ty == .noreturn;
|
||||
var result = c.LLVMBuildCall2(self.builder, fn_ty, callee, args.ptr, arg_count, if (icall_void_like) "" else "icall");
|
||||
|
||||
// Coerce call result to instruction's expected type
|
||||
const expected_ty = self.toLLVMType(instruction.ty);
|
||||
if (instruction.ty != .void and c.LLVMTypeOf(result) != expected_ty) {
|
||||
if (!icall_void_like and c.LLVMTypeOf(result) != expected_ty) {
|
||||
result = self.coerceArg(result, expected_ty);
|
||||
}
|
||||
self.mapRef(result);
|
||||
|
||||
Reference in New Issue
Block a user