Watch, Follow, &
Connect with Us
Public Report
Report From: Delphi-BCB/Compiler/Delphi/Generics    [ Add a report in this area ]  
Report #:  121837   Status: Closed
[Regression] Return value not returned correctly for nested record types
Project:  Delphi Build #:  XE2, ... XE5
Version:    19.0 Submitted By:   Asbjørn Heid
Report Type:  Crash / Data loss / Total failure Date Reported:  1/18/2014 2:15:23 PM
Severity:    Infrequently encountered problem Last Updated: 4/15/2014 6:33:03 PM
Platform:    All versions Internal Tracking #:   46791
Resolution: Fixed (Resolution Comments) Resolved in Build: : XE6
Duplicate of:  None
Voting and Rating
Overall Rating: No Ratings Yet
0.00 out of 5
Total Votes: 10
Description
If a generic record A declares a (non-generic) nested record B, and B has a function X with return type A, then the value of A returned is not returned correctly to the caller if A contains an interface field.

This bug does not seem to happen if A is a non-generic record, nor if A contains a regular object reference instead of an interface reference. I have not yet tested with string types.
Steps to Reproduce:
1. Run the attached project.
2. Observe the output of the second line.
[Output]
----------
0x0000000001F78440
0x0000000000000000
----------

Expected output is the same value as the first line.
If the bug is present, the value printed will contain just zeros.

-----------------
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses System.SysUtils;

type
  TRec<T> = record
  private
    impl: IInterface;
  public
    type
      TSub = record
      public
        v: T;
        function GetRec: TRec<T>;
      end;
  public
    function Sub: TSub;
    procedure Print;
  end;

{ TRec<T> }
procedure TRec<T>.Print;
begin
  WriteLn(Format('0x%.16x', [NativeUInt(pointer(impl))]));
end;

function TRec<T>.Sub: TSub;
begin
  result.v := Default(T);
end;

{ TRec<T>.TSub }
function TRec<T>.TSub.GetRec: TRec<T>;
begin
  result.impl := TInterfacedObject.Create;
  result.Print;
end;

procedure Test;
var
  r: TRec<string>;
begin
  r := r.Sub.GetRec;
  r.Print;
end;

begin
  try
    Test;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  ReadLn;
end.
-----------------
Workarounds
None
Attachment
QC121837.zip
Comments

Asbjørn Heid at 1/19/2014 9:04:34 AM -
From my analysis it appears that the compiler incorrectly flags the Result variable in the GetRec funcion as a temporary, and calls FinalizeRecord on it when exiting the function.

Stefan Glienke at 1/20/2014 4:15:14 AM -
This is a regression and happened between XE (working) and XE2 (broken)

Server Response from: ETNACODE01