Skip to content

OptVMTs whole-program optimization optimizes away virtual methods of “object”s whose constructor address was taken.

I don’t really care as I stopped using WPO and objects long ago, but after I seen #40200 (closed) I remembered the problem I faced once, and checked it’s still present.

Run this program compiled with OptVMTs whole-program optimization.

{$mode objfpc} {$longstrings on}
uses
	Objects;

type
	MyObjBase = object
		constructor Create;
		function GetVirt: string; virtual; abstract;
	end;

	MyObjA = object(MyObjBase)
		constructor Create;
		function GetVirt: string; virtual;
	end;

	MyObjB = object(MyObjBase)
		constructor Create;
		function GetVirt: string; virtual;
	end;

	constructor MyObjBase.Create; begin end;
	constructor MyObjA.Create; begin end;
	function MyObjA.GetVirt: string; begin result := 'MyObjA.GetVirt'; end;
	constructor MyObjB.Create; begin end;
	function MyObjB.GetVirt: string; begin result := 'MyObjB.GetVirt'; end;

type
	MyObjFactory = record
		ctr: CodePointer;
		vmt: pointer;
	end;

const
	MyObjFactories: array[0 .. 1] of MyObjFactory =
	(
		(ctr: @MyObjA.Create; vmt: TypeOf(MyObjA)),
		(ctr: @MyObjB.Create; vmt: TypeOf(MyObjB))
	);

var
	o: MyObjBase;
	fact: MyObjFactory;

begin
	for fact in MyObjFactories do
	begin
		CallVoidConstructor(fact.ctr, @o, fact.vmt);
		writeln(o.GetVirt);
	end;
end.

Without WPO, it works correctly:

MyObjA.GetVirt
MyObjB.GetVirt

With WPO, it throws 211 Call to abstract method.

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