]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[modula2] Improve uninitialized variable analysis by combining basic blocks
authorGaius Mulley <gaiusmod2@gmail.com>
Tue, 11 Jul 2023 14:28:42 +0000 (15:28 +0100)
committerGaius Mulley <gaiusmod2@gmail.com>
Tue, 11 Jul 2023 14:28:42 +0000 (15:28 +0100)
This patch combines basic blocks for static analysis of uninitialized
variables providing that they are not the top of a loop, are not reached
by a conditional and are not reached after a procedure call.  It also
avoids checking array accesses for static analysis.  Finally the patch
adds switch modifiers to allow static analysis to include conditional
branches for subsequent basic block analysis.

gcc/ChangeLog:

* doc/gm2.texi (-Wuninit-variable-checking=) New item.

gcc/m2/ChangeLog:

* gm2-compiler/M2BasicBlock.def (InitBasicBlocksFromRange): New
parameter ScopeSym.
* gm2-compiler/M2BasicBlock.mod (ConvertQuads2BasicBlock): New
parameter ScopeSym.
(InitBasicBlocksFromRange): New parameter ScopeSym.  Call
ConvertQuads2BasicBlock with ScopeSym.
(DisplayBasicBlocks): Uncomment.
* gm2-compiler/M2Code.mod: Replace VariableAnalysis with
ScopeBlockVariableAnalysis.
(InitialDeclareAndOptiomize): Add parameter scope.
(SecondDeclareAndOptimize): Add parameter scope.
* gm2-compiler/M2GCCDeclare.mod (DeclareConstructor): Add scope
parameter to DeclareTypesConstantsProceduresInRange.
(DeclareTypesConstantsProceduresInRange): New parameter scope.
Pass scope to DisplayQuadRange.  Reformatted.
* gm2-compiler/M2GenGCC.def (ConvertQuadsToTree): New parameter
scope.
* gm2-compiler/M2GenGCC.mod (ConvertQuadsToTree): New parameter
scope.
* gm2-compiler/M2Optimize.mod (KnownReachable): New parameter
scope.
* gm2-compiler/M2Options.def (SetUninitVariableChecking): Add
arg parameter.
* gm2-compiler/M2Options.mod (SetUninitVariableChecking): Add
arg parameter and set boolean UninitVariableChecking and
UninitVariableConditionalChecking.
(UninitVariableConditionalChecking): New boolean set to FALSE.
* gm2-compiler/M2Quads.def (IsGoto): New procedure function.
(DisplayQuadRange): Add scope parameter.
(LoopAnalysis): Add scope parameter.
* gm2-compiler/M2Quads.mod: Import PutVarArrayRef.
(IsGoto): New procedure function.
(LoopAnalysis): Add scope parameter and use MetaErrorT1 instead
of WarnStringAt.
(BuildStaticArray): Call PutVarArrayRef.
(BuildDynamicArray): Call PutVarArrayRef.
(DisplayQuadRange): Add scope parameter.
(GetM2OperatorDesc): Add relational condition cases.
* gm2-compiler/M2Scope.def (ScopeProcedure): Add parameter.
* gm2-compiler/M2Scope.mod (DisplayScope): Pass scopeSym to
DisplayQuadRange.
(ForeachScopeBlockDo): Pass scopeSym to p.
* gm2-compiler/M2SymInit.def (VariableAnalysis): Rename to ...
(ScopeBlockVariableAnalysis): ... this.
* gm2-compiler/M2SymInit.mod (ScopeBlockVariableAnalysis): Add
scope parameter.
(bbEntry): New pointer to record.
(bbArray): New array.
(bbFreeList): New variable.
(errorList): New list.
(IssueConditional): New procedure.
(GenerateNoteFlow): New procedure.
(IssueWarning): New procedure.
(IsUniqueWarning): New procedure.
(CheckDeferredRecordAccess): Re-implement.
(CheckBinary): Add warning and lst parameters.
(CheckUnary): Add warning and lst parameters.
(CheckXIndr): Add warning and lst parameters.
(CheckIndrX): Add warning and lst parameters.
(CheckBecomes): Add warning and lst parameters.
(CheckComparison): Add warning and lst parameters.
(CheckReadBeforeInitQuad): Add warning and lst parameters to all
Check procedures.  Add all case quadruple clauses.
(FilterCheckReadBeforeInitQuad): Add warning and lst parameters.
(CheckReadBeforeInitFirstBasicBlock): Add warning and lst parameters.
(bbArrayKill): New procedure.
(DumpBBEntry): New procedure.
(DumpBBArray): New procedure.
(DumpBBSequence): New procedure.
(TestBBSequence): New procedure.
(CreateBBPermultations): New procedure.
(ScopeBlockVariableAnalysis): New procedure.
(GetOp3): New procedure.
(GenerateCFG): New procedure.
(NewEntry): New procedure.
(AppendEntry): New procedure.
(init): Initialize bbFreeList and errorList.
* gm2-compiler/SymbolTable.def (PutVarArrayRef): New procedure.
(IsVarArrayRef): New procedure function.
* gm2-compiler/SymbolTable.mod (SymVar): ArrayRef new field.
(MakeVar): Set ArrayRef to FALSE.
(PutVarArrayRef): New procedure.
(IsVarArrayRef): New procedure function.
* gm2-gcc/init.cc (_M2_M2SymInit_init): New prototype.
(init_PerCompilationInit): Add call to _M2_M2SymInit_init.
* gm2-gcc/m2options.h (M2Options_SetUninitVariableChecking):
New definition.
* gm2-lang.cc (gm2_langhook_handle_option): Add new case
OPT_Wuninit_variable_checking_.
* lang.opt: Wuninit-variable-checking= new entry.

gcc/testsuite/ChangeLog:

* gm2/switches/uninit-variable-checking/cascade/fail/cascadedif.mod: New test.
* gm2/switches/uninit-variable-checking/cascade/fail/switches-uninit-variable-checking-cascade-fail.exp:
New test.

Signed-off-by: Gaius Mulley <gaiusmod2@gmail.com>
24 files changed:
gcc/doc/gm2.texi
gcc/m2/gm2-compiler/M2BasicBlock.def
gcc/m2/gm2-compiler/M2BasicBlock.mod
gcc/m2/gm2-compiler/M2Code.mod
gcc/m2/gm2-compiler/M2GCCDeclare.mod
gcc/m2/gm2-compiler/M2GenGCC.def
gcc/m2/gm2-compiler/M2GenGCC.mod
gcc/m2/gm2-compiler/M2Optimize.mod
gcc/m2/gm2-compiler/M2Options.def
gcc/m2/gm2-compiler/M2Options.mod
gcc/m2/gm2-compiler/M2Quads.def
gcc/m2/gm2-compiler/M2Quads.mod
gcc/m2/gm2-compiler/M2Scope.def
gcc/m2/gm2-compiler/M2Scope.mod
gcc/m2/gm2-compiler/M2SymInit.def
gcc/m2/gm2-compiler/M2SymInit.mod
gcc/m2/gm2-compiler/SymbolTable.def
gcc/m2/gm2-compiler/SymbolTable.mod
gcc/m2/gm2-gcc/init.cc
gcc/m2/gm2-gcc/m2options.h
gcc/m2/gm2-lang.cc
gcc/m2/lang.opt
gcc/testsuite/gm2/switches/uninit-variable-checking/cascade/fail/cascadedif.mod [new file with mode: 0644]
gcc/testsuite/gm2/switches/uninit-variable-checking/cascade/fail/switches-uninit-variable-checking-cascade-fail.exp [new file with mode: 0644]

index ae87434217a574f800af48bb38a2327d7e07c138..8d5d95f9fc786e7ce6f05f421348fef0ec023073 100644 (file)
@@ -664,6 +664,17 @@ issue a warning if a variable is used before it is initialized.
 The checking only occurs in the first basic block in each procedure.
 It does not check parameters, array types or set types.
 
+@item -Wuninit-variable-checking=all,known,cond
+issue a warning if a variable is used before it is initialized.
+The checking will only occur in the first basic block in each
+procedure if @samp{known} is specified.  If @samp{cond} or @samp{all}
+is specified then checking continues into conditional branches of the
+flow graph.  All checking will stop when a procedure call is invoked
+or the top of a loop is encountered.
+The option @samp{-Wall} will turn on this flag with
+@samp{-Wuninit-variable-checking=known}.
+The @samp{-Wuninit-variable-checking=all} will increase compile time.
+
 @c the following warning options are complete but need to be
 @c regression tested against all other front ends
 @c to ensure the options do not conflict.
index 44606ddd6d894fd587d55e1eebf8ad6c27fab07e..3a67ea682981e50d54d7fa4078d6760b3e3d8fc2 100644 (file)
@@ -60,7 +60,8 @@ PROCEDURE InitBasicBlocks (sb: ScopeBlock) : BasicBlock ;
                               reachable are removed.
 *)
 
-PROCEDURE InitBasicBlocksFromRange (start, end: CARDINAL) : BasicBlock ;
+PROCEDURE InitBasicBlocksFromRange (ScopeSym: CARDINAL;
+                                    start, end: CARDINAL) : BasicBlock ;
 
 
 (*
index 1d005f6d74ae8f5281663a183717cd38725a7503..d3eb135fc7d9a5b3c307b466f8a12441ab667ccf 100644 (file)
@@ -35,12 +35,15 @@ FROM M2Quads IMPORT IsReferenced, IsConditional, IsUnConditional, IsCall,
                     IsInitialisingConst,
                     IsPseudoQuad, IsDefOrModFile,
                     GetNextQuad, GetQuad, QuadOperator,
-                    SubQuad ;
+                    SubQuad, DisplayQuadRange ;
 
 FROM M2Scope IMPORT ScopeBlock, ForeachScopeBlockDo ;
 FROM M2GenGCC IMPORT ConvertQuadsToTree ;
 
 
+CONST
+   Debugging = FALSE ;
+
 TYPE
    BasicBlock = POINTER TO RECORD
                    StartQuad  : CARDINAL ;  (* First Quad in Basic Block *)
@@ -77,10 +80,15 @@ END InitBasicBlocks ;
                               reachable are removed.
 *)
 
-PROCEDURE InitBasicBlocksFromRange (start, end: CARDINAL) : BasicBlock ;
+PROCEDURE InitBasicBlocksFromRange (ScopeSym: CARDINAL;
+                                    start, end: CARDINAL) : BasicBlock ;
 BEGIN
    HeadOfBasicBlock := NIL ;
-   ConvertQuads2BasicBlock(start, end) ;
+   ConvertQuads2BasicBlock (ScopeSym, start, end) ;
+   IF Debugging
+   THEN
+      DisplayBasicBlocks (HeadOfBasicBlock)
+   END ;
    RETURN( HeadOfBasicBlock )
 END InitBasicBlocksFromRange ;
 
@@ -144,7 +152,7 @@ END New ;
                              which has only has one entry and exit point.
 *)
 
-PROCEDURE ConvertQuads2BasicBlock (Start, End: CARDINAL) ;
+PROCEDURE ConvertQuads2BasicBlock (ScopeSym: CARDINAL; Start, End: CARDINAL) ;
 VAR
    LastQuadDefMod,
    LastQuadConditional,
