1 {
2     Copyright (c) 1998-2002 by Florian Klaempfl, Daniel Mantione
3 
4     Does the parsing and codegeneration at subroutine level
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 
20  ****************************************************************************
21 }
22 unit psub;
23 
24 {$i fpcdefs.inc}
25 
26 interface
27 
28     uses
29       globals,
30       node,nbas,
31       symdef,procinfo,optdfa;
32 
33     type
34       tcgprocinfo = class(tprocinfo)
35       private
36         procedure CreateInlineInfo;
37         { returns the node which is the start of the user code, this is needed by the dfa }
GetUserCodenull38         function GetUserCode: tnode;
39         procedure maybe_add_constructor_wrapper(var tocode: tnode; withexceptblock: boolean);
40         procedure add_entry_exit_code;
41         procedure setup_tempgen;
42       public
43         { code for the subroutine as tree }
44         code : tnode;
45         { positions in the tree for init/final }
46         entry_asmnode,
47         loadpara_asmnode,
48         exitlabel_asmnode,
49         stackcheck_asmnode,
50         init_asmnode,
51         final_asmnode : tasmnode;
52         final_used : boolean;
53         dfabuilder : TDFABuilder;
54 
55         destructor  destroy;override;
56 
calc_stackframe_sizenull57         function calc_stackframe_size : longint;override;
58 
59         procedure printproc(pass:string);
60         procedure generate_code;
61         procedure generate_code_tree;
62         procedure generate_exceptfilter(nestedpi: tcgprocinfo);
63         procedure resetprocdef;
64         procedure add_to_symtablestack;
65         procedure remove_from_symtablestack;
66         procedure parse_body;
67 
has_assembler_childnull68         function has_assembler_child : boolean;
69       end;
70 
71 
72     procedure printnode_reset;
73 
74     { reads the declaration blocks }
75     procedure read_declarations(islibrary : boolean);
76 
77     { reads declarations in the interface part of a unit }
78     procedure read_interface_declarations;
79 
80     { reads any routine in the implementation, or a non-method routine
81       declaration in the interface (depending on whether or not parse_only is
82       true) }
83     procedure read_proc(isclassmethod:boolean; usefwpd: tprocdef;isgeneric:boolean);
84 
85     { parses only the body of a non nested routine; needs a correctly setup pd }
86     procedure read_proc_body(pd:tprocdef);
87 
88     procedure import_external_proc(pd:tprocdef);
89 
90 
91 implementation
92 
93     uses
94        sysutils,
95        { common }
96        cutils,
97        { global }
98        globtype,tokens,verbose,comphook,constexp,
99        systems,cpubase,aasmbase,aasmtai,aasmdata,
100        { symtable }
101        symconst,symbase,symsym,symtype,symtable,defutil,defcmp,symcreat,
102        paramgr,
103        fmodule,
104        { pass 1 }
105        nutils,ngenutil,nld,ncal,ncon,nflw,nadd,ncnv,nmem,
106        pass_1,
107     {$ifdef state_tracking}
108        nstate,
109     {$endif state_tracking}
110        { pass 2 }
111 {$ifndef NOPASS2}
112        pass_2,
113 {$endif}
114        { parser }
115        scanner,gendef,
116        pbase,pstatmnt,pdecl,pdecsub,pexports,pgenutil,pparautl,
117        { codegen }
118        tgobj,cgbase,cgobj,hlcgobj,hlcgcpu,dbgbase,
119 {$ifdef llvm}
120       { override create_hlcodegen from hlcgcpu }
121       hlcgllvm,
122 {$endif}
123        ncgutil,
124        optbase,
125        opttail,
126        optcse,
127        optloop,
128        optconstprop,
129        optdeadstore,
130        optloadmodifystore,
131        optutils
132 {$if defined(arm)}
133        ,cpuinfo
134 {$endif arm}
135        {$ifndef NOOPT}
136        ,aopt
137        {$endif}
138        ;
139 
checknodeinliningnull140     function checknodeinlining(procdef: tprocdef): boolean;
141       var
142         i : integer;
143         currpara : tparavarsym;
144       begin
145         result := false;
146         { this code will never be used (only specialisations can be inlined),
147           and moreover contains references to defs that are not stored in the
148           ppu file }
149         if df_generic in current_procinfo.procdef.defoptions then
150           exit;
151         if pi_has_assembler_block in current_procinfo.flags then
152           begin
153             Message1(parser_h_not_supported_for_inline,'assembler');
154             Message(parser_h_inlining_disabled);
155             exit;
156           end;
157         if pi_has_global_goto in current_procinfo.flags then
158           begin
159             Message1(parser_h_not_supported_for_inline,'global goto');
160             Message(parser_h_inlining_disabled);
161             exit;
162           end;
163         if pi_has_nested_exit in current_procinfo.flags then
164           begin
165             Message1(parser_h_not_supported_for_inline,'nested exit');
166             Message(parser_h_inlining_disabled);
167             exit;
168           end;
169         if pi_calls_c_varargs in current_procinfo.flags then
170           begin
171             Message1(parser_h_not_supported_for_inline,'called C-style varargs functions');
172             Message(parser_h_inlining_disabled);
173             exit;
174           end;
175         { the compiler cannot handle inherited in inlined subroutines because
176           it tries to search for self in the symtable, however, the symtable
177           is not available }
178         if pi_has_inherited in current_procinfo.flags then
179           begin
180             Message1(parser_h_not_supported_for_inline,'inherited');
181             Message(parser_h_inlining_disabled);
182             exit;
183           end;
184         for i:=0 to procdef.paras.count-1 do
185           begin
186             currpara:=tparavarsym(procdef.paras[i]);
187             case currpara.vardef.typ of
188               formaldef :
189                 begin
190                   if (currpara.varspez in [vs_out,vs_var,vs_const,vs_constref]) then
191                     begin
192                       Message1(parser_h_not_supported_for_inline,'formal parameter');
193                       Message(parser_h_inlining_disabled);
194                       exit;
195                     end;
196                 end;
197               arraydef :
198                 begin
199                   if is_array_of_const(currpara.vardef) or
200                      is_variant_array(currpara.vardef) then
201                     begin
202                       Message1(parser_h_not_supported_for_inline,'array of const');
203                       Message(parser_h_inlining_disabled);
204                       exit;
205                     end;
206                   { open arrays might need re-basing of the index, i.e. if you pass
207                     an array[1..10] as open array, you have to add 1 to all index operations
208                     if you directly inline it }
209                   if is_open_array(currpara.vardef) then
210                     begin
211                       Message1(parser_h_not_supported_for_inline,'open array');
212                       Message(parser_h_inlining_disabled);
213                       exit;
214                     end;
215                 end;
216             end;
217         end;
218         result:=true;
219       end;
220 
221 
222 {****************************************************************************
223                       PROCEDURE/FUNCTION BODY PARSING
224 ****************************************************************************}
225 
226     procedure initializedefaultvars(p:TObject;arg:pointer);
227       var
228         b : tblocknode;
229       begin
230         if tsym(p).typ<>localvarsym then
231          exit;
232         with tabstractnormalvarsym(p) do
233          begin
234            if (vo_is_default_var in varoptions) and (vardef.size>0) then
235              begin
236                b:=tblocknode(arg);
237                b.left:=cstatementnode.create(
238                          ccallnode.createintern('fpc_zeromem',
239                            ccallparanode.create(
240                              cordconstnode.create(vardef.size,sizeuinttype,false),
241                              ccallparanode.create(
242                                caddrnode.create_internal(
243                                  cloadnode.create(tsym(p),tsym(p).owner)),
244                                  nil
245                                )
246                              )
247                            ),
248                          b.left);
249              end;
250          end;
251       end;
252 
253 
254     procedure initializevars(p:TObject;arg:pointer);
255       var
256         b : tblocknode;
257       begin
258         if not (tsym(p).typ in [localvarsym,staticvarsym]) then
259          exit;
260         with tabstractnormalvarsym(p) do
261          begin
262            if assigned(defaultconstsym) then
263             begin
264               b:=tblocknode(arg);
265               b.left:=cstatementnode.create(
266                         cassignmentnode.create(
267                             cloadnode.create(tsym(p),tsym(p).owner),
268                             cloadnode.create(defaultconstsym,defaultconstsym.owner)),
269                         b.left);
270             end
271            else
272              initializedefaultvars(p,arg);
273          end;
274       end;
275 
276 
277     procedure check_finalize_paras(p:TObject;arg:pointer);
278       begin
279         if (tsym(p).typ=paravarsym) then
280           begin
281             if tparavarsym(p).needs_finalization then
282               begin
283                 include(current_procinfo.flags,pi_needs_implicit_finally);
284                 include(current_procinfo.flags,pi_do_call);
285               end;
286             if (tparavarsym(p).varspez in [vs_value,vs_out]) and
287                (cs_create_pic in current_settings.moduleswitches) and
288                (tf_pic_uses_got in target_info.flags) and
289                is_rtti_managed_type(tparavarsym(p).vardef) then
290               include(current_procinfo.flags,pi_needs_got);
291           end;
292       end;
293 
294 
295     procedure check_finalize_locals(p:TObject;arg:pointer);
296       begin
297         { include the result: it needs to be finalized in case an exception }
298         { occurs                                                            }
299         if (tsym(p).typ=localvarsym) and
300            (tlocalvarsym(p).refs>0) and
301            is_managed_type(tlocalvarsym(p).vardef) then
302           begin
303             include(current_procinfo.flags,pi_needs_implicit_finally);
304             include(current_procinfo.flags,pi_do_call);
305             if is_rtti_managed_type(tlocalvarsym(p).vardef) and
306               (cs_create_pic in current_settings.moduleswitches) and
307               (tf_pic_uses_got in target_info.flags) then
308               include(current_procinfo.flags,pi_needs_got);
309           end;
310       end;
311 
312 
blocknull313     function block(islibrary : boolean) : tnode;
314       var
315         oldfilepos: tfileposinfo;
316       begin
317          { parse const,types and vars }
318          read_declarations(islibrary);
319 
320          { do we have an assembler block without the po_assembler?
321            we should allow this for Delphi compatibility (PFV) }
322          if (token=_ASM) and (m_delphi in current_settings.modeswitches) then
323            include(current_procinfo.procdef.procoptions,po_assembler);
324 
325          { Handle assembler block different }
326          if (po_assembler in current_procinfo.procdef.procoptions) then
327           begin
328             block:=assembler_block;
329             exit;
330           end;
331 
332          {Unit initialization?.}
333          if (
334              assigned(current_procinfo.procdef.localst) and
335              (current_procinfo.procdef.localst.symtablelevel=main_program_level) and
336              (current_module.is_unit or islibrary)
337             ) then
338            begin
339              if (token=_END) then
340                 begin
341                    consume(_END);
342                    { We need at least a node, else the entry/exit code is not
343                      generated and thus no PASCALMAIN symbol which we need (PFV) }
344                    if islibrary then
345                     block:=cnothingnode.create
346                    else
347                     block:=nil;
348                 end
349               else
350                 begin
351                    if token=_INITIALIZATION then
352                      begin
353                         { The library init code is already called and does not
354                           need to be in the initfinal table (PFV) }
355                         block:=statement_block(_INITIALIZATION);
356                      end
357                    else if token=_FINALIZATION then
358                      begin
359                        { when a unit has only a finalization section, we can come to this
360                          point when we try to read the nonh existing initalization section
361                          so we've to check if we are really try to parse the finalization }
362                        if current_procinfo.procdef.proctypeoption=potype_unitfinalize then
363                          block:=statement_block(_FINALIZATION)
364                        else
365                          block:=nil;
366                      end
367                    else
368                      block:=statement_block(_BEGIN);
369                 end;
370             end
371          else
372             begin
373                { parse routine body }
374                block:=statement_block(_BEGIN);
375                { initialized variables }
376                if current_procinfo.procdef.localst.symtabletype=localsymtable then
377                  begin
378                    { initialization of local variables with their initial
379                      values: part of function entry }
380                    oldfilepos:=current_filepos;
381                    current_filepos:=current_procinfo.entrypos;
382                    current_procinfo.procdef.localst.SymList.ForEachCall(@initializevars,block);
383                    current_filepos:=oldfilepos;
384                  end
385                else if current_procinfo.procdef.localst.symtabletype=staticsymtable then
386                  begin
387                    { for program and unit initialization code we also need to
388                      initialize the local variables used of Default() }
389                    oldfilepos:=current_filepos;
390                    current_filepos:=current_procinfo.entrypos;
391                    current_procinfo.procdef.localst.SymList.ForEachCall(@initializedefaultvars,block);
392                    current_filepos:=oldfilepos;
393                  end;
394 
395                if assigned(current_procinfo.procdef.parentfpstruct) then
396                  begin
397                    { we only do this after the code has been parsed because
398                      otherwise for-loop counters moved to the struct cause
399                      errors; we still do it nevertheless to prevent false
400                      "unused" symbols warnings and to assist debug info
401                      generation }
402                    redirect_parentfpstruct_local_syms(current_procinfo.procdef);
403                    { finish the parentfpstruct (add padding, ...) }
404                    finish_parentfpstruct(current_procinfo.procdef);
405                  end;
406             end;
407       end;
408 
409 
410 {****************************************************************************
411                        PROCEDURE/FUNCTION COMPILING
412 ****************************************************************************}
413 
414     procedure printnode_reset;
415       begin
416         assign(printnodefile,treelogfilename);
417         {$push}{$I-}
418          rewrite(printnodefile);
419         {$pop}
420         if ioresult<>0 then
421          begin
422            Comment(V_Error,'Error creating '+treelogfilename);
423            exit;
424          end;
425         close(printnodefile);
426       end;
427 
428 
429     procedure add_label_init(p:TObject;arg:pointer);
430       begin
431         if tstoredsym(p).typ=labelsym then
432           begin
433             addstatement(tstatementnode(arg^),
434               cifnode.create(caddnode.create(equaln,
435                 ccallnode.createintern('fpc_setjmp',
436                   ccallparanode.create(cloadnode.create(tlabelsym(p).jumpbuf,tlabelsym(p).jumpbuf.owner),nil)),
437                 cordconstnode.create(1,sinttype,true))
438               ,cgotonode.create(tlabelsym(p)),nil)
439             );
440           end;
441       end;
442 
443 
generate_bodyentry_blocknull444     function generate_bodyentry_block:tnode;
445       var
446         srsym        : tsym;
447         para         : tcallparanode;
448         call         : tcallnode;
449         newstatement : tstatementnode;
450         def          : tabstractrecorddef;
451       begin
452         result:=internalstatements(newstatement);
453 
454         if assigned(current_structdef) then
455           begin
456             { a constructor needs a help procedure }
457             if (current_procinfo.procdef.proctypeoption=potype_constructor) then
458               begin
459                 if is_class(current_structdef) or
460                     (
461                       is_objectpascal_helper(current_structdef) and
462                       is_class(tobjectdef(current_structdef).extendeddef)
463                     ) then
464                   begin
465                     if is_objectpascal_helper(current_structdef) then
466                       def:=tabstractrecorddef(tobjectdef(current_structdef).extendeddef)
467                     else
468                       def:=current_structdef;
469                     srsym:=search_struct_member(def,'NEWINSTANCE');
470                     if assigned(srsym) and
471                        (srsym.typ=procsym) then
472                       begin
473                         { if vmt=1 then newinstance }
474                         addstatement(newstatement,cifnode.create(
475                             caddnode.create_internal(equaln,
476                                 ctypeconvnode.create_internal(
477                                     load_vmt_pointer_node,
478                                     voidpointertype),
479                                 cpointerconstnode.create(1,voidpointertype)),
480                             cassignmentnode.create(
481                                 ctypeconvnode.create_internal(
482                                     load_self_pointer_node,
483                                     voidpointertype),
484                                 ccallnode.create(nil,tprocsym(srsym),srsym.owner,
485                                   ctypeconvnode.create_internal(load_self_pointer_node,cclassrefdef.create(current_structdef)),
486                                   [],nil)),
487                             nil));
488                       end
489                     else
490                       internalerror(200305108);
491                   end
492                 else
493                   if is_object(current_structdef) then
494                     begin
495                       { parameter 3 : vmt_offset }
496                       { parameter 2 : address of pointer to vmt,
497                         this is required to allow setting the vmt to -1 to indicate
498                         that memory was allocated }
499                       { parameter 1 : self pointer }
500                       para:=ccallparanode.create(
501                                 cordconstnode.create(tobjectdef(current_structdef).vmt_offset,s32inttype,false),
502                             ccallparanode.create(
503                                 ctypeconvnode.create_internal(
504                                     load_vmt_pointer_node,
505                                     voidpointertype),
506                             ccallparanode.create(
507                                 ctypeconvnode.create_internal(
508                                     load_self_pointer_node,
509                                     voidpointertype),
510                             nil)));
511                       addstatement(newstatement,cassignmentnode.create(
512                           ctypeconvnode.create_internal(
513                               load_self_pointer_node,
514                               voidpointertype),
515                           ccallnode.createintern('fpc_help_constructor',para)));
516                     end
517                 else
518                   if is_javaclass(current_structdef) or
519                      ((target_info.system in systems_jvm) and
520                       is_record(current_structdef)) then
521                     begin
522                       if (current_procinfo.procdef.proctypeoption=potype_constructor) and
523                          not current_procinfo.ConstructorCallingConstructor then
524                        begin
525                          { call inherited constructor }
526                          if is_javaclass(current_structdef) then
527                            srsym:=search_struct_member_no_helper(tobjectdef(current_structdef).childof,'CREATE')
528                          else
529                            srsym:=search_struct_member_no_helper(java_fpcbaserecordtype,'CREATE');
530                          if assigned(srsym) and
531                             (srsym.typ=procsym) then
532                            begin
533                              call:=ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[cnf_inherited],nil);
534                              exclude(tcallnode(call).callnodeflags,cnf_return_value_used);
535                              addstatement(newstatement,call);
536                            end
537                          else
538                            internalerror(2011010312);
539                        end;
540                     end
541                 else
542                   if not is_record(current_structdef) and
543                      not (
544                             is_objectpascal_helper(current_structdef) and
545                             (tobjectdef(current_structdef).extendeddef.typ<>objectdef)
546                          ) then
547                     internalerror(200305103);
548                 { if self=nil then exit
549                   calling fail instead of exit is useless because
550                   there is nothing to dispose (PFV) }
551                 if is_class_or_object(current_structdef) then
552                   addstatement(newstatement,cifnode.create(
553                     caddnode.create(equaln,
554                         load_self_pointer_node,
555                         cnilnode.create),
556                     cexitnode.create(nil),
557                     nil));
558               end;
559 
560             { maybe call BeforeDestruction for classes }
561             if (current_procinfo.procdef.proctypeoption=potype_destructor) and
562                is_class(current_structdef) then
563               begin
564                 srsym:=search_struct_member(current_structdef,'BEFOREDESTRUCTION');
565                 if assigned(srsym) and
566                    (srsym.typ=procsym) then
567                   begin
568                     { if vmt>0 then beforedestruction }
569                     addstatement(newstatement,cifnode.create(
570                         caddnode.create(gtn,
571                             ctypeconvnode.create_internal(
572                               load_vmt_pointer_node,ptrsinttype),
573                             ctypeconvnode.create_internal(
574                               cnilnode.create,ptrsinttype)),
575                         ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[],nil),
576                         nil));
577                   end
578                 else
579                   internalerror(200305104);
580               end;
581           end;
582         if m_non_local_goto in current_settings.modeswitches then
583           tsymtable(current_procinfo.procdef.localst).SymList.ForEachCall(@add_label_init,@newstatement);
584       end;
585 
586 
generate_bodyexit_blocknull587     function generate_bodyexit_block:tnode;
588       var
589         srsym : tsym;
590         para : tcallparanode;
591         newstatement : tstatementnode;
592         oldlocalswitches: tlocalswitches;
593       begin
594         result:=internalstatements(newstatement);
595 
596         if assigned(current_structdef) then
597           begin
598             { Don't test self and the vmt here. The reason is that  }
599             { a constructor already checks whether these are valid  }
600             { before. Further, in case of TThread the thread may    }
601             { free the class instance right after AfterConstruction }
602             { has been called, so it may no longer be valid (JM)    }
603             oldlocalswitches:=current_settings.localswitches;
604             current_settings.localswitches:=oldlocalswitches-[cs_check_object,cs_check_range];
605 
606             { a destructor needs a help procedure }
607             if (current_procinfo.procdef.proctypeoption=potype_destructor) then
608               begin
609                 if is_class(current_structdef) then
610                   begin
611                     srsym:=search_struct_member(current_structdef,'FREEINSTANCE');
612                     if assigned(srsym) and
613                        (srsym.typ=procsym) then
614                       begin
615                         { if self<>0 and vmt<>0 then freeinstance }
616                         addstatement(newstatement,cifnode.create(
617                             caddnode.create(andn,
618                                 caddnode.create(unequaln,
619                                     load_self_pointer_node,
620                                     cnilnode.create),
621                                 caddnode.create(unequaln,
622                                     ctypeconvnode.create(
623                                         load_vmt_pointer_node,
624                                         voidpointertype),
625                                     cpointerconstnode.create(0,voidpointertype))),
626                             ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[],nil),
627                             nil));
628                       end
629                     else
630                       internalerror(200305108);
631                   end
632                 else
633                   if is_object(current_structdef) then
634                     begin
635                       { finalize object data, but only if not in inherited call }
636                       if is_managed_type(current_structdef) then
637                         begin
638                           addstatement(newstatement,cifnode.create(
639                             caddnode.create(unequaln,
640                               ctypeconvnode.create_internal(load_vmt_pointer_node,voidpointertype),
641                               cnilnode.create),
642                             cnodeutils.finalize_data_node(load_self_node),
643                             nil));
644                         end;
645                       { parameter 3 : vmt_offset }
646                       { parameter 2 : pointer to vmt }
647                       { parameter 1 : self pointer }
648                       para:=ccallparanode.create(
649                                 cordconstnode.create(tobjectdef(current_structdef).vmt_offset,s32inttype,false),
650                             ccallparanode.create(
651                                 ctypeconvnode.create_internal(
652                                     load_vmt_pointer_node,
653                                     voidpointertype),
654                             ccallparanode.create(
655                                 ctypeconvnode.create_internal(
656                                     load_self_pointer_node,
657                                     voidpointertype),
658                             nil)));
659                       addstatement(newstatement,
660                           ccallnode.createintern('fpc_help_destructor',para));
661                     end
662                 else if is_javaclass(current_structdef) then
663                   begin
664                     { nothing to do }
665                   end
666                 else
667                   internalerror(200305105);
668               end;
669             current_settings.localswitches:=oldlocalswitches;
670           end;
671       end;
672 
673 
674 {****************************************************************************
675                                   TCGProcInfo
676 ****************************************************************************}
677 
678      destructor tcgprocinfo.destroy;
679        begin
680          code.free;
681          if not final_used then
682            final_asmnode.free;
683          inherited destroy;
684        end;
685 
686 
tcgprocinfo.calc_stackframe_sizenull687     function tcgprocinfo.calc_stackframe_size:longint;
688       begin
689         result:=Align(tg.direction*tg.lasttemp,current_settings.alignment.localalignmin);
690       end;
691 
692 
693     procedure tcgprocinfo.printproc(pass:string);
694       begin
695         assign(printnodefile,treelogfilename);
696         {$push}{$I-}
697          append(printnodefile);
698          if ioresult<>0 then
699           rewrite(printnodefile);
700         {$pop}
701         if ioresult<>0 then
702          begin
703            Comment(V_Error,'Error creating '+treelogfilename);
704            exit;
705          end;
706         writeln(printnodefile);
707         writeln(printnodefile,'*******************************************************************************');
708         writeln(printnodefile, pass);
709         writeln(printnodefile,procdef.fullprocname(false));
710         writeln(printnodefile,'*******************************************************************************');
711         printnode(printnodefile,code);
712         close(printnodefile);
713       end;
714 
715 
716     procedure tcgprocinfo.maybe_add_constructor_wrapper(var tocode: tnode; withexceptblock: boolean);
717       var
718         oldlocalswitches: tlocalswitches;
719         srsym: tsym;
720         constructionblock,
721         exceptblock,
722         newblock: tblocknode;
723         newstatement: tstatementnode;
724         pd: tprocdef;
725         constructionsuccessful: tlocalvarsym;
726       begin
727         if assigned(procdef.struct) and
728            (procdef.proctypeoption=potype_constructor) then
729           begin
730             withexceptblock:=
731               withexceptblock and
732               not(target_info.system in systems_garbage_collected_managed_types);
733             { Don't test self and the vmt here. See generate_bodyexit_block }
734             { why (JM)                                                      }
735             oldlocalswitches:=current_settings.localswitches;
736             current_settings.localswitches:=oldlocalswitches-[cs_check_object,cs_check_range];
737 
738             { call AfterConstruction for classes }
739             constructionsuccessful:=nil;
740             if is_class(procdef.struct) then
741               begin
742                 constructionsuccessful:=clocalvarsym.create(internaltypeprefixName[itp_vmt_afterconstruction_local],vs_value,ptrsinttype,[]);
743                 procdef.localst.insert(constructionsuccessful,false);
744                 srsym:=search_struct_member(procdef.struct,'AFTERCONSTRUCTION');
745                 if not assigned(srsym) or
746                    (srsym.typ<>procsym) then
747                   internalerror(200305106);
748 
749                 current_filepos:=entrypos;
750                 constructionblock:=internalstatements(newstatement);
751                 { initialise constructionsuccessful with -1, indicating that
752                   the construction was not successful and hence
753                   beforedestruction should not be called if a destructor is
754                   called from the constructor }
755                 addstatement(newstatement,cassignmentnode.create(
756                   cloadnode.create(constructionsuccessful,procdef.localst),
757                   genintconstnode(-1))
758                 );
759                 { first execute all constructor code. If no exception
760                   occurred then we will execute afterconstruction,
761                   otherwise we won't (the exception will jump over us) }
762                 addstatement(newstatement,tocode);
763                 current_filepos:=exitpos;
764                 { if implicit finally node wasn't created, then exit label and
765                   finalization code must be handled here and placed before
766                   afterconstruction }
767                 if not ((pi_needs_implicit_finally in flags) and
768                   (cs_implicit_exceptions in current_settings.moduleswitches)) then
769                   begin
770                     include(tocode.flags,nf_block_with_exit);
771                     addstatement(newstatement,final_asmnode);
772                     cnodeutils.procdef_block_add_implicit_finalize_nodes(procdef,newstatement);
773                     final_used:=true;
774                   end;
775 
776                 { construction successful -> beforedestruction should be called
777                   if an exception happens now }
778                 addstatement(newstatement,cassignmentnode.create(
779                   cloadnode.create(constructionsuccessful,procdef.localst),
780                   genintconstnode(1))
781                 );
782                 { Self can be nil when fail is called }
783                 { if self<>nil and vmt<>nil then afterconstruction }
784                 addstatement(newstatement,cifnode.create(
785                   caddnode.create(andn,
786                     caddnode.create(unequaln,
787                       load_self_node,
788                       cnilnode.create),
789                     caddnode.create(unequaln,
790                       load_vmt_pointer_node,
791                       cnilnode.create)),
792                     ccallnode.create(nil,tprocsym(srsym),srsym.owner,load_self_node,[],nil),
793                     nil));
794                 tocode:=constructionblock;
795               end;
796 
797             if withexceptblock and (procdef.struct.typ=objectdef) then
798               begin
799                 { Generate the implicit "fail" code for a constructor (destroy
800                   in case an exception happened) }
801                 pd:=tobjectdef(procdef.struct).find_destructor;
802                 { this will always be the case for classes, since tobject has
803                   a destructor }
804                 if assigned(pd) or is_object(procdef.struct) then
805                   begin
806                     current_filepos:=exitpos;
807                     exceptblock:=internalstatements(newstatement);
808                     { first free the instance if non-nil }
809                     if assigned(pd) then
810                       { if vmt<>0 then call destructor }
811                       addstatement(newstatement,
812                         cifnode.create(
813                           caddnode.create(unequaln,
814                             load_vmt_pointer_node,
815                             cnilnode.create),
816                           { cnf_create_failed -> don't call BeforeDestruction }
817                           ccallnode.create(nil,tprocsym(pd.procsym),pd.procsym.owner,load_self_node,[cnf_create_failed],nil),
818                           nil))
819                     else
820                       { object without destructor, call 'fail' helper }
821                       addstatement(newstatement,
822                         ccallnode.createintern('fpc_help_fail',
823                           ccallparanode.create(
824                             cordconstnode.create(tobjectdef(procdef.struct).vmt_offset,s32inttype,false),
825                           ccallparanode.create(
826                             ctypeconvnode.create_internal(
827                               load_vmt_pointer_node,
828                               voidpointertype),
829                           ccallparanode.create(
830                             ctypeconvnode.create_internal(
831                               load_self_pointer_node,
832                               voidpointertype),
833                           nil))))
834                       );
835                     { then re-raise the exception }
836                     addstatement(newstatement,craisenode.create(nil,nil,nil));
837                     current_filepos:=entrypos;
838                     newblock:=internalstatements(newstatement);
839                     { try
840                         tocode
841                       except
842                         exceptblock
843                       end
844                     }
845                     addstatement(newstatement,ctryexceptnode.create(
846                       tocode,
847                       nil,
848                       exceptblock));
849                     tocode:=newblock;
850                   end;
851               end;
852             current_settings.localswitches:=oldlocalswitches;
853           end;
854       end;
855 
856 
857     procedure tcgprocinfo.add_entry_exit_code;
858       var
859         finalcode,
860         bodyentrycode,
861         bodyexitcode,
862         wrappedbody,
863         newblock     : tnode;
864         codestatement,
865         newstatement : tstatementnode;
866         oldfilepos   : tfileposinfo;
867         is_constructor: boolean;
868       begin
869         is_constructor:=assigned(procdef.struct) and
870           (procdef.proctypeoption=potype_constructor);
871 
872         oldfilepos:=current_filepos;
873         { Generate code/locations used at start of proc }
874         current_filepos:=entrypos;
875         entry_asmnode:=casmnode.create_get_position;
876         loadpara_asmnode:=casmnode.create_get_position;
877         stackcheck_asmnode:=casmnode.create_get_position;
878         init_asmnode:=casmnode.create_get_position;
879         bodyentrycode:=generate_bodyentry_block;
880         { Generate code/locations used at end of proc }
881         current_filepos:=exitpos;
882         exitlabel_asmnode:=casmnode.create_get_position;
883         final_asmnode:=casmnode.create_get_position;
884         final_used:=false;
885         bodyexitcode:=generate_bodyexit_block;
886         { Check if bodyexitcode is not empty }
887         with tstatementnode(tblocknode(bodyexitcode).statements) do
888           if (statement.nodetype<>nothingn) or assigned(next) then
889             { Indicate that the extra code is executed after the exit statement }
890             include(flowcontrol,fc_no_direct_exit);
891 
892         { Generate procedure by combining init+body+final,
893           depending on the implicit finally we need to add
894           an try...finally...end wrapper }
895         current_filepos:=entrypos;
896         newblock:=internalstatements(newstatement);
897         { initialization is common for all cases }
898         addstatement(newstatement,loadpara_asmnode);
899         addstatement(newstatement,stackcheck_asmnode);
900         addstatement(newstatement,entry_asmnode);
901         cnodeutils.procdef_block_add_implicit_initialize_nodes(procdef,newstatement);
902         addstatement(newstatement,init_asmnode);
903         if assigned(procdef.parentfpinitblock) then
904           begin
905             if assigned(tblocknode(procdef.parentfpinitblock).left) then
906               begin
907                 { could be an asmn in case of a pure assembler procedure,
908                   but those shouldn't access nested variables }
909                 addstatement(newstatement,procdef.parentfpinitblock);
910               end
911             else
912               procdef.parentfpinitblock.free;
913             procdef.parentfpinitblock:=nil;
914           end;
915         addstatement(newstatement,bodyentrycode);
916 
917         if (cs_implicit_exceptions in current_settings.moduleswitches) and
918            (pi_needs_implicit_finally in flags) and
919            { but it's useless in init/final code of units }
920            not(procdef.proctypeoption in [potype_unitfinalize,potype_unitinit]) and
921            not(target_info.system in systems_garbage_collected_managed_types) then
922           begin
923             { Any result of managed type must be returned in parameter }
924             if is_managed_type(procdef.returndef) and
925                (not paramanager.ret_in_param(procdef.returndef,procdef)) and
926                (not is_class(procdef.returndef)) then
927                InternalError(2013121301);
928 
929             { Generate special exception block only needed when
930               implicit finaly is used }
931             current_filepos:=exitpos;
932             { Generate code that will be in the try...finally }
933             finalcode:=internalstatements(codestatement);
934             addstatement(codestatement,final_asmnode);
935             cnodeutils.procdef_block_add_implicit_finalize_nodes(procdef,codestatement);
936             final_used:=true;
937 
938             current_filepos:=entrypos;
939             wrappedbody:=ctryfinallynode.create_implicit(code,finalcode);
940             { afterconstruction must be called after final_asmnode, because it
941                has to execute after the temps have been finalised in case of a
942                refcounted class (afterconstruction decreases the refcount
943                without freeing the instance if the count becomes nil, while
944                the finalising of the temps can free the instance) }
945             maybe_add_constructor_wrapper(wrappedbody,true);
946             addstatement(newstatement,wrappedbody);
947             addstatement(newstatement,exitlabel_asmnode);
948             addstatement(newstatement,bodyexitcode);
949             { set flag the implicit finally has been generated }
950             include(flags,pi_has_implicit_finally);
951           end
952         else
953           begin
954             { constructors need destroy-on-exception code even if they don't
955               have managed variables/temps }
956             maybe_add_constructor_wrapper(code,
957               cs_implicit_exceptions in current_settings.moduleswitches);
958             current_filepos:=entrypos;
959             addstatement(newstatement,code);
960             current_filepos:=exitpos;
961             if assigned(nestedexitlabel) then
962               addstatement(newstatement,clabelnode.create(cnothingnode.create,nestedexitlabel));
963             addstatement(newstatement,exitlabel_asmnode);
964             addstatement(newstatement,bodyexitcode);
965             if not is_constructor then
966               begin
967                 addstatement(newstatement,final_asmnode);
968                 cnodeutils.procdef_block_add_implicit_finalize_nodes(procdef,newstatement);
969                 final_used:=true;
970               end;
971           end;
972         if not final_used then
973           begin
974             current_filepos:=exitpos;
975             cnodeutils.procdef_block_add_implicit_finalize_nodes(procdef,newstatement);
976           end;
977         do_firstpass(newblock);
978         code:=newblock;
979         current_filepos:=oldfilepos;
980       end;
981 
982 
983     procedure clearrefs(p:TObject;arg:pointer);
984       begin
985          if (tsym(p).typ in [localvarsym,paravarsym,staticvarsym]) then
986            if tabstractvarsym(p).refs>1 then
987              tabstractvarsym(p).refs:=1;
988       end;
989 
990 
991     procedure translate_registers(p:TObject;list:pointer);
992       begin
993          if (tsym(p).typ in [localvarsym,paravarsym,staticvarsym]) and
994             (tabstractnormalvarsym(p).localloc.loc in [LOC_REGISTER,LOC_CREGISTER,LOC_MMREGISTER,
995               LOC_CMMREGISTER,LOC_FPUREGISTER,LOC_CFPUREGISTER]) then
996            begin
997              if not(cs_no_regalloc in current_settings.globalswitches) then
998                begin
999                  cg.translate_register(tabstractnormalvarsym(p).localloc.register);
1000                  if (tabstractnormalvarsym(p).localloc.registerhi<>NR_NO) then
1001                    cg.translate_register(tabstractnormalvarsym(p).localloc.registerhi);
1002                end;
1003            end;
1004       end;
1005 
1006 
1007 {$if defined(i386) or defined(x86_64) or defined(arm)}
1008     const
1009       exception_flags: array[boolean] of tprocinfoflags = (
1010         [],
1011         [pi_uses_exceptions,pi_needs_implicit_finally,pi_has_implicit_finally]
1012       );
1013 {$endif}
1014 
1015     procedure tcgprocinfo.setup_tempgen;
1016       begin
1017         tg:=tgobjclass.create;
1018 
1019 {$if defined(i386) or defined(x86_64) or defined(arm)}
1020 {$if defined(arm)}
1021         { frame and stack pointer must be always the same on arm thumb so it makes no
1022           sense to fiddle with a frame pointer }
1023         if GenerateThumbCode then
1024           begin
1025             framepointer:=NR_STACK_POINTER_REG;
1026             tg.direction:=1;
1027           end
1028         else
1029 {$endif defined(arm)}
1030           begin
1031             { try to strip the stack frame }
1032             { set the framepointer to esp if:
1033               - no assembler directive, those are handled in assembler_block
1034                 in pstatment.pas (for cases not caught by the Delphi
1035                 exception below)
1036               - no exceptions are used
1037               - no pushes are used/esp modifications, could be:
1038                 * outgoing parameters on the stack on non-fixed stack target
1039                 * incoming parameters on the stack
1040                 * open arrays
1041               - no inline assembler
1042              or
1043               - Delphi mode
1044               - assembler directive
1045               - no pushes are used/esp modifications, could be:
1046                 * outgoing parameters on the stack
1047                 * incoming parameters on the stack
1048                 * open arrays
1049               - no local variables
1050 
1051               - stack frame cannot be optimized if using Win64 SEH
1052                 (at least with the current state of our codegenerator).
1053             }
1054             if ((po_assembler in procdef.procoptions) and
1055                (m_delphi in current_settings.modeswitches) and
1056                { localst at main_program_level is a staticsymtable }
1057                 (procdef.localst.symtablelevel<>main_program_level) and
1058                 (tabstractlocalsymtable(procdef.localst).count_locals = 0)) or
1059                ((cs_opt_stackframe in current_settings.optimizerswitches) and
1060                 not(cs_generate_stackframes in current_settings.localswitches) and
1061                 not(cs_profile in current_settings.moduleswitches) and
1062                 not(po_assembler in procdef.procoptions) and
1063                 not ((pi_has_stackparameter in flags)
1064 {$ifndef arm}   { Outgoing parameter(s) on stack do not need stackframe on x86 targets
1065                  with fixed stack. On ARM it fails, see bug #25050 }
1066                   and (not paramanager.use_fixed_stack)
1067 {$endif arm}
1068                   ) and
1069                 ((flags*([pi_has_assembler_block,pi_is_assembler,
1070                         pi_needs_stackframe]+
1071                         exception_flags[(target_info.cpu=cpu_i386)
1072 {$ifndef DISABLE_WIN64_SEH}
1073                         or (target_info.system=system_x86_64_win64)
1074 {$endif DISABLE_WIN64_SEH}
1075                         ]))=[])
1076                )
1077             then
1078               begin
1079                 { we need the parameter info here to determine if the procedure gets
1080                   parameters on the stack
1081 
1082                   calling generate_parameter_info doesn't hurt but it costs time
1083                   (necessary to init para_stack_size)
1084                 }
1085                 generate_parameter_info;
1086 
1087                 if not(procdef.stack_tainting_parameter(calleeside)) and
1088                    not(has_assembler_child) and (para_stack_size=0) then
1089                   begin
1090                     { Only need to set the framepointer }
1091                     framepointer:=NR_STACK_POINTER_REG;
1092                     tg.direction:=1;
1093                   end
1094 {$if defined(arm)}
1095                 { On arm, the stack frame size can be estimated to avoid using an extra frame pointer,
1096                   in case parameters are passed on the stack.
1097 
1098                   However, the draw back is, if the estimation fails, compilation will break later on
1099                   with an internal error, so this switch is not enabled by default yet. To overcome this,
1100                   multipass compilation of subroutines must be supported
1101                 }
1102                 else if (cs_opt_forcenostackframe in current_settings.optimizerswitches) and
1103                    not(has_assembler_child) then
1104                   begin
1105                     { Only need to set the framepointer }
1106                     framepointer:=NR_STACK_POINTER_REG;
1107                     tg.direction:=1;
1108                     include(flags,pi_estimatestacksize);
1109                     set_first_temp_offset;
1110                     procdef.has_paraloc_info:=callnoside;
1111                     generate_parameter_info;
1112                     exit;
1113                   end;
1114 {$endif defined(arm)}
1115               end;
1116           end;
1117 {$endif defined(x86) or defined(arm)}
1118         { set the start offset to the start of the temp area in the stack }
1119         set_first_temp_offset;
1120       end;
1121 
tcgprocinfo.has_assembler_childnull1122     function tcgprocinfo.has_assembler_child : boolean;
1123       var
1124         hp : tprocinfo;
1125       begin
1126         result:=false;
1127         hp:=get_first_nestedproc;
1128         while assigned(hp) do
1129           begin
1130             if (hp.flags*[pi_has_assembler_block,pi_is_assembler])<>[] then
1131               begin
1132                 result:=true;
1133                 exit;
1134               end;
1135             hp:=tprocinfo(hp.next);
1136           end;
1137       end;
1138 
1139     procedure tcgprocinfo.generate_code_tree;
1140       var
1141         hpi : tcgprocinfo;
1142       begin
1143         { generate code for this procedure }
1144         generate_code;
1145         { process nested procedures }
1146         hpi:=tcgprocinfo(get_first_nestedproc);
1147         while assigned(hpi) do
1148           begin
1149             hpi.generate_code_tree;
1150             hpi:=tcgprocinfo(hpi.next);
1151           end;
1152         resetprocdef;
1153       end;
1154 
1155     { For SEH, the code from 'finally' blocks must be put into a separate procedures,
1156       which can be called by OS during stack unwind. This resembles nested procedures,
1157       but finalizer procedures do not have their own local variables and work directly
1158       with the stack frame of parent. In particular, the tempgen must be shared, so
1159       1) finalizer procedure is able to finalize temps of the parent,
1160       2) if the finalizer procedure is complex enough to need its own temps, they are
1161          allocated in stack frame of parent, so second-level finalizer procedures are
1162          not needed.
1163 
1164       Due to requirement of shared tempgen we cannot process finalizer as a regular nested
1165       procedure (after the parent) and have to do it inline.
1166       This is called by platform-specific tryfinallynodes during pass2.
1167       Here we put away the codegen (which carries the register allocator state), process
1168       the 'nested' procedure, then restore previous cg and continue processing the parent
1169       procedure. generate_code() will create another cg, but not another tempgen because
1170       setup_tempgen() is not called for potype_exceptfilter procedures. }
1171 
1172     procedure tcgprocinfo.generate_exceptfilter(nestedpi: tcgprocinfo);
1173       var
1174         saved_cg: tcg;
1175         saved_hlcg: thlcgobj;
1176 {$ifdef cpu64bitalu}
1177         saved_cg128 : tcg128;
1178 {$else cpu64bitalu}
1179         saved_cg64 : tcg64;
1180 {$endif cpu64bitalu}
1181       begin
1182         if nestedpi.procdef.proctypeoption<>potype_exceptfilter then
1183           InternalError(201201141);
1184         { flush code generated this far }
1185         aktproccode.concatlist(current_asmdata.CurrAsmList);
1186         { save the codegen }
1187         saved_cg:=cg;
1188         saved_hlcg:=hlcg;
1189         cg:=nil;
1190         hlcg:=nil;
1191 {$ifdef cpu64bitalu}
1192         saved_cg128:=cg128;
1193         cg128:=nil;
1194 {$else cpu64bitalu}
1195         saved_cg64:=cg64;
1196         cg64:=nil;
1197 {$endif cpu64bitalu}
1198         nestedpi.generate_code;
1199         { prevents generating code the second time when processing nested procedures }
1200         nestedpi.resetprocdef;
1201         cg:=saved_cg;
1202         hlcg:=saved_hlcg;
1203 {$ifdef cpu64bitalu}
1204         cg128:=saved_cg128;
1205 {$else cpu64bitalu}
1206         cg64:=saved_cg64;
1207 {$endif cpu64bitalu}
1208         add_reg_instruction_hook:=@cg.add_reg_instruction;
1209       end;
1210 
1211 
1212      procedure TCGProcinfo.CreateInlineInfo;
1213        begin
1214         new(procdef.inlininginfo);
1215         procdef.inlininginfo^.code:=code.getcopy;
1216         procdef.inlininginfo^.flags:=flags;
1217         { The blocknode needs to set an exit label }
1218         if procdef.inlininginfo^.code.nodetype=blockn then
1219           include(procdef.inlininginfo^.code.flags,nf_block_with_exit);
1220         procdef.has_inlininginfo:=true;
1221        end;
1222 
1223 
searchusercodenull1224     function searchusercode(var n: tnode; arg: pointer): foreachnoderesult;
1225       begin
1226         if nf_usercode_entry in n.flags then
1227           begin
1228             pnode(arg)^:=n;
1229             result:=fen_norecurse_true
1230           end
1231         else
1232           result:=fen_false;
1233       end;
1234 
1235 
TCGProcinfo.GetUserCodenull1236     function TCGProcinfo.GetUserCode : tnode;
1237       var
1238         n : tnode;
1239       begin
1240         n:=nil;
1241         foreachnodestatic(code,@searchusercode,@n);
1242         if not(assigned(n)) then
1243           internalerror(2013111004);
1244         result:=n;
1245       end;
1246 
1247 
1248     procedure tcgprocinfo.generate_code;
1249       var
1250         old_current_procinfo : tprocinfo;
1251         oldmaxfpuregisters : longint;
1252         oldfilepos : tfileposinfo;
1253         old_current_structdef : tabstractrecorddef;
1254         templist : TAsmList;
1255         headertai : tai;
1256         i : integer;
1257         {RedoDFA : boolean;}
1258 
1259         procedure delete_marker(anode: tasmnode);
1260           var
1261             ai: tai;
1262           begin
1263             if assigned(anode) then
1264               begin
1265                 ai:=anode.currenttai;
1266                 if assigned(ai) then
1267                   begin
1268                     aktproccode.remove(ai);
1269                     ai.free;
1270                     anode.currenttai:=nil;
1271                   end;
1272               end;
1273           end;
1274 
1275       begin
1276         { the initialization procedure can be empty, then we
1277           don't need to generate anything. When it was an empty
1278           procedure there would be at least a blocknode }
1279         if not assigned(code) then
1280           exit;
1281 
1282         { We need valid code }
1283         if Errorcount<>0 then
1284           exit;
1285 
1286         { No code can be generated for generic template }
1287         if (df_generic in procdef.defoptions) then
1288           internalerror(200511152);
1289 
1290         { For regular procedures the RA and Tempgen shall not be available yet,
1291           but exception filters reuse Tempgen of parent }
1292         if assigned(tg)<>(procdef.proctypeoption=potype_exceptfilter) then
1293           internalerror(200309201);
1294 
1295         old_current_procinfo:=current_procinfo;
1296         oldfilepos:=current_filepos;
1297         old_current_structdef:=current_structdef;
1298         oldmaxfpuregisters:=current_settings.maxfpuregisters;
1299 
1300         current_procinfo:=self;
1301         current_filepos:=entrypos;
1302         current_structdef:=procdef.struct;
1303 
1304         { store start of user code, it must be a block node, it will be used later one to
1305           check variable lifeness }
1306         include(code.flags,nf_usercode_entry);
1307 
1308         { add wrapping code if necessary (initialization of typed constants on
1309           some platforms, initing of local variables and out parameters with
1310           trashing values, ...) }
1311         { init/final code must be wrapped later (after code for main proc body
1312           has been generated) }
1313         if not(current_procinfo.procdef.proctypeoption in [potype_unitinit,potype_unitfinalize]) then
1314           code:=cnodeutils.wrap_proc_body(procdef,code);
1315 
1316         { automatic inlining? }
1317         if (cs_opt_autoinline in current_settings.optimizerswitches) and
1318            { inlining not turned off? }
1319            (cs_do_inline in current_settings.localswitches) and
1320            { no inlining yet? }
1321            not(procdef.has_inlininginfo) and not(has_nestedprocs) and
1322             not(procdef.proctypeoption in [potype_proginit,potype_unitinit,potype_unitfinalize,potype_constructor,
1323                                            potype_destructor,potype_class_constructor,potype_class_destructor]) and
1324             ((procdef.procoptions*[po_exports,po_external,po_interrupt,po_virtualmethod,po_iocheck])=[]) and
1325             (not(procdef.proccalloption in [pocall_safecall])) and
1326             { rough approximation if we should auto inline }
1327             (node_count(code)<=10) then
1328           begin
1329             { Can we inline this procedure? }
1330             if checknodeinlining(procdef) then
1331               begin
1332                 Message1(cg_d_autoinlining,procdef.GetTypeName);
1333                 include(procdef.procoptions,po_inline);
1334                 CreateInlineInfo;
1335               end;
1336           end;
1337 
1338         templist:=TAsmList.create;
1339 
1340         { add parast/localst to symtablestack }
1341         add_to_symtablestack;
1342 
1343         { clear register count }
1344         procdef.localst.SymList.ForEachCall(@clearrefs,nil);
1345         procdef.parast.SymList.ForEachCall(@clearrefs,nil);
1346 
1347         { there's always a call to FPC_INITIALIZEUNITS/FPC_DO_EXIT in the main program }
1348         if (procdef.localst.symtablelevel=main_program_level) and
1349            (not current_module.is_unit) then
1350           begin
1351             include(flags,pi_do_call);
1352             { the main program never returns due to the do_exit call }
1353             if not(current_module.islibrary) and (procdef.proctypeoption=potype_proginit) then
1354               include(procdef.procoptions,po_noreturn);
1355           end;
1356 
1357         { set implicit_finally flag when there are locals/paras to be finalized }
1358         if not(po_assembler in current_procinfo.procdef.procoptions) then
1359           begin
1360             procdef.parast.SymList.ForEachCall(@check_finalize_paras,nil);
1361             procdef.localst.SymList.ForEachCall(@check_finalize_locals,nil);
1362           end;
1363 
1364 {$ifdef SUPPORT_SAFECALL}
1365         { set implicit_finally flag for if procedure is safecall }
1366         if (tf_safecall_exceptions in target_info.flags) and
1367            (procdef.proccalloption=pocall_safecall) then
1368           include(flags, pi_needs_implicit_finally);
1369 {$endif}
1370         { firstpass everything }
1371         flowcontrol:=[];
1372         do_firstpass(code);
1373 
1374 {$if defined(i386) or defined(i8086)}
1375         if node_resources_fpu(code)>0 then
1376           include(flags,pi_uses_fpu);
1377 {$endif i386 or i8086}
1378 
1379         { Print the node to tree.log }
1380         if paraprintnodetree=1 then
1381           printproc( 'after the firstpass');
1382 
1383         { do this before adding the entry code else the tail recursion recognition won't work,
1384           if this causes troubles, it must be if'ed
1385         }
1386         if (cs_opt_tailrecursion in current_settings.optimizerswitches) and
1387           (pi_is_recursive in flags) then
1388           do_opttail(code,procdef);
1389 
1390         if cs_opt_constant_propagate in current_settings.optimizerswitches then
1391           do_optconstpropagate(code);
1392 
1393         if (cs_opt_nodedfa in current_settings.optimizerswitches) and
1394           { creating dfa is not always possible }
1395           ((flags*[pi_has_assembler_block,pi_uses_exceptions,pi_is_assembler])=[]) then
1396           begin
1397             dfabuilder:=TDFABuilder.Create;
1398             dfabuilder.createdfainfo(code);
1399             include(flags,pi_dfaavailable);
1400 
1401             { when life info is available, we can give more sophisticated warning about uninitialized
1402               variables ...
1403               ... but not for the finalization section of a unit, we would need global dfa to handle
1404               it properly }
1405             if potype_unitfinalize<>procdef.proctypeoption then
1406               { iterate through life info of the first node }
1407               for i:=0 to dfabuilder.nodemap.count-1 do
1408                 begin
1409                   if DFASetIn(GetUserCode.optinfo^.life,i) then
1410                     begin
1411                       { do not warn for certain parameters: }
1412                       if not((tnode(dfabuilder.nodemap[i]).nodetype=loadn) and (tloadnode(dfabuilder.nodemap[i]).symtableentry.typ=paravarsym) and
1413                         { do not warn about parameters passed by var }
1414                         (((tparavarsym(tloadnode(dfabuilder.nodemap[i]).symtableentry).varspez=vs_var) and
1415                         { function result is passed by var but it must be initialized }
1416                         not(vo_is_funcret in tparavarsym(tloadnode(dfabuilder.nodemap[i]).symtableentry).varoptions)) or
1417                         { do not warn about initialized hidden parameters }
1418                         ((tparavarsym(tloadnode(dfabuilder.nodemap[i]).symtableentry).varoptions*[vo_is_high_para,vo_is_parentfp,vo_is_result,vo_is_self])<>[]))) then
1419                         CheckAndWarn(GetUserCode,tnode(dfabuilder.nodemap[i]));
1420                     end
1421                   else
1422                     begin
1423                       if (tnode(dfabuilder.nodemap[i]).nodetype=loadn) and
1424                         (tloadnode(dfabuilder.nodemap[i]).symtableentry.typ in [staticvarsym,localvarsym]) then
1425                         tabstractnormalvarsym(tloadnode(dfabuilder.nodemap[i]).symtableentry).noregvarinitneeded:=true
1426                     end;
1427                 end;
1428           end;
1429 
1430         if (pi_dfaavailable in flags) and (cs_opt_dead_store_eliminate in current_settings.optimizerswitches) then
1431           do_optdeadstoreelim(code);
1432 
1433         if (cs_opt_loopstrength in current_settings.optimizerswitches)
1434           { our induction variable strength reduction doesn't like
1435             for loops with more than one entry }
1436           and not(pi_has_label in flags) then
1437           begin
1438             {RedoDFA:=}OptimizeInductionVariables(code);
1439           end;
1440 
1441         if (cs_opt_remove_emtpy_proc in current_settings.optimizerswitches) and
1442           (procdef.proctypeoption in [potype_operator,potype_procedure,potype_function]) and
1443           (code.nodetype=blockn) and (tblocknode(code).statements=nil) then
1444           procdef.isempty:=true;
1445 
1446         { add implicit entry and exit code }
1447         add_entry_exit_code;
1448 
1449         if cs_opt_nodecse in current_settings.optimizerswitches then
1450           do_optcse(code);
1451 
1452         if cs_opt_use_load_modify_store in current_settings.optimizerswitches then
1453           do_optloadmodifystore(code);
1454 
1455         { only do secondpass if there are no errors }
1456         if (ErrorCount=0) then
1457           begin
1458             create_hlcodegen;
1459 
1460             if (procdef.proctypeoption<>potype_exceptfilter) then
1461               setup_tempgen;
1462 
1463             { Create register allocator, must come after framepointer is known }
1464             hlcg.init_register_allocators;
1465 
1466             generate_parameter_info;
1467 
1468             { allocate got register if needed }
1469             allocate_got_register(aktproccode);
1470 
1471             { Allocate space in temp/registers for parast and localst }
1472             current_filepos:=entrypos;
1473             gen_alloc_symtable(aktproccode,procdef,procdef.parast);
1474             gen_alloc_symtable(aktproccode,procdef,procdef.localst);
1475 
1476             { Store temp offset for information about 'real' temps }
1477             tempstart:=tg.lasttemp;
1478 
1479             { Generate code to load register parameters in temps and insert local
1480               copies for values parameters. This must be done before the code for the
1481               body is generated because the localloc is updated.
1482               Note: The generated code will be inserted after the code generation of
1483               the body is finished, because only then the position is known }
1484 {$ifdef oldregvars}
1485             assign_regvars(code);
1486 {$endif oldreg}
1487             current_filepos:=entrypos;
1488 
1489             hlcg.gen_load_para_value(templist);
1490 
1491             { caller paraloc info is also necessary in the stackframe_entry
1492               code of the ppc (and possibly other processors)               }
1493             procdef.init_paraloc_info(callerside);
1494 
1495             CalcExecutionWeights(code);
1496 
1497             { Print the node to tree.log }
1498             if paraprintnodetree=1 then
1499               printproc( 'right before code generation');
1500 
1501             { generate code for the node tree }
1502             do_secondpass(code);
1503             aktproccode.concatlist(current_asmdata.CurrAsmList);
1504 
1505             { The position of the loadpara_asmnode is now known }
1506             aktproccode.insertlistafter(loadpara_asmnode.currenttai,templist);
1507 
1508             { first generate entry and initialize code with the correct
1509               position and switches }
1510             current_filepos:=entrypos;
1511             current_settings.localswitches:=entryswitches;
1512 
1513             cg.set_regalloc_live_range_direction(rad_backwards);
1514 
1515             hlcg.gen_entry_code(templist);
1516             aktproccode.insertlistafter(entry_asmnode.currenttai,templist);
1517             hlcg.gen_initialize_code(templist);
1518             aktproccode.insertlistafter(init_asmnode.currenttai,templist);
1519 
1520             { now generate finalize and exit code with the correct position
1521               and switches }
1522             current_filepos:=exitpos;
1523             current_settings.localswitches:=exitswitches;
1524 
1525             cg.set_regalloc_live_range_direction(rad_forward);
1526 
1527             if assigned(finalize_procinfo) then
1528               generate_exceptfilter(tcgprocinfo(finalize_procinfo))
1529             else
1530               begin
1531                 hlcg.gen_finalize_code(templist);
1532                 { the finalcode must be concated if there was no position available,
1533                   using insertlistafter will result in an insert at the start
1534                   when currentai=nil }
1535                 if assigned(final_asmnode) and assigned(final_asmnode.currenttai) then
1536                   aktproccode.insertlistafter(final_asmnode.currenttai,templist)
1537                 else
1538                   aktproccode.concatlist(templist);
1539               end;
1540             { insert exit label at the correct position }
1541             hlcg.a_label(templist,CurrExitLabel);
1542             if assigned(exitlabel_asmnode.currenttai) then
1543               aktproccode.insertlistafter(exitlabel_asmnode.currenttai,templist)
1544             else
1545               aktproccode.concatlist(templist);
1546             { exit code }
1547             hlcg.gen_exit_code(templist);
1548             aktproccode.concatlist(templist);
1549 
1550 {$ifdef OLDREGVARS}
1551             { note: this must be done only after as much code as possible has  }
1552             {   been generated. The result is that when you ungetregister() a  }
1553             {   regvar, it will actually free the regvar (and alse free the    }
1554             {   the regvars at the same time). Doing this too early will       }
1555             {   confuse the register allocator, as the regvars will still be   }
1556             {   used. It should be done before loading the result regs (so     }
1557             {   they don't conflict with the regvars) and before               }
1558             {   gen_entry_code (that one has to be able to allocate the        }
1559             {   regvars again) (JM)                                            }
1560             free_regvars(aktproccode);
1561 {$endif OLDREGVARS}
1562 
1563             { generate symbol and save end of header position }
1564             current_filepos:=entrypos;
1565             hlcg.gen_proc_symbol(templist);
1566             headertai:=tai(templist.last);
1567             { insert symbol }
1568             aktproccode.insertlist(templist);
1569 
1570             { Free space in temp/registers for parast and localst, must be
1571               done after gen_entry_code }
1572             current_filepos:=exitpos;
1573 
1574             { make sure the got/pic register doesn't get freed in the }
1575             { middle of a loop                                        }
1576             if (cs_create_pic in current_settings.moduleswitches) and
1577                (pi_needs_got in flags) and
1578                (got<>NR_NO) then
1579               cg.a_reg_sync(aktproccode,got);
1580 
1581             gen_free_symtable(aktproccode,procdef.localst);
1582             gen_free_symtable(aktproccode,procdef.parast);
1583 
1584             { add code that will load the return value, this is not done
1585               for assembler routines when they didn't reference the result
1586               variable }
1587             hlcg.gen_load_return_value(templist);
1588             aktproccode.concatlist(templist);
1589 
1590             { Already reserve all registers for stack checking code and
1591               generate the call to the helper function }
1592             if not(tf_no_generic_stackcheck in target_info.flags) and
1593                (cs_check_stack in entryswitches) and
1594                not(po_assembler in procdef.procoptions) and
1595                (procdef.proctypeoption<>potype_proginit) then
1596               begin
1597                 current_filepos:=entrypos;
1598                 hlcg.gen_stack_check_call(templist);
1599                 aktproccode.insertlistafter(stackcheck_asmnode.currenttai,templist)
1600               end;
1601 
1602             { this code (got loading) comes before everything which has }
1603             { already been generated, so reset the info about already   }
1604             { backwards extended registers (so their live range can be  }
1605             { extended backwards even further if needed)                }
1606             { This code must be                                         }
1607             {  a) generated after do_secondpass has been called         }
1608             {     (because pi_needs_got may be set there)               }
1609             {  b) generated before register allocation, because the     }
1610             {     got/pic register can be a virtual one                 }
1611             {  c) inserted before the entry code, because the entry     }
1612             {     code may need global symbols such as init rtti        }
1613             {  d) inserted after the stackframe allocation, because     }
1614             {     this register may have to be spilled                  }
1615             cg.set_regalloc_live_range_direction(rad_backwards_reinit);
1616             current_filepos:=entrypos;
1617             { load got if necessary }
1618             cg.g_maybe_got_init(templist);
1619 
1620             aktproccode.insertlistafter(headertai,templist);
1621 
1622             { re-enable if more code at the end is ever generated here
1623             cg.set_regalloc_live_range_direction(rad_forward);
1624             }
1625 
1626 
1627 {$ifndef NoOpt}
1628 {$ifndef i386}
1629             if (cs_opt_scheduler in current_settings.optimizerswitches) and
1630               { do not optimize pure assembler procedures }
1631               not(pi_is_assembler in flags) then
1632               preregallocschedule(aktproccode);
1633 {$endif i386}
1634 {$endif NoOpt}
1635 
1636             { The procedure body is finished, we can now
1637               allocate the registers }
1638             cg.do_register_allocation(aktproccode,headertai);
1639 
1640             { translate imag. register to their real counter parts
1641               this is necessary for debuginfo and verbose assembler output
1642               when SSA will be implented, this will be more complicated because we've to
1643               maintain location lists }
1644             procdef.parast.SymList.ForEachCall(@translate_registers,templist);
1645             procdef.localst.SymList.ForEachCall(@translate_registers,templist);
1646             if (cs_create_pic in current_settings.moduleswitches) and
1647                (pi_needs_got in flags) and
1648                not(cs_no_regalloc in current_settings.globalswitches) and
1649                (got<>NR_NO) then
1650               cg.translate_register(got);
1651 
1652             { Add save and restore of used registers }
1653             current_filepos:=entrypos;
1654             gen_save_used_regs(templist);
1655             { Remember the last instruction of register saving block
1656               (may be =nil for e.g. assembler procedures) }
1657             endprologue_ai:=templist.last;
1658             aktproccode.insertlistafter(headertai,templist);
1659             current_filepos:=exitpos;
1660             gen_restore_used_regs(aktproccode);
1661             { We know the size of the stack, now we can generate the
1662               parameter that is passed to the stack checking code }
1663             if not(tf_no_generic_stackcheck in target_info.flags) and
1664                (cs_check_stack in entryswitches) and
1665                not(po_assembler in procdef.procoptions) and
1666                (procdef.proctypeoption<>potype_proginit) then
1667               begin
1668                 current_filepos:=entrypos;
1669                 hlcg.gen_stack_check_size_para(templist);
1670                 aktproccode.insertlistafter(stackcheck_asmnode.currenttai,templist)
1671               end;
1672             { Add entry code (stack allocation) after header }
1673             current_filepos:=entrypos;
1674             gen_proc_entry_code(templist);
1675             aktproccode.insertlistafter(headertai,templist);
1676 {$ifdef SUPPORT_SAFECALL}
1677             { Set return value of safecall procedure if implicit try/finally blocks are disabled }
1678             if not (cs_implicit_exceptions in current_settings.moduleswitches) and
1679                (tf_safecall_exceptions in target_info.flags) and
1680                (procdef.proccalloption=pocall_safecall) then
1681               cg.a_load_const_reg(aktproccode,OS_ADDR,0,NR_FUNCTION_RETURN_REG);
1682 {$endif}
1683             { Add exit code at the end }
1684             current_filepos:=exitpos;
1685             gen_proc_exit_code(templist);
1686             aktproccode.concatlist(templist);
1687 
1688             { check if the implicit finally has been generated. The flag
1689               should already be set in pass1 }
1690             if (cs_implicit_exceptions in current_settings.moduleswitches) and
1691                not(procdef.proctypeoption in [potype_unitfinalize,potype_unitinit]) and
1692                (pi_needs_implicit_finally in flags) and
1693                not(pi_has_implicit_finally in flags) and
1694                not(target_info.system in systems_garbage_collected_managed_types) then
1695              internalerror(200405231);
1696 
1697             { Position markers are only used to insert additional code after the secondpass
1698               and before this point. They are of no use in optimizer. Instead of checking and
1699               ignoring all over the optimizer, just remove them here. }
1700             delete_marker(entry_asmnode);
1701             delete_marker(loadpara_asmnode);
1702             delete_marker(exitlabel_asmnode);
1703             delete_marker(stackcheck_asmnode);
1704             delete_marker(init_asmnode);
1705             delete_marker(final_asmnode);
1706 
1707 {$ifndef NoOpt}
1708             if not(cs_no_regalloc in current_settings.globalswitches) then
1709               begin
1710                 if (cs_opt_level1 in current_settings.optimizerswitches) and
1711                    { do not optimize pure assembler procedures }
1712                    not(pi_is_assembler in flags)  then
1713                   optimize(aktproccode);
1714 {$ifndef i386}
1715                 { schedule after assembler optimization, it could have brought up
1716                   new schedule possibilities }
1717                 if (cs_opt_scheduler in current_settings.optimizerswitches) and
1718                   { do not optimize pure assembler procedures }
1719                   not(pi_is_assembler in flags)  then
1720                   preregallocschedule(aktproccode);
1721 {$endif i386}
1722               end;
1723 {$endif NoOpt}
1724 
1725             { Perform target-specific processing if necessary }
1726             postprocess_code;
1727 
1728             { Add end symbol and debug info }
1729             { this must be done after the pcrelativedata is appended else the distance calculation of
1730               insertpcrelativedata will be wrong, further the pc indirect data is part of the procedure
1731               so it should be inserted before the end symbol (FK)
1732             }
1733             current_filepos:=exitpos;
1734             hlcg.gen_proc_symbol_end(templist);
1735             aktproccode.concatlist(templist);
1736 
1737             { insert line debuginfo }
1738             if (cs_debuginfo in current_settings.moduleswitches) or
1739                (cs_use_lineinfo in current_settings.globalswitches) then
1740               current_debuginfo.insertlineinfo(aktproccode);
1741 
1742             hlcg.record_generated_code_for_procdef(current_procinfo.procdef,aktproccode,aktlocaldata);
1743 
1744             { only now we can remove the temps }
1745             if (procdef.proctypeoption<>potype_exceptfilter) then
1746               begin
1747                 tg.resettempgen;
1748                 tg.free;
1749                 tg:=nil;
1750               end;
1751             { stop tempgen and ra }
1752             hlcg.done_register_allocators;
1753             destroy_hlcodegen;
1754           end;
1755 
1756         dfabuilder.free;
1757 
1758         { restore symtablestack }
1759         remove_from_symtablestack;
1760 
1761         { restore }
1762         templist.free;
1763         current_settings.maxfpuregisters:=oldmaxfpuregisters;
1764         current_filepos:=oldfilepos;
1765         current_structdef:=old_current_structdef;
1766         current_procinfo:=old_current_procinfo;
1767       end;
1768 
1769 
1770     procedure tcgprocinfo.add_to_symtablestack;
1771       begin
1772         { insert symtables for the class, but only if it is no nested function }
1773         if assigned(procdef.struct) and
1774            not(assigned(parent) and
1775                assigned(parent.procdef) and
1776                assigned(parent.procdef.struct)) then
1777           push_nested_hierarchy(procdef.struct);
1778 
1779         { insert parasymtable in symtablestack when parsing
1780           a function }
1781         if procdef.parast.symtablelevel>=normal_function_level then
1782           symtablestack.push(procdef.parast);
1783 
1784         { insert localsymtable, except for the main procedure
1785           (in that case the localst is the unit's static symtable,
1786            which is already on the stack) }
1787         if procdef.localst.symtablelevel>=normal_function_level then
1788           symtablestack.push(procdef.localst);
1789       end;
1790 
1791 
1792     procedure tcgprocinfo.remove_from_symtablestack;
1793       begin
1794         { remove localsymtable }
1795         if procdef.localst.symtablelevel>=normal_function_level then
1796           symtablestack.pop(procdef.localst);
1797 
1798         { remove parasymtable }
1799         if procdef.parast.symtablelevel>=normal_function_level then
1800           symtablestack.pop(procdef.parast);
1801 
1802         { remove symtables for the class, but only if it is no nested function }
1803         if assigned(procdef.struct) and
1804            not(assigned(parent) and
1805                assigned(parent.procdef) and
1806                assigned(parent.procdef.struct)) then
1807           pop_nested_hierarchy(procdef.struct);
1808       end;
1809 
1810 
1811     procedure tcgprocinfo.resetprocdef;
1812       begin
1813          { remove code tree, if not inline procedure }
1814          if assigned(code) then
1815           begin
1816             { the inline procedure has already got a copy of the tree
1817               stored in procdef.inlininginfo }
1818             code.free;
1819             code:=nil;
1820           end;
1821        end;
1822 
1823 
1824     procedure tcgprocinfo.parse_body;
1825       var
1826          old_current_procinfo : tprocinfo;
1827          old_block_type : tblock_type;
1828          st : TSymtable;
1829          old_current_structdef: tabstractrecorddef;
1830          old_current_genericdef,
1831          old_current_specializedef: tstoreddef;
1832          parentfpinitblock: tnode;
1833          old_parse_generic: boolean;
1834          recordtokens : boolean;
1835 
1836       begin
1837          old_current_procinfo:=current_procinfo;
1838          old_block_type:=block_type;
1839          old_current_structdef:=current_structdef;
1840          old_current_genericdef:=current_genericdef;
1841          old_current_specializedef:=current_specializedef;
1842          old_parse_generic:=parse_generic;
1843 
1844          current_procinfo:=self;
1845          current_structdef:=procdef.struct;
1846 
1847 
1848         { check if the definitions of certain types are available which might not be available in older rtls and
1849           which are assigned "on the fly" in types_dec }
1850 {$ifndef jvm}
1851         if not assigned(rec_exceptaddr) then
1852           Message1(cg_f_internal_type_not_found,'TEXCEPTADDR');
1853         if not assigned(rec_tguid) then
1854           Message1(cg_f_internal_type_not_found,'TGUID');
1855         if not assigned(rec_jmp_buf) then
1856           Message1(cg_f_internal_type_not_found,'TJMPBUF');
1857 {$endif}
1858 
1859          { if the procdef is truly a generic (thus takes parameters itself) then
1860            /that/ is our genericdef, not the - potentially - generic struct }
1861          if procdef.is_generic then
1862            begin
1863              current_genericdef:=procdef;
1864              parse_generic:=true;
1865            end
1866          else if assigned(current_structdef) and (df_generic in current_structdef.defoptions) then
1867            begin
1868              current_genericdef:=current_structdef;
1869              parse_generic:=true;
1870            end;
1871          if assigned(current_structdef) and (df_specialization in current_structdef.defoptions) then
1872            current_specializedef:=current_structdef;
1873 
1874          { calculate the lexical level }
1875          if procdef.parast.symtablelevel>maxnesting then
1876            Message(parser_e_too_much_lexlevel);
1877          block_type:=bt_body;
1878 
1879     {$ifdef state_tracking}
1880 {    aktstate:=Tstate_storage.create;}
1881     {$endif state_tracking}
1882 
1883          { allocate the symbol for this procedure }
1884          alloc_proc_symbol(procdef);
1885 
1886          { add parast/localst to symtablestack }
1887          add_to_symtablestack;
1888 
1889          { save entry info }
1890          entrypos:=current_filepos;
1891          entryswitches:=current_settings.localswitches;
1892 
1893          recordtokens:=procdef.is_generic or
1894                        (
1895                          assigned(procdef.struct) and
1896                          (df_generic in procdef.struct.defoptions) and
1897                          assigned(procdef.owner) and
1898                          (procdef.owner.defowner=procdef.struct)
1899                        );
1900 
1901          if recordtokens then
1902            begin
1903              { start token recorder for generic template }
1904              procdef.initgeneric;
1905              current_scanner.startrecordtokens(procdef.generictokenbuf);
1906            end;
1907 
1908          { parse the code ... }
1909          code:=block(current_module.islibrary);
1910 
1911          if recordtokens then
1912            begin
1913              { stop token recorder for generic template }
1914              current_scanner.stoprecordtokens;
1915 
1916              { Give an error for accesses in the static symtable that aren't visible
1917                outside the current unit }
1918              st:=procdef.owner;
1919              while (st.symtabletype in [ObjectSymtable,recordsymtable]) do
1920                st:=st.defowner.owner;
1921              if (pi_uses_static_symtable in flags) and
1922                 (st.symtabletype<>staticsymtable) then
1923                Message(parser_e_global_generic_references_static);
1924            end;
1925 
1926          { save exit info }
1927          exitswitches:=current_settings.localswitches;
1928          exitpos:=last_endtoken_filepos;
1929 
1930          { the procedure is now defined }
1931          procdef.forwarddef:=false;
1932 
1933          if assigned(code) then
1934            begin
1935              { get a better entry point }
1936              entrypos:=code.fileinfo;
1937 
1938              { Finish type checking pass }
1939              do_typecheckpass(code);
1940 
1941              if assigned(procdef.parentfpinitblock) then
1942                begin
1943                  if assigned(tblocknode(procdef.parentfpinitblock).left) then
1944                    begin
1945                      parentfpinitblock:=procdef.parentfpinitblock;
1946                      do_typecheckpass(parentfpinitblock);
1947                      procdef.parentfpinitblock:=parentfpinitblock;
1948                    end
1949                end;
1950 
1951            end;
1952 
1953          { Check for unused labels, forwards, symbols for procedures. Static
1954            symtable is checked in pmodules.
1955            The check must be done after the typecheckpass }
1956          if (Errorcount=0) and
1957             (tstoredsymtable(procdef.localst).symtabletype<>staticsymtable) then
1958            begin
1959              { check if forwards are resolved }
1960              tstoredsymtable(procdef.localst).check_forwards;
1961              { check if all labels are used }
1962              tstoredsymtable(procdef.localst).checklabels;
1963              { check for unused symbols, but only if there is no asm block }
1964              if not(pi_has_assembler_block in flags) then
1965                begin
1966                  tstoredsymtable(procdef.localst).allsymbolsused;
1967                  tstoredsymtable(procdef.parast).allsymbolsused;
1968                end;
1969            end;
1970 
1971          if (po_inline in procdef.procoptions) and
1972            { Can we inline this procedure? }
1973            checknodeinlining(procdef) then
1974            CreateInlineInfo;
1975 
1976          { Print the node to tree.log }
1977          if paraprintnodetree=1 then
1978            printproc( 'after parsing');
1979 
1980          { ... remove symbol tables }
1981          remove_from_symtablestack;
1982 
1983     {$ifdef state_tracking}
1984 {    aktstate.destroy;}
1985     {$endif state_tracking}
1986 
1987          current_structdef:=old_current_structdef;
1988          current_genericdef:=old_current_genericdef;
1989          current_specializedef:=old_current_specializedef;
1990          current_procinfo:=old_current_procinfo;
1991          parse_generic:=old_parse_generic;
1992 
1993          { Restore old state }
1994          block_type:=old_block_type;
1995       end;
1996 
1997 
1998 {****************************************************************************
1999                         PROCEDURE/FUNCTION PARSING
2000 ****************************************************************************}
2001 
2002 
2003     procedure check_init_paras(p:TObject;arg:pointer);
2004       begin
2005         if tsym(p).typ<>paravarsym then
2006          exit;
2007         with tparavarsym(p) do
2008           if (is_managed_type(vardef) and
2009              (varspez in [vs_value,vs_out])) or
2010              (is_shortstring(vardef) and
2011              (varspez=vs_value)) then
2012             include(current_procinfo.flags,pi_do_call);
2013       end;
2014 
2015 
2016     procedure read_proc_body(old_current_procinfo:tprocinfo;pd:tprocdef);
2017       {
2018         Parses the procedure directives, then parses the procedure body, then
2019         generates the code for it
2020       }
2021 
2022       var
2023         oldfailtokenmode : tmodeswitches;
2024         isnestedproc     : boolean;
2025       begin
2026         Message1(parser_d_procedure_start,pd.fullprocname(false));
2027         oldfailtokenmode:=[];
2028 
2029         { create a new procedure }
2030         current_procinfo:=cprocinfo.create(old_current_procinfo);
2031         current_module.procinfo:=current_procinfo;
2032         current_procinfo.procdef:=pd;
2033         isnestedproc:=(current_procinfo.procdef.parast.symtablelevel>normal_function_level);
2034 
2035         { Insert mangledname }
2036         pd.aliasnames.insert(pd.mangledname);
2037 
2038         { Handle Export of this procedure }
2039         if (po_exports in pd.procoptions) and
2040            (target_info.system in [system_i386_os2,system_i386_emx]) then
2041           begin
2042             pd.aliasnames.insert(pd.procsym.realname);
2043             if cs_link_deffile in current_settings.globalswitches then
2044               deffile.AddExport(pd.mangledname);
2045           end;
2046 
2047         { Insert result variables in the localst }
2048         insert_funcret_local(pd);
2049 
2050         { check if there are para's which require initing -> set }
2051         { pi_do_call (if not yet set)                            }
2052         if not(pi_do_call in current_procinfo.flags) then
2053           pd.parast.SymList.ForEachCall(@check_init_paras,nil);
2054 
2055         { set _FAIL as keyword if constructor }
2056         if (pd.proctypeoption=potype_constructor) then
2057          begin
2058            oldfailtokenmode:=tokeninfo^[_FAIL].keyword;
2059            tokeninfo^[_FAIL].keyword:=alllanguagemodes;
2060          end;
2061 
2062         tcgprocinfo(current_procinfo).parse_body;
2063 
2064         { reset _FAIL as _SELF normal }
2065         if (pd.proctypeoption=potype_constructor) then
2066           tokeninfo^[_FAIL].keyword:=oldfailtokenmode;
2067 
2068         { We can't support inlining for procedures that have nested
2069           procedures because the nested procedures use a fixed offset
2070           for accessing locals in the parent procedure (PFV) }
2071         if current_procinfo.has_nestedprocs then
2072           begin
2073             if (po_inline in current_procinfo.procdef.procoptions) then
2074               begin
2075                 Message1(parser_h_not_supported_for_inline,'nested procedures');
2076                 Message(parser_h_inlining_disabled);
2077                 exclude(current_procinfo.procdef.procoptions,po_inline);
2078               end;
2079           end;
2080 
2081         { When it's a nested procedure then defer the code generation,
2082           when back at normal function level then generate the code
2083           for all defered nested procedures and the current procedure }
2084         if not isnestedproc then
2085           begin
2086             if not(df_generic in current_procinfo.procdef.defoptions) then
2087               begin
2088                 { also generate the bodies for all previously done
2089                   specializations so that we might inline them }
2090                 generate_specialization_procs;
2091                 tcgprocinfo(current_procinfo).generate_code_tree;
2092               end;
2093           end;
2094 
2095         { release procinfo }
2096         if tprocinfo(current_module.procinfo)<>current_procinfo then
2097           internalerror(200304274);
2098         current_module.procinfo:=current_procinfo.parent;
2099 
2100         { For specialization we didn't record the last semicolon. Moving this parsing
2101           into the parse_body routine is not done because of having better file position
2102           information available }
2103         if not current_procinfo.procdef.is_specialization and
2104             (
2105               not assigned(current_procinfo.procdef.struct) or
2106               not (df_specialization in current_procinfo.procdef.struct.defoptions)
2107               or not (
2108                 assigned(current_procinfo.procdef.owner) and
2109                 (current_procinfo.procdef.owner.defowner=current_procinfo.procdef.struct)
2110               )
2111             ) then
2112           consume(_SEMICOLON);
2113 
2114         if not isnestedproc then
2115           { current_procinfo is checked for nil later on }
2116           freeandnil(current_procinfo);
2117       end;
2118 
2119 
2120     procedure read_proc_body(pd:tprocdef);
2121       var
2122         old_module_procinfo : tobject;
2123         old_current_procinfo : tprocinfo;
2124       begin
2125         old_current_procinfo:=current_procinfo;
2126         old_module_procinfo:=current_module.procinfo;
2127         current_procinfo:=nil;
2128         current_module.procinfo:=nil;
2129         read_proc_body(nil,pd);
2130         current_procinfo:=old_current_procinfo;
2131         current_module.procinfo:=old_module_procinfo;
2132       end;
2133 
2134 
2135     procedure read_proc(isclassmethod:boolean; usefwpd: tprocdef;isgeneric:boolean);
2136       {
2137         Parses the procedure directives, then parses the procedure body, then
2138         generates the code for it
2139       }
2140 
2141       var
2142         old_current_procinfo : tprocinfo;
2143         old_current_structdef: tabstractrecorddef;
2144         old_current_genericdef,
2145         old_current_specializedef: tstoreddef;
2146         pdflags    : tpdflags;
2147         def,pd,firstpd : tprocdef;
2148         srsym : tsym;
2149         i : longint;
2150       begin
2151          { save old state }
2152          old_current_procinfo:=current_procinfo;
2153          old_current_structdef:=current_structdef;
2154          old_current_genericdef:=current_genericdef;
2155          old_current_specializedef:=current_specializedef;
2156 
2157          { reset current_procinfo.procdef to nil to be sure that nothing is writing
2158            to another procdef }
2159          current_procinfo:=nil;
2160          current_structdef:=nil;
2161          current_genericdef:=nil;
2162          current_specializedef:=nil;
2163 
2164          if not assigned(usefwpd) then
2165            { parse procedure declaration }
2166            pd:=parse_proc_dec(isclassmethod,old_current_structdef,isgeneric)
2167          else
2168            pd:=usefwpd;
2169 
2170          { set the default function options }
2171          if parse_only then
2172           begin
2173             pd.forwarddef:=true;
2174             { set also the interface flag, for better error message when the
2175               implementation doesn't match this header }
2176             pd.interfacedef:=true;
2177             include(pd.procoptions,po_global);
2178             pdflags:=[pd_interface];
2179           end
2180          else
2181           begin
2182             pdflags:=[pd_body];
2183             if (not current_module.in_interface) then
2184               include(pdflags,pd_implemen);
2185             if (not current_module.is_unit) or
2186                create_smartlink_library then
2187               include(pd.procoptions,po_global);
2188             pd.forwarddef:=false;
2189           end;
2190 
2191          if not assigned(usefwpd) then
2192            begin
2193              { parse the directives that may follow }
2194              parse_proc_directives(pd,pdflags);
2195 
2196              { hint directives, these can be separated by semicolons here,
2197                that needs to be handled here with a loop (PFV) }
2198              while try_consume_hintdirective(pd.symoptions,pd.deprecatedmsg) do
2199               Consume(_SEMICOLON);
2200 
2201              { Set calling convention }
2202              if parse_only then
2203                handle_calling_convention(pd,hcc_default_actions_intf)
2204              else
2205                handle_calling_convention(pd,hcc_default_actions_impl)
2206            end;
2207 
2208          { search for forward declarations }
2209          if not proc_add_definition(pd) then
2210            begin
2211              { A method must be forward defined (in the object declaration) }
2212              if assigned(pd.struct) and
2213                 (not assigned(old_current_structdef)) then
2214               begin
2215                 MessagePos1(pd.fileinfo,parser_e_header_dont_match_any_member,pd.fullprocname(false));
2216                 tprocsym(pd.procsym).write_parameter_lists(pd);
2217               end
2218              else
2219               begin
2220                 { Give a better error if there is a forward def in the interface and only
2221                   a single implementation }
2222                 firstpd:=tprocdef(tprocsym(pd.procsym).ProcdefList[0]);
2223                 if (not pd.forwarddef) and
2224                    (not pd.interfacedef) and
2225                    (tprocsym(pd.procsym).ProcdefList.Count>1) and
2226                    firstpd.forwarddef and
2227                    firstpd.interfacedef and
2228                    not(tprocsym(pd.procsym).ProcdefList.Count>2) and
2229                    { don't give an error if it may be an overload }
2230                    not(m_fpc in current_settings.modeswitches) and
2231                    (not(po_overload in pd.procoptions) or
2232                     not(po_overload in firstpd.procoptions)) then
2233                  begin
2234                    MessagePos1(pd.fileinfo,parser_e_header_dont_match_forward,pd.fullprocname(false));
2235                    tprocsym(pd.procsym).write_parameter_lists(pd);
2236                  end
2237                 else
2238                   begin
2239                     if pd.is_generic and not assigned(pd.struct) then
2240                       tprocsym(pd.procsym).owner.includeoption(sto_has_generic);
2241                   end;
2242               end;
2243            end;
2244 
2245          { Set mangled name }
2246          proc_set_mangledname(pd);
2247 
2248          { inherit generic flags from parent routine }
2249          if assigned(old_current_procinfo) and
2250              (old_current_procinfo.procdef.defoptions*[df_specialization,df_generic]<>[]) then
2251            begin
2252              if df_generic in old_current_procinfo.procdef.defoptions then
2253                include(pd.defoptions,df_generic);
2254              if df_specialization in old_current_procinfo.procdef.defoptions then
2255                begin
2256                  include(pd.defoptions,df_specialization);
2257                  { the procdefs encountered here are nested procdefs of which
2258                    their complete definition also resides inside the current token
2259                    stream, thus access to their genericdef is not required }
2260                  {$ifdef genericdef_for_nested}
2261                  { find the corresponding routine in the generic routine }
2262                  if not assigned(old_current_procinfo.procdef.genericdef) then
2263                    internalerror(2016121701);
2264                  srsym:=tsym(tprocdef(old_current_procinfo.procdef.genericdef).getsymtable(gs_local).find(pd.procsym.name));
2265                  if not assigned(srsym) or (srsym.typ<>procsym) then
2266                    internalerror(2016121702);
2267                  { in practice the generic procdef should be at the same index
2268                    as the index of the current procdef, but as there *might* be
2269                    differences between the amount of defs generated for the
2270                    specialization and the generic search for the def using
2271                    parameter comparison }
2272                  for i:=0 to tprocsym(srsym).procdeflist.count-1 do
2273                    begin
2274                      def:=tprocdef(tprocsym(srsym).procdeflist[i]);
2275                      if (compare_paras(def.paras,pd.paras,cp_none,[cpo_ignorehidden,cpo_openequalisexact,cpo_ignoreuniv])=te_exact) and
2276                          (compare_defs(def.returndef,pd.returndef,nothingn)=te_exact) then
2277                        begin
2278                          pd.genericdef:=def;
2279                          break;
2280                        end;
2281                    end;
2282                  if not assigned(pd.genericdef) then
2283                    internalerror(2016121703);
2284                  {$endif}
2285                end;
2286            end;
2287 
2288          { compile procedure when a body is needed }
2289          if (pd_body in pdflags) then
2290            begin
2291              read_proc_body(old_current_procinfo,pd);
2292            end
2293          else
2294            begin
2295              { Handle imports }
2296              if (po_external in pd.procoptions) then
2297                begin
2298                  import_external_proc(pd);
2299 {$ifdef cpuhighleveltarget}
2300                  { it's hard to factor this out in a virtual method, because the
2301                    generic version (the one inside this ifdef) doesn't fit in
2302                    hlcgobj but in symcreat or here, while the other version
2303                    doesn't fit in symcreat (since it uses the code generator).
2304                    Maybe we need another class for this kind of code that could
2305                    either be symcreat- or hlcgobj-based
2306                  }
2307                  if (not pd.forwarddef) and
2308                     (pd.hasforward) and
2309                     (proc_get_importname(pd)<>'') then
2310                    call_through_new_name(pd,proc_get_importname(pd))
2311                  else
2312 {$endif cpuhighleveltarget}
2313                    begin
2314                      create_hlcodegen;
2315                      hlcg.handle_external_proc(
2316                        current_asmdata.asmlists[al_procedures],
2317                        pd,
2318                        proc_get_importname(pd));
2319                      destroy_hlcodegen;
2320                    end
2321                end;
2322            end;
2323 
2324          { always register public functions that are only declared in the
2325            implementation section as they might be called using an external
2326            declaration from another unit }
2327          if (po_global in pd.procoptions) and
2328              not pd.interfacedef and
2329              ([df_generic,df_specialization]*pd.defoptions=[]) then
2330            begin
2331              pd.register_def;
2332              pd.procsym.register_sym;
2333            end;
2334 
2335          { make sure that references to forward-declared functions are not }
2336          { treated as references to external symbols, needed for darwin.   }
2337 
2338          { make sure we don't change the binding of real external symbols }
2339          if (([po_external,po_weakexternal]*pd.procoptions)=[]) and (pocall_internproc<>pd.proccalloption) then
2340            begin
2341              if (po_global in pd.procoptions) or
2342                 (cs_profile in current_settings.moduleswitches) then
pdnull2343                current_asmdata.DefineAsmSymbol(pd.mangledname,AB_GLOBAL,AT_FUNCTION,pd)
2344              else
2345                current_asmdata.DefineAsmSymbol(pd.mangledname,AB_LOCAL,AT_FUNCTION,pd);
2346            end;
2347 
2348          current_structdef:=old_current_structdef;
2349          current_genericdef:=old_current_genericdef;
2350          current_specializedef:=old_current_specializedef;
2351          current_procinfo:=old_current_procinfo;
2352       end;
2353 
2354 
2355     procedure import_external_proc(pd:tprocdef);
2356       var
2357         name : string;
2358       begin
2359         if not (po_external in pd.procoptions) then
2360           internalerror(2015121101);
2361 
2362         { Import DLL specified? }
2363         if assigned(pd.import_dll) then
2364           begin
2365             if assigned (pd.import_name) then
2366               current_module.AddExternalImport(pd.import_dll^,
2367                 pd.import_name^,proc_get_importname(pd),
2368                 pd.import_nr,false,false)
2369             else
2370               current_module.AddExternalImport(pd.import_dll^,
2371                 proc_get_importname(pd),proc_get_importname(pd),
2372                 pd.import_nr,false,true);
2373           end
2374         else
2375           begin
2376             name:=proc_get_importname(pd);
2377             { add import name to external list for DLL scanning }
2378             if tf_has_dllscanner in target_info.flags then
2379               current_module.dllscannerinputlist.Add(name,pd);
2380             { needed for units that use functions in packages this way }
2381             current_module.add_extern_asmsym(name,AB_EXTERNAL,AT_FUNCTION);
endnull2382           end;
2383       end;
2384 
2385 {****************************************************************************
2386                              DECLARATION PARSING
2387 ****************************************************************************}
2388 
2389     { search in symtablestack for not complete classes }
2390     procedure check_forward_class(p:TObject;arg:pointer);
2391       begin
2392         if (tsym(p).typ=typesym) and
2393            (ttypesym(p).typedef.typ=objectdef) and
2394            (oo_is_forward in tobjectdef(ttypesym(p).typedef).objectoptions) then
2395           MessagePos1(tsym(p).fileinfo,sym_e_forward_type_not_resolved,tsym(p).realname);
2396       end;
2397 
2398 
2399     procedure read_declarations(islibrary : boolean);
2400       var
2401         hadgeneric : boolean;
2402 
2403         procedure handle_unexpected_had_generic;
2404           begin
2405             if hadgeneric then
2406               begin
2407                 Message(parser_e_procedure_or_function_expected);
2408                 hadgeneric:=false;
2409               end;
2410           end;
2411 
2412       var
2413         is_classdef:boolean;
2414       begin
2415         is_classdef:=false;
2416         hadgeneric:=false;
2417         repeat
2418            if not assigned(current_procinfo) then
2419              internalerror(200304251);
2420            case token of
2421               _LABEL:
2422                 begin
2423                   handle_unexpected_had_generic;
2424                   label_dec;
2425                 end;
2426               _CONST:
2427                 begin
2428                   handle_unexpected_had_generic;
2429                   const_dec(hadgeneric);
2430                 end;
2431               _TYPE:
2432                 begin
2433                   handle_unexpected_had_generic;
2434                   type_dec(hadgeneric);
2435                 end;
2436               _VAR:
2437                 begin
2438                   handle_unexpected_had_generic;
2439                   var_dec(hadgeneric);
2440                 end;
2441               _THREADVAR:
2442                 begin
2443                   handle_unexpected_had_generic;
2444                   threadvar_dec(hadgeneric);
2445                 end;
2446               _CLASS:
2447                 begin
2448                   is_classdef:=false;
2449                   if try_to_consume(_CLASS) then
2450                    begin
2451                      { class modifier is only allowed for procedures, functions, }
2452                      { constructors, destructors                                 }
_PROCEDUREnull2453                      if not((token in [_FUNCTION,_PROCEDURE,_DESTRUCTOR,_OPERATOR]) or (token=_CONSTRUCTOR)) and
2454                         not((token=_ID) and (idtoken=_OPERATOR)) then
2455                        Message(parser_e_procedure_or_function_expected);
2456 
2457                      if is_interface(current_structdef) then
2458                        Message(parser_e_no_static_method_in_interfaces)
2459                      else
2460                        { class methods are also allowed for Objective-C protocols }
2461                        is_classdef:=true;
2462                    end;
2463                 end;
2464               _CONSTRUCTOR,
2465               _DESTRUCTOR,
2466               _FUNCTION,
2467               _PROCEDURE,
2468               _OPERATOR:
2469                 begin
2470                   if hadgeneric and not (token in [_PROCEDURE,_FUNCTION]) then
2471                     begin
2472                       Message(parser_e_procedure_or_function_expected);
2473                       hadgeneric:=false;
2474                     end;
2475                   read_proc(is_classdef,nil,hadgeneric);
2476                   is_classdef:=false;
2477                   hadgeneric:=false;
2478                 end;
2479               _EXPORTS:
2480                 begin
2481                    handle_unexpected_had_generic;
2482                    if (current_procinfo.procdef.localst.symtablelevel>main_program_level) then
2483                      begin
2484                         Message(parser_e_syntax_error);
2485                         consume_all_until(_SEMICOLON);
2486                      end
2487                    else if islibrary or
2488                      (target_info.system in systems_unit_program_exports) then
2489                      read_exports
2490                    else
2491                      begin
2492                         Message(parser_w_unsupported_feature);
2493                         consume(_BEGIN);
2494                      end;
2495                 end;
2496               _PROPERTY:
2497                 begin
2498                   handle_unexpected_had_generic;
2499                   if (m_fpc in current_settings.modeswitches) then
2500                     property_dec
2501                   else
2502                     break;
2503                 end;
2504               else
2505                 begin
2506                   case idtoken of
2507                     _RESOURCESTRING:
2508                       begin
2509                         handle_unexpected_had_generic;
2510                         { m_class is needed, because the resourcestring
2511                           loading is in the ObjPas unit }
2512 {                        if (m_class in current_settings.modeswitches) then}
2513                           resourcestring_dec(hadgeneric)
2514 {                        else
2515                           break;}
2516                       end;
2517                     _OPERATOR:
2518                       begin
2519                         handle_unexpected_had_generic;
2520                         if is_classdef then
2521                           begin
2522                             read_proc(is_classdef,nil,false);
2523                             is_classdef:=false;
2524                           end
2525                         else
2526                           break;
2527                       end;
2528                     _GENERIC:
2529                       begin
2530                         handle_unexpected_had_generic;
2531                         if not (m_delphi in current_settings.modeswitches) then
2532                           begin
2533                             consume(_ID);
2534                             hadgeneric:=true;
2535                           end
2536                         else
2537                           break;
2538                       end
2539                     else
2540                       break;
2541                   end;
2542                 end;
2543            end;
2544          until false;
2545 
2546          { add implementations for synthetic method declarations added by
2547            the compiler (not for unit/program init functions, their localst
2548            is the staticst -> would duplicate the work done in pmodules) }
2549          if current_procinfo.procdef.localst.symtabletype=localsymtable then
2550            add_synthetic_method_implementations(current_procinfo.procdef.localst);
2551 
2552          { check for incomplete class definitions, this is only required
2553            for fpc modes }
2554          if (m_fpc in current_settings.modeswitches) then
2555            current_procinfo.procdef.localst.SymList.ForEachCall(@check_forward_class,nil);
2556       end;
2557 
2558 
2559     procedure read_interface_declarations;
2560       var
2561         hadgeneric : boolean;
2562 
2563         procedure handle_unexpected_had_generic;
2564           begin
2565             if hadgeneric then
2566               begin
2567                 Message(parser_e_procedure_or_function_expected);
2568                 hadgeneric:=false;
2569               end;
2570           end;
2571 
2572       begin
2573          hadgeneric:=false;
2574          repeat
2575            case token of
2576              _CONST :
2577                begin
2578                  handle_unexpected_had_generic;
2579                  const_dec(hadgeneric);
2580                end;
2581              _TYPE :
2582                begin
2583                  handle_unexpected_had_generic;
2584                  type_dec(hadgeneric);
2585                end;
2586              _VAR :
2587                begin
2588                  handle_unexpected_had_generic;
2589                  var_dec(hadgeneric);
2590                end;
2591              _THREADVAR :
2592                begin
2593                  handle_unexpected_had_generic;
2594                  threadvar_dec(hadgeneric);
2595                end;
2596              _FUNCTION,
_PROCEDUREnull2597              _PROCEDURE,
2598              _OPERATOR :
2599                begin
2600                  if hadgeneric and not (token in [_FUNCTION, _PROCEDURE]) then
2601                    begin
2602                      message(parser_e_procedure_or_function_expected);
2603                      hadgeneric:=false;
2604                    end;
2605                  read_proc(false,nil,hadgeneric);
2606                  hadgeneric:=false;
2607                end;
2608              else
2609                begin
2610                  case idtoken of
2611                    _RESOURCESTRING :
2612                      begin
2613                        handle_unexpected_had_generic;
2614                        resourcestring_dec(hadgeneric);
2615                      end;
2616                    _PROPERTY:
2617                      begin
2618                        handle_unexpected_had_generic;
2619                        if (m_fpc in current_settings.modeswitches) then
2620                          property_dec
2621                        else
2622                          break;
2623                      end;
2624                    _GENERIC:
2625                      begin
2626                        handle_unexpected_had_generic;
2627                        if not (m_delphi in current_settings.modeswitches) then
2628                          begin
2629                            hadgeneric:=true;
2630                            consume(_ID);
2631                          end
2632                        else
2633                          break;
2634                      end
2635                    else
2636                      break;
2637                  end;
2638                end;
2639            end;
2640          until false;
2641          { check for incomplete class definitions, this is only required
2642            for fpc modes }
2643          if (m_fpc in current_settings.modeswitches) then
2644           symtablestack.top.SymList.ForEachCall(@check_forward_class,nil);
2645       end;
2646 
2647 
2648 end.
2649