| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956 | {    DFA    Copyright (c) 2007 by Florian Klaempfl    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ****************************************************************************}{ $define DEBUG_DFA}{ $define EXTDEBUG_DFA}{ this unit implements routines to perform dfa }unit optdfa;{$i fpcdefs.inc}  interface    uses      node,optutils;    type      TDFABuilder = class      protected        procedure CreateLifeInfo(node : tnode;map : TIndexedNodeSet);      public        resultnode : tnode;        nodemap : TIndexedNodeSet;        { reset all dfa info, this is required before creating dfa info          if the tree has been changed without updating dfa }        procedure resetdfainfo(node : tnode);        procedure createdfainfo(node : tnode);        destructor destroy;override;      end;    procedure CheckAndWarn(code : tnode;nodetosearch : tnode);  implementation    uses      globtype,globals,      verbose,      cpuinfo,      symconst,symdef,symsym,      defutil,      procinfo,      nutils,htypechk,      nbas,nflw,ncon,ninl,ncal,nset,nld,nadd,      optbase;    (*    function initnodes(var n:tnode; arg: pointer) : foreachnoderesult;      begin        { node worth to add? }        if (node_complexity(n)>1) and (tstoreddef(n.resultdef).is_intregable or tstoreddef(n.resultdef).is_fpuregable) then          begin            plists(arg)^.nodelist.Add(n);            plists(arg)^.locationlist.Add(@n);            result:=fen_false;          end        else          result:=fen_norecurse_false;      end;    *)    {      x:=f;         read: [f]      while x do    read: []        a:=b;       read: [a,b,d]  def: [a]       life:  read*def=[a]          c:=d;     read: [a,d]    def: [a,c]     life:  read*def=[a]            e:=a;   read: [a]      def: [a,c,e]   life:  read*def=[a]      function f(b,d,x : type) : type;        begin          while x do        alive: b,d,x            begin              a:=b;         alive: b,d,x              c:=d;         alive: a,d,x              e:=a+c;       alive: a,c,x              dec(x);       alive: c,e,x            end;          result:=c+e;      alive: c,e        end;                alive: result    }    type      tdfainfo = record        use : PDFASet;        def : PDFASet;        map : TIndexedNodeSet      end;      pdfainfo = ^tdfainfo;    function AddDefUse(var n: tnode; arg: pointer): foreachnoderesult;      begin        case n.nodetype of          tempcreaten:            begin              if assigned(ttempcreatenode(n).tempinfo^.tempinitcode) then                begin                  pdfainfo(arg)^.map.Add(n);                  DFASetInclude(pdfainfo(arg)^.def^,n.optinfo^.index);                end;            end;          temprefn,          loadn:            begin              pdfainfo(arg)^.map.Add(n);              if nf_modify in n.flags then                begin                  DFASetInclude(pdfainfo(arg)^.use^,n.optinfo^.index);                  DFASetInclude(pdfainfo(arg)^.def^,n.optinfo^.index)                end              else if nf_write in n.flags then                DFASetInclude(pdfainfo(arg)^.def^,n.optinfo^.index)              else                DFASetInclude(pdfainfo(arg)^.use^,n.optinfo^.index);            end;        end;        result:=fen_false;      end;    function ResetProcessing(var n: tnode; arg: pointer): foreachnoderesult;      begin        exclude(n.flags,nf_processing);        { dfa works only on normalized trees, so do not recurse into expressions, because          ResetProcessing eats a signififcant amount of time of CheckAndWarn          the following set contains (hopefully) most of the expression nodes }        if n.nodetype in [calln,inlinen,assignn,callparan,andn,addn,orn,subn,muln,divn,slashn,notn,equaln,unequaln,gtn,ltn,lten,gten,loadn,          typeconvn,vecn,subscriptn,addrn,derefn] then          result:=fen_norecurse_false        else          result:=fen_false;      end;    function ResetDFA(var n: tnode; arg: pointer): foreachnoderesult;      begin        if assigned(n.optinfo) then          begin            with n.optinfo^ do              begin                life:=nil;                def:=nil;                use:=nil;                defsum:=nil;              end;          end;        result:=fen_false;      end;    procedure TDFABuilder.CreateLifeInfo(node : tnode;map : TIndexedNodeSet);      var        changed : boolean;      procedure CreateInfo(node : tnode);        { update life entry of a node with l, set changed if this changes          life info for the node        }        procedure updatelifeinfo(n : tnode;l : TDFASet);          var            b : boolean;          begin            b:=DFASetNotEqual(l,n.optinfo^.life);{$ifdef DEBUG_DFA}            if not(changed) and b then              begin                writeln('Another DFA pass caused by: ',nodetype2str[n.nodetype],'(',n.fileinfo.line,',',n.fileinfo.column,')');                write('  Life info set was:     ');PrintDFASet(Output,n.optinfo^.life);writeln;                write('  Life info set will be: ');PrintDFASet(Output,l);writeln;              end;{$endif DEBUG_DFA}            changed:=changed or b;            n.optinfo^.life:=l;          end;        procedure calclife(n : tnode);          var            l : TDFASet;          begin            if assigned(n.successor) then              begin                { ensure we can access optinfo }                DFASetDiff(l,n.successor.optinfo^.life,n.optinfo^.def);                DFASetIncludeSet(l,n.optinfo^.use);                DFASetIncludeSet(l,n.optinfo^.life);              end            else              begin                l:=n.optinfo^.use;                DFASetIncludeSet(l,n.optinfo^.life);              end;            updatelifeinfo(n,l);          end;        var          dfainfo : tdfainfo;          l : TDFASet;          save: TDFASet;          i : longint;          counteruse_after_loop : boolean;        begin          if node=nil then            exit;          { ensure we've already optinfo set }          node.allocoptinfo;          if nf_processing in node.flags then            exit;          include(node.flags,nf_processing);          if assigned(node.successor) then            CreateInfo(node.successor);{$ifdef EXTDEBUG_DFA}          writeln('Handling: ',nodetype2str[node.nodetype],'(',node.fileinfo.line,',',node.fileinfo.column,')');{$endif EXTDEBUG_DFA}          { life:=succesorlive-definition+use }          case node.nodetype of            whilerepeatn:              begin                { analyze the loop condition }                if not(assigned(node.optinfo^.def)) and                   not(assigned(node.optinfo^.use)) then                  begin                    dfainfo.use:[email protected]^.use;                    dfainfo.def:[email protected]^.def;                    dfainfo.map:=map;                    foreachnodestatic(pm_postprocess,twhilerepeatnode(node).left,@AddDefUse,@dfainfo);                  end;                { NB: this node should typically have empty def set }                if assigned(node.successor) then                  DFASetDiff(l,node.successor.optinfo^.life,node.optinfo^.def)                else if assigned(resultnode) then                  DFASetDiff(l,resultnode.optinfo^.life,node.optinfo^.def)                else                  l:=nil;                { for repeat..until, node use set in included at the end of loop }                if not (lnf_testatbegin in twhilerepeatnode(node).loopflags) then                  DFASetIncludeSet(l,node.optinfo^.use);                DFASetIncludeSet(l,node.optinfo^.life);                save:=node.optinfo^.life;                { to process body correctly, we need life info in place (because                  whilerepeatnode is successor of its body). }                node.optinfo^.life:=l;                { now process the body }                CreateInfo(twhilerepeatnode(node).right);                { restore, to prevent infinite recursion via changed flag }                node.optinfo^.life:=save;                { for while loops, node use set is included at the beginning of loop }                l:=twhilerepeatnode(node).right.optinfo^.life;                if lnf_testatbegin in twhilerepeatnode(node).loopflags then                  DFASetIncludeSet(l,node.optinfo^.use);                UpdateLifeInfo(node,l);                { ... and a second iteration for fast convergence }                CreateInfo(twhilerepeatnode(node).right);              end;            forn:              begin                {                  left: loopvar                  right: from                  t1: to                  t2: body                }                node.allocoptinfo;                tfornode(node).loopiteration.allocoptinfo;                if not(assigned(node.optinfo^.def)) and                   not(assigned(node.optinfo^.use)) then                  begin                    dfainfo.use:[email protected]^.use;                    dfainfo.def:[email protected]^.def;                    dfainfo.map:=map;                    foreachnodestatic(pm_postprocess,tfornode(node).left,@AddDefUse,@dfainfo);                    foreachnodestatic(pm_postprocess,tfornode(node).right,@AddDefUse,@dfainfo);                    foreachnodestatic(pm_postprocess,tfornode(node).t1,@AddDefUse,@dfainfo);                  end;                { create life for the body }                CreateInfo(tfornode(node).t2);                { is the counter living after the loop?                  if left is a record element, it might not be tracked by dfa, so                  optinfo might not be assigned                }                counteruse_after_loop:=assigned(tfornode(node).left.optinfo) and assigned(node.successor) and                  DFASetIn(node.successor.optinfo^.life,tfornode(node).left.optinfo^.index);                { if yes, then we should warn }                { !!!!!! }                { first update the dummy node }                { get the life of the loop block }                l:=copy(tfornode(node).t2.optinfo^.life);                { take care of the sucessor }                if assigned(node.successor) then                  DFASetIncludeSet(l,node.successor.optinfo^.life);                { the counter variable is living as well inside the for loop                  if left is a record element, it might not be tracked by dfa, so                  optinfo might not be assigned                }                if assigned(tfornode(node).left.optinfo) then                  DFASetInclude(l,tfornode(node).left.optinfo^.index);                { force block node life info }                UpdateLifeInfo(tfornode(node).loopiteration,l);                { now update the for node itself }                { get the life of the loop block }                l:=copy(tfornode(node).t2.optinfo^.life);                { take care of the sucessor as it's possible that we don't have one execution of the body }                if (not(tfornode(node).right.nodetype=ordconstn) or not(tfornode(node).t1.nodetype=ordconstn)) and                  assigned(node.successor) then                  DFASetIncludeSet(l,node.successor.optinfo^.life);                {                  the counter variable is not living at the entry of the for node                  if left is a record element, it might not be tracked by dfa, so                    optinfo might not be assigned                }                if assigned(tfornode(node).left.optinfo) then                  DFASetExclude(l,tfornode(node).left.optinfo^.index);                { ... but it could be that left/right use it, so do this after                  removing the def of the counter variable }                DFASetIncludeSet(l,node.optinfo^.use);                UpdateLifeInfo(node,l);                { ... and a second iteration for fast convergence }                CreateInfo(tfornode(node).t2);              end;            temprefn,            loadn,            typeconvn,            assignn:              begin                if not(assigned(node.optinfo^.def)) and                  not(assigned(node.optinfo^.use)) then                  begin                    dfainfo.use:[email protected]^.use;                    dfainfo.def:[email protected]^.def;                    dfainfo.map:=map;                    foreachnodestatic(pm_postprocess,node,@AddDefUse,@dfainfo);                  end;                calclife(node);              end;            statementn:              begin                { nested statement }                CreateInfo(tstatementnode(node).statement);                { inherit info }                node.optinfo^.life:=tstatementnode(node).statement.optinfo^.life;              end;            blockn:              begin                CreateInfo(tblocknode(node).statements);                { ensure that we don't remove life info }                l:=node.optinfo^.life;                if assigned(node.successor) then                  DFASetIncludeSet(l,node.successor.optinfo^.life);                UpdateLifeInfo(node,l);              end;            ifn:              begin                { get information from cond. expression }                if not(assigned(node.optinfo^.def)) and                   not(assigned(node.optinfo^.use)) then                  begin                    dfainfo.use:[email protected]^.use;                    dfainfo.def:[email protected]^.def;                    dfainfo.map:=map;                    foreachnodestatic(pm_postprocess,tifnode(node).left,@AddDefUse,@dfainfo);                  end;                { create life info for then and else node }                CreateInfo(tifnode(node).right);                CreateInfo(tifnode(node).t1);                { ensure that we don't remove life info }                l:=node.optinfo^.life;                { get life info from then branch }                if assigned(tifnode(node).right) then                  DFASetIncludeSet(l,tifnode(node).right.optinfo^.life);                { get life info from else branch }                if assigned(tifnode(node).t1) then                  DFASetIncludeSet(l,tifnode(node).t1.optinfo^.life)                else if assigned(node.successor) then                  DFASetIncludeSet(l,node.successor.optinfo^.life);                { remove def info from the cond. expression }                DFASetExcludeSet(l,tifnode(node).optinfo^.def);                { add use info from the cond. expression }                DFASetIncludeSet(l,tifnode(node).optinfo^.use);                { finally, update the life info of the node }                UpdateLifeInfo(node,l);              end;            casen:              begin                { get information from "case" expression }                if not(assigned(node.optinfo^.def)) and                   not(assigned(node.optinfo^.use)) then                  begin                    dfainfo.use:[email protected]^.use;                    dfainfo.def:[email protected]^.def;                    dfainfo.map:=map;                    foreachnodestatic(pm_postprocess,tcasenode(node).left,@AddDefUse,@dfainfo);                  end;                { create life info for block and else nodes }                for i:=0 to tcasenode(node).blocks.count-1 do                  CreateInfo(pcaseblock(tcasenode(node).blocks[i])^.statement);                CreateInfo(tcasenode(node).elseblock);                { ensure that we don't remove life info }                l:=node.optinfo^.life;                { get life info from case branches }                for i:=0 to tcasenode(node).blocks.count-1 do                  DFASetIncludeSet(l,pcaseblock(tcasenode(node).blocks[i])^.statement.optinfo^.life);                { get life info from else branch or the succesor }                if assigned(tcasenode(node).elseblock) then                  DFASetIncludeSet(l,tcasenode(node).elseblock.optinfo^.life)                else if assigned(node.successor) then                  DFASetIncludeSet(l,node.successor.optinfo^.life);                { add use info from the "case" expression }                DFASetIncludeSet(l,tcasenode(node).optinfo^.use);                { finally, update the life info of the node }                UpdateLifeInfo(node,l);              end;            exitn:              begin                if not(is_void(current_procinfo.procdef.returndef)) then                  begin                    if not(assigned(node.optinfo^.def)) and                       not(assigned(node.optinfo^.use)) then                      begin                        if assigned(texitnode(node).left) then                          begin                            node.optinfo^.def:=resultnode.optinfo^.def;                            dfainfo.use:[email protected]^.use;                            dfainfo.def:[email protected]^.def;                            dfainfo.map:=map;                            foreachnodestatic(pm_postprocess,texitnode(node).left,@AddDefUse,@dfainfo);                            calclife(node);                          end                        else                          begin                            { get info from faked resultnode }                            node.optinfo^.use:=resultnode.optinfo^.use;                            node.optinfo^.life:=node.optinfo^.use;                            changed:=true;                          end;                      end;                  end;              end;            asn,            inlinen,            calln:              begin                if not(assigned(node.optinfo^.def)) and                  not(assigned(node.optinfo^.use)) then                  begin                    dfainfo.use:[email protected]^.use;                    dfainfo.def:[email protected]^.def;                    dfainfo.map:=map;                    foreachnodestatic(pm_postprocess,node,@AddDefUse,@dfainfo);                  end;                calclife(node);              end;            labeln:              begin                calclife(node);                if assigned(tlabelnode(node).left) then                  begin                    l:=node.optinfo^.life;                    DFASetIncludeSet(l,tlabelnode(node).optinfo^.life);                    UpdateLifeInfo(node,l);                  end;              end;            tempcreaten,            tempdeleten,            nothingn,            continuen,            goton,            breakn:              begin                calclife(node);              end;            else              internalerror(2007050502);          end;        end;      var        runs : integer;      begin        runs:=0;        repeat          inc(runs);          changed:=false;          CreateInfo(node);          foreachnodestatic(pm_postprocess,node,@ResetProcessing,nil);          { the result node is not reached by foreachnodestatic }          exclude(resultnode.flags,nf_processing);{$ifdef DEBUG_DFA}          PrintIndexedNodeSet(output,map);          PrintDFAInfo(output,node);{$endif DEBUG_DFA}        until not(changed);{$ifdef DEBUG_DFA}        writeln('DFA solver iterations: ',runs);{$endif DEBUG_DFA}      end;    { reset all dfa info, this is required before creating dfa info      if the tree has been changed without updating dfa }    procedure TDFABuilder.resetdfainfo(node : tnode);      begin        foreachnodestatic(pm_postprocess,node,@ResetDFA,nil);      end;    procedure TDFABuilder.createdfainfo(node : tnode);      var        dfarec : tdfainfo;      begin        if not(assigned(nodemap)) then          nodemap:=TIndexedNodeSet.Create;        { create a fake node using the result which will be the last node }        if not(is_void(current_procinfo.procdef.returndef)) then          begin            if current_procinfo.procdef.proctypeoption=potype_constructor then              resultnode:=load_self_node            else              resultnode:=load_result_node;            resultnode.allocoptinfo;            dfarec.use:[email protected]^.use;            dfarec.def:[email protected]^.def;            dfarec.map:=nodemap;            AddDefUse(resultnode,@dfarec);            resultnode.optinfo^.life:=resultnode.optinfo^.use;          end        else          begin            resultnode:=cnothingnode.create;            resultnode.allocoptinfo;          end;        { add controll flow information }        SetNodeSucessors(node,resultnode);        { now, collect life information }        CreateLifeInfo(node,nodemap);      end;    destructor TDFABuilder.Destroy;      begin        Resultnode.free;        nodemap.free;        inherited destroy;      end;    var      { we have to pass the address of SearchNode in a call inside of SearchNode:        @SearchNode does not work because the compiler thinks we take the address of the result        so store the address from outside }      SearchNodeProcPointer : function(var n: tnode; arg: pointer): foreachnoderesult;    type      { helper structure to be able to pass more than one variable to the iterator function }      TSearchNodeInfo = record        nodetosearch : tnode;        { this contains a list of all file locations where a warning was thrown already,          the same location might appear multiple times because nodes might have been copied }        warnedfilelocs : array of tfileposinfo;      end;      PSearchNodeInfo = ^TSearchNodeInfo;    { searches for a given node n and warns if the node is found as being uninitialized. If a node is      found, searching is stopped so each call issues only one warning/hint }    function SearchNode(var n: tnode; arg: pointer): foreachnoderesult;      function WarnedForLocation(f : tfileposinfo) : boolean;        var          i : longint;        begin          result:=true;          for i:=0 to high(PSearchNodeInfo(arg)^.warnedfilelocs) do            with PSearchNodeInfo(arg)^.warnedfilelocs[i] do              begin                if (f.column=column) and (f.fileindex=fileindex) and (f.line=line) and (f.moduleindex=moduleindex) then                  exit;              end;          result:=false;        end;      procedure AddFilepos(const f : tfileposinfo);        begin          Setlength(PSearchNodeInfo(arg)^.warnedfilelocs,length(PSearchNodeInfo(arg)^.warnedfilelocs)+1);          PSearchNodeInfo(arg)^.warnedfilelocs[high(PSearchNodeInfo(arg)^.warnedfilelocs)]:=f;        end;      var        varsym : tabstractnormalvarsym;        methodpointer,        hpt : tnode;      begin        result:=fen_false;        case n.nodetype of          callparan:            begin              { do not warn about variables passed by var, just issue a hint, this                is a workaround for old code e.g. using fillchar }              if assigned(tcallparanode(n).parasym) and (tcallparanode(n).parasym.varspez in [vs_var,vs_out]) then                begin                  hpt:=tcallparanode(n).left;                  while assigned(hpt) and (hpt.nodetype in [subscriptn,vecn,typeconvn]) do                    hpt:=tunarynode(hpt).left;                  if assigned(hpt) and (hpt.nodetype=loadn) and not(WarnedForLocation(hpt.fileinfo)) and                    { warn only on the current symtable level }                    (((tabstractnormalvarsym(tloadnode(hpt).symtableentry).owner=current_procinfo.procdef.localst) and                      (current_procinfo.procdef.localst.symtablelevel=tabstractnormalvarsym(tloadnode(hpt).symtableentry).owner.symtablelevel)                     ) or                     ((tabstractnormalvarsym(tloadnode(hpt).symtableentry).owner=current_procinfo.procdef.parast) and                      (current_procinfo.procdef.parast.symtablelevel=tabstractnormalvarsym(tloadnode(hpt).symtableentry).owner.symtablelevel)                     )                    ) and                    PSearchNodeInfo(arg)^.nodetosearch.isequal(hpt) then                    begin                      { issue only a hint for var, when encountering the node passed as out, we need only to stop searching }                      if tcallparanode(n).parasym.varspez=vs_var then                        UninitializedVariableMessage(hpt.fileinfo,false,                          tloadnode(hpt).symtable.symtabletype=localsymtable,                          is_managed_type(tloadnode(hpt).resultdef),                          tloadnode(hpt).symtableentry.RealName);                      AddFilepos(hpt.fileinfo);                      result:=fen_norecurse_true;                    end                end;            end;          orn,          andn:            begin              { take care of short boolean evaluation: if the expression to be search is found in left,                we do not need to search right }              if foreachnodestatic(pm_postprocess,taddnode(n).left,SearchNodeProcPointer,arg) or                foreachnodestatic(pm_postprocess,taddnode(n).right,SearchNodeProcPointer,arg) then                result:=fen_norecurse_true              else                result:=fen_norecurse_false;            end;          calln:            begin              methodpointer:=tcallnode(n).methodpointer;              if assigned(methodpointer) and (methodpointer.nodetype<>typen) then               begin                  { Remove all postfix operators }                  hpt:=methodpointer;                  while assigned(hpt) and (hpt.nodetype in [subscriptn,vecn]) do                    hpt:=tunarynode(hpt).left;                 { skip (absolute and other simple) type conversions -- only now,                   because the checks above have to take type conversions into                   e.g. class reference types account }                 hpt:=actualtargetnode(@hpt)^;                  { R.Init then R will be initialized by the constructor,                    Also allow it for simple loads }                  if (tcallnode(n).procdefinition.proctypeoption=potype_constructor) or                     (PSearchNodeInfo(arg)^.nodetosearch.isequal(hpt) and                      (((methodpointer.resultdef.typ=objectdef) and                        not(oo_has_virtual in tobjectdef(methodpointer.resultdef).objectoptions)) or                       (methodpointer.resultdef.typ=recorddef)                      )                     ) then                    begin                      { don't warn about the method pointer }                      AddFilepos(hpt.fileinfo);                      if not(foreachnodestatic(pm_postprocess,tcallnode(n).left,SearchNodeProcPointer,arg)) then                        foreachnodestatic(pm_postprocess,tcallnode(n).right,SearchNodeProcPointer,arg);                      result:=fen_norecurse_true                    end;                 end;            end;          loadn:            begin              if (tloadnode(n).symtableentry.typ in [localvarsym,paravarsym,staticvarsym]) and                PSearchNodeInfo(arg)^.nodetosearch.isequal(n) and ((nf_modify in n.flags) or not(nf_write in n.flags)) then                begin                  varsym:=tabstractnormalvarsym(tloadnode(n).symtableentry);                  { Give warning/note for living locals, result and parameters, but only about the current                    symtables }                  if assigned(varsym.owner) and                    (((varsym.owner=current_procinfo.procdef.localst) and                      (current_procinfo.procdef.localst.symtablelevel=varsym.owner.symtablelevel)                     ) or                     ((varsym.owner=current_procinfo.procdef.parast) and                      (varsym.typ=paravarsym) and                      (current_procinfo.procdef.parast.symtablelevel=varsym.owner.symtablelevel) and                      { all parameters except out parameters are initialized by the caller }                      (tparavarsym(varsym).varspez=vs_out)                     ) or                     ((vo_is_funcret in varsym.varoptions) and                      (current_procinfo.procdef.parast.symtablelevel=varsym.owner.symtablelevel)                     )                    ) and                    not(vo_is_external in varsym.varoptions) then                    begin                      if (vo_is_funcret in varsym.varoptions) and not(WarnedForLocation(n.fileinfo)) then                        begin                          if is_managed_type(varsym.vardef) then                            MessagePos(n.fileinfo,sym_w_managed_function_result_uninitialized)                          else                            MessagePos(n.fileinfo,sym_w_function_result_uninitialized);                          AddFilepos(n.fileinfo);                          result:=fen_norecurse_true;                        end                      else                        begin                          { typed consts are initialized, further, warn only once per location }                          if not (vo_is_typed_const in varsym.varoptions) and not(WarnedForLocation(n.fileinfo)) then                            begin                              UninitializedVariableMessage(n.fileinfo,true,varsym.typ=localvarsym,is_managed_type(varsym.vardef),varsym.realname);                              AddFilepos(n.fileinfo);                              result:=fen_norecurse_true;                            end;                        end;                    end{$ifdef dummy}                  { if a the variable we are looking for is passed as a var parameter, we stop searching }                  else if assigned(varsym.owner) and                     (varsym.owner=current_procinfo.procdef.parast) and                     (varsym.typ=paravarsym) and                     (current_procinfo.procdef.parast.symtablelevel=varsym.owner.symtablelevel) and                     (tparavarsym(varsym).varspez=vs_var) then                    result:=fen_norecurse_true;{$endif dummy}                end;            end;        end;      end;    procedure CheckAndWarn(code : tnode;nodetosearch : tnode);      var        SearchNodeInfo : TSearchNodeInfo;      function DoCheck(node : tnode) : boolean;        var          i : longint;          touchesnode : Boolean;        procedure MaybeDoCheck(n : tnode);inline;          begin            Result:=Result or DoCheck(n);          end;        procedure MaybeSearchIn(n : tnode);          begin            if touchesnode then              Result:=Result or foreachnodestatic(pm_postprocess,n,@SearchNode,@SearchNodeInfo);          end;        begin          result:=false;          if node=nil then            exit;          if nf_processing in node.flags then            exit;          include(node.flags,nf_processing);          if not(DFASetIn(node.optinfo^.life,nodetosearch.optinfo^.index)) then            exit;          { we do not need this info always, so try to safe some time here, CheckAndWarn            takes a lot of time anyways }          if not(node.nodetype in [statementn,blockn]) then            touchesnode:=DFASetIn(node.optinfo^.use,nodetosearch.optinfo^.index) or              DFASetIn(node.optinfo^.def,nodetosearch.optinfo^.index)          else            touchesnode:=false;          case node.nodetype of            whilerepeatn:              begin                MaybeSearchIn(twhilerepeatnode(node).left);                MaybeDoCheck(twhilerepeatnode(node).right);              end;            forn:              begin                MaybeSearchIn(tfornode(node).right);                MaybeSearchIn(tfornode(node).t1);                MaybeDoCheck(tfornode(node).t2);              end;            statementn:              MaybeDoCheck(tstatementnode(node).statement);            blockn:              MaybeDoCheck(tblocknode(node).statements);            ifn:              begin                MaybeSearchIn(tifnode(node).left);                MaybeDoCheck(tifnode(node).right);                MaybeDoCheck(tifnode(node).t1);              end;            casen:              begin                MaybeSearchIn(tcasenode(node).left);                for i:=0 to tcasenode(node).blocks.count-1 do                  MaybeDoCheck(pcaseblock(tcasenode(node).blocks[i])^.statement);                MaybeDoCheck(tcasenode(node).elseblock);              end;            labeln:              MaybeDoCheck(tlabelnode(node).left);            { we are aware of the following nodes so if new node types are added to the compiler              and pop up in the search, the ie below kicks in as a reminder }            exitn:              begin                MaybeSearchIn(texitnode(node).left);                { exit uses the resultnode implicitly, so searching for a matching node is                  useless, if we reach the exit node and found the living node not in left, then                  it can be only the resultnode  }                if not(Result) and not(is_void(current_procinfo.procdef.returndef)) and                  not(assigned(texitnode(node).resultexpr)) and                  { don't warn about constructors }                  not(current_procinfo.procdef.proctypeoption in [potype_class_constructor,potype_constructor]) then                  begin                    if is_managed_type(current_procinfo.procdef.returndef) then                      MessagePos(node.fileinfo,sym_w_managed_function_result_uninitialized)                    else                      MessagePos(node.fileinfo,sym_w_function_result_uninitialized);                    Setlength(SearchNodeInfo.warnedfilelocs,length(SearchNodeInfo.warnedfilelocs)+1);                    SearchNodeInfo.warnedfilelocs[high(SearchNodeInfo.warnedfilelocs)]:=node.fileinfo;                  end              end;            { could be the implicitly generated load node for the result }            loadn,            assignn,            calln,            temprefn,            typeconvn,            inlinen,            tempcreaten,            tempdeleten:              MaybeSearchIn(node);            nothingn,            continuen,            goton,            breakn:              ;            else              internalerror(2013111301);          end;          { if already a warning has been issued, then stop }          if Result then            exit;          if assigned(node.successor) then            MaybeDoCheck(node.successor);        end;      begin        SearchNodeInfo.nodetosearch:=nodetosearch;        DoCheck(code);        foreachnodestatic(pm_postprocess,code,@ResetProcessing,nil);      end;begin  SearchNodeProcPointer:=@SearchNode;end.
 |