1 {
2     DFA
3 
4     Copyright (c) 2007 by Florian Klaempfl
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 
23 { $define DEBUG_DFA}
24 { $define EXTDEBUG_DFA}
25 
26 { this unit implements routines to perform dfa }
27 unit optdfa;
28 
29 {$i fpcdefs.inc}
30 
31   interface
32 
33     uses
34       node,optutils;
35 
36     type
37       TDFABuilder = class
38       protected
39         procedure CreateLifeInfo(node : tnode;map : TIndexedNodeSet);
40       public
41         resultnode : tnode;
42         nodemap : TIndexedNodeSet;
43         { reset all dfa info, this is required before creating dfa info
44           if the tree has been changed without updating dfa }
45         procedure resetdfainfo(node : tnode);
46 
47         procedure createdfainfo(node : tnode);
48         destructor destroy;override;
49       end;
50 
51     procedure CheckAndWarn(code : tnode;nodetosearch : tnode);
52 
53   implementation
54 
55     uses
56       globtype,
57       verbose,
58       symconst,symdef,symsym,
59       defutil,
60       procinfo,
61       nutils,htypechk,
62       nbas,nflw,ncal,nset,nld,nadd,
63       optbase;
64 
65 
66     (*
67     function initnodes(var n:tnode; arg: pointer) : foreachnoderesult;
68       begin
69         { node worth to add? }
70         if (node_complexity(n)>1) and (tstoreddef(n.resultdef).is_intregable or tstoreddef(n.resultdef).is_fpuregable) then
71           begin
72             plists(arg)^.nodelist.Add(n);
73             plists(arg)^.locationlist.Add(@n);
74             result:=fen_false;
75           end
76         else
77           result:=fen_norecurse_false;
78       end;
79     *)
80 
81     {
82       x:=f;         read: [f]
83 
84       while x do    read: []
85 
86         a:=b;       read: [a,b,d]  def: [a]       life:  read*def=[a]
87           c:=d;     read: [a,d]    def: [a,c]     life:  read*def=[a]
88             e:=a;   read: [a]      def: [a,c,e]   life:  read*def=[a]
89 
90 
91       function f(b,d,x : type) : type;
92 
93         begin
94           while x do        alive: b,d,x
95             begin
96               a:=b;         alive: b,d,x
97               c:=d;         alive: a,d,x
98               e:=a+c;       alive: a,c,x
99               dec(x);       alive: c,e,x
100             end;
101           result:=c+e;      alive: c,e
102         end;                alive: result
103 
104     }
105 
106     type
107       tdfainfo = record
108         use : PDFASet;
109         def : PDFASet;
110         map : TIndexedNodeSet
111       end;
112       pdfainfo = ^tdfainfo;
113 
AddDefUsenull114     function AddDefUse(var n: tnode; arg: pointer): foreachnoderesult;
115       begin
116         case n.nodetype of
117           tempcreaten:
118             begin
119               if assigned(ttempcreatenode(n).tempinfo^.tempinitcode) then
120                 begin
121                   pdfainfo(arg)^.map.Add(n);
122                   DFASetInclude(pdfainfo(arg)^.def^,n.optinfo^.index);
123                 end;
124             end;
125           temprefn,
126           loadn:
127             begin
128               pdfainfo(arg)^.map.Add(n);
129               if nf_modify in n.flags then
130                 begin
131                   DFASetInclude(pdfainfo(arg)^.use^,n.optinfo^.index);
132                   DFASetInclude(pdfainfo(arg)^.def^,n.optinfo^.index)
133                 end
134               else if nf_write in n.flags then
135                 DFASetInclude(pdfainfo(arg)^.def^,n.optinfo^.index)
136               else
137                 DFASetInclude(pdfainfo(arg)^.use^,n.optinfo^.index);
138             end;
139         end;
140         result:=fen_false;
141       end;
142 
143 
ResetProcessingnull144     function ResetProcessing(var n: tnode; arg: pointer): foreachnoderesult;
145       begin
146         exclude(n.flags,nf_processing);
147         { dfa works only on normalized trees, so do not recurse into expressions, because
148           ResetProcessing eats a signififcant amount of time of CheckAndWarn
149 
150           the following set contains (hopefully) most of the expression nodes }
151         if n.nodetype in [calln,inlinen,assignn,callparan,andn,addn,orn,subn,muln,divn,slashn,notn,equaln,unequaln,gtn,ltn,lten,gten,loadn,
152           typeconvn,vecn,subscriptn,addrn,derefn] then
153           result:=fen_norecurse_false
154         else
155           result:=fen_false;
156       end;
157 
158 
ResetDFAnull159     function ResetDFA(var n: tnode; arg: pointer): foreachnoderesult;
160       begin
161         if assigned(n.optinfo) then
162           begin
163             with n.optinfo^ do
164               begin
165                 life:=nil;
166                 def:=nil;
167                 use:=nil;
168                 defsum:=nil;
169               end;
170           end;
171         result:=fen_false;
172       end;
173 
174 
175     procedure TDFABuilder.CreateLifeInfo(node : tnode;map : TIndexedNodeSet);
176 
177       var
178         changed : boolean;
179 
180       procedure CreateInfo(node : tnode);
181 
182         { update life entry of a node with l, set changed if this changes
183           life info for the node
184         }
185         procedure updatelifeinfo(n : tnode;l : TDFASet);
186           var
187             b : boolean;
188           begin
189             b:=DFASetNotEqual(l,n.optinfo^.life);
190 {$ifdef DEBUG_DFA}
191             if not(changed) and b then
192               begin
193                 writeln('Another DFA pass caused by: ',nodetype2str[n.nodetype],'(',n.fileinfo.line,',',n.fileinfo.column,')');
194                 write('  Life info set was:     ');PrintDFASet(Output,n.optinfo^.life);writeln;
195                 write('  Life info set will be: ');PrintDFASet(Output,l);writeln;
196               end;
197 {$endif DEBUG_DFA}
198 
199             changed:=changed or b;
200             n.optinfo^.life:=l;
201           end;
202 
203         procedure calclife(n : tnode);
204           var
205             l : TDFASet;
206           begin
207             if assigned(n.successor) then
208               begin
209                 { ensure we can access optinfo }
210                 DFASetDiff(l,n.successor.optinfo^.life,n.optinfo^.def);
211                 DFASetIncludeSet(l,n.optinfo^.use);
212                 DFASetIncludeSet(l,n.optinfo^.life);
213               end
214             else
215               begin
216                 l:=n.optinfo^.use;
217                 DFASetIncludeSet(l,n.optinfo^.life);
218               end;
219             updatelifeinfo(n,l);
220           end;
221 
222         var
223           dfainfo : tdfainfo;
224           l : TDFASet;
225           save: TDFASet;
226           i : longint;
227           counteruse_after_loop : boolean;
228         begin
229           if node=nil then
230             exit;
231 
232           { ensure we've already optinfo set }
233           node.allocoptinfo;
234 
235           if nf_processing in node.flags then
236             exit;
237           include(node.flags,nf_processing);
238 
239           if assigned(node.successor) then
240             CreateInfo(node.successor);
241 
242 {$ifdef EXTDEBUG_DFA}
243           writeln('Handling: ',nodetype2str[node.nodetype],'(',node.fileinfo.line,',',node.fileinfo.column,')');
244 {$endif EXTDEBUG_DFA}
245           { life:=succesorlive-definition+use }
246 
247           case node.nodetype of
248             whilerepeatn:
249               begin
250                 { analyze the loop condition }
251                 if not(assigned(node.optinfo^.def)) and
252                    not(assigned(node.optinfo^.use)) then
253                   begin
254                     dfainfo.use:=@node.optinfo^.use;
255                     dfainfo.def:=@node.optinfo^.def;
256                     dfainfo.map:=map;
257                     foreachnodestatic(pm_postprocess,twhilerepeatnode(node).left,@AddDefUse,@dfainfo);
258                   end;
259 
260                 { NB: this node should typically have empty def set }
261                 if assigned(node.successor) then
262                   DFASetDiff(l,node.successor.optinfo^.life,node.optinfo^.def)
263                 else if assigned(resultnode) then
264                   DFASetDiff(l,resultnode.optinfo^.life,node.optinfo^.def)
265                 else
266                   l:=nil;
267 
268                 { for repeat..until, node use set in included at the end of loop }
269                 if not (lnf_testatbegin in twhilerepeatnode(node).loopflags) then
270                   DFASetIncludeSet(l,node.optinfo^.use);
271 
272                 DFASetIncludeSet(l,node.optinfo^.life);
273 
274                 save:=node.optinfo^.life;
275                 { to process body correctly, we need life info in place (because
276                   whilerepeatnode is successor of its body). }
277                 node.optinfo^.life:=l;
278 
279                 { now process the body }
280                 CreateInfo(twhilerepeatnode(node).right);
281 
282                 { restore, to prevent infinite recursion via changed flag }
283                 node.optinfo^.life:=save;
284 
285                 { for while loops, node use set is included at the beginning of loop }
286                 l:=twhilerepeatnode(node).right.optinfo^.life;
287                 if lnf_testatbegin in twhilerepeatnode(node).loopflags then
288                   DFASetIncludeSet(l,node.optinfo^.use);
289 
290                 UpdateLifeInfo(node,l);
291 
292                 { ... and a second iteration for fast convergence }
293                 CreateInfo(twhilerepeatnode(node).right);
294               end;
295 
296             forn:
297               begin
298                 {
299                   left: loopvar
300                   right: from
301                   t1: to
302                   t2: body
303                 }
304                 node.allocoptinfo;
305                 tfornode(node).loopiteration.allocoptinfo;
306                 if not(assigned(node.optinfo^.def)) and
307                    not(assigned(node.optinfo^.use)) then
308                   begin
309                     dfainfo.use:=@node.optinfo^.use;
310                     dfainfo.def:=@node.optinfo^.def;
311                     dfainfo.map:=map;
312                     foreachnodestatic(pm_postprocess,tfornode(node).left,@AddDefUse,@dfainfo);
313                     foreachnodestatic(pm_postprocess,tfornode(node).right,@AddDefUse,@dfainfo);
314                     foreachnodestatic(pm_postprocess,tfornode(node).t1,@AddDefUse,@dfainfo);
315                   end;
316 
317                 { create life for the body }
318                 CreateInfo(tfornode(node).t2);
319 
320                 { is the counter living after the loop?
321 
322                   if left is a record element, it might not be tracked by dfa, so
323                   optinfo might not be assigned
324                 }
325                 counteruse_after_loop:=assigned(tfornode(node).left.optinfo) and assigned(node.successor) and
326                   DFASetIn(node.successor.optinfo^.life,tfornode(node).left.optinfo^.index);
327 
328                 if counteruse_after_loop then
329                   begin
330                     { if yes, then we should warn }
331                     { !!!!!! }
332                   end;
333 
334                 { first update the dummy node }
335 
336                 { get the life of the loop block }
337                 l:=copy(tfornode(node).t2.optinfo^.life);
338 
339                 { take care of the sucessor }
340                 if assigned(node.successor) then
341                   DFASetIncludeSet(l,node.successor.optinfo^.life);
342 
343                 { the counter variable is living as well inside the for loop
344 
345                   if left is a record element, it might not be tracked by dfa, so
346                   optinfo might not be assigned
347                 }
348                 if assigned(tfornode(node).left.optinfo) then
349                   DFASetInclude(l,tfornode(node).left.optinfo^.index);
350 
351                 { force block node life info }
352                 UpdateLifeInfo(tfornode(node).loopiteration,l);
353 
354                 { now update the for node itself }
355 
356                 { get the life of the loop block }
357                 l:=copy(tfornode(node).t2.optinfo^.life);
358 
359                 { take care of the sucessor as it's possible that we don't have one execution of the body }
360                 if (not(tfornode(node).right.nodetype=ordconstn) or not(tfornode(node).t1.nodetype=ordconstn)) and
361                   assigned(node.successor) then
362                   DFASetIncludeSet(l,node.successor.optinfo^.life);
363 
364                 {
365                   the counter variable is not living at the entry of the for node
366 
367                   if left is a record element, it might not be tracked by dfa, so
368                     optinfo might not be assigned
369                 }
370                 if assigned(tfornode(node).left.optinfo) then
371                   DFASetExclude(l,tfornode(node).left.optinfo^.index);
372 
373                 { ... but it could be that left/right use it, so do this after
374                   removing the def of the counter variable }
375                 DFASetIncludeSet(l,node.optinfo^.use);
376 
377                 UpdateLifeInfo(node,l);
378 
379                 { ... and a second iteration for fast convergence }
380                 CreateInfo(tfornode(node).t2);
381               end;
382 
383             temprefn,
384             loadn,
385             typeconvn,
386             derefn,
387             assignn:
388               begin
389                 if not(assigned(node.optinfo^.def)) and
390                   not(assigned(node.optinfo^.use)) then
391                   begin
392                     dfainfo.use:=@node.optinfo^.use;
393                     dfainfo.def:=@node.optinfo^.def;
394                     dfainfo.map:=map;
395                     foreachnodestatic(pm_postprocess,node,@AddDefUse,@dfainfo);
396                   end;
397                 calclife(node);
398               end;
399 
400             statementn:
401               begin
402                 { nested statement }
403                 CreateInfo(tstatementnode(node).statement);
404                 { inherit info }
405                 node.optinfo^.life:=tstatementnode(node).statement.optinfo^.life;
406               end;
407 
408             blockn:
409               begin
410                 CreateInfo(tblocknode(node).statements);
411                 { ensure that we don't remove life info }
412                 l:=node.optinfo^.life;
413                 if assigned(node.successor) then
414                   DFASetIncludeSet(l,node.successor.optinfo^.life);
415                 UpdateLifeInfo(node,l);
416               end;
417 
418             ifn:
419               begin
420                 { get information from cond. expression }
421                 if not(assigned(node.optinfo^.def)) and
422                    not(assigned(node.optinfo^.use)) then
423                   begin
424                     dfainfo.use:=@node.optinfo^.use;
425                     dfainfo.def:=@node.optinfo^.def;
426                     dfainfo.map:=map;
427                     foreachnodestatic(pm_postprocess,tifnode(node).left,@AddDefUse,@dfainfo);
428                   end;
429 
430                 { create life info for then and else node }
431                 CreateInfo(tifnode(node).right);
432                 CreateInfo(tifnode(node).t1);
433 
434                 { ensure that we don't remove life info }
435                 l:=node.optinfo^.life;
436 
437                 { get life info from then branch }
438                 if assigned(tifnode(node).right) then
439                   DFASetIncludeSet(l,tifnode(node).right.optinfo^.life);
440 
441                 { get life info from else branch }
442                 if assigned(tifnode(node).t1) then
443                   DFASetIncludeSet(l,tifnode(node).t1.optinfo^.life)
444                 else if assigned(node.successor) then
445                   DFASetIncludeSet(l,node.successor.optinfo^.life);
446 
447                 { remove def info from the cond. expression }
448                 DFASetExcludeSet(l,tifnode(node).optinfo^.def);
449 
450                 { add use info from the cond. expression }
451                 DFASetIncludeSet(l,tifnode(node).optinfo^.use);
452 
453                 { finally, update the life info of the node }
454                 UpdateLifeInfo(node,l);
455               end;
456 
457             casen:
458               begin
459                 { get information from "case" expression }
460                 if not(assigned(node.optinfo^.def)) and
461                    not(assigned(node.optinfo^.use)) then
462                   begin
463                     dfainfo.use:=@node.optinfo^.use;
464                     dfainfo.def:=@node.optinfo^.def;
465                     dfainfo.map:=map;
466                     foreachnodestatic(pm_postprocess,tcasenode(node).left,@AddDefUse,@dfainfo);
467                   end;
468 
469                 { create life info for block and else nodes }
470                 for i:=0 to tcasenode(node).blocks.count-1 do
471                   CreateInfo(pcaseblock(tcasenode(node).blocks[i])^.statement);
472 
473                 CreateInfo(tcasenode(node).elseblock);
474 
475                 { ensure that we don't remove life info }
476                 l:=node.optinfo^.life;
477 
478                 { get life info from case branches }
479                 for i:=0 to tcasenode(node).blocks.count-1 do
480                   DFASetIncludeSet(l,pcaseblock(tcasenode(node).blocks[i])^.statement.optinfo^.life);
481 
482                 { get life info from else branch or the succesor }
483                 if assigned(tcasenode(node).elseblock) then
484                   DFASetIncludeSet(l,tcasenode(node).elseblock.optinfo^.life)
485                 else if assigned(node.successor) then
486                   DFASetIncludeSet(l,node.successor.optinfo^.life);
487 
488                 { add use info from the "case" expression }
489                 DFASetIncludeSet(l,tcasenode(node).optinfo^.use);
490 
491                 { finally, update the life info of the node }
492                 UpdateLifeInfo(node,l);
493               end;
494 
495             exitn:
496               begin
497                 if not(is_void(current_procinfo.procdef.returndef)) then
498                   begin
499                     if not(assigned(node.optinfo^.def)) and
500                        not(assigned(node.optinfo^.use)) then
501                       begin
502                         if assigned(texitnode(node).left) then
503                           begin
504                             node.optinfo^.def:=resultnode.optinfo^.def;
505 
506                             dfainfo.use:=@node.optinfo^.use;
507                             dfainfo.def:=@node.optinfo^.def;
508                             dfainfo.map:=map;
509                             foreachnodestatic(pm_postprocess,texitnode(node).left,@AddDefUse,@dfainfo);
510                             calclife(node);
511                           end
512                         else
513                           begin
514                             { get info from faked resultnode }
515                             node.optinfo^.use:=resultnode.optinfo^.use;
516                             node.optinfo^.life:=node.optinfo^.use;
517                             changed:=true;
518                           end;
519                       end;
520                   end;
521               end;
522 
523 {$ifdef JVM}
524             { all other platforms except jvm translate raise nodes into call nodes during pass_1 }
525             raisen,
526 {$endif JVM}
527             asn,
528             inlinen,
529             calln:
530               begin
531                 if not(assigned(node.optinfo^.def)) and
532                   not(assigned(node.optinfo^.use)) then
533                   begin
534                     dfainfo.use:=@node.optinfo^.use;
535                     dfainfo.def:=@node.optinfo^.def;
536                     dfainfo.map:=map;
537                     foreachnodestatic(pm_postprocess,node,@AddDefUse,@dfainfo);
538                   end;
539                 calclife(node);
540               end;
541 
542             labeln:
543               begin
544                 calclife(node);
545 
546                 if assigned(tlabelnode(node).left) then
547                   begin
548                     l:=node.optinfo^.life;
549                     DFASetIncludeSet(l,tlabelnode(node).optinfo^.life);
550                     UpdateLifeInfo(node,l);
551                   end;
552               end;
553             tempcreaten,
554             tempdeleten,
555             nothingn,
556             continuen,
557             goton,
558             breakn:
559               begin
560                 calclife(node);
561               end;
562             else
563               internalerror(2007050502);
564           end;
565         end;
566 
567       var
568         runs : integer;
569       begin
570         runs:=0;
571         repeat
572           inc(runs);
573           changed:=false;
574           CreateInfo(node);
575           foreachnodestatic(pm_postprocess,node,@ResetProcessing,nil);
576           { the result node is not reached by foreachnodestatic }
577           exclude(resultnode.flags,nf_processing);
578 {$ifdef DEBUG_DFA}
579           PrintIndexedNodeSet(output,map);
580           PrintDFAInfo(output,node);
581 {$endif DEBUG_DFA}
582         until not(changed);
583 {$ifdef DEBUG_DFA}
584         writeln('DFA solver iterations: ',runs);
585 {$endif DEBUG_DFA}
586       end;
587 
588 
589     { reset all dfa info, this is required before creating dfa info
590       if the tree has been changed without updating dfa }
591     procedure TDFABuilder.resetdfainfo(node : tnode);
592       begin
593         foreachnodestatic(pm_postprocess,node,@ResetDFA,nil);
594       end;
595 
596 
597     procedure TDFABuilder.createdfainfo(node : tnode);
598       var
599         dfarec : tdfainfo;
600       begin
601         if not(assigned(nodemap)) then
602           nodemap:=TIndexedNodeSet.Create;
603 
604         { create a fake node using the result which will be the last node }
605         if not(is_void(current_procinfo.procdef.returndef)) then
606           begin
607             if current_procinfo.procdef.proctypeoption=potype_constructor then
608               resultnode:=load_self_node
609             else
610               resultnode:=load_result_node;
611             resultnode.allocoptinfo;
612             dfarec.use:=@resultnode.optinfo^.use;
613             dfarec.def:=@resultnode.optinfo^.def;
614             dfarec.map:=nodemap;
615             AddDefUse(resultnode,@dfarec);
616             resultnode.optinfo^.life:=resultnode.optinfo^.use;
617           end
618         else
619           begin
620             resultnode:=cnothingnode.create;
621             resultnode.allocoptinfo;
622           end;
623 
624         { add controll flow information }
625         SetNodeSucessors(node,resultnode);
626 
627         { now, collect life information }
628         CreateLifeInfo(node,nodemap);
629       end;
630 
631 
632     destructor TDFABuilder.Destroy;
633       begin
634         Resultnode.free;
635         nodemap.free;
636         inherited destroy;
637       end;
638 
639     var
640       { we have to pass the address of SearchNode in a call inside of SearchNode:
641         @SearchNode does not work because the compiler thinks we take the address of the result
642         so store the address from outside }
arnull643       SearchNodeProcPointer : function(var n: tnode; arg: pointer): foreachnoderesult;
644 
645     type
646       { helper structure to be able to pass more than one variable to the iterator function }
647       TSearchNodeInfo = record
648         nodetosearch : tnode;
649         { this contains a list of all file locations where a warning was thrown already,
650           the same location might appear multiple times because nodes might have been copied }
651         warnedfilelocs : array of tfileposinfo;
652       end;
653 
654       PSearchNodeInfo = ^TSearchNodeInfo;
655 
656     { searches for a given node n and warns if the node is found as being uninitialized. If a node is
657       found, searching is stopped so each call issues only one warning/hint }
SearchNodenull658     function SearchNode(var n: tnode; arg: pointer): foreachnoderesult;
659 
WarnedForLocationnull660       function WarnedForLocation(f : tfileposinfo) : boolean;
661         var
662           i : longint;
663         begin
664           result:=true;
665           for i:=0 to high(PSearchNodeInfo(arg)^.warnedfilelocs) do
666             with PSearchNodeInfo(arg)^.warnedfilelocs[i] do
667               begin
668                 if (f.column=column) and (f.fileindex=fileindex) and (f.line=line) and (f.moduleindex=moduleindex) then
669                   exit;
670               end;
671           result:=false;
672         end;
673 
674 
675       procedure AddFilepos(const f : tfileposinfo);
676         begin
677           Setlength(PSearchNodeInfo(arg)^.warnedfilelocs,length(PSearchNodeInfo(arg)^.warnedfilelocs)+1);
678           PSearchNodeInfo(arg)^.warnedfilelocs[high(PSearchNodeInfo(arg)^.warnedfilelocs)]:=f;
679         end;
680 
681 
682       { Checks if the symbol is a candidate for a warning.
683         Emit warning/note for living locals, result and parameters, but only about the current
684         symtables }
SymbolCandidateForWarningOrHintnull685       function SymbolCandidateForWarningOrHint(sym : tabstractnormalvarsym) : Boolean;
686         begin
687           Result:=(((sym.owner=current_procinfo.procdef.localst) and
688                     (current_procinfo.procdef.localst.symtablelevel=sym.owner.symtablelevel)
689                    ) or
690                    ((sym.owner=current_procinfo.procdef.parast) and
691                     (sym.typ=paravarsym) and
692                     (current_procinfo.procdef.parast.symtablelevel=sym.owner.symtablelevel) and
693                     { all parameters except out parameters are initialized by the caller }
694                     (tparavarsym(sym).varspez=vs_out)
695                    ) or
696                    ((vo_is_funcret in sym.varoptions) and
697                     (current_procinfo.procdef.parast.symtablelevel=sym.owner.symtablelevel)
698                    )
699                   ) and not(vo_is_external in sym.varoptions)
700         end;
701 
702       var
703         varsym : tabstractnormalvarsym;
704         methodpointer,
705         hpt : tnode;
706       begin
707         result:=fen_false;
708         case n.nodetype of
709           callparan:
710             begin
711               { do not warn about variables passed by var, just issue a hint, this
712                 is a workaround for old code e.g. using fillchar }
713               if assigned(tcallparanode(n).parasym) and (tcallparanode(n).parasym.varspez in [vs_var,vs_out]) then
714                 begin
715                   hpt:=tcallparanode(n).left;
716                   while assigned(hpt) and (hpt.nodetype in [subscriptn,vecn,typeconvn]) do
717                     hpt:=tunarynode(hpt).left;
718                   if assigned(hpt) and (hpt.nodetype=loadn) and not(WarnedForLocation(hpt.fileinfo)) and
719                     SymbolCandidateForWarningOrHint(tabstractnormalvarsym(tloadnode(hpt).symtableentry)) and
720                     PSearchNodeInfo(arg)^.nodetosearch.isequal(hpt) then
721                     begin
722                       { issue only a hint for var, when encountering the node passed as out, we need only to stop searching }
723                       if tcallparanode(n).parasym.varspez=vs_var then
724                         UninitializedVariableMessage(hpt.fileinfo,false,
725                           tloadnode(hpt).symtable.symtabletype=localsymtable,
726                           is_managed_type(tloadnode(hpt).resultdef),
727                           tloadnode(hpt).symtableentry.RealName);
728                       AddFilepos(hpt.fileinfo);
729                       result:=fen_norecurse_true;
730                     end
731                 end;
732             end;
733           orn,
734           andn:
735             begin
736               { take care of short boolean evaluation: if the expression to be search is found in left,
737                 we do not need to search right }
738               if foreachnodestatic(pm_postprocess,taddnode(n).left,SearchNodeProcPointer,arg) or
739                 foreachnodestatic(pm_postprocess,taddnode(n).right,SearchNodeProcPointer,arg) then
740                 result:=fen_norecurse_true
741               else
742                 result:=fen_norecurse_false;
743             end;
744           calln:
745             begin
746               methodpointer:=tcallnode(n).methodpointer;
747               if assigned(methodpointer) and (methodpointer.nodetype<>typen) then
748                begin
749                   { Remove all postfix operators }
750                   hpt:=methodpointer;
751                   while assigned(hpt) and (hpt.nodetype in [subscriptn,vecn]) do
752                     hpt:=tunarynode(hpt).left;
753 
754                  { skip (absolute and other simple) type conversions -- only now,
755                    because the checks above have to take type conversions into
756                    e.g. class reference types account }
757                  hpt:=actualtargetnode(@hpt)^;
758 
759                   { R.Init then R will be initialized by the constructor,
760                     Also allow it for simple loads }
761                   if (tcallnode(n).procdefinition.proctypeoption=potype_constructor) or
762                      (PSearchNodeInfo(arg)^.nodetosearch.isequal(hpt) and
763                       (((methodpointer.resultdef.typ=objectdef) and
764                         not(oo_has_virtual in tobjectdef(methodpointer.resultdef).objectoptions)) or
765                        (methodpointer.resultdef.typ=recorddef)
766                       )
767                      ) then
768                     begin
769                       { don't warn about the method pointer }
770                       AddFilepos(hpt.fileinfo);
771 
772                       if not(foreachnodestatic(pm_postprocess,tcallnode(n).left,SearchNodeProcPointer,arg)) then
773                         foreachnodestatic(pm_postprocess,tcallnode(n).right,SearchNodeProcPointer,arg);
774                       result:=fen_norecurse_true
775                     end;
776                  end;
777             end;
778           loadn:
779             begin
780               if (tloadnode(n).symtableentry.typ in [localvarsym,paravarsym,staticvarsym]) and
781                 PSearchNodeInfo(arg)^.nodetosearch.isequal(n) and ((nf_modify in n.flags) or not(nf_write in n.flags)) then
782                 begin
783                   varsym:=tabstractnormalvarsym(tloadnode(n).symtableentry);
784 
785                   if assigned(varsym.owner) and SymbolCandidateForWarningOrHint(varsym) then
786                     begin
787                       if (vo_is_funcret in varsym.varoptions) and not(WarnedForLocation(n.fileinfo)) then
788                         begin
789                           if is_managed_type(varsym.vardef) then
790                             MessagePos(n.fileinfo,sym_w_managed_function_result_uninitialized)
791                           else
792                             MessagePos(n.fileinfo,sym_w_function_result_uninitialized);
793                           AddFilepos(n.fileinfo);
794                           result:=fen_norecurse_true;
795                         end
796                       else
797                         begin
798                           { typed consts are initialized, further, warn only once per location }
799                           if not (vo_is_typed_const in varsym.varoptions) and not(WarnedForLocation(n.fileinfo)) then
800                             begin
801                               UninitializedVariableMessage(n.fileinfo,true,varsym.typ=localvarsym,is_managed_type(varsym.vardef),varsym.realname);
802                               AddFilepos(n.fileinfo);
803                               result:=fen_norecurse_true;
804                             end;
805                         end;
806                     end
807 {$ifdef dummy}
808                   { if a the variable we are looking for is passed as a var parameter, we stop searching }
809                   else if assigned(varsym.owner) and
810                      (varsym.owner=current_procinfo.procdef.parast) and
811                      (varsym.typ=paravarsym) and
812                      (current_procinfo.procdef.parast.symtablelevel=varsym.owner.symtablelevel) and
813                      (tparavarsym(varsym).varspez=vs_var) then
814                     result:=fen_norecurse_true;
815 {$endif dummy}
816                 end;
817             end;
818         end;
819       end;
820 
821 
822     procedure CheckAndWarn(code : tnode;nodetosearch : tnode);
823 
824       var
825         SearchNodeInfo : TSearchNodeInfo;
826 
DoChecknull827       function DoCheck(node : tnode) : boolean;
828         var
829           i : longint;
830           touchesnode : Boolean;
831 
832         procedure MaybeDoCheck(n : tnode);inline;
833           begin
834             Result:=Result or DoCheck(n);
835           end;
836 
837         procedure MaybeSearchIn(n : tnode);
838           begin
839             if touchesnode then
840               Result:=Result or foreachnodestatic(pm_postprocess,n,@SearchNode,@SearchNodeInfo);
841           end;
842 
843         begin
844           result:=false;
845 
846           if node=nil then
847             exit;
848 
849           if nf_processing in node.flags then
850             exit;
851           include(node.flags,nf_processing);
852 
853           if not(DFASetIn(node.optinfo^.life,nodetosearch.optinfo^.index)) then
854             exit;
855 
856           { we do not need this info always, so try to safe some time here, CheckAndWarn
857             takes a lot of time anyways }
858           if not(node.nodetype in [statementn,blockn]) then
859             touchesnode:=DFASetIn(node.optinfo^.use,nodetosearch.optinfo^.index) or
860               DFASetIn(node.optinfo^.def,nodetosearch.optinfo^.index)
861           else
862             touchesnode:=false;
863 
864           case node.nodetype of
865             whilerepeatn:
866               begin
867                 MaybeSearchIn(twhilerepeatnode(node).left);
868                 MaybeDoCheck(twhilerepeatnode(node).right);
869               end;
870 
871             forn:
872               begin
873                 MaybeSearchIn(tfornode(node).right);
874                 MaybeSearchIn(tfornode(node).t1);
875                 MaybeDoCheck(tfornode(node).t2);
876               end;
877 
878             statementn:
879               MaybeDoCheck(tstatementnode(node).statement);
880 
881             blockn:
882               MaybeDoCheck(tblocknode(node).statements);
883 
884             ifn:
885               begin
886                 MaybeSearchIn(tifnode(node).left);
887                 MaybeDoCheck(tifnode(node).right);
888                 MaybeDoCheck(tifnode(node).t1);
889               end;
890 
891             casen:
892               begin
893                 MaybeSearchIn(tcasenode(node).left);
894                 for i:=0 to tcasenode(node).blocks.count-1 do
895                   MaybeDoCheck(pcaseblock(tcasenode(node).blocks[i])^.statement);
896 
897                 MaybeDoCheck(tcasenode(node).elseblock);
898               end;
899 
900             labeln:
901               MaybeDoCheck(tlabelnode(node).left);
902 
903             { we are aware of the following nodes so if new node types are added to the compiler
904               and pop up in the search, the ie below kicks in as a reminder }
905             exitn:
906               begin
907                 MaybeSearchIn(texitnode(node).left);
908                 { exit uses the resultnode implicitly, so searching for a matching node is
909                   useless, if we reach the exit node and found the living node not in left, then
910                   it can be only the resultnode  }
911                 if not(Result) and not(is_void(current_procinfo.procdef.returndef)) and
912                   not(assigned(texitnode(node).resultexpr)) and
913                   { don't warn about constructors }
914                   not(current_procinfo.procdef.proctypeoption in [potype_class_constructor,potype_constructor]) then
915                   begin
916                     if is_managed_type(current_procinfo.procdef.returndef) then
917                       MessagePos(node.fileinfo,sym_w_managed_function_result_uninitialized)
918                     else
919                       MessagePos(node.fileinfo,sym_w_function_result_uninitialized);
920 
921                     Setlength(SearchNodeInfo.warnedfilelocs,length(SearchNodeInfo.warnedfilelocs)+1);
922                     SearchNodeInfo.warnedfilelocs[high(SearchNodeInfo.warnedfilelocs)]:=node.fileinfo;
923                   end
924               end;
925             { could be the implicitly generated load node for the result }
926 {$ifdef JVM}
927             { all other platforms except jvm translate raise nodes into call nodes during pass_1 }
928             raisen,
929 {$endif JVM}
930             loadn,
931             assignn,
932             calln,
933             temprefn,
934             typeconvn,
935             inlinen,
936             tempcreaten,
937             tempdeleten:
938               MaybeSearchIn(node);
939             nothingn,
940             continuen,
941             goton,
942             breakn:
943               ;
944             else
945               internalerror(2013111301);
946           end;
947 
948           { if already a warning has been issued, then stop }
949           if Result then
950             exit;
951 
952           if assigned(node.successor) then
953             MaybeDoCheck(node.successor);
954         end;
955 
956       begin
957         SearchNodeInfo.nodetosearch:=nodetosearch;
958         DoCheck(code);
959         foreachnodestatic(pm_postprocess,code,@ResetProcessing,nil);
960       end;
961 
962 
963 begin
964   SearchNodeProcPointer:=@SearchNode;
965 end.
966