Default and inline handling conflict
Summary
Default and inline can lead to unreliable code generation
System Information
- Operating system: Any, but resulting in linking error on AIX OS only!
- Processor architecture: Any
- Compiler version: trunk
- Device:
Steps to reproduce
Copy the tree files below:
muller@cfarm14:~/pas/check$ cat ufpsockets.pp
unit ufpsockets;
{$mode ObjFPC}{$H+}
{$TypedAddress on}
{$modeswitch advancedrecords}
{$COPERATORS ON}
interface
uses
{$IfDEF WINDOWS}WinSock2, {$ENDIF}
{$IFDEF unix}BaseUnix, termio, {$EndIf}
ctypes, classes,
sysutils, sockets, nullable, tuples;
type
TAddressType = (atIN4, atIN6, atUnixSock);
TNetworkAddress = record
Address: String;
AddressType: TAddressType;
end;
function isIPv4Address(const Address: String): Boolean; inline;
function isIPv6Address(const Address: String): Boolean; inline;
function NetAddr(const Address: String): TNetworkAddress;inline;
function DefAddr : TNetworkAddress;
implementation
function isIPv4Address(const Address:String):Boolean;
var
dummy:sockets.in_addr;
begin
Result := TryStrToHostAddr(Address, dummy);
end;
function isIPv6Address(const Address:String):Boolean;
var
dummy:in6_addr;
begin
Result := TryStrToHostAddr6(Address, dummy);
end;
{$ifndef SHOW_FIX}
function DefAddr : TNetworkAddress;
begin
DefAddr:=Default(TNetworkAddress);
end;
{$endif}
function NetAddr(const Address: String): TNetworkAddress;
begin
Result := Default(TNetworkAddress);
if isIPv4Address(Address) then
Result.AddressType := atIN4
else if isIPv6Address(Address) then
Result.AddressType := atIN6
else // Filenames can be pretty much anything
Result.AddressType := atUnixSock;
Result.Address := Address;
end;
{$ifdef SHOW_FIX}
function DefAddr : TNetworkAddress;
begin
DefAddr:=Default(TNetworkAddress);
end;
{$endif}
end.
muller@cfarm14:~/pas/check$ cat ussockets.pp
{$MODE objfpc}{$H+}
{$COPERATORS ON}
{$inline on}
unit ussockets;
interface
uses
{$ifdef windows}
winsock2, windows,
{$endif}
SysUtils, Classes, ctypes, sockets, ufpsockets, tuples;
operator:=(const AStr:String):TNetworkAddress;
var
DefaultAddress : TNetworkAddress;
LocalHostAddress : TNetworkAddress;
implementation
operator:=(const AStr:String):TNetworkAddress;
begin
Result := NetAddr(AStr);
end;
begin
DefaultAddress:=Default(TNetworkAddress);
LocalHostAddress:='127.0.0.1';
end.
muller@cfarm14:~/pas/check$ cat tsockets.pp
uses
ussockets;
begin
Writeln('LocalHost address: ',LocalHostAddress.Address);
end.
And compile for AIX target:
muller@cfarm14:~/pas/check$ ppcppc64 -Taix -gl -B -altr tsockets.pp -XR/home/muller/sys-root/powerpc64-aix
Free Pascal Compiler version 3.3.1-18415-g045cd97d73 [2025/08/30] for powerpc64
Copyright (c) 1993-2025 by Florian Klaempfl and others
Target OS: AIX for PowerPC64
Compiling tsockets.pp
Compiling ussockets.pp
Compiling ufpsockets.pp
Assembling ufpsockets
Assembling ussockets
Assembling program
Linking tsockets
/home/muller/bin/powerpc64-aix-ld: ./ussockets.o:ussockets.pp:(.pr+0x1e): undefined reference to `TC_.UFPSOCKETS_..__zero_.UFPSOCKETS_.._TNETWORKADDRESS'
/home/muller/bin/powerpc64-aix-ld: ./ussockets.o:ussockets.pp:(.tc+0x0): undefined reference to `TC_.UFPSOCKETS_..__zero_.UFPSOCKETS_.._TNETWORKADDRESS'
An error occurred while linking
tsockets.pp(5,32) Error: Error while linking
tsockets.pp(5,32) Fatal: There were 1 errors compiling module, stopping
Fatal: Compilation aborted
Example Project
See above.
What is the current bug behavior?
Local constant TC.*zero.*TNETWORKADDRESS is reused in other unit,
but considered as local in first unit because the first use of Default function
is in a non-inlined function DefAddr.
If you reverse the order of the two functions, the compilation is successful:
muller@cfarm14:~/pas/check$ ppcppc64 -Taix -gl -B -altr tsockets.pp -XR/home/muller/sys-root/powerpc64-aix -dSHOW_FIX
Free Pascal Compiler version 3.3.1-18415-g045cd97d73 [2025/08/30] for powerpc64
Copyright (c) 1993-2025 by Florian Klaempfl and others
Target OS: AIX for PowerPC64
Compiling tsockets.pp
Compiling ussockets.pp
Compiling ufpsockets.pp
Assembling ufpsockets
Assembling ussockets
Assembling program
Linking tsockets
111 lines compiled, 0.4 sec
What is the expected (correct) behavior?
The compiler needs to be fixed to always consider this constant to be global if it can appear in any code that can be inlined.