[modula2] Improve uninitialized variable analysis by combining basic blocks

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>
This commit is contained in:
Gaius Mulley 2023-07-11 15:28:42 +01:00
parent 8c2fc744a2
commit 40b91158c3
24 changed files with 982 additions and 243 deletions

View 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.

View 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 ;
(*

View 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

View 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() ;
Count := CountQuads () ;
FreeBasicBlocks (InitBasicBlocksFromRange (scope, start, end)) ;
BasicB := Count - CountQuads () ;
Count := CountQuads () ;
FoldBranches(start, end) ;
Jump := 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 ;

View 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) ;

View 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) ;
(*

View 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) ;

View 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 ;

View 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 ;
(*

View 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.

View 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) ;
(*

View 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

View file

@ -37,7 +37,7 @@ EXPORT QUALIFIED ScopeBlock, ScopeProcedure,
TYPE
ScopeBlock ;
ScopeProcedure = PROCEDURE (CARDINAL, CARDINAL) ;
ScopeProcedure = PROCEDURE (CARDINAL, CARDINAL, CARDINAL) ;
(*

View 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 ;

View 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) ;

View 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
END ;
IF start = end
THEN
RETURN
END ;
start := GetNextQuad (start)
ELSE
start := GetNextQuad (start)
END
END
END CheckReadBeforeInitFirstBasicBlock ;
(*
VariableAnalysis - checks to see whether a variable is:
read before it has been initialized
bbArrayKill -
*)
PROCEDURE VariableAnalysis (Start, End: CARDINAL) ;
PROCEDURE bbArrayKill ;
VAR
Op : QuadOperator ;
Op1, Op2, Op3: CARDINAL ;
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 ;
(*
DumpBBEntry -
*)
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
bbPtr: bbEntry ;
i, n : CARDINAL ;
BEGIN
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
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 ;
(*
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 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
GetQuad (Start, Op, Op1, Op2, Op3) ;
CASE Op OF
NewLocalVarOp: initBlock ;
CheckReadBeforeInitFirstBasicBlock (Op3, Start, End) ;
killBlock
ELSE
END
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 VariableAnalysis ;
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 ;

View 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.
*)

View 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

View 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);
}

View 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

View 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;

View 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

View file

@ -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.

View file

@ -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
}