Prechádzať zdrojové kódy

* don't mark classes used in "is"- or "as"-expressions as potentially
instantiated (for wpo)
* also replace vmt-entries for classes for which we don't have any
information at all with FPC_ABSTRACTERROR (since that means they
certainly are not instantiated), except for their published and
virtual class methods
* fixed check for published methods in wpo

git-svn-id: trunk@13219 -

Jonas Maebe 16 rokov pred
rodič
commit
66c14c8a88
4 zmenil súbory, kde vykonal 51 pridanie a 15 odobranie
  1. 9 0
      compiler/ncnv.pas
  2. 4 3
      compiler/nmem.pas
  3. 10 1
      compiler/node.pas
  4. 28 11
      compiler/optvirt.pas

+ 9 - 0
compiler/ncnv.pas

@@ -3202,6 +3202,11 @@ implementation
          if codegenerror then
            exit;
 
+         { Passing a class type to an "is" expression cannot result in a class
+           of that type to be constructed.
+         }
+         include(right.flags,nf_ignore_for_wpo);
+
          if (right.resultdef.typ=classrefdef) then
           begin
             { left must be a class }
@@ -3399,6 +3404,10 @@ implementation
         procname: string;
       begin
         result:=nil;
+        { Passing a class type to an "as" expression cannot result in a class
+          of that type to be constructed.
+        }
+        include(right.flags,nf_ignore_for_wpo);
         if not assigned(call) then
           begin
             if is_class(left.resultdef) and

+ 4 - 3
compiler/nmem.pas

@@ -172,9 +172,10 @@ implementation
          expectloc:=LOC_REGISTER;
          if left.nodetype<>typen then
            firstpass(left)
-         else if not assigned(current_procinfo) or
-             (po_inline in current_procinfo.procdef.procoptions) or
-             wpoinfomanager.symbol_live(current_procinfo.procdef.mangledname) then
+         else if not(nf_ignore_for_wpo in flags) and
+             (not assigned(current_procinfo) or
+              (po_inline in current_procinfo.procdef.procoptions) or
+              wpoinfomanager.symbol_live(current_procinfo.procdef.mangledname)) then
            begin
              { keep track of which classes might be instantiated via a classrefdef }
              if (left.resultdef.typ=classrefdef) then

+ 10 - 1
compiler/node.pas

@@ -255,7 +255,16 @@ interface
          nf_get_asm_position,
 
          { tblocknode }
-         nf_block_with_exit
+         nf_block_with_exit,
+
+         { tloadvmtaddrnode }
+         nf_ignore_for_wpo  { we know that this loadvmtaddrnode cannot be used to construct a class instance }
+
+         { WARNING: there are now 32 elements in this type, and a set of this
+             type is written to the PPU. So before adding any more elements,
+             either move some flags to specific nodes, or stream a normalset
+             to the ppu
+         }
 
        );
 

+ 28 - 11
compiler/optvirt.pas

@@ -1054,34 +1054,51 @@ unit optvirt;
              exit;
            end;
 
+         { if it's for a vmtentry of an objdef and the objdef is
+           not instantiated, then we can fill the vmt with pointers
+           to FPC_ABSTRACTERROR, except for published methods
+           (these can be called via rtti, so always have to point
+            to the original method)
+         }
+         if forvmtentry and
+            (tprocdef(procdef).visibility=vis_published) then
+           begin
+             result:=false;
+             exit;
+           end;
+
          { get the component names for the class/procdef combo }
          defsdecompose(realobjdef,tprocdef(procdef),unitid,classid,vmtentry);
 
+         { If we don't have information about a particular unit/class/method,
+           it means that such class cannot be instantiated. So if we are
+           looking up information for a vmt entry, we can always safely return
+           FPC_ABSTRACTERROR if we do not find anything, unless it's a
+           published method (but those are handled already above) or a
+           class method (can be called even if the class is not instantiated).
+         }
+         result:=
+           forvmtentry and
+           not(po_classmethod in tprocdef(procdef).procoptions);
+         staticname:='FPC_ABSTRACTERROR';
+
          { do we have any info for this unit? }
          unitdevirtinfo:=findunit(unitid^);
-         result:=false;
          if not assigned(unitdevirtinfo) then
            exit;
          { and for this class? }
          classdevirtinfo:=unitdevirtinfo.findclass(classid^);
          if not assigned(classdevirtinfo) then
            exit;
-         { if it's for a vmtentry of an objdef and the objdef is
-           not instantiated, then we can fill the vmt with pointers
-           to FPC_ABSTRACTERROR, except for published methods
-           (these can be called via rtti, so always have to point
-            to the original method)
-         }
-         if forvmtentry and
-            (tprocdef(procdef).procsym.visibility=vis_published) then
-           exit;
          if forvmtentry and
             (objdef.typ=objectdef) and
             not classdevirtinfo.instantiated and
             { virtual class methods can be called even if the class is not instantiated }
             not(po_classmethod in tprocdef(procdef).procoptions) then
            begin
-             staticname:='FPC_ABSTRACTERROR';
+             { already set above
+               staticname:='FPC_ABSTRACTERROR';
+             }
              result:=true;
            end
          else