PChar → string implicit conversion missing in call args (and assignment helper)
- Type: bug (parser/overload resolution + RTL helper wiring)
- Status: backlog (Track A)
- Owner: — (Track A —
compiler/**) - Opened: 2026-06-24
- Found-by: [[feature-synapse-compile-check]] — Synapse's
SynaFpccallsdynlibs.LoadLibrary(ModuleName)withModuleName: PCharagainst astring-param routine; FPC auto-converts, PXX rejects.
Symptom
FPC implicitly converts PChar to string/AnsiString when passing an
argument or assigning. PXX does not:
function f(const s: string): Integer; begin Result := Length(s); end;
var pc: PChar;
begin pc := 'abc'; writeln(f(pc)); end.
→ Mismatch in MatchProcCall: name = f, nArgs = 1 (overload resolution does not
consider PChar assignable to a string parameter).
Plain assignment is half-wired — it tries to convert but the helper is not found in a minimal program:
var s: string; pc: PChar;
begin pc := 'abc'; s := pc; end.
→ compiler error: PCharToString helper not found
So there are two faces of the same gap:
- Argument passing / overload match (
MatchProcCall): PChar is not treated as convertible to a string param, so the call does not match at all. - Assignment: the conversion path exists (emits a
PCharToStringhelper call) but the helper is not always resolvable.
Why platonic (not a lib workaround)
PXX currently compiles Synapse only because lib/rtl/dynlibs.pas adds an extra
PChar overload of LoadLibrary/GetProcedureAddress to dodge gap #1. That
is a workaround, not idiomatic — FPC's dynlibs does not need a separate PChar
overload because the language converts the argument. Once this lands, remove
those PChar overloads from lib/rtl/dynlibs.pas (string overload only) and
re-verify the synafpc probe still compiles.
Fix sketch
- In overload/assignability checking, make
PChar(andPAnsiChar) assignable tostring/AnsiStringparameters and l-values, inserting the samePCharToStringconversion the assignment path already emits. - Ensure the
PCharToStringhelper is reachable from any compile that needs it (auto-loaded like the other System string helpers), so the assignment form stops failing with "helper not found" in standalone programs. - Keep the reverse (
string→PChar) behaviour unchanged.
Done when
f(pc)(PChar arg into aconst stringparam) ands := pcboth compile and run correctly in a standalone program (no extrauses).- The PChar overloads are removed from
lib/rtl/dynlibs.pasand Synapse'ssynafpcstill gets pastdynlibs([[feature-synapse-compile-check]]). - Regression test under
make testcovering both arg-passing and assignment.
Resolution (2026-06-25, Track A)
Done. (1) Overload match: MatchCallDelphiProcAddr retries a failed match treating
each PChar arg as AnsiString; on success wraps every PChar arg whose matched param
is a string in PCharToString. Only fires after a normal match fails (never
overrides a stricter overload). (2) Helper availability: a PChar/PAnsiChar token
in scope pulls the builtin unit (gated by not NoDefaultRtl so the compiler's own
self-build is untouched), fixing the standalone s := pc "helper not found".
(3) lib/rtl/dynlibs.pas PChar overloads removed — LoadLibrary/GetProcedureAddress
take const string, PChar callers (Synapse SynaFpc) bind via the conversion;
verified LoadLibrary(pc) compiles + loads.
Scope: the reverse pc := 'literal' (string->PChar, stores the inline length-
prefix addr) is a SEPARATE gap, left unchanged per "keep string->PChar unchanged".
Tests: test/test_pchar_to_string.pas. Self-host byte-identical; make test + cross green.