Browse Source

* reject overloads if they only differ in the result types (as long as they aren't operator overloads)
+ added tests

git-svn-id: trunk@45973 -

svenbarth 5 years ago
parent
commit
b62045809d
7 changed files with 187 additions and 26 deletions
  1. 5 0
      .gitattributes
  2. 61 26
      compiler/pparautl.pas
  3. 22 0
      tests/test/tover5.pp
  4. 25 0
      tests/test/tover6.pp
  5. 17 0
      tests/test/tover7.pp
  6. 17 0
      tests/test/tover8.pp
  7. 40 0
      tests/test/tover9.pp

+ 5 - 0
.gitattributes

@@ -15462,6 +15462,11 @@ tests/test/tover2.pp svneol=native#text/plain
 tests/test/tover3.pp svneol=native#text/plain
 tests/test/tover3.pp svneol=native#text/plain
 tests/test/tover4.pas svneol=native#text/plain
 tests/test/tover4.pas svneol=native#text/plain
 tests/test/tover4.pp svneol=native#text/plain
 tests/test/tover4.pp svneol=native#text/plain
+tests/test/tover5.pp svneol=native#text/pascal
+tests/test/tover6.pp svneol=native#text/pascal
+tests/test/tover7.pp svneol=native#text/pascal
+tests/test/tover8.pp svneol=native#text/pascal
+tests/test/tover9.pp svneol=native#text/pascal
 tests/test/tpackrec.pp svneol=native#text/plain
 tests/test/tpackrec.pp svneol=native#text/plain
 tests/test/tparray1.pp svneol=native#text/plain
 tests/test/tparray1.pp svneol=native#text/plain
 tests/test/tparray10.pp svneol=native#text/plain
 tests/test/tparray10.pp svneol=native#text/plain

+ 61 - 26
compiler/pparautl.pas

@@ -676,16 +676,18 @@ implementation
         end;
         end;
 
 
 
 
-      function equal_generic_procdefs(fwpd,currpd:tprocdef):boolean;
+      function equal_generic_procdefs(fwpd,currpd:tprocdef;out sameparas,sameret:boolean):boolean;
         var
         var
           i : longint;
           i : longint;
           fwsym,
           fwsym,
           currsym : tsym;
           currsym : tsym;
-          fwtype : ttypesym absolute fwsym;
           currtype : ttypesym absolute currsym;
           currtype : ttypesym absolute currsym;
-          foundretdef : boolean;
+          convdummy: tconverttype;
+          pddummy: tprocdef;
         begin
         begin
           result:=false;
           result:=false;
+          sameparas:=false;
+          sameret:=false;
           if fwpd.genericparas.count<>currpd.genericparas.count then
           if fwpd.genericparas.count<>currpd.genericparas.count then
             exit;
             exit;
           { comparing generic declarations is a bit more cumbersome as the
           { comparing generic declarations is a bit more cumbersome as the
@@ -696,7 +698,6 @@ implementation
               constraints while currpd must only contain undefineddefs
               constraints while currpd must only contain undefineddefs
             - forward declaration in implementation: here constraints must be
             - forward declaration in implementation: here constraints must be
               repeated }
               repeated }
-          foundretdef:=false;
           for i:=0 to fwpd.genericparas.count-1 do
           for i:=0 to fwpd.genericparas.count-1 do
             begin
             begin
               fwsym:=tsym(fwpd.genericparas[i]);
               fwsym:=tsym(fwpd.genericparas[i]);
@@ -728,28 +729,32 @@ implementation
                       as well }
                       as well }
                     exit;
                     exit;
                 end;
                 end;
-              if not foundretdef and (fwsym.typ=typesym) then
-                begin
-                  { if the returndef is the same as this parameter's def then this
-                    needs to be the case for both procdefs }
-                  foundretdef:=fwpd.returndef=fwtype.typedef;
-                  if foundretdef xor (currpd.returndef=currtype.typedef) then
-                    exit;
-                end;
             end;
             end;
           if compare_paras(fwpd.paras,currpd.paras,cp_none,[cpo_ignorehidden,cpo_openequalisexact,cpo_ignoreuniv,cpo_generic])<>te_exact then
           if compare_paras(fwpd.paras,currpd.paras,cp_none,[cpo_ignorehidden,cpo_openequalisexact,cpo_ignoreuniv,cpo_generic])<>te_exact then
             exit;
             exit;
