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

--
βþ
# 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
_______________________________________________
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply via email to