[fpc-devel] Assigning instance methods, accessed via a type, to method pointers

Blaise at blaise.ru Blaise at blaise.ru
Thu Dec 23 19:13:01 CET 2021


Subj silently produces invalid codegen:
-------8<-------
var Z: procedure of object;

type R = record
	procedure Foo;
end;
procedure R.Foo; begin end;

type O = object
	procedure Foo;
end;
procedure O.Foo; begin end;

type C = class
	procedure Foo;
	class procedure ClassCtx;
end;
procedure C.Foo; begin end;
class procedure C.ClassCtx;
begin
	Z := Foo; // BadCG: .Code = C.Foo; .Data = C
end;

type CC = class of C;
var aCC: CC = nil;

type H = class helper for C
	procedure Bar;
	class procedure ClassCtx2;
end;
procedure H.Bar; begin end;
class procedure H.ClassCtx2;
begin
	Z := Bar; // BadCG: .Code = H.Bar; .Data = C
end;

begin
	Z := R.Foo; // BadCG: GARBAGE
	Z := O.Foo; // BadCG: GARBAGE
	Z := C.Foo; // BadCG: .Code = C.Foo; .Data = C
	Z := CC.Foo; // BadCG: GARBAGE
	Z := aCC.Foo; // BadCG: .Code = C.Foo; .Data = aCC

	// Currently allowed, and we get the fix for this for free.
	// Such qualification may become rejected;
	//	see https://lists.freepascal.org/pipermail/fpc-devel/2021-December/044251.html
	Z := H.Bar; // BadCG: GARBAGE
end.
-------8<-------

The attached methptr_to_instancemeth_via_type.patch catches all these cases and reports the proper error:
> Error: Only class methods, class properties and class variables can be referred with class references

-- 
βþ
-------------- next part --------------
# HG changeset patch
# User Blaise.ru
# Date 1640264248 -10800
#      Thu Dec 23 15:57:28 2021 +0300
! reject assignments of instance methods, accessed via a type, to method pointers (invalid codegen)

diff -r d880e6695537 -r 4fddd039bb22 pexpr.pas
--- a/pexpr.pas	Mon Dec 20 20:55:22 2021 +0300
+++ b/pexpr.pas	Thu Dec 23 15:57:28 2021 +0300
@@ -1361,8 +1361,26 @@
                                    again,p1,callflags,spezcontext);
                       { we need to know which procedure is called }
                       do_typecheckpass(p1);
+
+                      { We are loading... }
+                      if p1.nodetype=loadn then
+                       begin
+                         if
+                           { an instance method }
+                           not(po_classmethod in tloadnode(p1).procdef.procoptions)
+                           { into a method pointer (not just taking a code address) }
+                           and not getaddr
+                           { and the selfarg is... }
+                           and(
+                             { either a record/object/helper type, }
+                             not assigned(tloadnode(p1).left)
+                             { or a class/metaclass type, or a class reference }
+                             or{else} (tloadnode(p1).left.resultdef.typ=classrefdef)
+                           ) then
+                             Message(parser_e_only_class_members_via_class_ref);
+                       end
                       { calling using classref? }
-                      if (
+                      else if (
                             isclassref or
                             (
                               (isobjecttype or


More information about the fpc-devel mailing list