@@ -154,6 +162,10 @@ VAR
    CurrentBB          : BasicBlock ;
    LastBB             : BasicBlock ;
 BEGIN
+   IF Debugging
+   THEN
+      DisplayQuadRange (ScopeSym, Start, End)
+   END ;
    (*
       Algorithm to perform Basic Block:
 
@@ -323,7 +335,6 @@ END Sub ;
    DisplayBasicBlocks - displays the basic block data structure.
 *)
 
-(*
 PROCEDURE DisplayBasicBlocks (bb: BasicBlock) ;
 VAR
    b: BasicBlock ;
@@ -347,7 +358,6 @@ BEGIN
       WriteString(' end   ') ; WriteCard(EndQuad, 6) ;
    END
 END DisplayBlock ;
-*)
 
 
 BEGIN
index c4069e9a8d750e656959bc4e098d8b75b5471e5e..d2ace72bc8fea33d3f1dd253d6ac3e74a30bc926 100644 (file)
@@ -45,7 +45,7 @@ FROM M2Quads IMPORT CountQuads, GetFirstQuad, DisplayQuadList, DisplayQuadRange,
                     BackPatchSubrangesAndOptParam,
                     LoopAnalysis, ForLoopAnalysis, GetQuad, QuadOperator ;
 
-FROM M2SymInit IMPORT VariableAnalysis ;
+FROM M2SymInit IMPORT ScopeBlockVariableAnalysis ;
 
 FROM M2Pass IMPORT SetPassToNoPass, SetPassToCodeGeneration ;
 
@@ -293,16 +293,16 @@ END Code ;
    InitialDeclareAndCodeBlock - declares all objects within scope,
 *)
 
-PROCEDURE InitialDeclareAndOptimize (start, end: CARDINAL) ;
+PROCEDURE InitialDeclareAndOptimize (scope: CARDINAL; start, end: CARDINAL) ;
 BEGIN
-   Count := CountQuads() ;
-   FreeBasicBlocks(InitBasicBlocksFromRange(start, end)) ;
-   BasicB := Count - CountQuads() ;
-   Count := CountQuads() ;
-
-   FoldBranches(start, end) ;
-   Jump := Count - CountQuads() ;
-   Count := CountQuads()
+   Count := CountQuads () ;
+   FreeBasicBlocks (InitBasicBlocksFromRange (scope, start, end)) ;
+   BasicB := Count - CountQuads () ;
+   Count := CountQuads () ;
+
+   FoldBranches (start, end) ;
+   Jump := Count - CountQuads () ;
+   Count := CountQuads ()
 END InitialDeclareAndOptimize ;
 
 
@@ -310,24 +310,25 @@ END InitialDeclareAndOptimize ;
    DeclareAndCodeBlock - declares all objects within scope,
 *)
 
-PROCEDURE SecondDeclareAndOptimize (start, end: CARDINAL) ;
+PROCEDURE SecondDeclareAndOptimize (scope: CARDINAL;
+                                    start, end: CARDINAL) ;
 BEGIN
    REPEAT
       FoldConstants(start, end) ;
       DeltaConst := Count - CountQuads () ;
       Count := CountQuads () ;
 
-      FreeBasicBlocks(InitBasicBlocksFromRange (start, end)) ;
+      FreeBasicBlocks(InitBasicBlocksFromRange (scope, start, end)) ;
 
       DeltaBasicB := Count - CountQuads () ;
       Count := CountQuads () ;
 
-      FreeBasicBlocks (InitBasicBlocksFromRange (start, end)) ;
+      FreeBasicBlocks (InitBasicBlocksFromRange (scope, start, end)) ;
       FoldBranches(start, end) ;
       DeltaJump := Count - CountQuads () ;
       Count := CountQuads () ;
 
-      FreeBasicBlocks(InitBasicBlocksFromRange (start, end)) ;
+      FreeBasicBlocks(InitBasicBlocksFromRange (scope, start, end)) ;
       INC (DeltaBasicB, Count - CountQuads ()) ;
       Count := CountQuads () ;
 
@@ -374,20 +375,6 @@ BEGIN
 END Init ;
 
 
-(*
-   BasicBlockVariableAnalysis -
-*)
-
-PROCEDURE BasicBlockVariableAnalysis (start, end: CARDINAL) ;
-VAR
-   bb: BasicBlock ;
-BEGIN
-   bb := InitBasicBlocksFromRange(start, end) ;
-   ForeachBasicBlockDo (bb, VariableAnalysis) ;
-   KillBasicBlocks (bb)
-END BasicBlockVariableAnalysis ;
-
-
 (*
    DisplayQuadsInScope -
 *)
@@ -416,7 +403,7 @@ BEGIN
    OptimTimes := 1 ;
    Current := CountQuads () ;
    ForeachScopeBlockDo (sb, InitialDeclareAndOptimize) ;
-   ForeachScopeBlockDo (sb, BasicBlockVariableAnalysis) ;
+   ForeachScopeBlockDo (sb, ScopeBlockVariableAnalysis) ;
    REPEAT
       ForeachScopeBlockDo (sb, SecondDeclareAndOptimize) ;
       Previous := Current ;
index c50272674fad3cd6e036ba6ac01d8e8aaead82d1..eaa3255f623a3a72707c5d2c1e2e27d8e67f1bec 100644 (file)
@@ -1610,13 +1610,13 @@ BEGIN
    THEN
       InternalError ('trying to declare the NulSym')
    END ;
-   IF IsConstructor(sym) AND (NOT GccKnowsAbout(sym))
+   IF IsConstructor (sym) AND (NOT GccKnowsAbout (sym))
    THEN
-      WalkConstructor(sym, TraverseDependants) ;
-      DeclareTypesConstantsProceduresInRange(quad, quad) ;
-      Assert(IsConstructorDependants(sym, IsFullyDeclared)) ;
-      PushValue(sym) ;
-      DeclareConstantFromTree(sym, PopConstructorTree(tokenno))
+      WalkConstructor (sym, TraverseDependants) ;
+      DeclareTypesConstantsProceduresInRange (GetScope (sym), quad, quad) ;
+      Assert (IsConstructorDependants (sym, IsFullyDeclared)) ;
+      PushValue (sym) ;
+      DeclareConstantFromTree (sym, PopConstructorTree (tokenno))
    END
 END DeclareConstructor ;
 
@@ -2539,24 +2539,24 @@ END FoldConstants ;
    DeclareTypesConstantsProceduresInRange -
 *)
 
-PROCEDURE DeclareTypesConstantsProceduresInRange (start, end: CARDINAL) ;
+PROCEDURE DeclareTypesConstantsProceduresInRange (scope, start, end: CARDINAL) ;
 VAR
    n, m: CARDINAL ;
 BEGIN
    IF DisplayQuadruples
    THEN
-      DisplayQuadRange(start, end)
+      DisplayQuadRange (scope, start, end)
    END ;
    REPEAT
       n := NoOfElementsInSet(ToDoList) ;
-      WHILE ResolveConstantExpressions(DeclareConstFully, start, end) DO
+      WHILE ResolveConstantExpressions (DeclareConstFully, start, end) DO
       END ;
       (* we need to evaluate some constant expressions to resolve these types *)
       IF DeclaredOutstandingTypes (FALSE)
       THEN
       END ;
       m := NoOfElementsInSet(ToDoList)
-   UNTIL (NOT ResolveConstantExpressions(DeclareConstFully, start, end)) AND
+   UNTIL (NOT ResolveConstantExpressions (DeclareConstFully, start, end)) AND
          (n=m)
 END DeclareTypesConstantsProceduresInRange ;
 
@@ -2620,16 +2620,16 @@ VAR
    s, t: CARDINAL ;
    sb  : ScopeBlock ;
 BEGIN
-   sb := InitScopeBlock(scope) ;
-   PushBinding(scope) ;
+   sb := InitScopeBlock (scope) ;
+   PushBinding (scope) ;
    REPEAT
-      s := NoOfElementsInSet(ToDoList) ;
+      s := NoOfElementsInSet (ToDoList) ;
       (* ForeachLocalSymDo(scope, DeclareTypeInfo) ; *)
-      ForeachScopeBlockDo(sb, DeclareTypesConstantsProceduresInRange) ;
-      t := NoOfElementsInSet(ToDoList) ;
+      ForeachScopeBlockDo (sb, DeclareTypesConstantsProceduresInRange) ;
+      t := NoOfElementsInSet (ToDoList) ;
    UNTIL s=t ;
-   PopBinding(scope) ;
-   KillScopeBlock(sb)
+   PopBinding (scope) ;
+   KillScopeBlock (sb)
 END DeclareTypesConstantsProcedures ;
 
 
@@ -2691,7 +2691,7 @@ BEGIN
    WalkTypesInProcedure(scope) ;
    DeclareProcedure(scope) ;
    ForeachInnerModuleDo(scope, WalkTypesInModule) ;
-   DeclareTypesConstantsProcedures(scope) ;
+   DeclareTypesConstantsProcedures (scope) ;
    ForeachInnerModuleDo(scope, DeclareTypesConstantsProcedures) ;
    DeclareLocalVariables(scope) ;
    ForeachInnerModuleDo(scope, DeclareModuleVariables) ;
index 646e09eb2bc9020f896aef14ef5705673f2e7404..b132bf0607f0f81e203c6bb54eecac24506c9c5b 100644 (file)
@@ -45,7 +45,7 @@ EXPORT QUALIFIED ConvertQuadsToTree, ResolveConstantExpressions,
                         the GCC tree structure.
 *)
 
-PROCEDURE ConvertQuadsToTree (Start, End: CARDINAL) ;
+PROCEDURE ConvertQuadsToTree (Scope: CARDINAL; Start, End: CARDINAL) ;
 
 
 (*
index 8b877e272e4f54100dba5c812a0f75f7c7eb1a77..0955106dbb60e19b5a4f37a97759ec5a82406bde 100644 (file)
@@ -395,7 +395,7 @@ BEGIN
          THEN
             RETURN FALSE
          END ;
-         scope := GetScope(scope)
+         scope := GetScope (scope)
       END ;
       InternalError ('expecting scope to eventually reach a module or defimp symbol')
    ELSE
@@ -410,7 +410,7 @@ END IsExportedGcc ;
                         the GCC tree structure.
 *)
 
-PROCEDURE ConvertQuadsToTree (Start, End: CARDINAL) ;
+PROCEDURE ConvertQuadsToTree (Scope: CARDINAL; Start, End: CARDINAL) ;
 BEGIN
    REPEAT
       CodeStatement (Start) ;
index 416eb42c6a76ee337ce243baf0f745cf90b8f127..408e9585280f8f2a81f07580c11b51db82b99c10 100644 (file)
@@ -351,7 +351,8 @@ BEGIN
 END RemoveProcedures ;
 
 
-PROCEDURE KnownReachable (Start, End: CARDINAL) ;
+PROCEDURE KnownReachable (Scope: CARDINAL;
+                          Start, End: CARDINAL) ;
 VAR
    Op           : QuadOperator ;
    Op1, Op2, Op3: CARDINAL ;
