compiler:

- postpone insertion of hidden params into record methods after the full record parse to prevent interface and implementation difference because of the possible record size change after the method parse (issue #0021044)
  - skip hidden arguments during methods search for a property setter because of the above change and also for consistency with getter method search
  - test

git-svn-id: trunk@20161 -
This commit is contained in:
paul 2012-01-24 01:45:31 +00:00
parent c8ff351634
commit d752ce2c11
5 changed files with 184 additions and 98 deletions

1
.gitattributes vendored
View File

@ -12168,6 +12168,7 @@ tests/webtbs/tw20995a.pp svneol=native#text/pascal
tests/webtbs/tw20995b.pp svneol=native#text/pascal tests/webtbs/tw20995b.pp svneol=native#text/pascal
tests/webtbs/tw20998.pp svneol=native#text/pascal tests/webtbs/tw20998.pp svneol=native#text/pascal
tests/webtbs/tw21029.pp svneol=native#text/plain tests/webtbs/tw21029.pp svneol=native#text/plain
tests/webtbs/tw21044.pp svneol=native#text/pascal
tests/webtbs/tw21073.pp svneol=native#text/plain tests/webtbs/tw21073.pp svneol=native#text/plain
tests/webtbs/tw2109.pp svneol=native#text/plain tests/webtbs/tw2109.pp svneol=native#text/plain
tests/webtbs/tw2110.pp svneol=native#text/plain tests/webtbs/tw2110.pp svneol=native#text/plain

View File

@ -48,6 +48,15 @@ interface
); );
tpdflags=set of tpdflag; tpdflags=set of tpdflag;
// flags of handle_calling_convention routine
thccflag=(
hcc_check, // perform checks and outup errors if found
hcc_insert_hidden_paras // insert hidden parameters
);
thccflags=set of thccflag;
const
hcc_all=[hcc_check,hcc_insert_hidden_paras];
function check_proc_directive(isprocvar:boolean):boolean; function check_proc_directive(isprocvar:boolean):boolean;
procedure insert_funcret_local(pd:tprocdef); procedure insert_funcret_local(pd:tprocdef);
@ -56,7 +65,7 @@ interface
function proc_get_importname(pd:tprocdef):string; function proc_get_importname(pd:tprocdef):string;
procedure proc_set_mangledname(pd:tprocdef); procedure proc_set_mangledname(pd:tprocdef);
procedure handle_calling_convention(pd:tabstractprocdef); procedure handle_calling_convention(pd:tabstractprocdef;flags:thccflags=hcc_all);
procedure parse_parameter_dec(pd:tabstractprocdef); procedure parse_parameter_dec(pd:tabstractprocdef);
procedure parse_proc_directives(pd:tabstractprocdef;var pdflags:tpdflags); procedure parse_proc_directives(pd:tabstractprocdef;var pdflags:tpdflags);
@ -2839,7 +2848,9 @@ const
end; end;
procedure handle_calling_convention(pd:tabstractprocdef); procedure handle_calling_convention(pd:tabstractprocdef;flags:thccflags=hcc_all);
begin
if hcc_check in flags then
begin begin
{ set the default calling convention if none provided } { set the default calling convention if none provided }
if (pd.typ=procdef) and if (pd.typ=procdef) and
@ -2917,7 +2928,10 @@ const
Message(parser_e_varargs_need_cdecl_and_external); Message(parser_e_varargs_need_cdecl_and_external);
end; end;
end; end;
end;
if hcc_insert_hidden_paras in flags then
begin
{ insert hidden high parameters } { insert hidden high parameters }
pd.parast.SymList.ForEachCall(@insert_hidden_para,pd); pd.parast.SymList.ForEachCall(@insert_hidden_para,pd);
@ -2936,6 +2950,7 @@ const
{ insert parentfp parameter if required } { insert parentfp parameter if required }
insert_parentfp_para(pd); insert_parentfp_para(pd);
end;
{ Calculate parameter tlist } { Calculate parameter tlist }
pd.calcparas; pd.calcparas;

View File