-          if not foundretdef then
-            begin
-              if (df_specialization in tstoreddef(fwpd.returndef).defoptions) and (df_specialization in tstoreddef(currpd.returndef).defoptions) then
-                { for specializations we're happy with equal defs instead of exactly the same defs }
-                result:=equal_defs(fwpd.returndef,currpd.returndef)
-              else
-                { the returndef isn't a type parameter, so compare as usual }
-                result:=compare_defs(fwpd.returndef,currpd.returndef,nothingn)=te_exact;
-            end
+          sameparas:=true;
+          if (df_specialization in tstoreddef(fwpd.returndef).defoptions) and (df_specialization in tstoreddef(currpd.returndef).defoptions) then
+            { for specializations we're happy with equal defs instead of exactly the same defs }
+            result:=equal_defs(fwpd.returndef,currpd.returndef)
           else
           else
-            result:=true;
+            begin
+              { strictly compare defs using compare_defs_ext, but allow
+                non exactly equal undefineddefs }
+              convdummy:=tc_none;
+              pddummy:=nil;
+              result:=(compare_defs_ext(fwpd.returndef,currpd.returndef,nothingn,convdummy,pddummy,[cdo_allow_variant,cdo_strict_undefined_check])=te_exact) or
+                        equal_genfunc_paradefs(fwpd.returndef,currpd.returndef,fwpd.parast,currpd.parast);
+            end;
+          { the result variable is only set depending on the return type, so we
+            can simply use "result" }
+          sameret:=result;
+        end;
+
+      function equal_signature(fwpd,currpd:tprocdef;out sameparas,sameret:boolean):boolean;
+        begin
+          sameparas:=compare_paras(fwpd.paras,currpd.paras,cp_none,[cpo_ignorehidden,cpo_openequalisexact,cpo_ignoreuniv])=te_exact;
+          sameret:=compare_defs(fwpd.returndef,currpd.returndef,nothingn)=te_exact;
+          result:=sameparas and sameret;
         end;
         end;
 
 
       {
       {
@@ -767,6 +772,11 @@ implementation
         i       : longint;
         i       : longint;
         po_comp : tprocoptions;
         po_comp : tprocoptions;
         paracompopt: tcompare_paras_options;
         paracompopt: tcompare_paras_options;
+        sameparasfound,
+        gensameparas,
+        gensameret,
+        sameparas,
+        sameret,
         forwardfound : boolean;
         forwardfound : boolean;
         symentry: TSymEntry;
         symentry: TSymEntry;
         item : tlinkedlistitem;
         item : tlinkedlistitem;
@@ -781,6 +791,9 @@ implementation
             exit;
             exit;
           end;
           end;
 
 
+        sameparasfound:=false;
+        fwpd:=nil;
+
         { check overloaded functions if the same function already exists }
         { check overloaded functions if the same function already exists }
         for i:=0 to tprocsym(currpd.procsym).ProcdefList.Count-1 do
         for i:=0 to tprocsym(currpd.procsym).ProcdefList.Count-1 do
          begin
          begin
@@ -797,6 +810,11 @@ implementation
            if fwpd.procsym<>currpd.procsym then
            if fwpd.procsym<>currpd.procsym then
              continue;
              continue;
 
 
+           gensameparas:=false;
+           gensameret:=false;
+           sameparas:=false;
+           sameret:=false;
+
            { check the parameters, for delphi/tp it is possible to
            { check the parameters, for delphi/tp it is possible to
              leave the parameters away in the implementation (forwarddef=false).
              leave the parameters away in the implementation (forwarddef=false).
              But for an overload declared function this is not allowed }
              But for an overload declared function this is not allowed }
@@ -810,7 +828,7 @@ implementation
               (
               (
                 fwpd.is_generic and
                 fwpd.is_generic and
                 currpd.is_generic and
                 currpd.is_generic and
-                equal_generic_procdefs(fwpd,currpd)
+                equal_generic_procdefs(fwpd,currpd,gensameparas,gensameret)
               ) or
               ) or
               { check arguments, we need to check only the user visible parameters. The hidden parameters
               { check arguments, we need to check only the user visible parameters. The hidden parameters
                 can be in a different location because of the calling convention, eg. L-R vs. R-L order (PFV)
                 can be in a different location because of the calling convention, eg. L-R vs. R-L order (PFV)
@@ -819,8 +837,9 @@ implementation
                 values should be reported as mismatches (since you can't overload based on different default
                 values should be reported as mismatches (since you can't overload based on different default
                 parameter values) }
                 parameter values) }
               (
               (
-               (compare_paras(fwpd.paras,currpd.paras,cp_none,[cpo_ignorehidden,cpo_openequalisexact,cpo_ignoreuniv])=te_exact) and
-               (compare_defs(fwpd.returndef,currpd.returndef,nothingn)=te_exact)
+                not fwpd.is_generic and
+                not currpd.is_generic and
+                equal_signature(fwpd,currpd,sameparas,sameret)
               ) then
               ) then
              begin
              begin
                { Check if we've found the forwarddef, if found then
                { Check if we've found the forwarddef, if found then
@@ -897,7 +916,7 @@ implementation
                          (
                          (
                            fwpd.is_generic and
                            fwpd.is_generic and
                            currpd.is_generic and
                            currpd.is_generic and
-                           not equal_generic_procdefs(fwpd,currpd)
+                           not equal_generic_procdefs(fwpd,currpd,sameparas,sameret)
                          ) or
                          ) or
                          (
                          (
                            (
                            (
@@ -1124,8 +1143,24 @@ implementation
                   end;
                   end;
                end;
                end;
             end; { equal arguments }
             end; { equal arguments }
+
+           { we found a match with the same parameter signature, but mismatching
+             return types; complain about that, but only once we've checked for
+             a forward to improve error recovery }
+           if (sameparas and not sameret and
+               { ensure that specifiers are the same as well }
+               (compare_paras(fwpd.paras,currpd.paras,cp_all,[cpo_ignorehidden,cpo_openequalisexact,cpo_ignoreuniv])=te_exact)
+               ) or (gensameparas and not gensameret) then
+             sameparasfound:=true;
          end;
          end;
 
 
+        if sameparasfound and
+            not (currpd.proctypeoption=potype_operator) then
+          begin
+            MessagePos(currpd.fileinfo,parser_e_overloaded_have_same_parameters);
+            tprocsym(currpd.procsym).write_parameter_lists(currpd);
+          end;
+
         { if we didn't reuse a forwarddef then we add the procdef to the overloaded
         { if we didn't reuse a forwarddef then we add the procdef to the overloaded
           list }
           list }
         if not forwardfound then
         if not forwardfound then

+ 22 - 0
tests/test/tover5.pp

@@ -0,0 +1,22 @@
+{ %FAIL }
+
+program tover5;
+
+{$mode objfpc}
+
+type
+  TTestClass = class
+    procedure Test(aArg1: LongInt);
+    function Test(aArg1: LongInt): LongInt;
+  end;
+
+procedure TTestClass.Test(aArg1: LongInt);
+begin
+end;
+
+function TTestClass.Test(aArg1: Longint): LongInt;
+begin
+end;
+
+begin
+end.

+ 25 - 0
tests/test/tover6.pp

@@ -0,0 +1,25 @@
+{ %FAIL }
+
+unit tover6;
+
+{$mode objfpc}{$H+}
+
+interface
+
+procedure Test(aArg: LongInt);
+function Test(aArg: LongInt): LongInt;
+
+implementation
+
+procedure Test(aArg: LongInt);
+begin
+
+end;
+
+function Test(aArg: LongInt): LongInt;
+begin
+
+end;
+
+end.
+

+ 17 - 0
tests/test/tover7.pp

@@ -0,0 +1,17 @@
+{ %FAIL }
+
+program tover7;
+
+{$mode objfpc}
+
+procedure Test(aArg: LongInt);
+begin
+end;
+
+function Test(aArg: LongInt): LongInt;
+begin
+end;
+
+begin
+
+end.

+ 17 - 0
tests/test/tover8.pp

@@ -0,0 +1,17 @@
+{ %FAIL }
+
+program tover8;
+
+{$mode objfpc}
+
+generic procedure Test<T>(aArg: T);
+begin
+end;
+
+generic function Test<T>(aArg: T): T;
+begin
+end;
+
+begin
+
+end.

+ 40 - 0
tests/test/tover9.pp

@@ -0,0 +1,40 @@
+unit tover9;
+
+{$mode objfpc}
+
+interface
+
+{ this is the for xmlSchemaSetParserErrors in the xmlschemas.inc of the libxml
+  package }
+
+procedure Test(aArg: PLongInt);
+function Test(var aArg: LongInt): LongInt;
+
+{ also check generic routines just to be sure }
+
+generic procedure Test2<T>(aArg: PLongInt);
+generic function Test2<T>(var aArg: LongInt): LongInt;
+
+implementation
+
+procedure Test(aArg: PLongInt);
+begin
+
+end;
+
+function Test(var aArg: LongInt): LongInt;
+begin
+
+end;
+
+generic procedure Test2<T>(aArg: PLongInt);
+begin
+
+end;
+
+generic function Test2<T>(var aArg: LongInt): LongInt;
+begin
+
+end;
+
+end.