From e859e4748bf9e69df020bb73bb563a736a67f8e4 Mon Sep 17 00:00:00 2001 From: TetzkatLipHoka Date: Sat, 11 Jul 2026 15:50:25 +0200 Subject: [PATCH] Fix FPC compilation of uPSRuntime Free Pascal 3.2.2 could not compile uPSRuntime.pas: - Inc()/Dec() on a Variant is a Delphi extension; FPC rejects it ('Operator is not overloaded'). Use := Variant +/- 1 instead, which is semantically identical and compiles on both. - ResultAsRegister was recently added to the interface section, but its implementation sits inside the {$else} region of empty_methods_handler. FPC on cpu64/arm/powerpc defines empty_methods_handler, so the whole region - including the implementation - disappeared and the unit failed with 'Forward declaration not solved'. Move the implementation in front of the region; it is plain Pascal with no dependency on the handlers. Repro: fpc 3.2.2 x86_64-linux fails on master with 4 errors + 1 fatal; with this change all uPS* core units compile and a script compile/run smoke test passes on Linux. No change for Delphi (verified DCC32/DCC64). Co-Authored-By: Claude Fable 5 --- Source/uPSRuntime.pas | 102 ++++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 49 deletions(-) diff --git a/Source/uPSRuntime.pas b/Source/uPSRuntime.pas index d22c6182..0212cdb3 100644 --- a/Source/uPSRuntime.pas +++ b/Source/uPSRuntime.pas @@ -9159,7 +9159,8 @@ function TPSExec.RunScript: Boolean; bts64: dec(tbts64(vd.P^)); btU64: dec(tbtu64(vd.P^)); {$ENDIF} - btVariant: dec(Variant(vd.P^)); + // Inc/Dec on a Variant is Delphi-only; +/- 1 works on FPC too + btVariant: Variant(vd.P^) := Variant(vd.P^) - 1; else begin CMD_Err(ErTypeMismatch); @@ -9192,7 +9193,8 @@ function TPSExec.RunScript: Boolean; bts64: Inc(tbts64(vd.P^)); btU64: Inc(tbtu64(vd.P^)); {$ENDIF} - btVariant: Inc(Variant(vd.P^)); + // Inc/Dec on a Variant is Delphi-only; +/- 1 works on FPC too + btVariant: Variant(vd.P^) := Variant(vd.P^) + 1; else begin CMD_Err(ErTypeMismatch); @@ -12473,6 +12475,55 @@ function ParamAsVariable(const Modifier: tbtchar; aType: TPSTypeRec): Boolean; Result := (Modifier = '%') or (Modifier = '!') or AlwaysAsVariable(aType); end; +{ implementation must stay outside the empty_methods_handler region below: + the interface declares it unconditionally } +function ResultAsRegister(b: TPSTypeRec): Boolean; +begin + case b.BaseType of + btSingle, + btDouble, + btExtended, + btCurrency, + btU8, + bts8, + bts16, + btu16, + bts32, + btu32, +{$IFDEF PS_FPCSTRINGWORKAROUND} + btString, +{$ENDIF} +{$IFNDEF PS_NOINT64} + bts64, + btU64, +{$ENDIF} + btPChar, +{$IFNDEF PS_NOWIDESTRING} + btWideChar, +{$ENDIF} + btChar, + btclass, + btEnum: Result := true; +{$IFDEF DELPHI} + { The Delphi x64 ABI returns a record of 1, 2, or 4 bytes in RAX, and + the x86 ABI a record of 1 or 2 bytes in AL/AX (see System.Rtti's + UseResultPointer). Records of these sizes never contain a managed + field, so no managed check is needed. A record of pointer size is + also returned in RAX/EAX, but only when it contains no managed + field. Static arrays follow the same rule: UseResultPointer treats + tkArray like tkRecord. } + btRecord, btStaticArray: Result := (b.RealSize in [1, 2{$IFDEF CPU64}, 4{$ENDIF}]) or + ((b.RealSize = PointerSize) and not IsManagedType(b)); +{$ENDIF} + btSet: Result := b.RealSize <= PointerSize; +{$IFNDEF DELPHI} + btStaticArray: Result := b.RealSize <= PointerSize; +{$ENDIF} + else + Result := false; + end; +end; + {$ifdef fpc} {$if defined(cpupowerpc) or defined(cpuarm) or defined(cpu64)} {$define empty_methods_handler} @@ -12617,53 +12668,6 @@ procedure MyAllMethodsHandler; {$ENDIF} {$endif CPU64} -function ResultAsRegister(b: TPSTypeRec): Boolean; -begin - case b.BaseType of - btSingle, - btDouble, - btExtended, - btCurrency, - btU8, - bts8, - bts16, - btu16, - bts32, - btu32, -{$IFDEF PS_FPCSTRINGWORKAROUND} - btString, -{$ENDIF} -{$IFNDEF PS_NOINT64} - bts64, - btU64, -{$ENDIF} - btPChar, -{$IFNDEF PS_NOWIDESTRING} - btWideChar, -{$ENDIF} - btChar, - btclass, - btEnum: Result := true; -{$IFDEF DELPHI} - { The Delphi x64 ABI returns a record of 1, 2, or 4 bytes in RAX, and - the x86 ABI a record of 1 or 2 bytes in AL/AX (see System.Rtti's - UseResultPointer). Records of these sizes never contain a managed - field, so no managed check is needed. A record of pointer size is - also returned in RAX/EAX, but only when it contains no managed - field. Static arrays follow the same rule: UseResultPointer treats - tkArray like tkRecord. } - btRecord, btStaticArray: Result := (b.RealSize in [1, 2{$IFDEF CPU64}, 4{$ENDIF}]) or - ((b.RealSize = PointerSize) and not IsManagedType(b)); -{$ENDIF} - btSet: Result := b.RealSize <= PointerSize; -{$IFNDEF DELPHI} - btStaticArray: Result := b.RealSize <= PointerSize; -{$ENDIF} - else - Result := false; - end; -end; - function SupportsRegister(b: TPSTypeRec): Boolean; begin case b.BaseType of