@ -602,11 +602,17 @@ implementation
{ Insert hidden parameters } { Insert hidden parameters }
handle_calling_convention(writeprocdef); handle_calling_convention(writeprocdef);
{ search procdefs matching writeprocdef } { search procdefs matching writeprocdef }
{ skip hidden part (same as for _READ part ) because of the }
{ possible different calling conventions and especialy for }
{ records - their methods hidden parameters are handled }
{ after the full record parse }
if cs_varpropsetter in current_settings.localswitches then if cs_varpropsetter in current_settings.localswitches then
p.propaccesslist[palt_write].procdef:=Tprocsym(sym).Find_procdef_bypara(writeprocdef.paras,writeprocdef.returndef,[cpo_allowdefaults,cpo_ignorevarspez]) p.propaccesslist[palt_write].procdef:=Tprocsym(sym).Find_procdef_bypara(writeprocdef.paras,writeprocdef.returndef,[cpo_allowdefaults,cpo_ignorevarspez,cpo_ignorehidden])
else else
p.propaccesslist[palt_write].procdef:=Tprocsym(sym).Find_procdef_bypara(writeprocdef.paras,writeprocdef.returndef,[cpo_allowdefaults]); p.propaccesslist[palt_write].procdef:=Tprocsym(sym).Find_procdef_bypara(writeprocdef.paras,writeprocdef.returndef,[cpo_allowdefaults,cpo_ignorehidden]);
if not assigned(p.propaccesslist[palt_write].procdef) then if not assigned(p.propaccesslist[palt_write].procdef) or
{ because of cpo_ignorehidden we need to compare if it is a static class method and we have a class property }
((sp_static in p.symoptions) <> tprocdef(p.propaccesslist[palt_write].procdef).no_self_node) then
Message(parser_e_ill_property_access_sym); Message(parser_e_ill_property_access_sym);
end; end;
fieldvarsym : fieldvarsym :

View File

@ -402,7 +402,7 @@ implementation
end; end;
end; end;
procedure parse_record_members; procedure parse_record_members(procdeflist:TFPObjectList);
procedure maybe_parse_hint_directives(pd:tprocdef); procedure maybe_parse_hint_directives(pd:tprocdef);
var var
@ -548,7 +548,9 @@ implementation
begin begin
parse_record_proc_directives(pd); parse_record_proc_directives(pd);
handle_calling_convention(pd); // postpone adding hidden params
handle_calling_convention(pd,[hcc_check]);
procdeflist.add(pd);
{ add definition to procsym } { add definition to procsym }
proc_add_definition(pd); proc_add_definition(pd);
@ -618,7 +620,11 @@ implementation
if is_classdef and not (po_staticmethod in pd.procoptions) then if is_classdef and not (po_staticmethod in pd.procoptions) then
MessagePos(pd.fileinfo, parser_e_class_methods_only_static_in_records); MessagePos(pd.fileinfo, parser_e_class_methods_only_static_in_records);
handle_calling_convention(pd); // we can't add hidden params here because record is not yet defined
// and therefore record size which has influence on paramter passing rules may change too
// look at record_dec to see where calling conventions are applied (issue #0021044)
handle_calling_convention(pd,[hcc_check]);
procdeflist.add(pd);
{ add definition to procsym } { add definition to procsym }
proc_add_definition(pd); proc_add_definition(pd);
@ -705,6 +711,11 @@ implementation
old_current_specializedef: tstoreddef; old_current_specializedef: tstoreddef;
old_parse_generic: boolean; old_parse_generic: boolean;
recst: trecordsymtable; recst: trecordsymtable;
procdeflist: TFPObjectList;
i: integer;
pd: tprocdef;
oldparse_only: boolean;
oldpos : tfileposinfo;
begin begin
old_current_structdef:=current_structdef; old_current_structdef:=current_structdef;
old_current_genericdef:=current_genericdef; old_current_genericdef:=current_genericdef;
@ -739,7 +750,23 @@ implementation
include(current_structdef.defoptions, df_generic); include(current_structdef.defoptions, df_generic);
parse_generic:=(df_generic in current_structdef.defoptions); parse_generic:=(df_generic in current_structdef.defoptions);
if m_advanced_records in current_settings.modeswitches then if m_advanced_records in current_settings.modeswitches then
parse_record_members begin
procdeflist:=TFPObjectList.Create(false);
parse_record_members(procdeflist);
// handle calling conventions of record methods
oldpos:=current_filepos;
oldparse_only:=parse_only;
parse_only:=true;
for i := 0 to procdeflist.count - 1 do
begin
pd:=tprocdef(procdeflist[i]);
current_filepos:=pd.fileinfo;
handle_calling_convention(pd,[hcc_insert_hidden_paras]);
end;
parse_only:=oldparse_only;
current_filepos:=oldpos;
procdeflist.free;
end
else else
begin begin
read_record_fields([vd_record]); read_record_fields([vd_record]);

37
tests/webtbs/tw21044.pp Normal file
View File

@ -0,0 +1,37 @@
{ %norun}
program tw21044;
{$mode Delphi}
uses
SysUtils, Classes;
type
{ TTestRecord }
TTestRecord = record
public
function Test(const Lhs, Rhs: TTestRecord): TTestRecord;
// operator overloads
class operator Add(const Lhs, Rhs: TTestRecord): TTestRecord;
// this part changes the size of record and so the way of parameter handling
// on some 64bit systems
case Boolean of
False: (Value: Single);
True: (AsInteger: Integer);
end;
{ TTestRecord }
function TTestRecord.Test(const Lhs, Rhs: TTestRecord): TTestRecord;
begin
Result.AsInteger := Lhs.AsInteger + Rhs.AsInteger;
end;
class operator TTestRecord.Add(const Lhs, Rhs: TTestRecord): TTestRecord;
begin
Result.Value := Lhs.Value + Rhs.Value;
end;
begin
end.