index 722e56c69c7d1befc5add05d73609a5b2ea36338..d8d3845a73941dc477a482e603c9eee6362c07e7 100644 (file)
@@ -73,6 +73,7 @@ EXPORT QUALIFIED SetReturnCheck, SetNilCheck, SetCaseCheck,
                  VariantValueChecking,
                  UnusedVariableChecking, UnusedParameterChecking,
                  UninitVariableChecking, SetUninitVariableChecking,
+                 UninitVariableConditionalChecking,
                  SetUnusedVariableChecking, SetUnusedParameterChecking,
                  Quiet, LineDirectives, StrictTypeChecking,
                  CPreProcessor, Xcode, ExtendedOpaque,
@@ -162,6 +163,10 @@ VAR
    UnusedParameterChecking,      (* Should we warn about unused parameters?  *)
    UninitVariableChecking,       (* Should we warn about accessing           *)
                                  (* uninitialized variables in the first bb? *)
+   UninitVariableConditionalChecking,
+                                 (* Should we warn about accessing           *)
+                                 (* uninitialized variables in subsequent    *)
+                                 (* basic blocks? *)
    LowerCaseKeywords,            (* Should keywords in errors be in lower?   *)
    DebugBuiltins,                (* Should we always call a real function?   *)
    AutoInit,                     (* -fauto-init assigns pointers to NIL.     *)
@@ -922,10 +927,13 @@ PROCEDURE SetShared (value: BOOLEAN) ;
 
 
 (*
-   SetUninitVariableChecking - sets the UninitVariableChecking flag to value.
+   SetUninitVariableChecking - sets the UninitVariableChecking flag to value
+                               or UninitVariableConditionalChecking to value.
+                               Arg can be "known", "known,cond", "cond,known"
+                               or "all".
 *)
 
-PROCEDURE SetUninitVariableChecking (value: BOOLEAN) ;
+PROCEDURE SetUninitVariableChecking (value: BOOLEAN; arg: ADDRESS) : INTEGER ;
 
 
 (*
index 84fcb572319abaa0ebf77baff853785c3454d421..1174a0d54222582aeb88eb350a7070032abcac1f 100644 (file)
@@ -28,7 +28,7 @@ FROM M2Search IMPORT SetDefExtension, SetModExtension ;
 FROM PathName IMPORT DumpPathName, AddInclude ;
 FROM M2Printf IMPORT printf0, printf1, fprintf1 ;
 FROM FIO IMPORT StdErr ;
-FROM libc IMPORT exit ;
+FROM libc IMPORT exit, printf ;
 FROM Debug IMPORT Halt ;
 FROM m2linemap IMPORT location_t ;
 FROM m2configure IMPORT FullPathCPP ;
@@ -1369,84 +1369,114 @@ END SetShared ;
    SetUninitVariableChecking - sets the UninitVariableChecking flag to value.
 *)
 
-PROCEDURE SetUninitVariableChecking (value: BOOLEAN) ;
+PROCEDURE SetUninitVariableChecking (value: BOOLEAN; arg: ADDRESS) : INTEGER ;
+VAR
+   s: String ;
 BEGIN
-   UninitVariableChecking := value
+   IF Debugging
+   THEN
+      IF value
+      THEN
+         printf ("SetUninitVariableChecking (TRUE, %s)\n", arg)
+      ELSE
+         printf ("SetUninitVariableChecking (FALSE, %s)\n", arg)
+      END
+   END ;
+   s := InitStringCharStar (arg) ;
+   IF EqualArray (s, "all") OR
+      EqualArray (s, "known,cond") OR
+      EqualArray (s, "cond,known") OR
+      EqualArray (s, "cond")
+   THEN
+      UninitVariableChecking := value ;
+      UninitVariableConditionalChecking := value ;
+      s := KillString (s) ;
+      RETURN 1
+   ELSIF EqualArray (s, "known")
+   THEN
+      UninitVariableChecking := value ;
+      UninitVariableConditionalChecking := NOT value ;
+      s := KillString (s) ;
+      RETURN 1
+   ELSE
+      s := KillString (s) ;
+      RETURN 0
+   END
 END SetUninitVariableChecking ;
 
 
-
 BEGIN
-   cflag                        := FALSE ;  (* -c.  *)
-   RuntimeModuleOverride        := InitString (DefaultRuntimeModuleOverride) ;
-   CppArgs                      := InitString ('') ;
-   Pim                          :=  TRUE ;
-   Pim2                         := FALSE ;
-   Pim3                         := FALSE ;
-   Pim4                         :=  TRUE ;
-   PositiveModFloorDiv          := FALSE ;
-   Iso                          := FALSE ;
-   SeenSources                  := FALSE ;
-   Statistics                   := FALSE ;
-   StyleChecking                := FALSE ;
-   CompilerDebugging            := FALSE ;
-   GenerateDebugging            := FALSE ;
-   Optimizing                   := FALSE ;
-   Pedantic                     := FALSE ;
-   Verbose                      := FALSE ;
-   Quiet                        :=  TRUE ;
-   CC1Quiet                     :=  TRUE ;
-   Profiling                    := FALSE ;
-   DisplayQuadruples            := FALSE ;
-   OptimizeBasicBlock           := FALSE ;
-   OptimizeUncalledProcedures   := FALSE ;
-   OptimizeCommonSubExpressions := FALSE ;
-   NilChecking                  := FALSE ;
-   WholeDivChecking             := FALSE ;
-   WholeValueChecking           := FALSE ;
-   FloatValueChecking           := FALSE ;
-   IndexChecking                := FALSE ;
-   RangeChecking                := FALSE ;
-   ReturnChecking               := FALSE ;
-   CaseElseChecking             := FALSE ;
-   CPreProcessor                := FALSE ;
-   LineDirectives               := FALSE ;
-   ExtendedOpaque               := FALSE ;
-   UnboundedByReference         := FALSE ;
-   VerboseUnbounded             := FALSE ;
-   PedanticParamNames           := FALSE ;
-   PedanticCast                 := FALSE ;
-   Xcode                        := FALSE ;
-   DumpSystemExports            := FALSE ;
-   GenerateSwig                 := FALSE ;
-   Exceptions                   :=  TRUE ;
-   DebugBuiltins                := FALSE ;
-   ForcedLocation               := FALSE ;
-   WholeProgram                 := FALSE ;
-   DebugTraceQuad               := FALSE ;
-   DebugTraceAPI                := FALSE ;
-   DebugFunctionLineNumbers     := FALSE ;
-   GenerateStatementNote        := FALSE ;
-   LowerCaseKeywords            := FALSE ;
-   UnusedVariableChecking       := FALSE ;
-   UnusedParameterChecking      := FALSE ;
-   StrictTypeChecking           := TRUE ;
-   AutoInit                     := FALSE ;
-   SaveTemps                    := FALSE ;
-   ScaffoldDynamic              := TRUE ;
-   ScaffoldStatic               := FALSE ;
-   ScaffoldMain                 := FALSE ;
-   UselistFilename              := NIL ;
-   GenModuleList                := FALSE ;
-   GenModuleListFilename        := NIL ;
-   SharedFlag                   := FALSE ;
-   Barg                         := NIL ;
-   MDarg                        := NIL ;
-   MMDarg                       := NIL ;
-   MQarg                        := NIL ;
-   SaveTempsDir                 := NIL ;
-   DumpDir                      := NIL ;
-   UninitVariableChecking       := FALSE ;
-   M2Prefix                     := InitString ('') ;
-   M2PathName                   := InitString ('')
+   cflag                             := FALSE ;  (* -c.  *)
+   RuntimeModuleOverride             := InitString (DefaultRuntimeModuleOverride) ;
+   CppArgs                           := InitString ('') ;
+   Pim                               :=  TRUE ;
+   Pim2                              := FALSE ;
+   Pim3                              := FALSE ;
+   Pim4                              :=  TRUE ;
+   PositiveModFloorDiv               := FALSE ;
+   Iso                               := FALSE ;
+   SeenSources                       := FALSE ;
+   Statistics                        := FALSE ;
+   StyleChecking                     := FALSE ;
+   CompilerDebugging                 := FALSE ;
+   GenerateDebugging                 := FALSE ;
+   Optimizing                        := FALSE ;
+   Pedantic                          := FALSE ;
+   Verbose                           := FALSE ;
+   Quiet                             :=  TRUE ;
+   CC1Quiet                          :=  TRUE ;
+   Profiling                         := FALSE ;
+   DisplayQuadruples                 := FALSE ;
+   OptimizeBasicBlock                := FALSE ;
+   OptimizeUncalledProcedures        := FALSE ;
+   OptimizeCommonSubExpressions      := FALSE ;
+   NilChecking                       := FALSE ;
+   WholeDivChecking                  := FALSE ;
+   WholeValueChecking                := FALSE ;
+   FloatValueChecking                := FALSE ;
+   IndexChecking                     := FALSE ;
+   RangeChecking                     := FALSE ;
+   ReturnChecking                    := FALSE ;
+   CaseElseChecking                  := FALSE ;
+   CPreProcessor                     := FALSE ;
+   LineDirectives                    := FALSE ;
+   ExtendedOpaque                    := FALSE ;
+   UnboundedByReference              := FALSE ;
+   VerboseUnbounded                  := FALSE ;
+   PedanticParamNames                := FALSE ;
+   PedanticCast                      := FALSE ;
+   Xcode                             := FALSE ;
+   DumpSystemExports                 := FALSE ;
+   GenerateSwig                      := FALSE ;
+   Exceptions                        :=  TRUE ;
+   DebugBuiltins                     := FALSE ;
+   ForcedLocation                    := FALSE ;
+   WholeProgram                      := FALSE ;
+   DebugTraceQuad                    := FALSE ;
+   DebugTraceAPI                     := FALSE ;
+   DebugFunctionLineNumbers          := FALSE ;
+   GenerateStatementNote             := FALSE ;
+   LowerCaseKeywords                 := FALSE ;
+   UnusedVariableChecking            := FALSE ;
+   UnusedParameterChecking           := FALSE ;
+   StrictTypeChecking                := TRUE ;
+   AutoInit                          := FALSE ;
+   SaveTemps                         := FALSE ;
+   ScaffoldDynamic                   := TRUE ;
+   ScaffoldStatic                    := FALSE ;
+   ScaffoldMain                      := FALSE ;
+   UselistFilename                   := NIL ;
+   GenModuleList                     := FALSE ;
+   GenModuleListFilename             := NIL ;
+   SharedFlag                        := FALSE ;
+   Barg                              := NIL ;
+   MDarg                             := NIL ;
+   MMDarg                            := NIL ;
+   MQarg                             := NIL ;
+   SaveTempsDir                      := NIL ;
+   DumpDir                           := NIL ;
+   UninitVariableChecking            := FALSE ;
+   UninitVariableConditionalChecking := FALSE ;
+   M2Prefix                          := InitString ('') ;
+   M2PathName                        := InitString ('')
 END M2Options.
