← board

A unit's private external hides a C header function of the same name

Repro (riscv32 ESP object; probably every target)

ch.h:

unsigned long largest(unsigned int caps);

cu.pas:

unit cu;
interface
function UnitLargest: LongWord;
implementation
function largest(caps: LongWord): NativeUInt; external;
function UnitLargest: LongWord;
begin
  Result := largest(4);
end;
end.

cp.pas:

program cp;
uses cu, ch;
function Get: LongWord; cdecl;
begin
  Result := largest(4) + UnitLargest;
end;
begin
end.
pascal26 --target=riscv32 --platform=esp --no-signals --emit-obj -I. -Fu. cp.pas cp.o
pascal26:5: error: undefined variable (largest)

With uses ch, cu; instead it compiles.

Expected

An implementation-section declaration is private to its unit, so it should not affect name lookup in units that use it. Even if it did leak, it names the same C symbol with a compatible signature, so it should not end up as "undefined variable".

Real-world hit

lib/rtl/scheduler.pas:628 (930d67d54a, TrySpawnSized) declares heap_caps_get_largest_free_block privately. museum_landkaart/async/src/lkapp.pas has uses platform, scheduler, ...; and then uses idf;, and calls heap_caps_get_largest_free_block from the header, which now fails. The app works around it by putting uses idf; first. (espsys.pas:47 has the same private declaration and would cause the same failure if an app uses espsys.)

Log