fix(ffi): replace silent .void arg-type fallback with loud .unresolved (issue 0074)
Four FFI call-arg lowering sites resolved an argument's IR type via `getRefIRType(arg_ref) orelse .void` — a silent fallback to the load-bearing real type `.void`. A failed lookup there is a codegen invariant violation, but `.void` is treated by downstream `toLLVMType` → `abiCoerceParamType` → `coerceArg` as a legitimate void-typed foreign argument, corrupting the call ABI with no diagnostic. Add one shared resolver `LLVMEmitter.argIRTypeOrFail` that returns the dedicated `.unresolved` sentinel on a failed lookup — never `.void`/`.s64` — so the failure cannot masquerade as a real type and trips `toLLVMType`'s existing hard `@panic` tripwire at the call site. Route all four sites through it: - src/ir/emit_llvm.zig JNI constructor (NewObject) arg loop - src/backend/llvm/ops.zig objc_msgSend arg loop - src/backend/llvm/ops.zig JNI non-virtual call arg loop - src/backend/llvm/ops.zig JNI Call<Type>Method arg loop Happy path is byte-identical (every real arg already has a resolved type); FFI examples stay green with zero snapshot churn. Regression test (fail-before/pass-after) in src/ir/emit_llvm.test.zig asserts an unresolvable FFI arg ref now yields `.unresolved`, not the old silent `.void`.
This commit is contained in:
@@ -514,7 +514,7 @@ pub const Ops = struct {
|
||||
// coercion applied so structs / strings decay the
|
||||
// same way they do for any C foreign call.
|
||||
for (msg.args, 0..) |arg_ref, i| {
|
||||
const raw_ty = self.e.getRefIRType(arg_ref) orelse .void;
|
||||
const raw_ty = self.e.argIRTypeOrFail(arg_ref);
|
||||
const raw_llvm = self.e.toLLVMType(raw_ty);
|
||||
const coerced_ty = self.e.abiCoerceParamType(raw_ty, raw_llvm);
|
||||
param_types[i + 2 + sret_off] = coerced_ty;
|
||||
@@ -728,7 +728,7 @@ pub const Ops = struct {
|
||||
call_args_nv[2] = cls;
|
||||
call_args_nv[3] = mid_val;
|
||||
for (msg.args, 0..) |arg_ref, i| {
|
||||
const raw_ty = self.e.getRefIRType(arg_ref) orelse .void;
|
||||
const raw_ty = self.e.argIRTypeOrFail(arg_ref);
|
||||
const raw_llvm = self.e.toLLVMType(raw_ty);
|
||||
const coerced_ty = self.e.abiCoerceParamType(raw_ty, raw_llvm);
|
||||
call_param_types_nv[i + 4] = coerced_ty;
|
||||
@@ -758,7 +758,7 @@ pub const Ops = struct {
|
||||
call_args[1] = target;
|
||||
call_args[2] = mid;
|
||||
for (msg.args, 0..) |arg_ref, i| {
|
||||
const raw_ty = self.e.getRefIRType(arg_ref) orelse .void;
|
||||
const raw_ty = self.e.argIRTypeOrFail(arg_ref);
|
||||
const raw_llvm = self.e.toLLVMType(raw_ty);
|
||||
const coerced_ty = self.e.abiCoerceParamType(raw_ty, raw_llvm);
|
||||
call_param_types[i + 3] = coerced_ty;
|
||||
|
||||
Reference in New Issue
Block a user