index ef6c06c39599d4d44f3b273ae6b34c66370f54ba..cd011baf54959ad51752131de081266e9be3d525 100644 (file)
@@ -106,6 +106,7 @@ EXPORT QUALIFIED StartBuildDefFile, StartBuildModFile, EndBuildFile,
                  IsBackReference,
                  IsUnConditional,
                  IsConditional, IsBackReferenceConditional,
+                 IsGoto,
                  IsCall,
                  IsReturn,
                  IsProcedureScope,
@@ -249,6 +250,13 @@ PROCEDURE IsConditional (QuadNo: CARDINAL) : BOOLEAN ;
 PROCEDURE IsBackReferenceConditional (q: CARDINAL) : BOOLEAN ;
 
 
+(*
+   IsGoto - returns true if QuadNo is a goto operation.
+*)
+
+PROCEDURE IsGoto (QuadNo: CARDINAL) : BOOLEAN ;
+
+
 (*
    IsCall - returns true if QuadNo is a call operation.
 *)
@@ -382,7 +390,7 @@ PROCEDURE DisplayQuadList ;
    DisplayQuadRange - displays all quads in list range, start..end.
 *)
 
-PROCEDURE DisplayQuadRange (start, end: CARDINAL) ;
+PROCEDURE DisplayQuadRange (scope: CARDINAL; start, end: CARDINAL) ;
 
 
 (*
@@ -2591,7 +2599,7 @@ PROCEDURE BuildStmtNote (offset: INTEGER) ;
    LoopAnalysis - checks whether an infinite loop exists.
 *)
 
-PROCEDURE LoopAnalysis (Current, End: CARDINAL) ;
+PROCEDURE LoopAnalysis (Scope: CARDINAL; Current, End: CARDINAL) ;
 
 
 (*
index dc7326540034b6e1450bfc2e4b7f6ac39371b11b..5ed2252876352c6f1d3f61cb5ad347bd73100ec2 100644 (file)
@@ -126,6 +126,7 @@ FROM SymbolTable IMPORT ModeOfAddr, GetMode, PutMode, GetSymName, IsUnknown,
                         GetUnboundedRecordType,
                         GetUnboundedAddressOffset,
                         GetUnboundedHighOffset,
+                        PutVarArrayRef,
 
                         ForeachFieldEnumerationDo, ForeachLocalSymDo,
                         GetExported, PutImported, GetSym, GetLibName,
@@ -588,6 +589,7 @@ BEGIN
                           RETURN( TRUE )
                        END
 
+      ELSE
       END ;
       i := GetNextQuad (i)
    END ;
@@ -711,6 +713,16 @@ BEGIN
 END IsQuadA ;
 
 
+(*
+   IsGoto - returns true if QuadNo is a goto operation.
+*)
+
+PROCEDURE IsGoto (QuadNo: CARDINAL) : BOOLEAN ;
+BEGIN
+   RETURN( IsQuadA (QuadNo, GotoOp) )
+END IsGoto ;
+
+
 (*
    IsCall - returns true if QuadNo is a call operation.
 *)
@@ -10667,7 +10679,7 @@ END IsInfiniteLoop ;
    LoopAnalysis - checks whether an infinite loop exists.
 *)
 
-PROCEDURE LoopAnalysis (Current, End: CARDINAL) ;
+PROCEDURE LoopAnalysis (Scope: CARDINAL; Current, End: CARDINAL) ;
 VAR
    op           : QuadOperator ;
    op1, op2, op3: CARDINAL ;
@@ -10683,10 +10695,18 @@ BEGIN
                (* found a loop - ie a branch which goes back in quadruple numbers *)
                IF IsInfiniteLoop(Current)
                THEN
+                  MetaErrorT1 (QuadToTokenNo(op3),
+                               'it is very likely (although not absolutely certain) that the top of an infinite loop exists here in {%1Wad}',
+                               Scope) ;
+                  MetaErrorT1 (QuadToTokenNo(Current),
+                               'and the bottom of the infinite loop is ends here in {%1Wad} or alternatively a component of this loop is never executed',
+                               Scope) ;
+(*
                   WarnStringAt(InitString('it is very likely (although not absolutely certain) that the top of an infinite loop is here'),
                                QuadToTokenNo(op3)) ;
                   WarnStringAt(InitString('and the bottom of the infinite loop is ends here or alternatively a component of this loop is never executed'),
                                QuadToTokenNo(Current))
+*)
                END
             END
          END ;
@@ -11216,6 +11236,7 @@ BEGIN
       (* BuildDesignatorArray may have detected des is a constant.  *)
       PutVarConst (Adr, IsVarConst (Array))
    END ;
