Search code examples
arrayspointersdelphidereferencepointer-arithmetic

Delphi: double indexing a pointer-of-array leads to “Array type required” error


A pointer of arrays is indexed once to get the array, then indexed again to get the element. This C-style trick should work with {$POINTERMATH ON}, but it definitely doesn't:

{$POINTERMATH ON}
...
type
  TYMMQWords = Array[0 .. 3] of UInt64;
  PYMMQWords = ^TYMMQWords; 

var 
  currentFlag: Integer; 
  temp: UInt64; 
  arrayFlags: PYMMQWords;

begin
  temp := arrayFlags[currentFlag][0];
end;

Let's take it step by step:

  • arrayFlags[currentFlag] is obviously a 4-element array of QWords. That's how pointer arithmetic works, and moreover, there is even no ambiguity here, this expression would simply give an error without {$POINTERMATH ON}.
  • In turn, arrayFlags[currentFlag][0], that is, (arrayFlags[currentFlag])[0], being an element of a QWord array, should denote a QWord element. No ambiguity, as well.

However, Delphi gives a compiler error here:

Array type required

Where am I wrong?


Solution

  • This looks like a compiler bug. The compiler is simply not interpreting this code correctly when POINTERMATH is used with a pointer to an array.

    Here is another example that shows the problem is even worse:

    {$POINTERMATH ON}
    ...
    type
      TYMMQWords = Array[0 .. 3] of UInt64;
      PYMMQWords = ^TYMMQWords; 
    
    var 
      arr: array[0..3] of TYMMQWords; 
      currentFlag: Integer; 
      temp: TYMMQWords; 
      arrayFlags: PYMMQWords;
    
    begin
      arrayFlags := @arr[0];
      currentFlag := 3;
      temp := arrayFlags[currentFlag];   // ERROR
      temp := (arrayFlags+currentFlag)^; // OK
    end;
    

    The compiler error is completely wrong:

    E2010 Incompatible types: 'TYMMQWords' and 'UInt64'

    Neither temp nor arrayFlags[currentFlag] are a UInt64. arrayFlags is a pointer to a TYMMQWords, and so logically arrayFlags[currentFlag] should yield (a reference to) a TYMMQWords instance. But the compiler seems to think that indexing this pointer yields an element of the array rather than the array itself.

    So, the Array type required error makes more sense when taken in this context. In arrayFlags[currentFlag][0], the compiler is clearly trying to apply the [0] to a UInt64, not to a TYMMQWords, hence the Array type required error.

    I have opened a bug ticket with Embarcadero:

    RSS-2077: PointerMath is broken for array types