[fpc-devel] Overloading problem in generic class.

Bart bartjunk64 at gmail.com
Sun Sep 18 11:37:23 CEST 2022


Hi,

The following program will compile for Windows 32 and 64 bit.
It fails to compile for Linix 64 bit (and if I understand correctly,
also for MacOS 64 bit).

=== begin code ===
program test;
{$mode objfpc}
{$H+}


{$ifdef FPC_HAS_TYPE_EXTENDED}
function SameValue(const A, B: Extended): Boolean;inline; overload;
begin
  writeln('SameValue Extended');
  Result := A=B;
end;
{$endif}

{$ifdef FPC_HAS_TYPE_DOUBLE}
function SameValue(const A, B: Double): Boolean;inline; overload;
begin
  writeln('SameValue Double');
  Result := A=B;
end;
{$endif}

function SameValue(const A, B: Single): Boolean;inline; overload;
begin
  writeln('SameValue Single');
  Result := A=B;
end;

type

  generic TBase<T> = class
  private
    const _Def = 1;
  public
    FValue: T;
    function IsStored: Boolean;
  end;

function TBase.IsStored: Boolean;
begin
  Result := SameValue(FValue, T(_Def));  // << this is line 40
end;

type
  TDouble = specialize TBase<Double>;

var
  D: TDouble;
const
  ADef = 1.0;

begin
  {$ifdef WINDOWS}
  write('Windows ');
  {$endif}
  {$ifdef darwin}
  write('MacOS ');
  {$endif}
  {$ifdef linux}
  write('Linux ');
  {$endif}
  {$ifdef CPU32}
  writeln('32-bit');
  {$ENDIF}
  {$ifdef CPU64}
  writeln('64-bit');
  {$ENDIF}
  {$ifdef FPC_HAS_TYPE_EXTENDED}
  writeln('FPC_HAS_TYPE_EXTENDED');
  {$ELSE}
  writeln('NOT FPC_HAS_TYPE_EXTENDED');
  {$endif}

  {$ifdef FPC_HAS_TYPE_DOUBLE}
  writeln('FPC_HAS_TYPE_DOUBLE');
  {$ELSE}
  writeln('NOT FPC_HAS_TYPE_DOUBLE');
  {$endif}



  write('Literal 1.0  : ');
  SameValue(1.0,ADef);
  write('Literal 4E38 : '); //cannot be a single
  SameValue(4E38,ADef);
  {$ifdef FPC_HAS_TYPE_EXTENDED}
  write('Literal 2E308: '); //cannot be a Double
  SameValue(2E308,ADef);
  {$endif}

  write('TDouble      : ');
  D := TDouble.Create;
  D.FValue := 1.0;
  D.IsStored;
  D.Free;
end.
=== end code ===

Linux 64-bit
Compile Project, Target: test: Exit code 1, Errors: 1, Hints: 3
test.lpr(40,13) Error: Can't determine which overloaded function to call
test.lpr(22,10) Hint: Found declaration: SameValue(const Single;const
Single):Boolean;
test.lpr(15,10) Hint: Found declaration: SameValue(const Double;const
Double):Boolean;
test.lpr(7,10) Hint: Found declaration: SameValue(const Extended;const
Extended):Boolean;

If I remove the typecast then it compiles OK on all platforms.

(fpc 3.2.2 of fpc main seem to do the same)

I simply do not understand where the difference between
Windows/Non-Windows comes from.

Some background:
We had a crash in the Lazarus IDE when setting MaxValue (declared as
Double) to a value > MaxSingle: Floating point overflow.
(See https://gitlab.com/freepascal.org/lazarus/lazarus/-/issues/39792)
The backtrace suggest that this happens in the function
MaxValueStored: this simply does:
function TCustomFloatSpinEdit.MaxValueStored: Boolean;
begin
  Result := not SameValue(FMaxValue, DefMaxValue);
end;
DefMaxValue is declared as a private constant:
  private const
    DefMaxValue = 0;

The crash goes away if we do either of two things:
- in the call to SameValue typecast DefMaxValue to Double
- declare DefMaxValue as Double(0)

So far, so good.
But we also have a component TFloatSpinEditEx which is a generic
implementation of similar kind.
This component uses the same method for the MaxValueStored and thus
also crashed in the IDE.
So, I tried the same solution there: typecast DefMaxValue as
T(DefMaxValue) in the call to SameValue and then it turned out this
wouldn't compile on MacOS and Linux 64 bit.
-- 
Bart


More information about the fpc-devel mailing list