+   PutVarArrayRef (Adr, TRUE) ;
    (*
       From now on it must reference the array element by its lvalue
       - so we create the type of the referenced entity
@@ -11246,15 +11267,15 @@ BEGIN
    THEN
       (* ti has no type since constant *)
       ti := MakeTemporary (tok, ImmediateValue) ;
-      PutVar(ti, Cardinal) ;
+      PutVar (ti, Cardinal) ;
       GenQuadO (tok, ElementSizeOp, ti, arrayType, 1, TRUE)
    ELSE
       INC(dim) ;
       tk := MakeTemporary (tok, RightValue) ;
-      PutVar(tk, Cardinal) ;
+      PutVar (tk, Cardinal) ;
       GenHigh (tok, tk, dim, arraySym) ;
       tl := MakeTemporary (tok, RightValue) ;
-      PutVar(tl, Cardinal) ;
+      PutVar (tl, Cardinal) ;
       GenQuadO (tok, AddOp, tl, tk, MakeConstLit (tok, MakeKey ('1'), Cardinal), TRUE) ;
       tj := calculateMultipicand (tok, arraySym, arrayType, dim) ;
       ti := MakeTemporary (tok, RightValue) ;
@@ -11385,6 +11406,7 @@ BEGIN
 
    GenQuad (MultOp, tk, ti, tj) ;
    Adr := MakeTemporary (combinedTok, LeftValue) ;
+   PutVarArrayRef (Adr, TRUE) ;
    (*
       Ok must reference by address
       - but we contain the type of the referenced entity
@@ -13168,14 +13190,14 @@ END DisplayQuadList ;
    DisplayQuadRange - displays all quads in list range, start..end.
 *)
 
-PROCEDURE DisplayQuadRange (start, end: CARDINAL) ;
+PROCEDURE DisplayQuadRange (scope: CARDINAL; start, end: CARDINAL) ;
 VAR
    f: QuadFrame ;
 BEGIN
-   printf0('Quadruples:\n') ;
-   WHILE (start<=end) AND (start#0) DO
-      DisplayQuad(start) ;
-      f := GetQF(start) ;
+   printf0 ('Quadruples for scope: ') ; WriteOperand (scope) ; printf0 ('\n') ;
+   WHILE (start <= end) AND (start # 0) DO
+      DisplayQuad (start) ;
+      f := GetQF (start) ;
       start := f^.Next
    END
 END DisplayQuadRange ;
@@ -13194,10 +13216,10 @@ BEGIN
    IF QuadrupleGeneration
    THEN
       WHILE QuadNo#0 DO
-         f := GetQF(QuadNo) ;
+         f := GetQF (QuadNo) ;
          WITH f^ DO
             i := Operand3 ;                       (* Next Link along the BackPatch *)
-            ManipulateReference(QuadNo, Value)    (* Filling in the BackPatch.     *)
+            ManipulateReference (QuadNo, Value)   (* Filling in the BackPatch.     *)
          END ;
          QuadNo := i
       END
@@ -13596,17 +13618,17 @@ PROCEDURE WriteOperand (Sym: CARDINAL) ;
 VAR
    n: Name ;
 BEGIN
-   IF Sym=NulSym
+   IF Sym = NulSym
    THEN
-      printf0('<nulsym>')
+      printf0 ('<nulsym>')
    ELSE
-      n := GetSymName(Sym) ;
-      printf1('%a', n) ;
-      IF IsVar(Sym) OR IsConst(Sym)
+      n := GetSymName (Sym) ;
+      printf1 ('%a', n) ;
+      IF IsVar (Sym) OR IsConst (Sym)
       THEN
-         printf0('[') ; WriteMode(GetMode(Sym)) ; printf0(']')
+         printf0 ('[') ; WriteMode (GetMode (Sym)) ; printf0(']')
       END ;
-      printf1('(%d)', Sym)
+      printf1 ('(%d)', Sym)
    END
 END WriteOperand ;
 
@@ -13666,7 +13688,15 @@ BEGIN
    LogicalOrOp :  RETURN InitString ('{%kOR}') |
    LogicalAndOp:  RETURN InitString ('{%kAND}') |
    InclOp      :  RETURN InitString ('{%kINCL}') |
-   ExclOp      :  RETURN InitString ('{%kEXCL}')
+   ExclOp      :  RETURN InitString ('{%kEXCL}') |
+   IfEquOp     :  RETURN InitString ('=') |
+   IfLessEquOp :  RETURN InitString ('<=') |
+   IfGreEquOp  :  RETURN InitString ('>=') |
+   IfGreOp     :  RETURN InitString ('>') |
+   IfLessOp    :  RETURN InitString ('<') |
+   IfNotEquOp  :  RETURN InitString ('#') |
+   IfInOp      :  RETURN InitString ('IN') |
+   IfNotInOp   :  RETURN InitString ('NOT IN')
 
    ELSE
       RETURN NIL
index 9aed02406988b564071504f4fbd3db4b99281062..c1b684ee9c525c877c3e4a444e464327151a8488 100644 (file)
@@ -37,7 +37,7 @@ EXPORT QUALIFIED ScopeBlock, ScopeProcedure,
 
 TYPE
    ScopeBlock ;
-   ScopeProcedure = PROCEDURE (CARDINAL, CARDINAL) ;
+   ScopeProcedure = PROCEDURE (CARDINAL, CARDINAL, CARDINAL) ;
 
 
 (*
index d840bf53aca9b829909c2e2fcddd746bc6b18b21..106c2a8a89570c768c04f5c9025e2d2422cc9586 100644 (file)
@@ -349,7 +349,7 @@ BEGIN
 
       END ;
       printf0 ("\n") ;
-      DisplayQuadRange (low, high) ;
+      DisplayQuadRange (scopeSym, low, high) ;
       IF next#NIL
       THEN
          DisplayScope (next)
@@ -428,7 +428,7 @@ BEGIN
          enter (sb) ;
          IF (low # 0) AND (high # 0)
          THEN
-            p (low, high)
+            p (scopeSym, low, high)
          END ;
          leave (sb)
       END ;
index 2ea6bfc2a98a86fbab206b476992dccf62c39c1d..d0e39fbf32c933df3e9f41787df5d9854cf9647d 100644 (file)
@@ -45,12 +45,11 @@ PROCEDURE GetFieldInitialized (desc: InitDesc; fieldlist: List) : BOOLEAN ;
 
 
 (*
-   VariableAnalysis - checks to see whether a variable is:
-
-                      read before it has been initialized
+   ScopeBlockVariableAnalysis - checks to see whether a variable is
+                                read before it has been initialized.
 *)
 
-PROCEDURE VariableAnalysis (Start, End: CARDINAL) ;
+PROCEDURE ScopeBlockVariableAnalysis (Scope: CARDINAL; Start, End: CARDINAL) ;
 
 
 PROCEDURE PrintSymInit (desc: InitDesc) ;
index 18200af06e73572463887f7a25dcdc2032f11be4..a5457ecbebd70a4320170b92549b1440573f27f9 100644 (file)
@@ -23,17 +23,28 @@ IMPLEMENTATION MODULE M2SymInit ;
 
 FROM Storage IMPORT ALLOCATE, DEALLOCATE ;
 FROM M2Debug IMPORT Assert ;
+FROM M2Printf IMPORT printf0, printf1, printf2, printf3, printf4 ;
 FROM libc IMPORT printf ;
 FROM NameKey IMPORT Name, NulName, KeyToCharStar ;
-FROM M2Options IMPORT UninitVariableChecking ;
-FROM M2MetaError IMPORT MetaErrorT1 ;
+
+FROM M2Options IMPORT UninitVariableChecking, UninitVariableConditionalChecking,
+                      CompilerDebugging ;
+
+FROM M2MetaError IMPORT MetaErrorT1, MetaErrorStringT1, MetaErrorStringT2 ;
 FROM M2LexBuf IMPORT UnknownTokenNo ;
+FROM DynamicStrings IMPORT String, InitString, Mark, ConCat, InitString ;
+FROM M2Error IMPORT InternalError ;
+
+FROM M2BasicBlock IMPORT BasicBlock,
+                         InitBasicBlocks, InitBasicBlocksFromRange,
+                        KillBasicBlocks, FreeBasicBlocks,
+                         ForeachBasicBlockDo ;
 
 IMPORT Indexing ;
 
 FROM Lists IMPORT List, InitList, GetItemFromList, PutItemIntoList,
                   IsItemInList, IncludeItemIntoList, NoOfItemsInList,
-                  RemoveItemFromList, ForeachItemInListDo, KillList ;
+                  RemoveItemFromList, ForeachItemInListDo, KillList, DuplicateList ;
 
 FROM SymbolTable IMPORT NulSym, ModeOfAddr, IsVar, IsRecord, GetSType,
                         GetNth, IsRecordField, IsSet, IsArray, IsProcedure,
@@ -43,10 +54,14 @@ FROM SymbolTable IMPORT NulSym, ModeOfAddr, IsVar, IsRecord, GetSType,
                         IsConst, IsConstString, NoOfParam, IsVarParam,
                         ForeachLocalSymDo, IsTemporary, ModeOfAddr,
                         IsReallyPointer, IsUnbounded,
-                        IsVarient, IsFieldVarient, GetVarient ;
+                        IsVarient, IsFieldVarient, GetVarient,
+                        IsVarArrayRef ;
+
+FROM M2Quads IMPORT QuadOperator, GetQuadOtok, GetQuad, GetNextQuad,
+                    IsNewLocalVar, IsReturn, IsKillLocalVar, IsConditional,
+                    IsUnConditional, IsBackReference, IsCall, IsGoto,
+                    GetM2OperatorDesc, Opposite, DisplayQuadRange ;
 
-FROM M2Quads IMPORT QuadOperator, GetQuadOtok, GetQuad, GetNextQuad ;
-FROM M2Options IMPORT CompilerDebugging ;
 FROM M2Printf IMPORT printf0, printf1, printf2 ;
 FROM M2GCCDeclare IMPORT PrintSym ;
 
@@ -78,9 +93,32 @@ TYPE
                             next  : symAlias ;
                          END ;
 
+   bbEntry = POINTER TO RECORD
+                           start, end: CARDINAL ;
+                           (* Is this the first bb?  *)
+                           first,
+                           (* Does it end with a call?  *)
+                           endCall,
+                           (* Does it end with a goto?  *)
+                           endGoto,
+                           (* Does it end with a conditional?  *)
+                           endCond,
+                           (* Does it form part of a loop?  *)
+                           topOfLoop: BOOLEAN ;
+                           indexBB,
+                           nextQuad,
+                           condQuad,
+                           nextBB,
+                           condBB   : CARDINAL ;
+                           next     : bbEntry ;
+                        END ;
+
 VAR
    aliasArray: Indexing.Index ;
    freeList  : symAlias ;
+   bbArray   : Indexing.Index ;
+   bbFreeList: bbEntry ;
+   errorList : List ;   (* Ensure that we only generate one set of warnings per token.  *)
 
 
 (*
@@ -426,12 +464,116 @@ BEGIN
 END ContainsVariant ;
 
 
+(*
+   IssueConditional -
+*)
+
+PROCEDURE IssueConditional (quad: CARDINAL; conditional: BOOLEAN) ;
+VAR
+   op                          : QuadOperator ;
+   op1, op2, op3               : CARDINAL ;
+   op1tok, op2tok, op3tok, qtok: CARDINAL ;
+   overflowChecking            : BOOLEAN ;
+   s                           : String ;
+BEGIN
+   GetQuadOtok (quad, qtok, op, op1, op2, op3, overflowChecking,
+                op1tok, op2tok, op3tok) ;
+   IF IsUniqueWarning (qtok)
+   THEN
+      op1tok := DefaultTokPos (op1tok, qtok) ;
+      op2tok := DefaultTokPos (op2tok, qtok) ;
+      op3tok := DefaultTokPos (op3tok, qtok) ;
+      IF NOT conditional
+      THEN
+         op := Opposite (op)
+      END ;
+      s := InitString ('depending upon the result of {%1Oad} ') ;
+      s := ConCat (s, Mark (GetM2OperatorDesc (op))) ;
+      s := ConCat (s, InitString (' {%2ad}')) ;
+      MetaErrorStringT2 (qtok, s, op1, op2)
+   END
+END IssueConditional ;
+
+
+(*
+   GenerateNoteFlow -
+*)
+
+PROCEDURE GenerateNoteFlow (lst: List; n: CARDINAL; warning: BOOLEAN) ;
+VAR
+   i     : CARDINAL ;
+   ip1Ptr,
+   iPtr  : bbEntry ;
+BEGIN
+   IF NOT warning
+   THEN
+      (* Only issue flow messages for non warnings.  *)
+      i := 1 ;
+      WHILE i <= n DO
+         iPtr := Indexing.GetIndice (bbArray, i) ;
+         IF iPtr^.endCond
+         THEN
+            IF i < n
+            THEN
+               ip1Ptr := Indexing.GetIndice (bbArray, i+1) ;
+               IssueConditional (iPtr^.end, iPtr^.condBB = ip1Ptr^.indexBB)
+            END
+         END ;
+         INC (i)
+      END
+   END
+END GenerateNoteFlow ;
+
+
+(*
+   IssueWarning - issue a warning or note at tok location.
+*)
+
+PROCEDURE IssueWarning (tok: CARDINAL;
+                        before, after: ARRAY OF CHAR;
+                        sym: CARDINAL; warning: BOOLEAN) ;
+VAR
+   s: String ;
+BEGIN
+   s := InitString (before) ;
+   IF warning
+   THEN
+      s := ConCat (s, Mark (InitString ('{%1Wad}')))
+   ELSE
+      s := ConCat (s, Mark (InitString ('{%1Oad}')))
+   END ;
+   s := ConCat (s, Mark (InitString (after))) ;
+   MetaErrorStringT1 (tok, s, sym)
+END IssueWarning ;
+
+
+(*
+   IsUniqueWarning - return TRUE if a warning has not been issued at tok.
+                     It remembers tok and subsequent calls will always return FALSE.
+*)
+
+PROCEDURE IsUniqueWarning (tok: CARDINAL) : BOOLEAN ;
+BEGIN
+   IF NOT IsItemInList (errorList, tok)
+   THEN
+      IncludeItemIntoList (errorList, tok) ;
+      RETURN TRUE
+   ELSE
+      RETURN FALSE
+   END
+END IsUniqueWarning ;
+
+
 (*
    CheckDeferredRecordAccess -
 *)
 
 PROCEDURE CheckDeferredRecordAccess (procsym: CARDINAL; tok: CARDINAL;
-                                     sym: CARDINAL; canDereference: BOOLEAN) ;
+                                     sym: CARDINAL;
+                                     canDereference, warning: BOOLEAN;
+                                     lst: List; i: CARDINAL) ;
+VAR
+   unique: BOOLEAN ;
 BEGIN
    IF IsVar (sym)
    THEN
@@ -459,32 +601,49 @@ BEGIN
       ELSIF IsComponent (sym)
       THEN
          Trace ("checkReadInit IsComponent (%d) is true)", sym) ;
-         IF NOT GetVarComponentInitialized (sym)
+         IF (NOT GetVarComponentInitialized (sym)) AND IsUniqueWarning (tok)
          THEN
-            MetaErrorT1 (tok,
-                         'attempting to access {%1Wad} before it has been initialized',
-                         sym)
+            GenerateNoteFlow (lst, i, warning) ;
+            IssueWarning (tok,
+                          'attempting to access ',
+                          ' before it has been initialized',
+                          sym, warning)
          END
       ELSIF (GetMode (sym) = LeftValue) AND canDereference
       THEN
          Trace ("checkReadInit GetMode (%d) = LeftValue and canDereference (LeftValue and RightValue VarCheckReadInit)", sym) ;
+         unique := TRUE ;
          IF NOT VarCheckReadInit (sym, LeftValue)
          THEN
-            MetaErrorT1 (tok,
-                         'attempting to access the address of {%1Wad} before it has been initialized',
-                         sym)
+            unique := IsUniqueWarning (tok) ;
+            IF unique
+            THEN
+               GenerateNoteFlow (lst, i, warning) ;
+               IssueWarning (tok,
+                             'attempting to access the address of ',
+                             ' before it has been initialized',
+                             sym, warning)
+            END
          END ;
          IF NOT VarCheckReadInit (sym, RightValue)
          THEN
-            MetaErrorT1 (tok,
-                         'attempting to access {%1Wad} before it has been initialized', sym)
+            IF unique
+            THEN
+               GenerateNoteFlow (lst, i, warning) ;
+               IssueWarning (tok,
+                             'attempting to access ', ' before it has been initialized',
+                             sym, warning)
+            END
          END
       ELSE
          Trace ("checkReadInit call VarCheckReadInit using GetMode (%d)", sym) ;
-         IF NOT VarCheckReadInit (sym, GetMode (sym))
+         IF (NOT VarCheckReadInit (sym, GetMode (sym))) AND IsUniqueWarning (tok)
          THEN
-            MetaErrorT1 (tok,
-                         'attempting to access {%1Wad} before it has been initialized', sym)
+            GenerateNoteFlow (lst, i, warning) ;
+            IssueWarning (tok,
+                          'attempting to access ',
+                          ' before it has been initialized',
+                          sym, warning)
          END
       END
    END
@@ -757,7 +916,7 @@ BEGIN
           (IsGlobalVar (sym) OR IsVarAParam (sym) OR
            ContainsVariant (GetSType (sym)) OR
            IsArray (GetSType (sym)) OR IsSet (GetSType (sym)) OR
-           IsUnbounded (GetSType (sym)))
+           IsUnbounded (GetSType (sym)) OR IsVarArrayRef (sym))
 END IsExempt ;
 
 
@@ -768,10 +927,11 @@ END IsExempt ;
 PROCEDURE CheckBinary (procSym,
                        op1tok, op1,
                        op2tok, op2,
-                       op3tok, op3: CARDINAL) ;
+                       op3tok, op3: CARDINAL; warning: BOOLEAN;
+                       lst: List; i: CARDINAL) ;
 BEGIN
-   CheckDeferredRecordAccess (procSym, op2tok, op2, FALSE) ;
-   CheckDeferredRecordAccess (procSym, op3tok, op3, FALSE) ;
+   CheckDeferredRecordAccess (procSym, op2tok, op2, FALSE, warning, lst, i) ;
+   CheckDeferredRecordAccess (procSym, op3tok, op3, FALSE, warning, lst, i) ;
    SetVarInitialized (op1, FALSE)
 END CheckBinary ;
 
@@ -782,9 +942,10 @@ END CheckBinary ;
 
 PROCEDURE CheckUnary (procSym,
                       lhstok, lhs,
-                      rhstok, rhs: CARDINAL) ;
+                      rhstok, rhs: CARDINAL; warning: BOOLEAN;
+                      lst: List; i: CARDINAL) ;
 BEGIN
-   CheckDeferredRecordAccess (procSym, rhstok, rhs, FALSE) ;
+   CheckDeferredRecordAccess (procSym, rhstok, rhs, FALSE, warning, lst, i) ;
    SetVarInitialized (lhs, FALSE)
 END CheckUnary ;
 
@@ -793,13 +954,15 @@ END CheckUnary ;
    CheckXIndr -
 *)
 
-PROCEDURE CheckXIndr (procSym, lhstok, lhs, type, rhstok, rhs: CARDINAL) ;
+PROCEDURE CheckXIndr (procSym, lhstok, lhs, type,
+                      rhstok, rhs: CARDINAL; warning: BOOLEAN;
+                      bblst: List; i: CARDINAL) ;
 VAR
    lst : List ;
    vsym: CARDINAL ;
 BEGIN
-   CheckDeferredRecordAccess (procSym, rhstok, rhs, FALSE) ;
-   CheckDeferredRecordAccess (procSym, lhstok, lhs, FALSE) ;
+   CheckDeferredRecordAccess (procSym, rhstok, rhs, FALSE, warning, bblst, i) ;
+   CheckDeferredRecordAccess (procSym, lhstok, lhs, FALSE, warning, bblst, i) ;
    (* Now see if we know what lhs is pointing to and set fields if necessary.  *)
    vsym := getAlias (lhs) ;
    IF (vsym # lhs) AND (GetSType (vsym) = type)
@@ -824,11 +987,13 @@ END CheckXIndr ;
    CheckIndrX -
 *)
 
-PROCEDURE CheckIndrX (procSym, lhstok, lhs, type, rhstok, rhs: CARDINAL) ;
+PROCEDURE CheckIndrX (procSym, lhstok, lhs, type, rhstok, rhs: CARDINAL;
+                      warning: BOOLEAN;
+                      lst: List; i: CARDINAL) ;
 BEGIN
-   CheckDeferredRecordAccess (procSym, rhstok, rhs, FALSE) ;
-   CheckDeferredRecordAccess (procSym, rhstok, rhs, TRUE) ;
-   SetVarInitialized (lhs, FALSE)
+   CheckDeferredRecordAccess (procSym, rhstok, rhs, FALSE, warning, lst, i) ;
+   CheckDeferredRecordAccess (procSym, rhstok, rhs, TRUE, warning, lst, i) ;
+   SetVarInitialized (lhs, IsVarAParam (rhs))
 END CheckIndrX ;
 
 
@@ -846,12 +1011,13 @@ END CheckRecordField ;
    CheckBecomes -
 *)
 
