Files
ww/test/wcc/data/fnptr_pp_derefless_reject/case.ww
Hojun-Cho 3d79735964 check: reject a deref-less multi-level **fn call, not silently miscompile (#14)
wwstage exprtype's N_CALL fn-value arm peeled ALL pointer levels before the
TY_FN gate, so a deref-less `pf(21)` where pf:**fn type-checked and lowered --
then segfaulted at runtime (a silent miscompile). cstage peels exactly one
level and loud-rejects (the C6a discipline, check.c:1947).

Align wwstage DOWN: peel one level (loop -> if); a remaining non-TY_FN callee
hits a loud "calling non-function" reject mirroring cstage's message. Both
stages now reject the exotic deref-less `**fn`/`***fn` shape; the legitimate
`(*pf)(21)` and one-level deref-less `f(21)` (f:*fn) still compile + run.
Multi-level autoderef is a separate deferred FEATURE, not a miscompile to lower
(rule 7/10 -- align the richer stage down to the leaner, no value ships).

ww-only change (cstage is the correct oracle); a reject emits no asm, so the
byte-id baselines and LANGBYTEID floor are unchanged.

Pins: cfail test/wcc/data/fnptr_pp_derefless_reject (both stages reject,
reddens-on-revert -- the silent miscompile resurfaces if the fix is reverted) +
test/lang/fnptr_derefless_call_test (positive guard (*pf)(21)==42 and one-level
f(21), value-asserted + byte-id, so the fix does not over-reject the legitimate
one-level autoderef).
2026-06-29 15:49:01 +09:00

22 lines
1.1 KiB
Plaintext

//ww:error "calling non-function"
// #14: a deref-less call through a pointer-to-pointer-to-fn (`pf(21)` where
// pf: **fn) is a hard reject in BOTH stages. The #181-cgen path lowers an
// indirect call by using the callee VALUE as the target, so it autoderefs
// exactly ONE pointer level — correct for a single `*fn`, but for a `**fn`
// the value is only the *address of* the fn-ptr, so a deref-less call ships
// a CALL through that address and segfaults. cstage rejected at one-level
// peel (cmd/wcc/check.c:1947); wwstage was the SILENT-miscompile side until
// it was aligned DOWN to the same one-level peel (selfhost/cmd/wcc/check.ww,
// task #14). Multi-level fn-ptr autoderef is a deferred FEATURE (#181); the
// legal one-explicit-deref `(*pf)(21)` stays accepted (test/lang/
// fnptr_derefless_call_test.ww derefless_pp_one_explicit_deref). REVERT
// MANIFESTATION: revert the wwstage peel loop->if and this case COMPILES
// again under w6c_ww (the runww ERROR arm runs both stages).
package main;
fn add1(x: i32) i32 = { return x + 21; };
export fn main() i32 = {
let f: *fn(x: i32) i32 = &add1;
let pf: **fn(x: i32) i32 = &f;
return pf(21);
};