Skip to content

Missing dwarf info for nested classes (in generics) - too eager to strip info, assuming it is not used

  • FPC 3.3.1 from 27th Jun 2022
  • Windows 10
  • 64 bit

In some cases, FPC omits dwarf info for some classes. I have only been able to reproduce this with generics, but as far as I can see that may just be a way to expose the underlaying issue, which is that FPC does not realize the class is being used.

In the code below (and attached) no info is generated for TMyBar.

FPC 3.2.3 generates info for the VMT (but also not for the actual class)

 <1><e3eed>: Abbrev Number: 2 (DW_TAG_typedef)
    <e3eee>   DW_AT_name        : $vmtdef$TGenFoo$1$crc9F312717.TMYBAR
    <e3f13>   DW_AT_type        : <0xe3f17>
 <1><e3f17>: Abbrev Number: 9 (DW_TAG_structure_type)
    <e3f18>   DW_AT_name        : $VMTDEF$TGENFOO$1$CRC9F312717.TMYBAR
    <e3f3d>   DW_AT_byte_size   : 216

FPC 3.3.1 generates nothing.

However having a class (for typecasting in the debugger) would really be useful.


If a public field FBarData:TMyBar; is added in TGenFoo then FPC notes that the class is used, and generates info.

However, this info is not useful:

  • if you have several specializations of TGenFoo
  • Then for each of them a dwarf entry TMyBar is created
    • all with the same name
    • all as stand-alone type, the type is not recognizable as being a subtype of the specialization of TGenFoo.

Well...

  • The type is refereed by the field FBarData, so if inspecting the specialized TGenFoo, the type will be found.
  • But if attempting to typecast a variable of that class, it can't be told which TMyBar it should be. Besides the ClassName of such a variable is something like: TGENFOO$1$CRC9F312717.TMYBAR

So, IMHO, it would be better if the dwarf entry for that class was also named TGENFOO$1$CRC9F312717.TMYBAR

Never mind, that FpDebug still needs to learn to typecast to `TGenFoo1crc713F463B.TMyBar` Especially, given that this is one single name (One single name in the dwarf info table), and the dot normally separates names...

program project1;
{$mode objfpc}{$H+}
uses Unit1;
var
  f: TFoo;
  b: TBar;
begin
  f := TMyFoo.Create;
  b := f.GetBar;
  b.GetData;
end.
unit Unit1;
{$mode ObjFPC}{$H+}

interface

type

  TBar = class
  public
    function GetData: Integer; virtual; abstract;
  end;

  TFoo = class
    function GetBar: TBar; virtual;
  end;

  generic TGenFoo<T> = class(TFoo)
  private type
    TMyBar = class(TBar)
    public
      FData: T;
      function GetData: Integer; override;
    end;

  public
    // FBarData:TMyBar;
    function GetBar: TBar; override;
  end;

  TMyFoo = class(specialize TGenFoo<integer>)
  end;

implementation

function TGenFoo.TMyBar.GetData: Integer;
begin
  Result := FData;
end;

function TGenFoo.GetBar: TBar;
begin
  Result := TMyBar.Create;
end;

function TFoo.GetBar: TBar;
begin
  Result := nil;
end;

end.

project1.lpr unit1.pas

Edited by Martin
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information