Преглед изворни кода

* disabled inlining when passing a refcounted parameter typecasted to
a non-refcounted type to a procedure, as this is incompatible with
the inlining process

git-svn-id: trunk@8391 -

Jonas Maebe пре 18 година
родитељ
комит
666d156e8e
3 измењених фајлова са 72 додато и 2 уклоњено
  1. 1 0
      .gitattributes
  2. 44 2
      compiler/ncal.pas
  3. 27 0
      tests/test/tinline9.pp

+ 1 - 0
.gitattributes

@@ -6905,6 +6905,7 @@ tests/test/tinline5.pp -text
 tests/test/tinline6.pp svneol=native#text/plain
 tests/test/tinline7.pp svneol=native#text/plain
 tests/test/tinline8.pp svneol=native#text/plain
+tests/test/tinline9.pp svneol=native#text/plain
 tests/test/tint2str1.pp svneol=native#text/plain
 tests/test/tint2str2.pp svneol=native#text/plain
 tests/test/tint641.pp svneol=native#text/plain

+ 44 - 2
compiler/ncal.pas

@@ -168,6 +168,9 @@ interface
           procedure secondcallparan;virtual;abstract;
           function docompare(p: tnode): boolean; override;
           procedure printnodetree(var t:text);override;
+          { returns whether a parameter contains a type conversion from }
+          { a refcounted into a non-refcounted type                     }
+          function contains_unsafe_typeconversion: boolean;
 
           property nextpara : tnode read right write right;
           property parametername : tnode read third write third;
@@ -1069,6 +1072,30 @@ implementation
       end;
 
 
+    function tcallparanode.contains_unsafe_typeconversion: boolean;
+      var
+        n: tnode;
+      begin
+        n:=left;
+        while assigned(n) and
+              (n.nodetype=typeconvn) do
+          begin
+            { look for type conversion nodes which convert a }
+            { refcounted type into a non-refcounted type     }
+            if (not n.resultdef.needs_inittable or
+                is_class(n.resultdef)) and
+               (ttypeconvnode(n).left.resultdef.needs_inittable and
+                not is_class(ttypeconvnode(n).left.resultdef)) then
+              begin
+                result:=true;
+                exit;
+              end;
+            n:=ttypeconvnode(n).left;
+          end;
+        result:=false;
+      end;
+
+
     procedure tcallparanode.firstcallparan;
       begin
         if not assigned(left.resultdef) then
@@ -2843,6 +2870,8 @@ implementation
     function tcallnode.pass_1 : tnode;
       var
         st : TSymtable;
+        n: tcallparanode;
+        do_inline: boolean;
       begin
          result:=nil;
 
@@ -2854,13 +2883,26 @@ implementation
              st:=procdefinition.owner;
              if (st.symtabletype=ObjectSymtable) then
                st:=st.defowner.owner;
+             do_inline:=true;
              if (pi_uses_static_symtable in tprocdef(procdefinition).inlininginfo^.flags) and
                 (st.symtabletype=globalsymtable) and
                 (not st.iscurrentunit) then
                begin
                  Comment(V_lineinfo+V_Debug,'Not inlining "'+tprocdef(procdefinition).procsym.realname+'", references static symtable');
-               end
-             else
+                 do_inline:=false;
+               end;
+             n:=tcallparanode(parameters);
+             while assigned(n) do
+               begin
+                 if n.contains_unsafe_typeconversion then
+                   begin
+                     Comment(V_lineinfo+V_Debug,'Not inlining "'+tprocdef(procdefinition).procsym.realname+'", invocation parameter contains unsafe type conversion');
+                     do_inline:=false;
+                     break;
+                   end;
+                 n:=tcallparanode(n.nextpara);
+               end;
+             if do_inline then
                begin
                  result:=pass1_inline;
                  exit;

+ 27 - 0
tests/test/tinline9.pp

@@ -0,0 +1,27 @@
+{$ifdef fpc}
+{$mode objfpc}
+{$inline on}
+{$endif}
+
+function fa: ansistring;
+begin
+  fa:='b';
+  fa:=result+'a';
+end;
+
+function fb: ansistring;
+begin
+  fb:='c';
+  fb:=result+'d';
+end;
+
+procedure test(const a,b: pointer); inline;
+begin
+  if (ansistring(a)<>'ba') or
+     (ansistring(b)<>'cd') then
+    halt(1);
+end;
+
+begin
+  test(pointer(fa()),pointer(fb()));
+end.