-PROCEDURE CheckBecomes (procSym, destok, des, exprtok, expr: CARDINAL) ;
+PROCEDURE CheckBecomes (procSym, destok, des, exprtok, expr: CARDINAL;
+                        warning: BOOLEAN; bblst: List; i: CARDINAL) ;
 VAR
    lst : List ;
    vsym: CARDINAL ;
 BEGIN
-   CheckDeferredRecordAccess (procSym, exprtok, expr, FALSE) ;
+   CheckDeferredRecordAccess (procSym, exprtok, expr, FALSE, warning, bblst, i) ;
    SetupAlias (des, expr) ;
    SetVarInitialized (des, FALSE) ;
    (* Now see if we know what lhs is pointing to and set fields if necessary.  *)
@@ -872,10 +1038,11 @@ END CheckBecomes ;
    CheckComparison -
 *)
 
-PROCEDURE CheckComparison (procSym, op1tok, op1, op2tok, op2: CARDINAL) ;
+PROCEDURE CheckComparison (procSym, op1tok, op1, op2tok, op2: CARDINAL;
+                           warning: BOOLEAN; lst: List; i: CARDINAL) ;
 BEGIN
-   CheckDeferredRecordAccess (procSym, op1tok, op1, FALSE) ;
-   CheckDeferredRecordAccess (procSym, op2tok, op2, FALSE)
+   CheckDeferredRecordAccess (procSym, op1tok, op1, FALSE, warning, lst, i) ;
+   CheckDeferredRecordAccess (procSym, op2tok, op2, FALSE, warning, lst, i)
 END CheckComparison ;
 
 
@@ -916,7 +1083,8 @@ END stop ;
    CheckReadBeforeInitQuad -
 *)
 
-PROCEDURE CheckReadBeforeInitQuad (procSym: CARDINAL; quad: CARDINAL) : BOOLEAN ;
+PROCEDURE CheckReadBeforeInitQuad (procSym: CARDINAL; quad: CARDINAL;
+                                   warning: BOOLEAN; lst: List; i: CARDINAL) : BOOLEAN ;
 VAR
    op                          : QuadOperator ;
    op1, op2, op3               : CARDINAL ;
@@ -949,7 +1117,7 @@ BEGIN
    IfLessOp,
    IfLessEquOp,
    IfGreOp,
-   IfGreEquOp        : CheckComparison (procSym, op1tok, op1, op2tok, op2) |
+   IfGreEquOp        : CheckComparison (procSym, op1tok, op1, op2tok, op2, warning, lst, i) |
    TryOp,
    ReturnOp,
    CallOp,
@@ -960,26 +1128,27 @@ BEGIN
    (* Variable references.  *)
 
    InclOp,
-   ExclOp            : CheckDeferredRecordAccess (procSym, op1tok, op1, FALSE) ;
-                       CheckDeferredRecordAccess (procSym, op1tok, op1, TRUE) ;
-                       CheckDeferredRecordAccess (procSym, op3tok, op3, FALSE) |
-   NegateOp          : CheckUnary (procSym, op1tok, op1, op3tok, op3) |
-   BecomesOp         : CheckBecomes (procSym, op1tok, op1, op3tok, op3) |
+   ExclOp            : CheckDeferredRecordAccess (procSym, op1tok, op1, FALSE, warning, lst, i) ;
+                       CheckDeferredRecordAccess (procSym, op1tok, op1, TRUE, warning, lst, i) ;
+                       CheckDeferredRecordAccess (procSym, op3tok, op3, FALSE, warning, lst, i) |
+   NegateOp          : CheckUnary (procSym, op1tok, op1, op3tok, op3, warning, lst, i) |
+   BecomesOp         : CheckBecomes (procSym, op1tok, op1, op3tok, op3, warning, lst, i) |
    UnboundedOp,
    FunctValueOp,
+   StandardFunctionOp,
    HighOp,
    SizeOp            : SetVarInitialized (op1, FALSE) |
    AddrOp            : CheckAddr (procSym, op1tok, op1, op3tok, op3) |
    ReturnValueOp     : SetVarInitialized (op1, FALSE) |
    NewLocalVarOp     : |
-   ParamOp           : CheckDeferredRecordAccess (procSym, op2tok, op2, FALSE) ;
-                       CheckDeferredRecordAccess (procSym, op3tok, op3, FALSE) ;
+   ParamOp           : CheckDeferredRecordAccess (procSym, op2tok, op2, FALSE, warning, lst, i) ;
+                       CheckDeferredRecordAccess (procSym, op3tok, op3, FALSE, warning, lst, i) ;
                        IF (op1 > 0) AND (op1 <= NoOfParam (op2)) AND
                           IsVarParam (op2, op1)
                        THEN
                           SetVarInitialized (op3, TRUE)
                        END |
-   ArrayOp           : CheckDeferredRecordAccess (procSym, op3tok, op3, FALSE) ;
+   ArrayOp           : CheckDeferredRecordAccess (procSym, op3tok, op3, FALSE, warning, lst, i) ;
                        SetVarInitialized (op1, TRUE) |
    RecordFieldOp     : CheckRecordField (procSym, op1tok, op1, op2tok, op2) |
    LogicalShiftOp,
@@ -1002,14 +1171,43 @@ BEGIN
    DivFloorOp,
    ModTruncOp,
    DivTruncOp        : CheckBinary (procSym,
-                                    op1tok, op1, op2tok, op2, op3tok, op3) |
-   XIndrOp           : CheckXIndr (procSym, op1tok, op1, op2, op3tok, op3) |
-   IndrXOp           : CheckIndrX (procSym, op1tok, op1, op2, op3tok, op3) |
-   RangeCheckOp      : |
+                                    op1tok, op1, op2tok, op2, op3tok, op3, warning, lst, i) |
+   XIndrOp           : CheckXIndr (procSym, op1tok, op1, op2, op3tok, op3, warning, lst, i) |
+   IndrXOp           : CheckIndrX (procSym, op1tok, op1, op2, op3tok, op3, warning, lst, i) |
    SaveExceptionOp   : SetVarInitialized (op1, FALSE) |
-   RestoreExceptionOp: CheckDeferredRecordAccess (procSym, op1tok, op1, FALSE)
+   RestoreExceptionOp: CheckDeferredRecordAccess (procSym, op1tok, op1, FALSE, warning, lst, i) |
+
+   SubrangeLowOp,
+   SubrangeHighOp    : InternalError ('quadruples should have been resolved') |
+   ElementSizeOp,
+   BuiltinConstOp,  (* Nothing to do, it is assigning a constant to op1 (also a const).  *)
+   BuiltinTypeInfoOp,  (* Likewise assigning op1 (const) with a type.  *)
+   ProcedureScopeOp,
+   InitEndOp,
+   InitStartOp,
+   FinallyStartOp,
+   FinallyEndOp,
+   CatchBeginOp,
+   CatchEndOp,
+   ThrowOp,
+   StartDefFileOp,
+   StartModFileOp,
+   EndFileOp,
+   CodeOnOp,
+   CodeOffOp,
+   ProfileOnOp,
+   ProfileOffOp,
+   OptimizeOnOp,
+   OptimizeOffOp,
+   InlineOp,
+   LineNumberOp,
+   StatementNoteOp,
+   SavePriorityOp,
+   RestorePriorityOp,
+   RangeCheckOp,
+   ModuleScopeOp,
+   ErrorOp          : |
 
-   ELSE
    END ;
    RETURN FALSE
 END CheckReadBeforeInitQuad ;
