C-style in-place assignments sometimes compute LHS twice

Original Reporter info from Mantis: runewalsh
  • Reporter name:

Description:

First half of the example gives not the result I expect. Namely, it behaves as if expression
a[F()] += 1
has been rewritten to
a[F()] := a[F()] + 1
instead of
temp_ptr := @a[F()];
temp_ptr^ += 1

Meanwhile, the second half that uses
F()^ += 1
works right the way I expect from in-place modification operators.

Steps to reproduce:

{$mode objfpc} {$h+} {$coperators on}

var
	a: array[0 .. 3] of uint32;
	whatToIncrementNext: SizeUint;

	procedure Reset;
	begin
		whatToIncrementNext := 0;
		FillChar(pUint32(a)^, length(a) * sizeof(a[0]), 0);
		writeln('Before: ', a[0], ' ', a[1], ' ', a[2], ' ', a[3], LineEnding);
	end;

	function NextIndex: SizeUint;
	begin
		result := whatToIncrementNext;
		writeln('Incrementing ', whatToIncrementNext, 'th element');
		whatToIncrementNext := (whatToIncrementNext + 1) mod length(a);
	end;

	function NextPtr: pUint32;
	begin
		result := @a[whatToIncrementNext];
		writeln('Incrementing ', whatToIncrementNext, 'th element');
		whatToIncrementNext := (whatToIncrementNext + 1) mod length(a);
	end;

var
	incr: uint32;

begin
	Reset;
	for incr in specialize TArray<uint32>.Create(1, 2, 4, 8) do
	begin
		writeln('a[NextIndex()] += ', incr, '...');
		a[NextIndex] += incr;
		writeln(a[0], ' ', a[1], ' ', a[2], ' ', a[3], LineEnding);
	end;

	Reset;
	for incr in specialize TArray<uint32>.Create(1, 2, 4, 8) do
	begin
		writeln('NextPtr()^ += ', incr, '...');
		NextPtr^ += incr;
		writeln(a[0], ' ', a[1], ' ', a[2], ' ', a[3], LineEnding);
	end;
end.

Additional information:

My output is:
Before: 0 0 0 0

a[NextIndex()] += 1...
Incrementing 0th element
Incrementing 1th element
1 0 0 0

a[NextIndex()] += 2...
Incrementing 2th element
Incrementing 3th element
1 0 2 0

a[NextIndex()] += 4...
Incrementing 0th element
Incrementing 1th element
4 0 2 0

a[NextIndex()] += 8...
Incrementing 2th element
Incrementing 3th element
4 0 8 0

Before: 0 0 0 0

NextPtr()^ += 1...
Incrementing 0th element
1 0 0 0

NextPtr()^ += 2...
Incrementing 1th element
1 2 0 0

NextPtr()^ += 4...
Incrementing 2th element
1 2 4 0

NextPtr()^ += 8...
Incrementing 3th element
1 2 4 8

Mantis conversion info:

  • Mantis ID: 39206
  • Build: r49583 [2021/07/08]
  • Version: 3.3.1
  • Fixed in version: 3.3.1
  • Fixed in revision: 49608 (#0d6a1d24)