From b62045809d9e996591c2bb9f2fa80e34108f557a Mon Sep 17 00:00:00 2001 From: svenbarth Date: Fri, 31 Jul 2020 15:55:34 +0000 Subject: [PATCH] * 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 - --- .gitattributes | 5 +++ compiler/pparautl.pas | 87 ++++++++++++++++++++++++++++++------------- tests/test/tover5.pp | 22 +++++++++++ tests/test/tover6.pp | 25 +++++++++++++ tests/test/tover7.pp | 17 +++++++++ tests/test/tover8.pp | 17 +++++++++ tests/test/tover9.pp | 40 ++++++++++++++++++++ 7 files changed, 187 insertions(+), 26 deletions(-) create mode 100644 tests/test/tover5.pp create mode 100644 tests/test/tover6.pp create mode 100644 tests/test/tover7.pp create mode 100644 tests/test/tover8.pp create mode 100644 tests/test/tover9.pp diff --git a/.gitattributes b/.gitattributes index d3c15faa7d..0a630627d5 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15462,6 +15462,11 @@ tests/test/tover2.pp svneol=native#text/plain tests/test/tover3.pp svneol=native#text/plain tests/test/tover4.pas 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/tparray1.pp svneol=native#text/plain tests/test/tparray10.pp svneol=native#text/plain diff --git a/compiler/pparautl.pas b/compiler/pparautl.pas index 141c9cca4e..792f7ea346 100644 --- a/compiler/pparautl.pas +++ b/compiler/pparautl.pas @@ -676,16 +676,18 @@ implementation end; - function equal_generic_procdefs(fwpd,currpd:tprocdef):boolean; + function equal_generic_procdefs(fwpd,currpd:tprocdef;out sameparas,sameret:boolean):boolean; var i : longint; fwsym, currsym : tsym; - fwtype : ttypesym absolute fwsym; currtype : ttypesym absolute currsym; - foundretdef : boolean; + convdummy: tconverttype; + pddummy: tprocdef; begin result:=false; + sameparas:=false; + sameret:=false; if fwpd.genericparas.count<>currpd.genericparas.count then exit; { comparing generic declarations is a bit more cumbersome as the @@ -696,7 +698,6 @@ implementation constraints while currpd must only contain undefineddefs - forward declaration in implementation: here constraints must be repeated } - foundretdef:=false; for i:=0 to fwpd.genericparas.count-1 do begin fwsym:=tsym(fwpd.genericparas[i]); @@ -728,28 +729,32 @@ implementation as well } exit; 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; if compare_paras(fwpd.paras,currpd.paras,cp_none,[cpo_ignorehidden,cpo_openequalisexact,cpo_ignoreuniv,cpo_generic])<>te_exact then 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 - 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; { @@ -767,6 +772,11 @@ implementation i : longint; po_comp : tprocoptions; paracompopt: tcompare_paras_options; + sameparasfound, + gensameparas, + gensameret, + sameparas, + sameret, forwardfound : boolean; symentry: TSymEntry; item : tlinkedlistitem; @@ -781,6 +791,9 @@ implementation exit; end; + sameparasfound:=false; + fwpd:=nil; + { check overloaded functions if the same function already exists } for i:=0 to tprocsym(currpd.procsym).ProcdefList.Count-1 do begin @@ -797,6 +810,11 @@ implementation if fwpd.procsym<>currpd.procsym then continue; + gensameparas:=false; + gensameret:=false; + sameparas:=false; + sameret:=false; + { check the parameters, for delphi/tp it is possible to leave the parameters away in the implementation (forwarddef=false). But for an overload declared function this is not allowed } @@ -810,7 +828,7 @@ implementation ( fwpd.is_generic and currpd.is_generic and - equal_generic_procdefs(fwpd,currpd) + equal_generic_procdefs(fwpd,currpd,gensameparas,gensameret) ) or { 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) @@ -819,8 +837,9 @@ implementation values should be reported as mismatches (since you can't overload based on different default 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 begin { Check if we've found the forwarddef, if found then @@ -897,7 +916,7 @@ implementation ( fwpd.is_generic and currpd.is_generic and - not equal_generic_procdefs(fwpd,currpd) + not equal_generic_procdefs(fwpd,currpd,sameparas,sameret) ) or ( ( @@ -1124,8 +1143,24 @@ implementation end; end; 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; + 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 list } if not forwardfound then diff --git a/tests/test/tover5.pp b/tests/test/tover5.pp new file mode 100644 index 0000000000..1ac03fb58e --- /dev/null +++ b/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. diff --git a/tests/test/tover6.pp b/tests/test/tover6.pp new file mode 100644 index 0000000000..a8bd797a9a --- /dev/null +++ b/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. + diff --git a/tests/test/tover7.pp b/tests/test/tover7.pp new file mode 100644 index 0000000000..c1a1a54685 --- /dev/null +++ b/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. diff --git a/tests/test/tover8.pp b/tests/test/tover8.pp new file mode 100644 index 0000000000..33bc46d373 --- /dev/null +++ b/tests/test/tover8.pp @@ -0,0 +1,17 @@ +{ %FAIL } + +program tover8; + +{$mode objfpc} + +generic procedure Test(aArg: T); +begin +end; + +generic function Test(aArg: T): T; +begin +end; + +begin + +end. diff --git a/tests/test/tover9.pp b/tests/test/tover9.pp new file mode 100644 index 0000000000..c391f2bba3 --- /dev/null +++ b/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(aArg: PLongInt); +generic function Test2(var aArg: LongInt): LongInt; + +implementation + +procedure Test(aArg: PLongInt); +begin + +end; + +function Test(var aArg: LongInt): LongInt; +begin + +end; + +generic procedure Test2(aArg: PLongInt); +begin + +end; + +generic function Test2(var aArg: LongInt): LongInt; +begin + +end; + +end.