@@ -1019,7 +1217,9 @@ END CheckReadBeforeInitQuad ;
    FilterCheckReadBeforeInitQuad -
 *)
 
-PROCEDURE FilterCheckReadBeforeInitQuad (procSym: CARDINAL; start: CARDINAL) : BOOLEAN ;
+PROCEDURE FilterCheckReadBeforeInitQuad (procSym: CARDINAL; start: CARDINAL;
+                                         warning: BOOLEAN;
+                                         lst: List; i: CARDINAL) : BOOLEAN ;
 VAR
    Op           : QuadOperator ;
    Op1, Op2, Op3: CARDINAL ;
@@ -1027,7 +1227,7 @@ BEGIN
    GetQuad (start, Op, Op1, Op2, Op3) ;
    IF (Op # RangeCheckOp) AND (Op # StatementNoteOp)
    THEN
-      RETURN CheckReadBeforeInitQuad (procSym, start)
+      RETURN CheckReadBeforeInitQuad (procSym, start, warning, lst, i)
    END ;
    RETURN FALSE
 END FilterCheckReadBeforeInitQuad ;
@@ -1038,43 +1238,366 @@ END FilterCheckReadBeforeInitQuad ;
 *)
 
 PROCEDURE CheckReadBeforeInitFirstBasicBlock (procSym: CARDINAL;
-                                              start, end: CARDINAL) ;
+                                              start, end: CARDINAL;
+                                              warning: BOOLEAN;
+                                              lst: List; i: CARDINAL) ;
 BEGIN
-   ForeachLocalSymDo (procSym, SetVarUninitialized) ;
    LOOP
-      IF FilterCheckReadBeforeInitQuad (procSym, start) OR (start = end)
+      IF FilterCheckReadBeforeInitQuad (procSym, start, warning, lst, i)
       THEN
-         RETURN
       END ;
-      start := GetNextQuad (start)
+      IF start = end
+      THEN
+         RETURN
+      ELSE
+         start := GetNextQuad (start)
+      END
    END
 END CheckReadBeforeInitFirstBasicBlock ;
 
 
 (*
-   VariableAnalysis - checks to see whether a variable is:
+   bbArrayKill -
+*)
+
+PROCEDURE bbArrayKill ;
+VAR
+   i, h : CARDINAL ;
+   bbPtr: bbEntry ;
+BEGIN
+   h := Indexing.HighIndice (bbArray) ;
+   i := 1 ;
+   WHILE i <= h DO
+      bbPtr := Indexing.GetIndice (bbArray, i) ;
+      bbPtr^.next := bbFreeList ;
+      bbFreeList := bbPtr ;
+      INC (i)
+   END ;
+   bbArray := Indexing.KillIndex (bbArray)
+END bbArrayKill ;
 
-                      read before it has been initialized
+
+(*
+   DumpBBEntry -
 *)
 
-PROCEDURE VariableAnalysis (Start, End: CARDINAL) ;
+PROCEDURE DumpBBEntry (bbPtr: bbEntry; procSym: CARDINAL) ;
+BEGIN
+   printf4 ("bb %d: scope %d:  quads: %d .. %d",
+            bbPtr^.indexBB, procSym, bbPtr^.start, bbPtr^.end) ;
+   IF bbPtr^.first
+   THEN
+      printf0 (" first")
+   END ;
+   IF bbPtr^.endCall
+   THEN
+      printf0 (" endcall")
+   END ;
+   IF bbPtr^.endGoto
+   THEN
+      printf0 (" endgoto")
+   END ;
+   IF bbPtr^.endCond
+   THEN
+      printf0 (" endcond")
+   END ;
+   IF bbPtr^.topOfLoop
+   THEN
+      printf0 (" topofloop")
+   END ;
+   IF bbPtr^.condBB # 0
+   THEN
+      printf1 (" cond %d", bbPtr^.condBB)
+   END ;
+   IF bbPtr^.nextBB # 0
+   THEN
+      printf1 (" next %d", bbPtr^.nextBB)
+   END ;
+   printf0 ("\n")
+END DumpBBEntry ;
+
+
+(*
+   DumpBBArray -
+*)
+
+PROCEDURE DumpBBArray (procSym: CARDINAL) ;
 VAR
-   Op           : QuadOperator ;
-   Op1, Op2, Op3: CARDINAL ;
+   bbPtr: bbEntry ;
+   i, n : CARDINAL ;
 BEGIN
-   IF UninitVariableChecking
+   i := 1 ;
+   n := Indexing.HighIndice (bbArray) ;
+   WHILE i <= n DO
+      bbPtr := Indexing.GetIndice (bbArray, i) ;
+      DumpBBEntry (bbPtr, procSym) ;
+      INC (i)
+   END ;
+   i := 1 ;
+   WHILE i <= n DO
+      bbPtr := Indexing.GetIndice (bbArray, i) ;
+      printf4 ("bb %d: scope %d:  quads: %d .. %d\n",
+               bbPtr^.indexBB, procSym, bbPtr^.start, bbPtr^.end) ;
+      DisplayQuadRange (procSym, bbPtr^.start, bbPtr^.end) ;
+      INC (i)
+   END
+END DumpBBArray ;
+
+
+(*
+   DumpBBSequence -
+*)
+
+PROCEDURE DumpBBSequence (procSym: CARDINAL; lst: List) ;
+VAR
+   arrayindex,
+   listindex, n: CARDINAL ;
+BEGIN
+   n := NoOfItemsInList (lst) ;
+   listindex := 1 ;
+   printf0 ("=============\n");
+   printf0 (" checking sequence:");
+   WHILE listindex <= n DO
+      arrayindex := GetItemFromList (lst, listindex) ;
+      printf1 (" [%d]", listindex) ;
+      INC (listindex)
+   END ;
+   printf0 ("\n")
+END DumpBBSequence ;
+
+
+(*
+   TestBBSequence -
+*)
+
+PROCEDURE TestBBSequence (procSym: CARDINAL; lst: List) ;
+VAR
+   bbPtr  : bbEntry ;
+   bbi,
+   i, n   : CARDINAL ;
+   warning: BOOLEAN ;  (* Should we issue a warning rather than a note?  *)
+BEGIN
+   IF Debugging
    THEN
-      GetQuad (Start, Op, Op1, Op2, Op3) ;
-      CASE Op OF
+      DumpBBSequence (procSym, lst)
+   END ;
+   ForeachLocalSymDo (procSym, SetVarUninitialized) ;
+   initBlock ;
+   n := NoOfItemsInList (lst) ;
+   i := 1 ;
+   warning := TRUE ;
+   WHILE i <= n DO
+      bbi := GetItemFromList (lst, i) ;
+      bbPtr := Indexing.GetIndice (bbArray, bbi) ;
+      CheckReadBeforeInitFirstBasicBlock (procSym, bbPtr^.start, bbPtr^.end, warning, lst, i) ;
+      IF bbPtr^.endCond
+      THEN
+         (* Check to see if we are moving into an conditional block in which case
+            we will issue a note.  *)
+         warning := FALSE
+      END ;
+      INC (i)
+   END ;
+   killBlock
+END TestBBSequence ;
 
-      NewLocalVarOp:  initBlock ;
-                      CheckReadBeforeInitFirstBasicBlock (Op3, Start, End) ;
-                      killBlock
 
+(*
+   CreateBBPermultations -
+*)
+
+PROCEDURE CreateBBPermultations (procSym: CARDINAL; i: CARDINAL; lst: List) ;
+VAR
+   duplst: List ;
+   iPtr  : bbEntry ;
+BEGIN
+   IF i = 0
+   THEN
+      TestBBSequence (procSym, lst)
+   ELSE
+      iPtr := Indexing.GetIndice (bbArray, i) ;
+      IF iPtr^.topOfLoop
+      THEN
+         TestBBSequence (procSym, lst)
       ELSE
+         duplst := DuplicateList (lst) ;
+         IncludeItemIntoList (duplst, i) ;
+         IF iPtr^.endCall
+         THEN
+            TestBBSequence (procSym, duplst)
+         ELSIF iPtr^.endGoto
+         THEN
+            CreateBBPermultations (procSym, iPtr^.nextBB, duplst)
+         ELSIF UninitVariableConditionalChecking AND iPtr^.endCond
+         THEN
+            CreateBBPermultations (procSym, iPtr^.nextBB, duplst) ;
+            CreateBBPermultations (procSym, iPtr^.condBB, duplst)
+         ELSIF iPtr^.endCond
+         THEN
+            TestBBSequence (procSym, duplst)
+         ELSE
+            (* Fall through.  *)
+            CreateBBPermultations (procSym, iPtr^.nextBB, duplst)
+         END ;
+         KillList (duplst)
       END
    END
