mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-11-02 10:09:35 +01:00
* current_objectdef is now always valid when parsing is within the
context of a class. This can be either the class declaration or
a method implementation
* replaced all current_procinfo.procdef._class with current_objectdef
git-svn-id: trunk@12059 -
This commit is contained in:
parent
b580cbc778
commit
8419161964
@ -217,7 +217,7 @@ implementation
|
||||
SysUtils,globals,
|
||||
verbose,systems,
|
||||
scanner,ppu,dbgbase,
|
||||
procinfo;
|
||||
procinfo,symdef;
|
||||
|
||||
{$ifdef MEMDEBUG}
|
||||
var
|
||||
@ -550,7 +550,10 @@ implementation
|
||||
if assigned(procinfo) then
|
||||
begin
|
||||
if current_procinfo=tprocinfo(procinfo) then
|
||||
current_procinfo:=nil;
|
||||
begin
|
||||
current_procinfo:=nil;
|
||||
current_objectdef:=nil;
|
||||
end;
|
||||
{ release procinfo tree }
|
||||
while assigned(procinfo) do
|
||||
begin
|
||||
@ -629,7 +632,10 @@ implementation
|
||||
if assigned(procinfo) then
|
||||
begin
|
||||
if current_procinfo=tprocinfo(procinfo) then
|
||||
current_procinfo:=nil;
|
||||
begin
|
||||
current_procinfo:=nil;
|
||||
current_objectdef:=nil;
|
||||
end;
|
||||
{ release procinfo tree }
|
||||
while assigned(procinfo) do
|
||||
begin
|
||||
|
||||
@ -1637,12 +1637,7 @@ implementation
|
||||
st.defowner.owner.iscurrentunit then
|
||||
topclassh:=tobjectdef(st.defowner)
|
||||
else
|
||||
begin
|
||||
if assigned(current_procinfo) then
|
||||
topclassh:=current_procinfo.procdef._class
|
||||
else
|
||||
topclassh:=nil;
|
||||
end;
|
||||
topclassh:=current_objectdef;
|
||||
|
||||
{ link all procedures which have the same # of parameters }
|
||||
for j:=0 to sym.ProcdefList.Count-1 do
|
||||
|
||||
@ -474,9 +474,9 @@ implementation
|
||||
result:=internalstatements(newstatement);
|
||||
|
||||
{ call fail helper and exit normal }
|
||||
if is_class(current_procinfo.procdef._class) then
|
||||
if is_class(current_objectdef) then
|
||||
begin
|
||||
srsym:=search_class_member(current_procinfo.procdef._class,'FREEINSTANCE');
|
||||
srsym:=search_class_member(current_objectdef,'FREEINSTANCE');
|
||||
if assigned(srsym) and
|
||||
(srsym.typ=procsym) then
|
||||
begin
|
||||
@ -496,13 +496,13 @@ implementation
|
||||
internalerror(200305108);
|
||||
end
|
||||
else
|
||||
if is_object(current_procinfo.procdef._class) then
|
||||
if is_object(current_objectdef) then
|
||||
begin
|
||||
{ parameter 3 : vmt_offset }
|
||||
{ parameter 2 : pointer to vmt }
|
||||
{ parameter 1 : self pointer }
|
||||
para:=ccallparanode.create(
|
||||
cordconstnode.create(current_procinfo.procdef._class.vmt_offset,s32inttype,false),
|
||||
cordconstnode.create(current_objectdef.vmt_offset,s32inttype,false),
|
||||
ccallparanode.create(
|
||||
ctypeconvnode.create_internal(
|
||||
load_vmt_pointer_node,
|
||||
|
||||
@ -42,7 +42,7 @@ implementation
|
||||
{$ENDIF}
|
||||
cutils,cclasses,
|
||||
globtype,version,tokens,systems,globals,verbose,switches,
|
||||
symbase,symtable,symsym,
|
||||
symbase,symtable,symdef,symsym,
|
||||
finput,fmodule,fppu,
|
||||
aasmbase,aasmtai,aasmdata,
|
||||
cgbase,
|
||||
@ -64,6 +64,7 @@ implementation
|
||||
current_module:=nil;
|
||||
current_asmdata:=nil;
|
||||
current_procinfo:=nil;
|
||||
current_objectdef:=nil;
|
||||
|
||||
loaded_units:=TLinkedList.Create;
|
||||
|
||||
@ -133,6 +134,7 @@ implementation
|
||||
current_module:=nil;
|
||||
current_procinfo:=nil;
|
||||
current_asmdata:=nil;
|
||||
current_objectdef:=nil;
|
||||
|
||||
{ unload units }
|
||||
if assigned(loaded_units) then
|
||||
@ -284,6 +286,11 @@ implementation
|
||||
olddata : polddata;
|
||||
hp,hp2 : tmodule;
|
||||
begin
|
||||
{ parsing a procedure or declaration should be finished }
|
||||
if assigned(current_procinfo) then
|
||||
internalerror(200811121);
|
||||
if assigned(current_objectdef) then
|
||||
internalerror(200811122);
|
||||
inc(compile_level);
|
||||
parser_current_file:=filename;
|
||||
{ Uses heap memory instead of placing everything on the
|
||||
|
||||
@ -1410,15 +1410,14 @@ implementation
|
||||
is_object(hdef) then
|
||||
begin
|
||||
consume(_POINT);
|
||||
if assigned(current_procinfo) and
|
||||
assigned(current_procinfo.procdef._class) and
|
||||
if assigned(current_objectdef) and
|
||||
not(getaddr) then
|
||||
begin
|
||||
if current_procinfo.procdef._class.is_related(tobjectdef(hdef)) then
|
||||
if current_objectdef.is_related(tobjectdef(hdef)) then
|
||||
begin
|
||||
p1:=ctypenode.create(hdef);
|
||||
{ search also in inherited methods }
|
||||
searchsym_in_class(tobjectdef(hdef),current_procinfo.procdef._class,pattern,srsym,srsymtable);
|
||||
searchsym_in_class(tobjectdef(hdef),current_objectdef,pattern,srsym,srsymtable);
|
||||
if assigned(srsym) then
|
||||
check_hints(srsym,srsym.symoptions);
|
||||
consume(_ID);
|
||||
@ -2160,8 +2159,7 @@ implementation
|
||||
{ Handle references to self }
|
||||
if (idtoken=_SELF) and
|
||||
not(block_type in [bt_const,bt_type,bt_const_type,bt_var_type]) and
|
||||
assigned(current_procinfo) and
|
||||
assigned(current_procinfo.procdef._class) then
|
||||
assigned(current_objectdef) then
|
||||
begin
|
||||
p1:=load_self_node;
|
||||
consume(_ID);
|
||||
@ -2198,9 +2196,9 @@ implementation
|
||||
again:=true;
|
||||
consume(_INHERITED);
|
||||
if assigned(current_procinfo) and
|
||||
assigned(current_procinfo.procdef._class) then
|
||||
assigned(current_objectdef) then
|
||||
begin
|
||||
hclassdef:=current_procinfo.procdef._class.childof;
|
||||
hclassdef:=current_objectdef.childof;
|
||||
{ if inherited; only then we need the method with
|
||||
the same name }
|
||||
if token in endtokens then
|
||||
@ -2218,7 +2216,7 @@ implementation
|
||||
if (po_msgstr in pd.procoptions) then
|
||||
searchsym_in_class_by_msgstr(hclassdef,pd.messageinf.str^,srsym,srsymtable)
|
||||
else
|
||||
searchsym_in_class(hclassdef,current_procinfo.procdef._class,hs,srsym,srsymtable);
|
||||
searchsym_in_class(hclassdef,current_objectdef,hs,srsym,srsymtable);
|
||||
end
|
||||
else
|
||||
begin
|
||||
@ -2226,7 +2224,7 @@ implementation
|
||||
hsorg:=orgpattern;
|
||||
consume(_ID);
|
||||
anon_inherited:=false;
|
||||
searchsym_in_class(hclassdef,current_procinfo.procdef._class,hs,srsym,srsymtable);
|
||||
searchsym_in_class(hclassdef,current_objectdef,hs,srsym,srsymtable);
|
||||
end;
|
||||
if assigned(srsym) then
|
||||
begin
|
||||
|
||||
@ -266,19 +266,18 @@ implementation
|
||||
srsym : tsym;
|
||||
para : tcallparanode;
|
||||
newstatement : tstatementnode;
|
||||
hdef : tdef;
|
||||
begin
|
||||
result:=internalstatements(newstatement);
|
||||
|
||||
if assigned(current_procinfo.procdef._class) then
|
||||
if assigned(current_objectdef) then
|
||||
begin
|
||||
{ a constructor needs a help procedure }
|
||||
if (current_procinfo.procdef.proctypeoption=potype_constructor) then
|
||||
begin
|
||||
if is_class(current_procinfo.procdef._class) then
|
||||
if is_class(current_objectdef) then
|
||||
begin
|
||||
include(current_procinfo.flags,pi_needs_implicit_finally);
|
||||
srsym:=search_class_member(current_procinfo.procdef._class,'NEWINSTANCE');
|
||||
srsym:=search_class_member(current_objectdef,'NEWINSTANCE');
|
||||
if assigned(srsym) and
|
||||
(srsym.typ=procsym) then
|
||||
begin
|
||||
@ -300,17 +299,15 @@ implementation
|
||||
internalerror(200305108);
|
||||
end
|
||||
else
|
||||
if is_object(current_procinfo.procdef._class) then
|
||||
if is_object(current_objectdef) then
|
||||
begin
|
||||
hdef:=current_procinfo.procdef._class;
|
||||
hdef:=tpointerdef.create(hdef);
|
||||
{ parameter 3 : vmt_offset }
|
||||
{ parameter 2 : address of pointer to vmt,
|
||||
this is required to allow setting the vmt to -1 to indicate
|
||||
that memory was allocated }
|
||||
{ parameter 1 : self pointer }
|
||||
para:=ccallparanode.create(
|
||||
cordconstnode.create(current_procinfo.procdef._class.vmt_offset,s32inttype,false),
|
||||
cordconstnode.create(current_objectdef.vmt_offset,s32inttype,false),
|
||||
ccallparanode.create(
|
||||
ctypeconvnode.create_internal(
|
||||
load_vmt_pointer_node,
|
||||
@ -341,9 +338,9 @@ implementation
|
||||
|
||||
{ maybe call BeforeDestruction for classes }
|
||||
if (current_procinfo.procdef.proctypeoption=potype_destructor) and
|
||||
is_class(current_procinfo.procdef._class) then
|
||||
is_class(current_objectdef) then
|
||||
begin
|
||||
srsym:=search_class_member(current_procinfo.procdef._class,'BEFOREDESTRUCTION');
|
||||
srsym:=search_class_member(current_objectdef,'BEFOREDESTRUCTION');
|
||||
if assigned(srsym) and
|
||||
(srsym.typ=procsym) then
|
||||
begin
|
||||
@ -373,7 +370,7 @@ implementation
|
||||
begin
|
||||
result:=internalstatements(newstatement);
|
||||
|
||||
if assigned(current_procinfo.procdef._class) then
|
||||
if assigned(current_objectdef) then
|
||||
begin
|
||||
{ Don't test self and the vmt here. The reason is that }
|
||||
{ a constructor already checks whether these are valid }
|
||||
@ -384,9 +381,9 @@ implementation
|
||||
current_settings.localswitches:=oldlocalswitches-[cs_check_object,cs_check_range];
|
||||
{ maybe call AfterConstruction for classes }
|
||||
if (current_procinfo.procdef.proctypeoption=potype_constructor) and
|
||||
is_class(current_procinfo.procdef._class) then
|
||||
is_class(current_objectdef) then
|
||||
begin
|
||||
srsym:=search_class_member(current_procinfo.procdef._class,'AFTERCONSTRUCTION');
|
||||
srsym:=search_class_member(current_objectdef,'AFTERCONSTRUCTION');
|
||||
if assigned(srsym) and
|
||||
(srsym.typ=procsym) then
|
||||
begin
|
||||
@ -410,9 +407,9 @@ implementation
|
||||
{ a destructor needs a help procedure }
|
||||
if (current_procinfo.procdef.proctypeoption=potype_destructor) then
|
||||
begin
|
||||
if is_class(current_procinfo.procdef._class) then
|
||||
if is_class(current_objectdef) then
|
||||
begin
|
||||
srsym:=search_class_member(current_procinfo.procdef._class,'FREEINSTANCE');
|
||||
srsym:=search_class_member(current_objectdef,'FREEINSTANCE');
|
||||
if assigned(srsym) and
|
||||
(srsym.typ=procsym) then
|
||||
begin
|
||||
@ -434,16 +431,16 @@ implementation
|
||||
internalerror(200305108);
|
||||
end
|
||||
else
|
||||
if is_object(current_procinfo.procdef._class) then
|
||||
if is_object(current_objectdef) then
|
||||
begin
|
||||
{ finalize object data }
|
||||
if current_procinfo.procdef._class.needs_inittable then
|
||||
if current_objectdef.needs_inittable then
|
||||
addstatement(newstatement,finalize_data_node(load_self_node));
|
||||
{ parameter 3 : vmt_offset }
|
||||
{ parameter 2 : pointer to vmt }
|
||||
{ parameter 1 : self pointer }
|
||||
para:=ccallparanode.create(
|
||||
cordconstnode.create(current_procinfo.procdef._class.vmt_offset,s32inttype,false),
|
||||
cordconstnode.create(current_objectdef.vmt_offset,s32inttype,false),
|
||||
ccallparanode.create(
|
||||
ctypeconvnode.create_internal(
|
||||
load_vmt_pointer_node,
|
||||
@ -474,14 +471,14 @@ implementation
|
||||
|
||||
{ a constructor needs call destructor (if available) when it
|
||||
is not inherited }
|
||||
if assigned(current_procinfo.procdef._class) and
|
||||
if assigned(current_objectdef) and
|
||||
(current_procinfo.procdef.proctypeoption=potype_constructor) then
|
||||
begin
|
||||
{ Don't test self and the vmt here. See generate_bodyexit_block }
|
||||
{ why (JM) }
|
||||
oldlocalswitches:=current_settings.localswitches;
|
||||
current_settings.localswitches:=oldlocalswitches-[cs_check_object,cs_check_range];
|
||||
pd:=current_procinfo.procdef._class.Finddestructor;
|
||||
pd:=current_objectdef.Finddestructor;
|
||||
if assigned(pd) then
|
||||
begin
|
||||
{ if vmt<>0 then call destructor }
|
||||
@ -691,9 +688,10 @@ implementation
|
||||
|
||||
procedure tcgprocinfo.generate_code;
|
||||
var
|
||||
oldprocinfo : tprocinfo;
|
||||
old_current_procinfo : tprocinfo;
|
||||
oldmaxfpuregisters : longint;
|
||||
oldfilepos : tfileposinfo;
|
||||
old_current_objectdef : tobjectdef;
|
||||
templist : TAsmList;
|
||||
headertai : tai;
|
||||
i : integer;
|
||||
@ -717,12 +715,14 @@ implementation
|
||||
if assigned(tg) then
|
||||
internalerror(200309201);
|
||||
|
||||
oldprocinfo:=current_procinfo;
|
||||
old_current_procinfo:=current_procinfo;
|
||||
oldfilepos:=current_filepos;
|
||||
old_current_objectdef:=current_objectdef;
|
||||
oldmaxfpuregisters:=current_settings.maxfpuregisters;
|
||||
|
||||
current_procinfo:=self;
|
||||
current_filepos:=entrypos;
|
||||
current_objectdef:=procdef._class;
|
||||
|
||||
templist:=TAsmList.create;
|
||||
|
||||
@ -1139,7 +1139,8 @@ implementation
|
||||
templist.free;
|
||||
current_settings.maxfpuregisters:=oldmaxfpuregisters;
|
||||
current_filepos:=oldfilepos;
|
||||
current_procinfo:=oldprocinfo;
|
||||
current_objectdef:=old_current_objectdef;
|
||||
current_procinfo:=old_current_procinfo;
|
||||
end;
|
||||
|
||||
|
||||
@ -1266,21 +1267,22 @@ implementation
|
||||
|
||||
procedure tcgprocinfo.parse_body;
|
||||
var
|
||||
oldprocinfo : tprocinfo;
|
||||
oldblock_type : tblock_type;
|
||||
old_current_procinfo : tprocinfo;
|
||||
old_block_type : tblock_type;
|
||||
st : TSymtable;
|
||||
old_current_objectdef : tobjectdef;
|
||||
begin
|
||||
oldprocinfo:=current_procinfo;
|
||||
oldblock_type:=block_type;
|
||||
|
||||
{ reset break and continue labels }
|
||||
block_type:=bt_body;
|
||||
old_current_procinfo:=current_procinfo;
|
||||
old_block_type:=block_type;
|
||||
old_current_objectdef:=current_objectdef;
|
||||
|
||||
current_procinfo:=self;
|
||||
current_objectdef:=procdef._class;
|
||||
|
||||
{ calculate the lexical level }
|
||||
if procdef.parast.symtablelevel>maxnesting then
|
||||
Message(parser_e_too_much_lexlevel);
|
||||
block_type:=bt_body;
|
||||
|
||||
{$ifdef state_tracking}
|
||||
{ aktstate:=Tstate_storage.create;}
|
||||
@ -1383,10 +1385,11 @@ implementation
|
||||
{ aktstate.destroy;}
|
||||
{$endif state_tracking}
|
||||
|
||||
current_procinfo:=oldprocinfo;
|
||||
current_objectdef:=old_current_objectdef;
|
||||
current_procinfo:=old_current_procinfo;
|
||||
|
||||
{ Restore old state }
|
||||
block_type:=oldblock_type;
|
||||
block_type:=old_block_type;
|
||||
end;
|
||||
|
||||
|
||||
@ -1526,23 +1529,22 @@ implementation
|
||||
|
||||
var
|
||||
old_current_procinfo : tprocinfo;
|
||||
old_current_objectdef : tobjectdef;
|
||||
pdflags : tpdflags;
|
||||
pd,firstpd : tprocdef;
|
||||
s : string;
|
||||
begin
|
||||
{ save old state }
|
||||
old_current_procinfo:=current_procinfo;
|
||||
old_current_objectdef:=current_objectdef;
|
||||
|
||||
{ reset current_procinfo.procdef to nil to be sure that nothing is writing
|
||||
to an other procdef }
|
||||
current_procinfo:=nil;
|
||||
current_objectdef:=nil;
|
||||
|
||||
{ parse procedure declaration }
|
||||
if assigned(old_current_procinfo) and
|
||||
assigned(old_current_procinfo.procdef) then
|
||||
pd:=parse_proc_dec(old_current_procinfo.procdef._class)
|
||||
else
|
||||
pd:=parse_proc_dec(nil);
|
||||
pd:=parse_proc_dec(old_current_objectdef);
|
||||
|
||||
{ set the default function options }
|
||||
if parse_only then
|
||||
@ -1586,7 +1588,7 @@ implementation
|
||||
begin
|
||||
{ A method must be forward defined (in the object declaration) }
|
||||
if assigned(pd._class) and
|
||||
(not assigned(old_current_procinfo.procdef._class)) then
|
||||
(not assigned(old_current_objectdef)) then
|
||||
begin
|
||||
MessagePos1(pd.fileinfo,parser_e_header_dont_match_any_member,pd.fullprocname(false));
|
||||
tprocsym(pd.procsym).write_parameter_lists(pd);
|
||||
@ -1667,6 +1669,7 @@ implementation
|
||||
current_asmdata.DefineAsmSymbol(pd.mangledname,AB_LOCAL,AT_FUNCTION);
|
||||
end;
|
||||
|
||||
current_objectdef:=old_current_objectdef;
|
||||
current_procinfo:=old_current_procinfo;
|
||||
end;
|
||||
|
||||
|
||||
@ -118,7 +118,7 @@ type
|
||||
constructor create(optype : tcoperand);virtual;
|
||||
destructor destroy;override;
|
||||
{ converts the instruction to an instruction how it's used by the assembler writer
|
||||
and concats it to the passed list. The newly created item is returned if the
|
||||
and concats it to the passed list. The newly created item is returned if the
|
||||
instruction was valid, otherwise nil is returned }
|
||||
function ConcatInstruction(p:TAsmList) : tai;virtual;
|
||||
Procedure Swapoperands;
|
||||
@ -693,7 +693,7 @@ end;
|
||||
Function TOperand.SetupSelf:boolean;
|
||||
Begin
|
||||
SetupSelf:=false;
|
||||
if assigned(current_procinfo.procdef._class) then
|
||||
if assigned(current_objectdef) then
|
||||
SetupSelf:=setupvar('self',false)
|
||||
else
|
||||
Message(asmr_e_cannot_use_SELF_outside_a_method);
|
||||
@ -1294,7 +1294,7 @@ Begin
|
||||
base:=Copy(s,1,i-1);
|
||||
delete(s,1,i);
|
||||
if base='SELF' then
|
||||
st:=current_procinfo.procdef._class.symtable
|
||||
st:=current_objectdef.symtable
|
||||
else
|
||||
begin
|
||||
asmsearchsym(base,sym,srsymtable);
|
||||
|
||||
@ -3863,14 +3863,14 @@ implementation
|
||||
|
||||
function tobjectdef.GetTypeName:string;
|
||||
begin
|
||||
if (self <> current_objectdef) then
|
||||
GetTypeName:=typename
|
||||
{ in this case we will go in endless recursion, because then }
|
||||
{ there is no tsym associated yet with the def. It can occur }
|
||||
{ (tests/webtbf/tw4757.pp), so for now give a generic name }
|
||||
{ instead of the actual type name }
|
||||
if not assigned(typesym) then
|
||||
result:='<Currently Parsed Class>'
|
||||
else
|
||||
{ in this case we will go in endless recursion, because then }
|
||||
{ there is no tsym associated yet with the def. It can occur }
|
||||
{ (tests/webtbf/tw4757.pp), so for now give a generic name }
|
||||
{ instead of the actual type name }
|
||||
GetTypeName:='<Currently Parsed Class>';
|
||||
result:=typename;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
@ -1579,14 +1579,8 @@ implementation
|
||||
(srsymtable.defowner.owner.iscurrentunit) then
|
||||
topclass:=tobjectdef(srsymtable.defowner)
|
||||
else
|
||||
begin
|
||||
if assigned(current_procinfo) then
|
||||
topclass:=current_procinfo.procdef._class;
|
||||
end;
|
||||
if assigned(current_procinfo) then
|
||||
context:=current_procinfo.procdef._class
|
||||
else
|
||||
context:=nil;
|
||||
topclass:=current_objectdef;
|
||||
context:=current_objectdef;
|
||||
if tsym(srsym).is_visible_for_object(topclass,context) then
|
||||
begin
|
||||
{ we need to know if a procedure references symbols
|
||||
@ -1636,8 +1630,8 @@ implementation
|
||||
srsym:=tsym(srsymtable.FindWithHash(hashedid));
|
||||
if assigned(srsym) and
|
||||
not(srsym.typ in [fieldvarsym,paravarsym]) and
|
||||
(not assigned(current_procinfo) or
|
||||
tsym(srsym).is_visible_for_object(current_procinfo.procdef._class,current_procinfo.procdef._class)) then
|
||||
(not assigned(current_objectdef) or
|
||||
tsym(srsym).is_visible_for_object(current_objectdef,current_objectdef)) then
|
||||
begin
|
||||
{ we need to know if a procedure references symbols
|
||||
in the static symtable, because then it can't be
|
||||
@ -1697,20 +1691,15 @@ implementation
|
||||
function searchsym_in_class(classh,contextclassh:tobjectdef;const s : TIDString;out srsym:tsym;out srsymtable:TSymtable):boolean;
|
||||
var
|
||||
hashedid : THashedIDString;
|
||||
currentclassh : tobjectdef;
|
||||
begin
|
||||
result:=false;
|
||||
hashedid.id:=s;
|
||||
if assigned(current_procinfo) and assigned(current_procinfo.procdef) then
|
||||
currentclassh:=current_procinfo.procdef._class
|
||||
else
|
||||
currentclassh:=nil;
|
||||
while assigned(classh) do
|
||||
begin
|
||||
srsymtable:=classh.symtable;
|
||||
srsym:=tsym(srsymtable.FindWithHash(hashedid));
|
||||
if assigned(srsym) and
|
||||
tsym(srsym).is_visible_for_object(contextclassh,currentclassh) then
|
||||
tsym(srsym).is_visible_for_object(contextclassh,current_objectdef) then
|
||||
begin
|
||||
addsymref(srsym);
|
||||
result:=true;
|
||||
@ -2155,7 +2144,6 @@ implementation
|
||||
class_tobject:=nil;
|
||||
interface_iunknown:=nil;
|
||||
rec_tguid:=nil;
|
||||
current_objectdef:=nil;
|
||||
dupnr:=0;
|
||||
end;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user