Browse Source

* Patch by Evgenii Savin to avoid IE 2010021502 when calling generic from other generic. Fixes issue #40770

Michaël Van Canneyt 1 year ago
parent
commit
1743df7b80
2 changed files with 65 additions and 3 deletions
  1. 15 3
      compiler/pgenutil.pas
  2. 50 0
      tests/webtbs/tw40770.pp

+ 15 - 3
compiler/pgenutil.pas

@@ -1680,6 +1680,17 @@ uses
               end;
           end;
 
+      function has_generic_paras(adef: tstoreddef): boolean;
+        var
+          i: Integer;
+        begin
+          result:=False;
+          if adef.genericparas<>nil then
+            for i:=0 to adef.genericparas.Count-1 do
+              if sp_generic_para in tsym(adef.genericparas[i]).symoptions then
+                exit(true);
+        end;
+
       var
         finalspecializename,
         ufinalspecializename : tidstring;
@@ -2151,7 +2162,7 @@ uses
                 tdef(item).ChangeOwner(specializest);
                 { for partial specializations we implicitely declare any methods as having their
                   implementations although we'll not specialize them in reality }
-                if parse_generic then
+                if parse_generic or has_generic_paras(tstoreddef(item)) then
                   unset_forwarddef(tdef(item));
               end;
 
@@ -2165,8 +2176,9 @@ uses
             specialization_done(state);
 
             { procdefs are only added once we know which overload we use }
-            if not parse_generic and (result.typ<>procdef) then
-              current_module.pendingspecializations.add(result.typename,result);
+            if not parse_generic and (result.typ<>procdef) and
+              not has_generic_paras(tstoreddef(result)) then
+                  current_module.pendingspecializations.add(result.typename,result);
           end;
 
         generictypelist.free;

+ 50 - 0
tests/webtbs/tw40770.pp

@@ -0,0 +1,50 @@
+program tw40770;
+
+{$ifdef FPC}{$mode DELPHI}{$endif}
+
+type
+  Wrapper<T> = record
+    Value: T;
+    function GetValue: T;
+  end;
+
+  Utils = record
+  public
+    class function Method1<T>(): Wrapper<T>; static;
+    class function Method2<T>(): Wrapper<T>; static;
+  end;
+
+function Wrapper<T>.GetValue: T;
+begin
+  Result := Value;
+end;
+
+var
+  Log: string;
+procedure AppendToLog(const S: string);
+begin
+  if Log = '' then Log := S else Log := Log + ' ' + S;
+end;
+
+class function Utils.Method1<T>(): Wrapper<T>;
+begin
+  if TypeInfo(T) = TypeInfo(Integer) then
+    AppendToLog('Method1<Integer>')
+  else if TypeInfo(T) = TypeInfo(string) then
+     AppendToLog('Method1<string>')
+  else
+    Halt(1);
+end;
+
+class function Utils.Method2<T>(): Wrapper<T>;
+begin
+  Result := Method1<T>();
+end;
+
+begin
+  Utils.Method2<Integer>();
+  Utils.Method2<string>();
+  if Log <> 'Method1<Integer> Method1<string>' then
+    Halt(2);
+  WriteLn('OK');
+end.