-END VariableAnalysis ;
+END CreateBBPermultations ;
+
+
+(*
+   ScopeBlockVariableAnalysis - checks to see whether a variable is
+                                read before it has been initialized.
+*)
+
+PROCEDURE ScopeBlockVariableAnalysis (Scope: CARDINAL;
+                                      Start, End: CARDINAL) ;
+VAR
+   bb : BasicBlock ;
+   lst: List ;
+BEGIN
+   IF UninitVariableChecking
+   THEN
+      bbArray := Indexing.InitIndex (1) ;
+      bb := InitBasicBlocksFromRange (Scope, Start, End) ;
+      ForeachBasicBlockDo (bb, AppendEntry) ;
+      KillBasicBlocks (bb) ;
+      GenerateCFG ;
+      IF Scope # NulSym
+      THEN
+         InitList (lst) ;
+         IF Debugging
+         THEN
+            DumpBBArray (Scope) ;
+            IF UninitVariableConditionalChecking
+            THEN
+               printf0 ("UninitVariableConditionalChecking is TRUE\n")
+            END
+         END ;
+         CreateBBPermultations (Scope, 1, lst) ;
+         KillList (lst)
+      END ;
+      bbArrayKill
+   END
+END ScopeBlockVariableAnalysis ;
+
+
+(*
+   GetOp3 -
+*)
+
+PROCEDURE GetOp3 (quad: CARDINAL) : CARDINAL ;
+VAR
+   op: QuadOperator ;
+   op1, op2, op3: CARDINAL ;
+BEGIN
+   GetQuad (quad, op, op1, op2, op3) ;
+   RETURN op3
+END GetOp3 ;
+
+
+(*
+   getBBindex - return the basic block index which starts with quad.
+*)
+
+PROCEDURE getBBindex (quad: CARDINAL) : CARDINAL ;
+VAR
+   iPtr   : bbEntry ;
+   i, high: CARDINAL ;
+BEGIN
+   i := 1 ;
+   high := Indexing.HighIndice (bbArray) ;
+   WHILE i <= high DO
+      iPtr := Indexing.GetIndice (bbArray, i) ;
+      IF iPtr^.start = quad
+      THEN
+         RETURN iPtr^.indexBB
+      END ;
+      INC (i)
+   END ;
+   RETURN 0
+END getBBindex ;
+
+
+(*
+   GenerateCFG -
+*)
+
+PROCEDURE GenerateCFG ;
+VAR
+   iPtr   : bbEntry ;
+   next,
+   i, high: CARDINAL ;
+BEGIN
+   i := 1 ;
+   high := Indexing.HighIndice (bbArray) ;
+   WHILE i <= high DO
+      iPtr := Indexing.GetIndice (bbArray, i) ;
+      IF IsKillLocalVar (iPtr^.end) OR IsReturn (iPtr^.end)
+      THEN
+         (* Nothing to do as we have reached the end of this scope.  *)
+      ELSE
+         next := GetNextQuad (iPtr^.end) ;
+         iPtr^.nextQuad := next ;
+         iPtr^.nextBB := getBBindex (next) ;
+         IF iPtr^.endCond
+         THEN
+            iPtr^.condQuad := GetOp3 (iPtr^.end) ;
+            iPtr^.condBB := getBBindex (iPtr^.condQuad)
+         END
+      END ;
+      INC (i)
+   END
+END GenerateCFG ;
+
+
+(*
+   NewEntry -
+*)
+
+PROCEDURE NewEntry () : bbEntry ;
+VAR
+   bbPtr: bbEntry ;
+BEGIN
+   IF bbFreeList = NIL
+   THEN
+      NEW (bbPtr)
+   ELSE
+      bbPtr := bbFreeList ;
+      bbFreeList := bbFreeList^.next
+   END ;
+   RETURN bbPtr
+END NewEntry ;
+
+
+(*
+   AppendEntry -
+*)
+
+PROCEDURE AppendEntry (Start, End: CARDINAL) ;
+VAR
+   bbPtr: bbEntry ;
+   high : CARDINAL ;
+BEGIN
+   high := Indexing.HighIndice (bbArray) ;
+   bbPtr := NewEntry () ;
+   WITH bbPtr^ DO
+      start := Start ;
+      end := End ;
+      first := high = 0 ;
+      endCall := IsCall (End) ;
+      endGoto := IsGoto (End) ;
+      endCond := IsConditional (End) ;
+      topOfLoop := IsBackReference (Start) ;
+      indexBB := high + 1 ;
+      nextQuad := 0 ;
+      condQuad := 0 ;
+      nextBB := 0 ;
+      condBB := 0 ;
+      next := NIL
+   END ;
+   Indexing.PutIndice (bbArray, high + 1, bbPtr)
+END AppendEntry ;
 
 
 (*
@@ -1298,7 +1821,9 @@ END SetupAlias ;
 
 PROCEDURE init ;
 BEGIN
-   freeList := NIL
+   freeList := NIL ;
+   bbFreeList := NIL ;
+   InitList (errorList)
 END init ;
 
 
index c861cffc0fac09fb7c8d7b3fdd1b8e7428464d50..8c4feed705506e140a44631938175e3fa0fc4db7 100644 (file)
@@ -158,6 +158,7 @@ EXPORT QUALIFIED NulSym,
                  PutDefLink,
                  PutModLink,
                  PutModuleBuiltin,
+                 PutVarArrayRef, IsVarArrayRef,
 
                  PutConstSet,
                  PutConstructor,
@@ -3561,6 +3562,20 @@ PROCEDURE IsModuleBuiltin (sym: CARDINAL) : BOOLEAN ;
 PROCEDURE PutModuleBuiltin (sym: CARDINAL; value: BOOLEAN) ;
 
 
+(*
+   PutVarArrayRef - assigns ArrayRef field with value.
+*)
+
+PROCEDURE PutVarArrayRef (sym: CARDINAL; value: BOOLEAN) ;
+
+
+(*
+   IsVarArrayRef - returns ArrayRef field value.
+*)
+
+PROCEDURE IsVarArrayRef (sym: CARDINAL) : BOOLEAN ;
+
+
 (*
    VarCheckReadInit - returns TRUE if sym has been initialized.
 *)
index c10e20cebf30e136f21e474d37f9f7232c0223fa..73528b5ea19c7de7800a96b62ca880ec5661b7f6 100644 (file)
@@ -525,6 +525,8 @@ TYPE
                IsWritten     : BOOLEAN ;      (* Is variable written to?     *)
                IsSSA         : BOOLEAN ;      (* Is variable a SSA?          *)
                IsConst       : BOOLEAN ;      (* Is variable read/only?      *)
+               ArrayRef      : BOOLEAN ;      (* Is variable used to point   *)
+                                              (* to an array?                *)
                InitState     : LRInitDesc ;   (* Initialization state.       *)
                At            : Where ;        (* Where was sym declared/used *)
                ReadUsageList,                 (* list of var read quads      *)
@@ -4260,6 +4262,7 @@ BEGIN
             IsWritten := FALSE ;
             IsSSA := FALSE ;
             IsConst := FALSE ;
+            ArrayRef := FALSE ;
             InitWhereDeclaredTok(tok, At) ;
             InitWhereFirstUsedTok(tok, At) ;   (* Where symbol first used.  *)
             InitList(ReadUsageList[RightValue]) ;
@@ -6904,6 +6907,48 @@ BEGIN
 END PutConst ;
 
 
+(*
+   PutVarArrayRef - assigns ArrayRef field with value.
+*)
+
+PROCEDURE PutVarArrayRef (sym: CARDINAL; value: BOOLEAN) ;
+VAR
+   pSym: PtrToSymbol ;
+BEGIN
+   pSym := GetPsym(sym) ;
+   WITH pSym^ DO
+      CASE SymbolType OF
+
+      VarSym: Var.ArrayRef := value
+
+      ELSE
+         InternalError ('expecting VarSym')
+      END
+   END
+END PutVarArrayRef ;
+
+
+(*
+   IsVarArrayRef - returns ArrayRef field value.
+*)
+
+PROCEDURE IsVarArrayRef (sym: CARDINAL) : BOOLEAN ;
+VAR
+   pSym: PtrToSymbol ;
+BEGIN
+   pSym := GetPsym(sym) ;
+   WITH pSym^ DO
+      CASE SymbolType OF
+
+      VarSym: RETURN (Var.ArrayRef)
+
+      ELSE
+         InternalError ('expecting VarSym')
+      END
+   END
+END IsVarArrayRef ;
+
+
 (*
    PutFieldRecord - places a field, FieldName and FieldType into a record, Sym.
                     VarSym is a optional varient symbol which can be returned
index 834a84e1cf76876f0f2f9699bdba1f66cbd4a019..7bf79cc395fcafbf1839343f6767e5bea6c09aed 100644 (file)
@@ -103,6 +103,7 @@ EXTERN void _M2_dtoa_init (int argc, char *argv[], char *envp[]);
 EXTERN void _M2_ldtoa_init (int argc, char *argv[], char *envp[]);
 EXTERN void _M2_M2Check_init (int argc, char *argv[], char *envp[]);
 EXTERN void _M2_M2SSA_init (int argc, char *argv[], char *envp[]);
+EXTERN void _M2_M2SymInit_init (int argc, char *argv[], char *envp[]);
 EXTERN void exit (int);
 EXTERN void M2Comp_compile (const char *filename);
 EXTERN void RTExceptions_DefaultErrorCatch (void);
@@ -195,6 +196,7 @@ init_PerCompilationInit (const char *filename)
   _M2_PCBuild_init (0, NULL, NULL);
   _M2_Sets_init (0, NULL, NULL);
   _M2_M2SSA_init (0, NULL, NULL);
+  _M2_M2SymInit_init (0, NULL, NULL);
   _M2_M2Check_init (0, NULL, NULL);
   M2Comp_compile (filename);
 }
index e203fce43da70f3f6fc95329e4d345601d5714a6..dd79509737e243fda0c2962b84fe101944a625fb 100644 (file)
@@ -136,7 +136,7 @@ EXTERN void M2Options_SetM2Prefix (const char *arg);
 EXTERN char *M2Options_GetM2Prefix (void);
 EXTERN void M2Options_SetM2PathName (const char *arg);
 EXTERN char *M2Options_GetM2PathName (void);
-EXTERN void M2Options_SetUninitVariableChecking (bool value);
+EXTERN int M2Options_SetUninitVariableChecking (bool value, const char *arg);
 
 
 #undef EXTERN
index ae999a3c4d14528bf0dbf00255ce3f408166d04c..c21d29b37e625efa8aa5c5ce737b3b5d2c1eac55 100644 (file)
@@ -470,8 +470,9 @@ gm2_langhook_handle_option (
       M2Options_SetUnusedParameterChecking (value);
       return 1;
     case OPT_Wuninit_variable_checking:
-      M2Options_SetUninitVariableChecking (value);
-      return 1;
+      return M2Options_SetUninitVariableChecking (value, "known");
+    case OPT_Wuninit_variable_checking_:
+      return M2Options_SetUninitVariableChecking (value, arg);
     case OPT_fm2_strict_type:
       M2Options_SetStrictTypeChecking (value);
       return 1;
index 6dbdf9d3110ad65f5914ebeacb66bbcbb8578a15..730a1a28683e80bce867f0424ac8bd7f33153504 100644 (file)
@@ -297,6 +297,10 @@ Wuninit-variable-checking
 Modula-2
 turns on compile time analysis in the first basic block of a procedure detecting access to uninitialized data.
 
+Wuninit-variable-checking=
+Modula-2 Joined
+turns on compile time analysis to detect access to uninitialized variables, the checking can be specified by: known,cond,all.
+
 B
 Modula-2
 ; Documented in c.opt
diff --git a/gcc/testsuite/gm2/switches/uninit-variable-checking/cascade/fail/cascadedif.mod b/gcc/testsuite/gm2/switches/uninit-variable-checking/cascade/fail/cascadedif.mod
new file mode 100644 (file)
index 0000000..4468ce0
--- /dev/null
@@ -0,0 +1,25 @@
+MODULE cascadedif ;
+
+
+PROCEDURE test ;
+VAR
+   i: CARDINAL ;
+   p: CARDINAL ;
+BEGIN
+   i := 1 ;
+   IF i = 1
+   THEN
+      IF p = 1
+      THEN
+      END
+   ELSE
+      IF p = 2
+      THEN
+      END
+   END
+END test ;
+
+
+BEGIN
+   test
+END cascadedif.
diff --git a/gcc/testsuite/gm2/switches/uninit-variable-checking/cascade/fail/switches-uninit-variable-checking-cascade-fail.exp b/gcc/testsuite/gm2/switches/uninit-variable-checking/cascade/fail/switches-uninit-variable-checking-cascade-fail.exp
new file mode 100644 (file)
index 0000000..f5e0c07
--- /dev/null
@@ -0,0 +1,37 @@
+# Expect driver script for GCC Regression Tests
+# Copyright (C) 2023 Free Software Foundation, Inc.
+
+# 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 3 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 GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# This file was written by Gaius Mulley (gaius.mulley@southwales.ac.uk)
+# for GNU Modula-2.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+# load support procs
+load_lib gm2-torture.exp
+
+gm2_init_pim "${srcdir}/gm2/switches/uninit-variable-checking/cascade/fail" -Wuninit-variable-checking=all
+
+foreach testcase [lsort [glob -nocomplain $srcdir/$subdir/*.mod]] {
+    # If we're only testing specific files and this isn't one of them, skip it.
+    if ![runtest_file_p $runtests $testcase] then {
+       continue
+    }
+
+    gm2-torture-fail $testcase
+}