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.)
I think you are mixing up range checking and type conversions.
FPC, and Delphi, always insert necessary implicit type conversions, regardless of the state of range checking. They are fundamental part of the language. Without them, most code would not compile at all.
If you enable range checking, then whenever an implicit ordinal type conversion is inserted whereby the target type cannot hold every valid value of the source type, the compiler will insert extra code that checks at run time whether this conversion is in fact valid. However, it will not change the behaviour of the implicit type conversion itself, nor will it insert extra type conversions.
Regarding Delphi giving errors even when range checking is not enabled, while FPC only prints warnings: when this was implemented, the then-current version of Delphi (Delphi 7) did not print anything at all when compiling that program, even when range checking was enabled. We tried to both keep compatibility with Delphi code (i.e., compile the code), and give feedback to the programmer about the issue (print a warning when range checking is disabled, print an error when it is enabled). Delphi's behaviour obviously has changed in the mean time, and maybe we should now also always give an error instead (although you can bet that would
also result in complaints and bug reports).
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.
[/quote]
It is a basic property of typed languages: if you use an entity of type A to perform an operation that expects an entity of type B, a compiler will always insert a type conversion. After that type conversion (which may simply reinterpret an existing bit pattern, e.g. when converting an integer to another integer type of the same size, or transform it in a more complex way, e.g. when converting an ansichar into a unicodestring), the result will be seen as an entity of this new type rather than of the original type.
See e.g.
https://en.wikibooks.org/wiki/Computer_Programming/Type_conversion for more information about the concept of type conversions.
If you apply what you are saying then the compiler should not even accept a signed type as an index for such an array.
It should, because type conversions between different integer types are defined in the language. It is possible for signed types to contain values that are also valid for unsigned types (any value that is 0 or positive). If it contains an invalid value, then the result is undefined, except if you enable range checking (in which case a range check error/exception will be thrown).
Even with range checking enabled, the compiler cannot simply decide to change the data type(s) the programmer declared.
The programmer has declared two different data types:
* the type of the indexing variable
* the type of the array's range type
When using the indexing variable to index the array, the indexing variable gets converted to the indexing type of the array. That is simply how type conversions work. Also in Delphi. It is even that way in C/C++. This particular scenario with array indexing is, however, irrelevant in C/C++ because there array indexing is simply an alias for pointer arithmetic (unlike in Pascal).
In the end, the issue is not whether implicit converting from signed to unsigned types should be possible. If it weren't, you would not be able to assign a longint to a byte or cardinal variable without a warning/error or explicit typecast (if you want a language that forbids this, have a look at e.g. Ada, but it takes quite a bit of getting used to this rigidity if you come from Pascal).
The issue is about what the index/range type of an array[0..0] should be. If it would be signed rather than unsigned, then your code would work the same as under Delphi. On the other hand, the efficiency of some code that
is type correct would be lowered (unnecessary sign extensions), and as mentioned before it would require of the compiler's code to be audited as well.
However, regardless of the above, your code will always be invalid according to any Pascal standard, because you are accessing an array using an invalid index.