fix(codegen): allow @ on dynamic-array elements
EmitAddrOfExpr's TStringSubscriptExpr block enumerated only static and open arrays. Taking the address of a dyn-array element via `@A[i]` fell through to the generic L-value path, which didn't know about TStringSubscriptExpr and raised Code generation error: Unsupported L-value form for var argument Read paths and SetLength already worked; only @-of-subscript broke. Add a tyDynArray branch that mirrors the open-array shape (no LowBound, element size from TDynArrayTypeDesc.ElementType.RawSize) — EmitExpr on a dyn-array var already returns the heap data pointer. E2E regression test in cp.test.e2e.dynarray.pas writes through the captured PRec to confirm the address points at the right element.
This commit is contained in:
parent
f6bb0ee029
commit
d0128ed645
|
|
@ -10497,6 +10497,23 @@ begin
|
|||
Result := ElemPtr;
|
||||
Exit;
|
||||
end;
|
||||
{ Dynamic-array element address: @A[I] — EmitExpr on a dyn-array var
|
||||
already returns the heap data pointer, so the address computation
|
||||
mirrors the open-array case (no LowBound). }
|
||||
if Sub.StrExpr.ResolvedType.Kind = tyDynArray then
|
||||
begin
|
||||
ElemSize := TDynArrayTypeDesc(Sub.StrExpr.ResolvedType).ElementType.RawSize;
|
||||
StrPtr := EmitExpr(Sub.StrExpr);
|
||||
IdxW := EmitExpr(Sub.IndexExpr);
|
||||
IdxL := AllocTemp;
|
||||
Offset := AllocTemp;
|
||||
ElemPtr := AllocTemp;
|
||||
EmitLine(Format(' %s =l extsw %s', [IdxL, IdxW]));
|
||||
EmitLine(Format(' %s =l mul %s, %d', [Offset, IdxL, ElemSize]));
|
||||
EmitLine(Format(' %s =l add %s, %s', [ElemPtr, StrPtr, Offset]));
|
||||
Result := ElemPtr;
|
||||
Exit;
|
||||
end;
|
||||
end;
|
||||
if AExpr.Expr is TIdentExpr then
|
||||
begin
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ type
|
|||
procedure TestCodegen_DynArray_Write_ComputesOffset;
|
||||
procedure TestCodegen_DynArray_High_CallsRTL;
|
||||
procedure TestCodegen_DynArray_Low_ReturnsZero;
|
||||
procedure TestCodegen_DynArray_AddrOfElement_ComputesOffset;
|
||||
procedure TestSemantic_DynArray_High_Accepted;
|
||||
procedure TestSemantic_DynArray_Low_Accepted;
|
||||
end;
|
||||
|
|
@ -426,6 +427,32 @@ begin
|
|||
Pos('copy 0', IR) > 0);
|
||||
end;
|
||||
|
||||
procedure TDynArrayTests.TestCodegen_DynArray_AddrOfElement_ComputesOffset;
|
||||
var IR: string;
|
||||
begin
|
||||
{ Regression: @A[i] on a dyn-array used to raise "Unsupported L-value
|
||||
form for var argument" because EmitAddrOfExpr only handled static
|
||||
and open arrays. The fix mirrors the open-array shape (element
|
||||
size from TDynArrayTypeDesc.ElementType.RawSize, no LowBound).
|
||||
Verify the offset arithmetic + base load are emitted without
|
||||
going through a temporary aggregate copy. }
|
||||
IR := GenIR('''
|
||||
program P;
|
||||
type TRec = record X: Integer; end;
|
||||
PRec = ^TRec;
|
||||
var A: array of TRec;
|
||||
P: PRec;
|
||||
begin
|
||||
SetLength(A, 3);
|
||||
P := @A[1]
|
||||
end.
|
||||
''');
|
||||
AssertTrue('mul for element offset in @A[i]',
|
||||
Self.CountOccurrences(IR, 'mul') > 0);
|
||||
AssertTrue('add to combine base + offset',
|
||||
Self.CountOccurrences(IR, 'add') > 0);
|
||||
end;
|
||||
|
||||
initialization
|
||||
RegisterTest(TDynArrayTests);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue