@JonasThe range checking argument you are putting forward, simply does not work and it is not even applicable. A range checking argument cannot be put forward to justify turning a signed type into an unsigned type. That is simply incorrect and, the short demo program in this post proves it conclusively.
When you index an array with any expression, this expression gets type-converted to the range type of the array. This is also the step at which range checking gets performed (if enabled). So what gets loaded in a 64bit registers is not RowIdx, but implicit_cast(RowIdx, array_range_type). And array_range_type cannot have negative values according to its declaration.
If FPC was doing range checking the way you describe then it would
_not_ compile the example program shown below. (cases 1 and 2.)
The code gets interpreted the same on both platforms by the compiler (index = unsigned). However, because on 32 bit platforms an address register is only 32 bit long, you don't notice a difference there.
That is not a valid argument. The index variable is a signed integer. The compiler cannot decide to turn it into an unsigned type because it's being used to access an array which can be indexed with an unsigned type. If you apply what you are saying then the compiler should not even accept a signed type as an index for such an array.
simply because compiler uses the type information it got from the program (and that is also the only information it can use).
You can't use an argument that the compiler "uses type information it got from the program" when the compiler is dropping the sign of a signed data type. The compiler has been told the indexing variable is a signed integer, it cannot simply turn that into an unsigned integer behind the programmer's back. That is incorrect.
Even with range checking enabled, the compiler cannot simply decide to change the data type(s) the programmer declared. It can give an error, a warning, a hint or whatever but, no compiler can simply choose to turn a signed type into an unsigned type.
here is a sample program which illustrates some of the problems FPC's incorrect sign extension handling/range checking causes:
{$APPTYPE CONSOLE}
{-----------------------------------------------------------------------------}
{ NOTE: this code tested with FPC v3.0.4 and Delphi 10 (Seattle) }
{-----------------------------------------------------------------------------}
program RangeChecks;
const
SPACE = ' ';
var
AnArray : array[0..0] of ansichar;
b : integer;
AnInt : integer; // 32bit integer
AnInt64 : int64; // 64bit integer
begin
AnArray[0] := SPACE; // no problem here
{$ifdef FPC}
// -------------------------------------------------------------------------
// case 1.
// Delphi emits an error for this expression (as it should)
// FPC emits a warning but, at least, generates CORRECT code.
AnArray[5] := SPACE; // Delphi won't compile this (which is correct)
// -------------------------------------------------------------------------
// case 2.
// same as above for this case
AnArray[-5] := SPACE; // nor this but, FPC does. At least, in this case
// it generates CORRECT code for it.
{$endif}
// if FPC did range checking the way it should be done, the above statements
// would NOT compile. A warning is not good enough.
//
// to FPC's credit, while it compiles those incorrect statements, the code
// it generates for them is correct. (the compiler did what the programmer
// told it to do.)
// ---------------------------------------------------------------------------
// case 3.
// Delphi emits neither a warning nor an error but, generates correct code.
// if/when runtime range checking is enabled then the problem will be
// reported.
// FPC neither emits a warning nor a hint and generates INCORRECT code.
// in this case, range checking should be done at runtime and, only if the
// programmer requested range checking.
b := 3;
AnInt := (b * 2) div 3;
AnArray[AnInt] := SPACE; // FPC generates INCORRECT code (no sign extension)
// effectively turning a signed int into an
// unsigned int. That is INCORRECT (64bit) and
// cannot be justified with a range-checking
// argument.
// Delphi generates correct code.
// ---------------------------------------------------------------------------
// case 4
// same as case 3 but using an int64 instead of an int32
AnInt64 := (b * 2) div 3; // for this expression FPC generates correct code
AnArray[AnInt64] := SPACE; // and doesn't complain about it.
// ---------------------------------------------------------------------------
// CONCLUSION:
// FPC compiles statements that it shouldn't compile (cases 1 and 2)
// FPC's incorrect handling of sign extension makes
//
// AnArray[AnInt] <> AnArray[AnInt64]
//
// there is no correct argument that can justify that behavior.
writeln('press enter/return to end this program');
readln;
end.
I sincerely hope this bug is corrected. The difference in results between 32bit and 64bit have nothing to do with platform in this case, it has everything to do with the fact that in 64bit, FPC decides to turn a signed type into an unsigned type.
FPC is the only compiler I've run into where the particular type of an integer makes a difference when indexing an array. For the same ordinal value (in this particular example, obviously limited to the range of an int8), AnArray[int8] should equal AnArray[int16] should equal AnArray[int32] should equal AnArray[int64] and, that has nothing to do with range checking, given the same ordinal value, the result should be the same.
Please, we the users, depend on you guys to fix these bugs. FPC should do sign extension like every other correct compiler does it. This FPC bug makes porting C/C++ and Delphi code more difficult, time consuming and riskier than it should be.