← board

bug: ParamStr/ArgStr result not usable inline (needs a string variable)

Resolution (2026-06-23)

Front-end only. Inline ParamStr(i) (the expression-form tkArgStr) now synthesizes a hidden FROZEN string temp, copies argv[i] into it via the existing 2-arg ArgStr path (EmitArgvToString — a frozen-buffer write, no managed release, so the temp needs no nil-init), and yields the temp via the AN_STR_FROM_CHAR (side-effect + read) pattern. So ParamStr(i) is usable directly in comparisons / arguments, not only as an assignment RHS. (The AN_STR_FROM_CHAR lowering now statement-marks its Left so the call-shaped side-effect is emitted; a store-shaped Left like String(c) is unaffected.) A frozen temp avoids the managed-temp-created-mid-parse nil-init crash landmine.

Also fixed the separate-observation segfault: EmitArgvToString / EmitArgvToStringManaged now bounds-check the index against argc ([initial_rsp]) and return '' (frozen) / nil (managed) for an out-of-range index, instead of dereferencing a NULL/past-end argv slot.

Verified byte-identical to FPC: ParamStr(1) = 'foo', Length(ParamStr(1)), no-args ParamStr(1) -> '' (was a segfault). Gate: make test (self-host byte-identical) + FPC oracle. Closes bug-paramstr-inline-argstr.

Symptom

Using ParamStr(i) directly in an expression fails at codegen:

program t;
begin
  if ParamStr(1) = chr(120) then writeln(1) else writeln(0);
end.

error: ArgStr expects a string variable in IR codegen.

Control — assigning to a string variable first compiles:

var s: string;
s := ParamStr(1);
if s = chr(120) then writeln(1) else writeln(0);

Expected

ParamStr(i) (→ ArgStr) should be usable as a normal string r-value in expressions, function arguments, comparisons — not only as the RHS of an assignment to a string variable. The codegen helper appears to require its result land in a named string variable.

Notes