1 (* M2SymInit.mod records initialization state for variables.
3 Copyright (C) 2001-2024 Free Software Foundation, Inc.
4 Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
6 This file is part of GNU Modula-2.
8 GNU Modula-2 is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 GNU Modula-2 is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Modula-2; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. *)
22 IMPLEMENTATION MODULE M2SymInit ;
24 FROM Storage IMPORT ALLOCATE, DEALLOCATE ;
25 FROM M2Debug IMPORT Assert ;
26 FROM M2Printf IMPORT printf0, printf1, printf2, printf3, printf4 ;
27 FROM libc IMPORT printf ;
28 FROM NameKey IMPORT Name, NulName, KeyToCharStar, MakeKey ;
29 FROM M2Base IMPORT Nil ;
31 FROM M2Options IMPORT UninitVariableChecking, UninitVariableConditionalChecking,
34 FROM M2MetaError IMPORT MetaErrorT1, MetaErrorStringT1, MetaErrorStringT2 ;
35 FROM M2LexBuf IMPORT UnknownTokenNo ;
36 FROM DynamicStrings IMPORT String, InitString, Mark, ConCat, InitString ;
37 FROM M2Error IMPORT InternalError ;
39 FROM M2BasicBlock IMPORT BasicBlock,
40 InitBasicBlocks, InitBasicBlocksFromRange,
41 KillBasicBlocks, FreeBasicBlocks,
45 FROM Indexing IMPORT Index ;
47 FROM Lists IMPORT List, InitList, GetItemFromList, PutItemIntoList,
48 IsItemInList, IncludeItemIntoList, NoOfItemsInList,
49 RemoveItemFromList, ForeachItemInListDo, KillList, DuplicateList ;
51 FROM SymbolTable IMPORT NulSym, ModeOfAddr, IsVar, IsRecord, GetSType,
52 GetNth, IsRecordField, IsSet, IsArray, IsProcedure,
53 GetVarScope, IsVarAParam, IsComponent, GetMode,
54 VarCheckReadInit, VarInitState, PutVarInitialized,
55 PutVarFieldInitialized, GetVarFieldInitialized,
56 IsConst, IsConstString, NoOfParam, IsVarParam,
57 ForeachLocalSymDo, ForeachParamSymDo,
58 IsTemporary, ModeOfAddr,
59 IsReallyPointer, IsUnbounded,
60 IsVarient, IsFieldVarient, GetVarient,
61 IsVarArrayRef, GetSymName,
63 GetParameterShadowVar, IsParameter, GetLType,
66 FROM M2Quads IMPORT QuadOperator, GetQuadOtok, GetQuad, GetNextQuad,
67 IsNewLocalVar, IsReturn, IsKillLocalVar, IsConditional,
68 IsUnConditional, IsBackReference, IsCall, IsGoto,
69 GetM2OperatorDesc, Opposite, DisplayQuadRange,
72 FROM M2Printf IMPORT printf0, printf1, printf2 ;
73 FROM M2GCCDeclare IMPORT PrintSym ;
80 descType = (scalar, record) ;
82 InitDesc = POINTER TO RECORD
83 sym, type : CARDINAL ;
84 initialized: BOOLEAN ;
85 CASE kind: descType OF
88 record: rec: recordDesc |
94 fieldDesc: Indexing.Index ;
97 symAlias = POINTER TO RECORD
103 bbEntry = POINTER TO RECORD
104 start, end: CARDINAL ;
105 (* Is this the first bb? *)
107 (* Does it end with a call? *)
109 (* Does it end with a goto? *)
111 (* Does it end with a conditional? *)
113 (* Does it form part of a loop? *)
114 topOfLoop : BOOLEAN ;
126 LArray : Indexing.Index ;
127 freeList : symAlias ;
128 bbArray : Indexing.Index ;
129 bbFreeList : bbEntry ;
131 errorList : List ; (* Ensure that we only generate one set of warnings per token. *)
138 PROCEDURE PrintSymInit (desc: InitDesc) ;
142 printf ("sym %d: type %d ", desc^.sym, desc^.type) ;
143 IF desc^.kind = scalar
149 IF NOT desc^.initialized
153 printf (" initialized\n") ;
154 IF (desc^.type # NulSym) AND IsRecord (desc^.type)
157 n := Indexing.HighIndice (desc^.rec.fieldDesc) ;
159 PrintSymInit (Indexing.GetIndice (desc^.rec.fieldDesc, i)) ;
166 PROCEDURE InitSymInit () : InitDesc ;
174 initialized := TRUE ;
181 PROCEDURE KillSymInit (VAR desc: InitDesc) ;
186 record: KillFieldDesc (rec.fieldDesc)
196 PROCEDURE ConfigSymInit (desc: InitDesc; sym: CARDINAL) ;
198 IF IsVar (sym) OR IsRecordField (sym)
201 desc^.type := GetSType (sym) ;
202 desc^.initialized := FALSE ;
203 IF IsRecord (desc^.type)
205 desc^.kind := record ;
206 desc^.rec.fieldDesc := Indexing.InitIndex (1) ;
207 PopulateFields (desc, desc^.type)
209 desc^.kind := scalar ;
210 IF IsArray (desc^.type)
212 desc^.initialized := TRUE (* For now we don't attempt to handle array types. *)
223 PROCEDURE KillFieldDesc (VAR fielddesc: Indexing.Index) ;
229 h := Indexing.HighIndice (fielddesc) ;
231 id := Indexing.GetIndice (fielddesc, i) ;
235 fielddesc := Indexing.KillIndex (fielddesc)
243 PROCEDURE PopulateFields (desc: InitDesc; recsym: CARDINAL) ;
249 Assert (IsRecord (recsym)) ;
252 field := GetNth (recsym, i) ;
255 fdesc := InitSymInit () ;
256 ConfigSymInit (fdesc, field) ;
257 Indexing.IncludeIndiceIntoIndex (desc^.rec.fieldDesc, fdesc) ;
264 PROCEDURE SetInitialized (desc: InitDesc) ;
266 desc^.initialized := TRUE
270 PROCEDURE GetInitialized (desc: InitDesc) : BOOLEAN ;
272 IF NOT desc^.initialized
274 IF IsRecord (desc^.type)
276 TrySetInitialized (desc)
283 RETURN desc^.initialized
287 PROCEDURE GetFieldDesc (desc: InitDesc; field: CARDINAL) : InitDesc ;
292 IF IsRecord (desc^.type)
296 fsym := GetNth (desc^.type, i) ;
299 RETURN Indexing.GetIndice (desc^.rec.fieldDesc, i)
308 PROCEDURE SetFieldInitialized (desc: InitDesc; fieldlist: List) : BOOLEAN ;
310 RETURN SetFieldInitializedNo (desc, fieldlist, 1)
311 END SetFieldInitialized ;
318 PROCEDURE TrySetInitialized (desc: InitDesc) ;
323 h := Indexing.HighIndice (desc^.rec.fieldDesc) ;
326 fdesc := Indexing.GetIndice (desc^.rec.fieldDesc, i) ;
327 IF NOT fdesc^.initialized
333 desc^.initialized := TRUE
334 END TrySetInitialized ;
338 SetFieldInitializedNo -
341 PROCEDURE SetFieldInitializedNo (desc: InitDesc;
342 fieldlist: List; level: CARDINAL) : BOOLEAN ;
347 IF level > NoOfItemsInList (fieldlist)
351 nsym := GetItemFromList (fieldlist, level) ;
352 fdesc := GetFieldDesc (desc, nsym) ;
356 ELSIF level = NoOfItemsInList (fieldlist)
358 SetInitialized (fdesc) ;
359 TrySetInitialized (desc) ;
360 RETURN desc^.initialized
362 IF SetFieldInitializedNo (fdesc, fieldlist, level + 1)
365 TrySetInitialized (desc) ;
366 RETURN desc^.initialized
369 END SetFieldInitializedNo ;
372 PROCEDURE GetFieldInitialized (desc: InitDesc; fieldlist: List) : BOOLEAN ;
374 RETURN GetFieldInitializedNo (desc, fieldlist, 1)
375 END GetFieldInitialized ;
378 PROCEDURE GetFieldInitializedNo (desc: InitDesc;
379 fieldlist: List; level: CARDINAL) : BOOLEAN ;
387 ELSIF level > NoOfItemsInList (fieldlist)
391 nsym := GetItemFromList (fieldlist, level) ;
392 fdesc := GetFieldDesc (desc, nsym) ;
395 (* The pointer variable maybe uninitialized and hence we cannot
396 find the record variable. *)
398 ELSIF fdesc^.initialized
402 RETURN GetFieldInitializedNo (fdesc, fieldlist, level + 1)
405 END GetFieldInitializedNo ;
412 PROCEDURE IsGlobalVar (sym: CARDINAL) : BOOLEAN ;
414 RETURN IsVar (sym) AND (NOT IsProcedure (GetVarScope (sym)))
421 PROCEDURE IsLocalVar (procsym, varsym: CARDINAL) : BOOLEAN ;
423 RETURN IsVar (varsym) AND (GetVarScope (varsym) = procsym)
429 RecordFieldContainsVarient -
432 PROCEDURE RecordFieldContainsVarient (sym: CARDINAL; visited: List) : BOOLEAN ;
434 Assert (IsRecordField (sym)) ;
435 IF doContainsVariant (GetSType (sym), visited)
439 RETURN GetVarient (sym) # NulSym
440 END RecordFieldContainsVarient ;
444 RecordContainsVarient -
447 PROCEDURE RecordContainsVarient (sym: CARDINAL; visited: List) : BOOLEAN ;
452 Assert (IsRecord (sym)) ;
455 fieldsym := GetNth (sym, i) ;
458 IF IsRecordField (fieldsym)
460 IF RecordFieldContainsVarient (fieldsym, visited)
464 ELSIF IsVarient (fieldsym)
470 UNTIL fieldsym = NulSym ;
472 END RecordContainsVarient ;
479 PROCEDURE VarContainsVarient (sym: CARDINAL; visited: List) : BOOLEAN ;
481 Assert (IsVar (sym)) ;
482 RETURN doContainsVariant (GetSType (sym), visited)
483 END VarContainsVarient ;
487 TypeContainsVarient -
490 PROCEDURE TypeContainsVarient (sym: CARDINAL; visited: List) : BOOLEAN ;
492 Assert (IsType (sym)) ;
493 RETURN doContainsVariant (GetSType (sym), visited)
494 END TypeContainsVarient ;
498 ArrayContainsVarient -
501 PROCEDURE ArrayContainsVarient (sym: CARDINAL; visited: List) : BOOLEAN ;
503 Assert (IsArray (sym)) ;
504 RETURN doContainsVariant (GetSType (sym), visited)
505 END ArrayContainsVarient ;
509 PointerContainsVarient -
512 PROCEDURE PointerContainsVarient (sym: CARDINAL; visited: List) : BOOLEAN ;
514 Assert (IsPointer (sym)) ;
515 RETURN doContainsVariant (GetSType (sym), visited)
516 END PointerContainsVarient ;
523 PROCEDURE doContainsVariant (sym: CARDINAL; visited: List) : BOOLEAN ;
525 IF (sym # NulSym) AND (NOT IsItemInList (visited, sym))
527 IncludeItemIntoList (visited, sym) ;
530 RETURN VarContainsVarient (sym, visited)
533 RETURN RecordContainsVarient (sym, visited)
534 ELSIF IsPointer (sym)
536 RETURN PointerContainsVarient (sym, visited)
539 RETURN ArrayContainsVarient (sym, visited)
542 RETURN TypeContainsVarient (sym, visited)
546 END doContainsVariant ;
550 ContainsVariant - returns TRUE if type sym contains a variant record.
553 PROCEDURE ContainsVariant (sym: CARDINAL) : BOOLEAN ;
559 result := doContainsVariant (sym, visited) ;
562 END ContainsVariant ;
569 PROCEDURE IssueConditional (quad: CARDINAL; conditional: BOOLEAN) ;
572 op1, op2, op3 : CARDINAL ;
573 op1tok, op2tok, op3tok, qtok: CARDINAL ;
574 overflowChecking : BOOLEAN ;
577 GetQuadOtok (quad, qtok, op, op1, op2, op3, overflowChecking,
578 op1tok, op2tok, op3tok) ;
579 IF IsUniqueWarning (qtok)
581 op1tok := DefaultTokPos (op1tok, qtok) ;
582 op2tok := DefaultTokPos (op2tok, qtok) ;
583 op3tok := DefaultTokPos (op3tok, qtok) ;
588 s := InitString ('depending upon the result of {%1Oad} ') ;
589 s := ConCat (s, Mark (GetM2OperatorDesc (op))) ;
590 s := ConCat (s, InitString (' {%2ad}')) ;
591 MetaErrorStringT2 (qtok, s, op1, op2)
593 END IssueConditional ;
600 PROCEDURE GenerateNoteFlow (n: CARDINAL; warning: BOOLEAN) ;
608 (* Only issue flow messages for non warnings. *)
611 iPtr := Indexing.GetIndice (bbArray, i) ;
616 ip1Ptr := Indexing.GetIndice (bbArray, i+1) ;
617 IssueConditional (iPtr^.end, iPtr^.condBB = ip1Ptr^.indexBB)
623 END GenerateNoteFlow ;
627 IssueWarning - issue a warning or note at tok location.
630 PROCEDURE IssueWarning (tok: CARDINAL;
631 before, after: ARRAY OF CHAR;
632 sym: CARDINAL; warning: BOOLEAN) ;
636 s := InitString (before) ;
639 s := ConCat (s, Mark (InitString ('{%1Wad}')))
641 s := ConCat (s, Mark (InitString ('{%1Oad}')))
643 s := ConCat (s, Mark (InitString (after))) ;
644 MetaErrorStringT1 (tok, s, sym)
649 IsUniqueWarning - return TRUE if a warning has not been issued at tok.
650 It remembers tok and subsequent calls will always return FALSE.
653 PROCEDURE IsUniqueWarning (tok: CARDINAL) : BOOLEAN ;
655 IF NOT IsItemInList (errorList, tok)
657 IncludeItemIntoList (errorList, tok) ;
662 END IsUniqueWarning ;
666 CheckDeferredRecordAccess -
669 PROCEDURE CheckDeferredRecordAccess (tok: CARDINAL;
671 canDereference, warning: BOOLEAN;
680 Trace ("CheckDeferredRecordAccess %d\n", sym) ;
684 printf1 ("checkReadInit (%d, true)\n", sym)
686 printf1 ("checkReadInit (%d, false)\n", sym)
691 Trace ("checkReadInit sym is a parameter or not a local variable (%d)", sym) ;
692 (* We assume parameters have been initialized. *)
693 PutVarInitialized (sym, LeftValue) ;
694 PutVarInitialized (sym, RightValue)
695 (* SetVarInitialized (sym, TRUE) *)
696 ELSIF IsUnbounded (GetSType (sym))
698 SetVarInitialized (sym, TRUE, tok)
699 ELSIF IsComponent (sym)
701 Trace ("checkReadInit IsComponent (%d) is true)", sym) ;
702 IF (NOT GetVarComponentInitialized (sym, tok)) AND IsUniqueWarning (tok)
704 GenerateNoteFlow (i, warning) ;
706 'attempting to access ',
707 ' before it has been initialized',
710 ELSIF (GetMode (sym) = LeftValue) AND canDereference
712 Trace ("checkReadInit GetMode (%d) = LeftValue and canDereference (LeftValue and RightValue VarCheckReadInit)", sym) ;
714 IF NOT VarCheckReadInit (sym, LeftValue)
716 unique := IsUniqueWarning (tok) ;
719 GenerateNoteFlow (i, warning) ;
721 'attempting to access the address of ',
722 ' before it has been initialized',
726 IF NOT VarCheckReadInit (sym, RightValue)
730 GenerateNoteFlow (i, warning) ;
732 'attempting to access ', ' before it has been initialized',
737 Trace ("checkReadInit call VarCheckReadInit using GetMode (%d)", sym) ;
738 IF (NOT VarCheckReadInit (sym, GetMode (sym))) AND IsUniqueWarning (tok)
740 GenerateNoteFlow (i, warning) ;
742 'attempting to access ',
743 ' before it has been initialized',
748 END CheckDeferredRecordAccess ;
752 SetVarUninitialized - resets variable init state.
755 PROCEDURE SetVarUninitialized (sym: CARDINAL) ;
759 IF NOT IsUnbounded (GetSType (sym))
764 END SetVarUninitialized ;
771 PROCEDURE ComponentFindVar (sym: CARDINAL;
773 tok: CARDINAL) : CARDINAL ;
780 nsym := GetNth (sym, i) ;
781 lvalue := GetMode (nsym) = LeftValue ;
782 nsym := getLAlias (nsym) ;
786 "attempting to dereference {%1Wad} which will be a {%kNIL} pointer",
789 ELSIF (nsym # NulSym) AND IsVar (nsym)
791 IF (nsym # sym) AND IsComponent (nsym)
793 RETURN ComponentFindVar (nsym, lvalue, tok)
799 UNTIL nsym = NulSym ;
801 END ComponentFindVar ;
805 ComponentCreateFieldList - builds a list of fields accessed by the component var.
806 Each item in the list will be a field of incremental levels
807 though a nested record. It is not a list of fields
817 { v, x } for example and not { v, w }
820 PROCEDURE ComponentCreateFieldList (sym: CARDINAL) : List ;
825 IF IsVar (sym) AND IsComponent (sym)
827 ComponentBuildFieldList (lst, sym)
830 END ComponentCreateFieldList ;
833 PROCEDURE ComponentBuildFieldList (lst: List; sym: CARDINAL) ;
839 nsym := GetNth (sym, i) ;
842 IF IsComponent (nsym)
844 ComponentBuildFieldList (lst, nsym)
845 ELSIF IsRecordField (nsym)
847 IncludeItemIntoList (lst, nsym)
852 END ComponentBuildFieldList ;
859 PROCEDURE deRefComponent (component: CARDINAL; lvalue: BOOLEAN;
860 sym: CARDINAL; tok: CARDINAL) : CARDINAL ;
864 RETURN getContent (component, sym, tok)
872 SetVarComponentInitialized -
875 PROCEDURE SetVarComponentInitialized (sym: CARDINAL; tok: CARDINAL) ;
883 vsym := ComponentFindVar (sym, lvalue, tok) ;
884 vsym := deRefComponent (vsym, lvalue, sym, tok) ;
889 printf0 ("*************** vsym is: ") ;
892 (* Build list accessing the field. *)
893 lst := ComponentCreateFieldList (sym) ;
896 printf2 ("sym = %d, vsym = %d, fields:", sym, vsym)
898 (* Now mark this field in the record variable as initialized. *)
899 IF PutVarFieldInitialized (vsym, RightValue, lst)
904 n := NoOfItemsInList (lst) ;
906 fsym := GetItemFromList (lst, i) ;
907 printf1 (" %d", fsym) ;
910 printf0 (" is initialized\n")
914 printf0 (" vsym is not a var\n")
918 END SetVarComponentInitialized ;
922 GetVarComponentInitialized -
925 PROCEDURE GetVarComponentInitialized (sym: CARDINAL; tok: CARDINAL) : BOOLEAN ;
933 component := ComponentFindVar (sym, lvalue, tok) ;
934 IF IsItemInList (ignoreList, component) OR IsExempt (component)
939 vsym := deRefComponent (component, lvalue, sym, tok) ;
946 (* Create list representing how the field is accessed. *)
947 lst := ComponentCreateFieldList (sym) ;
948 (* Now obtain the mark indicating whether this field was initialized. *)
949 init := GetVarFieldInitialized (vsym, RightValue, lst) ;
955 END GetVarComponentInitialized ;
962 PROCEDURE Trace (message: ARRAY OF CHAR; sym: CARDINAL) ;
966 printf1 (message, sym) ;
973 SetVarInitialized - if the variable has a left mode and can be dereferenced
974 then set the left and right initialization state.
977 PROCEDURE SetVarInitialized (sym: CARDINAL; canDereference: BOOLEAN;
982 RemoveItemFromList (ignoreList, sym) ;
985 Trace ("SetVarInitialized sym %d is a component and calling SetVarComponentInitialized", sym);
986 SetVarComponentInitialized (sym, tok)
987 ELSIF (GetMode (sym) = LeftValue) AND canDereference
989 Trace ("SetVarInitialized sym %d is LeftValue and canDeference and calling PutVarInitialized LeftValue and RightValue", sym);
990 PutVarInitialized (sym, LeftValue) ;
991 PutVarInitialized (sym, RightValue)
993 Trace ("SetVarInitialized sym %d calling PutVarInitialized with its mode", sym);
994 PutVarInitialized (sym, GetMode (sym))
1001 END SetVarInitialized ;
1005 doGetVarInitialized -
1008 PROCEDURE doGetVarInitialized (sym: CARDINAL; tok: CARDINAL) : BOOLEAN ;
1012 IF IsUnbounded (GetSType (sym))
1015 ELSIF IsComponent (sym)
1017 RETURN GetVarComponentInitialized (sym, tok)
1019 RETURN VarCheckReadInit (sym, GetMode (sym))
1021 RETURN IsConst (sym) AND IsConstString (sym)
1022 END doGetVarInitialized ;
1029 PROCEDURE GetVarInitialized (sym: CARDINAL; tok: CARDINAL) : BOOLEAN ;
1033 init := doGetVarInitialized (sym, tok) ;
1038 Trace ("GetVarInitialized (sym = %d) returning TRUE", sym)
1040 Trace ("GetVarInitialized (sym = %d) returning FALSE", sym)
1044 END GetVarInitialized ;
1048 IsExempt - returns TRUE if sym is a global variable or a parameter or
1049 a variable with a variant record type.
1052 PROCEDURE IsExempt (sym: CARDINAL) : BOOLEAN ;
1054 RETURN (sym # NulSym) AND IsVar (sym) AND
1055 (IsGlobalVar (sym) OR
1056 (* (IsVarAParam (sym) AND (GetMode (sym) = LeftValue)) OR *)
1057 ContainsVariant (sym) OR
1058 IsArray (GetSType (sym)) OR IsSet (GetSType (sym)) OR
1059 IsUnbounded (GetSType (sym)) OR IsVarArrayRef (sym) OR
1060 IsItemInList (ignoreList, sym))
1068 PROCEDURE CheckBinary (op1tok, op1,
1070 op3tok, op3: CARDINAL; warning: BOOLEAN;
1073 CheckDeferredRecordAccess (op2tok, op2, FALSE, warning, i) ;
1074 CheckDeferredRecordAccess (op3tok, op3, FALSE, warning, i) ;
1075 SetVarInitialized (op1, FALSE, op1tok)
1083 PROCEDURE CheckUnary (lhstok, lhs,
1084 rhstok, rhs: CARDINAL; warning: BOOLEAN;
1087 CheckDeferredRecordAccess (rhstok, rhs, FALSE, warning, i) ;
1088 SetVarInitialized (lhs, FALSE, lhstok)
1096 PROCEDURE CheckXIndr (lhstok, lhs, type,
1097 rhstok, rhs: CARDINAL; warning: BOOLEAN;
1103 CheckDeferredRecordAccess (rhstok, rhs, FALSE, warning, i) ;
1104 CheckDeferredRecordAccess (lhstok, lhs, FALSE, warning, i) ;
1105 (* Now see if we know what lhs is pointing to and set fields if necessary. *)
1106 content := getContent (getLAlias (lhs), lhs, lhstok) ;
1107 IF (content # NulSym) AND (content # lhs) AND (GetSType (content) = type)
1109 IF IsReallyPointer (rhs)
1111 SetupLAlias (content, rhs)
1115 (* Set all fields of content as initialized. *)
1116 SetVarInitialized (content, FALSE, lhstok)
1118 (* Set only the field assigned in vsym as initialized. *)
1119 lst := ComponentCreateFieldList (rhs) ;
1120 IF PutVarFieldInitialized (content, RightValue, lst)
1133 PROCEDURE CheckIndrX (lhstok, lhs, rhstok, rhs: CARDINAL;
1139 CheckDeferredRecordAccess (rhstok, rhs, FALSE, warning, i) ;
1140 content := getContent (getLAlias (rhs), rhs, rhstok) ;
1143 IncludeItemIntoList (ignoreList, lhs)
1145 CheckDeferredRecordAccess (rhstok, content, TRUE, warning, i) ;
1146 SetVarInitialized (lhs, VarCheckReadInit (content, RightValue), lhstok) ;
1147 IF IsReallyPointer (content)
1149 SetupLAlias (lhs, content)
1159 PROCEDURE CheckRecordField (op1: CARDINAL) ;
1161 PutVarInitialized (op1, LeftValue)
1162 END CheckRecordField ;
1169 PROCEDURE CheckBecomes (destok, des, exprtok, expr: CARDINAL;
1170 warning: BOOLEAN; i: CARDINAL) ;
1176 CheckDeferredRecordAccess (exprtok, expr, FALSE, warning, i) ;
1177 SetupLAlias (des, expr) ;
1178 SetVarInitialized (des, FALSE, destok) ;
1179 (* Now see if we know what lhs is pointing to and set fields if necessary. *)
1180 IF IsComponent (des)
1182 vsym := ComponentFindVar (des, lvalue, destok) ;
1183 vsym := deRefComponent (vsym, lvalue, des, destok) ;
1186 (* Set only the field assigned in vsym as initialized. *)
1187 lst := ComponentCreateFieldList (des) ;
1188 IF PutVarFieldInitialized (vsym, RightValue, lst)
1201 PROCEDURE CheckComparison (op1tok, op1, op2tok, op2: CARDINAL;
1202 warning: BOOLEAN; i: CARDINAL) ;
1204 CheckDeferredRecordAccess (op1tok, op1, FALSE, warning, i) ;
1205 CheckDeferredRecordAccess (op2tok, op2, FALSE, warning, i)
1206 END CheckComparison ;
1213 PROCEDURE CheckAddr (ptrtok, ptr, contenttok, content: CARDINAL) ;
1215 SetVarInitialized (ptr, GetVarInitialized (content, contenttok), ptrtok) ;
1216 SetupIndr (ptr, content)
1224 PROCEDURE DefaultTokPos (preferredPos, defaultPos: CARDINAL) : CARDINAL ;
1226 IF preferredPos = UnknownTokenNo
1243 CheckReadBeforeInitQuad -
1246 PROCEDURE CheckReadBeforeInitQuad (procSym: CARDINAL; quad: CARDINAL;
1247 warning: BOOLEAN; i: CARDINAL) : BOOLEAN ;
1250 op1, op2, op3 : CARDINAL ;
1251 op1tok, op2tok, op3tok, qtok: CARDINAL ;
1252 overflowChecking : BOOLEAN ;
1260 printf1 ("CheckReadBeforeInitQuad (quad %d)\n", quad) ;
1262 ForeachLocalSymDo (procSym, PrintSym) ;
1263 printf0 ("***********************************\n")
1265 GetQuadOtok (quad, qtok, op, op1, op2, op3, overflowChecking,
1266 op1tok, op2tok, op3tok) ;
1267 op1tok := DefaultTokPos (op1tok, qtok) ;
1268 op2tok := DefaultTokPos (op2tok, qtok) ;
1269 op3tok := DefaultTokPos (op3tok, qtok) ;
1272 (* Jumps, calls and branches. *)
1280 IfGreEquOp : CheckComparison (op1tok, op1, op2tok, op2, warning, i) |
1286 GotoOp : RETURN TRUE | (* End of basic block. *)
1288 (* Variable references. *)
1291 ExclOp : CheckDeferredRecordAccess (op1tok, op1, FALSE, warning, i) ;
1292 CheckDeferredRecordAccess (op1tok, op1, TRUE, warning, i) ;
1293 CheckDeferredRecordAccess (op3tok, op3, FALSE, warning, i) |
1294 NegateOp : CheckUnary (op1tok, op1, op3tok, op3, warning, i) |
1295 BecomesOp : CheckBecomes (op1tok, op1, op3tok, op3, warning, i) |
1300 SizeOp : SetVarInitialized (op1, FALSE, op1tok) |
1301 AddrOp : CheckAddr (op1tok, op1, op3tok, op3) |
1302 ReturnValueOp : SetVarInitialized (op1, FALSE, op1tok) |
1304 ParamOp : CheckDeferredRecordAccess (op2tok, op2, FALSE, warning, i) ;
1305 CheckDeferredRecordAccess (op3tok, op3, FALSE, warning, i) ;
1306 IF (op1 > 0) AND (op1 <= NoOfParam (op2)) AND
1307 IsVarParam (op2, op1)
1309 SetVarInitialized (op3, TRUE, op3tok)
1311 ArrayOp : CheckDeferredRecordAccess (op3tok, op3, FALSE, warning, i) ;
1312 SetVarInitialized (op1, TRUE, op1tok) |
1313 RecordFieldOp : CheckRecordField (op1) |
1334 DivTruncOp : CheckBinary (op1tok, op1, op2tok, op2, op3tok, op3, warning, i) |
1335 XIndrOp : CheckXIndr (op1tok, op1, op2, op3tok, op3, warning, i) |
1336 IndrXOp : CheckIndrX (op1tok, op1, op3tok, op3, warning, i) |
1337 SaveExceptionOp : SetVarInitialized (op1, FALSE, op1tok) |
1338 RestoreExceptionOp: CheckDeferredRecordAccess (op1tok, op1, FALSE, warning, i) |
1341 SubrangeHighOp : InternalError ('quadruples should have been resolved') |
1343 BuiltinConstOp, (* Nothing to do, it is assigning a constant to op1 (also a const). *)
1344 BuiltinTypeInfoOp, (* Likewise assigning op1 (const) with a type. *)
1376 END CheckReadBeforeInitQuad ;
1380 FilterCheckReadBeforeInitQuad -
1383 PROCEDURE FilterCheckReadBeforeInitQuad (procSym: CARDINAL; start: CARDINAL;
1385 i: CARDINAL) : BOOLEAN ;
1388 Op1, Op2, Op3: CARDINAL ;
1390 GetQuad (start, Op, Op1, Op2, Op3) ;
1391 IF (Op # RangeCheckOp) AND (Op # StatementNoteOp)
1393 RETURN CheckReadBeforeInitQuad (procSym, start, warning, i)
1396 END FilterCheckReadBeforeInitQuad ;
1400 CheckReadBeforeInitFirstBasicBlock -
1403 PROCEDURE CheckReadBeforeInitFirstBasicBlock (procSym: CARDINAL;
1404 start, end: CARDINAL;
1409 IF FilterCheckReadBeforeInitQuad (procSym, start, warning, i)
1416 start := GetNextQuad (start)
1419 END CheckReadBeforeInitFirstBasicBlock ;
1426 PROCEDURE bbArrayKill ;
1431 h := Indexing.HighIndice (bbArray) ;
1434 bbPtr := Indexing.GetIndice (bbArray, i) ;
1435 bbPtr^.next := bbFreeList ;
1436 bbFreeList := bbPtr ;
1439 bbArray := Indexing.KillIndex (bbArray)
1447 PROCEDURE DumpBBEntry (bbPtr: bbEntry; procSym: CARDINAL) ;
1449 printf4 ("bb %d: scope %d: quads: %d .. %d",
1450 bbPtr^.indexBB, procSym, bbPtr^.start, bbPtr^.end) ;
1457 printf0 (" endcall")
1461 printf0 (" endgoto")
1465 printf0 (" endcond")
1469 printf0 (" topofloop")
1471 IF bbPtr^.condBB # 0
1473 printf1 (" cond %d", bbPtr^.condBB)
1475 IF bbPtr^.nextBB # 0
1477 printf1 (" next %d", bbPtr^.nextBB)
1487 PROCEDURE DumpBBArray (procSym: CARDINAL) ;
1493 n := Indexing.HighIndice (bbArray) ;
1495 bbPtr := Indexing.GetIndice (bbArray, i) ;
1496 DumpBBEntry (bbPtr, procSym) ;
1501 bbPtr := Indexing.GetIndice (bbArray, i) ;
1502 printf4 ("bb %d: scope %d: quads: %d .. %d\n",
1503 bbPtr^.indexBB, procSym, bbPtr^.start, bbPtr^.end) ;
1504 DisplayQuadRange (procSym, bbPtr^.start, bbPtr^.end) ;
1514 PROCEDURE DumpBBSequence (lst: List) ;
1517 listindex, n: CARDINAL ;
1519 n := NoOfItemsInList (lst) ;
1521 printf0 ("=============\n");
1522 printf0 (" checking sequence:");
1523 WHILE listindex <= n DO
1524 arrayindex := GetItemFromList (lst, listindex) ;
1525 printf2 (" lst[%d] -> %d", listindex, arrayindex) ;
1529 END DumpBBSequence ;
1536 PROCEDURE trashParam (trashQuad: CARDINAL) ;
1539 op1, proc, param, paramValue : CARDINAL ;
1540 op1tok, op2tok, paramtok, qtok: CARDINAL ;
1541 overflowChecking : BOOLEAN ;
1542 heapValue, ptrToHeap : CARDINAL ;
1546 GetQuadOtok (trashQuad, qtok, op, op1, proc, param, overflowChecking,
1547 op1tok, op2tok, paramtok) ;
1548 heapValue := GetQuadTrash (trashQuad) ;
1551 printf1 ("heapValue = %d\n", heapValue)
1553 IF heapValue # NulSym
1555 SetVarInitialized (param, FALSE, paramtok) ;
1556 paramValue := getLAlias (param) ;
1557 ptrToHeap := getContent (paramValue, param, paramtok) ;
1558 IF ptrToHeap # NulSym
1560 IF IsDeallocate (proc)
1562 SetupLAlias (ptrToHeap, Nil) ;
1563 SetVarInitialized (ptrToHeap, FALSE, paramtok)
1565 SetupIndr (ptrToHeap, heapValue) ;
1566 SetVarInitialized (ptrToHeap, TRUE, paramtok)
1576 SetVarLRInitialized - this sets up an alias between the parameter
1577 value and the pointer for the case:
1579 procedure foo (var shadow: PtrToType) ;
1581 which allows shadow to be statically analyzed
1582 once it is re-assigned.
1585 PROCEDURE SetVarLRInitialized (param: CARDINAL) ;
1590 Assert (IsParameter (param)) ;
1591 shadow := GetParameterShadowVar (param) ;
1594 IncludeItemIntoList (ignoreList, shadow)
1596 heap := GetParameterHeapVar (param) ;
1597 IF (shadow # NulSym) AND (heap # NulSym)
1599 PutVarInitialized (shadow, GetMode (shadow)) ;
1600 PutVarInitialized (heap, GetMode (heap)) ;
1601 SetupIndr (shadow, heap) ;
1602 IncludeItemIntoList (ignoreList, heap)
1604 END SetVarLRInitialized ;
1611 PROCEDURE TestBBSequence (procSym: CARDINAL; lst: List) ;
1616 warning: BOOLEAN ; (* Should we issue a warning rather than a note? *)
1620 DumpBBSequence (lst)
1623 ForeachLocalSymDo (procSym, SetVarUninitialized) ;
1624 ForeachParamSymDo (procSym, SetVarLRInitialized) ;
1625 n := NoOfItemsInList (lst) ;
1629 bbi := GetItemFromList (lst, i) ;
1630 bbPtr := Indexing.GetIndice (bbArray, bbi) ;
1631 CheckReadBeforeInitFirstBasicBlock (procSym,
1632 bbPtr^.start, bbPtr^.end,
1636 (* Check to see if we are moving into an conditional block in which case
1637 we will issue a note. *)
1639 ELSIF bbPtr^.endCall AND (bbPtr^.trashQuad # 0)
1641 trashParam (bbPtr^.trashQuad)
1646 END TestBBSequence ;
1650 CreateBBPermultations -
1653 PROCEDURE CreateBBPermultations (procSym: CARDINAL; i: CARDINAL; lst: List) ;
1660 TestBBSequence (procSym, lst)
1662 iPtr := Indexing.GetIndice (bbArray, i) ;
1665 TestBBSequence (procSym, lst)
1667 duplst := DuplicateList (lst) ;
1668 IncludeItemIntoList (duplst, i) ;
1669 IF iPtr^.endCall AND (iPtr^.trashQuad = 0)
1671 TestBBSequence (procSym, duplst)
1674 CreateBBPermultations (procSym, iPtr^.nextBB, duplst)
1675 ELSIF UninitVariableConditionalChecking AND iPtr^.endCond
1677 CreateBBPermultations (procSym, iPtr^.nextBB, duplst) ;
1678 CreateBBPermultations (procSym, iPtr^.condBB, duplst)
1681 TestBBSequence (procSym, duplst)
1684 CreateBBPermultations (procSym, iPtr^.nextBB, duplst)
1689 END CreateBBPermultations ;
1693 ScopeBlockVariableAnalysis - checks to see whether a variable is
1694 read before it has been initialized.
1697 PROCEDURE ScopeBlockVariableAnalysis (Scope: CARDINAL;
1698 Start, End: CARDINAL) ;
1703 IF UninitVariableChecking
1705 bbArray := Indexing.InitIndex (1) ;
1706 bb := InitBasicBlocksFromRange (Scope, Start, End) ;
1707 ForeachBasicBlockDo (bb, AppendEntry) ;
1708 KillBasicBlocks (bb) ;
1715 DumpBBArray (Scope) ;
1716 IF UninitVariableConditionalChecking
1718 printf0 ("UninitVariableConditionalChecking is TRUE\n")
1721 CreateBBPermultations (Scope, 1, lst) ;
1726 END ScopeBlockVariableAnalysis ;
1733 PROCEDURE GetOp3 (quad: CARDINAL) : CARDINAL ;
1736 op1, op2, op3: CARDINAL ;
1738 GetQuad (quad, op, op1, op2, op3) ;
1744 getBBindex - return the basic block index which starts with quad.
1747 PROCEDURE getBBindex (quad: CARDINAL) : CARDINAL ;
1753 high := Indexing.HighIndice (bbArray) ;
1755 iPtr := Indexing.GetIndice (bbArray, i) ;
1756 IF iPtr^.start = quad
1758 RETURN iPtr^.indexBB
1770 PROCEDURE GenerateCFG ;
1777 high := Indexing.HighIndice (bbArray) ;
1779 iPtr := Indexing.GetIndice (bbArray, i) ;
1780 IF IsKillLocalVar (iPtr^.end) OR IsReturn (iPtr^.end)
1782 (* Nothing to do as we have reached the end of this scope. *)
1784 next := GetNextQuad (iPtr^.end) ;
1785 iPtr^.nextQuad := next ;
1786 iPtr^.nextBB := getBBindex (next) ;
1789 iPtr^.condQuad := GetOp3 (iPtr^.end) ;
1790 iPtr^.condBB := getBBindex (iPtr^.condQuad)
1802 PROCEDURE NewEntry () : bbEntry ;
1810 bbPtr := bbFreeList ;
1811 bbFreeList := bbFreeList^.next
1818 IsAllocate - return TRUE is sym is ALLOCATE.
1821 PROCEDURE IsAllocate (sym: CARDINAL) : BOOLEAN ;
1823 RETURN IsProcedure (sym) AND (GetSymName (sym) = MakeKey('ALLOCATE'))
1828 IsDeallocate - return TRUE is sym is DEALLOCATE.
1831 PROCEDURE IsDeallocate (sym: CARDINAL) : BOOLEAN ;
1833 RETURN IsProcedure (sym) AND (GetSymName (sym) = MakeKey('DEALLOCATE'))
1841 PROCEDURE DetectTrash (bbPtr: bbEntry) ;
1845 op1, op2, op3: CARDINAL ;
1851 GetQuad (i, op, op1, op2, op3) ;
1852 IF (op = ParamOp) AND (op1 = 1) AND (IsAllocate (op2) OR IsDeallocate (op2))
1854 bbPtr^.trashQuad := i
1860 i := GetNextQuad (i)
1870 PROCEDURE AppendEntry (Start, End: CARDINAL) ;
1875 high := Indexing.HighIndice (bbArray) ;
1876 bbPtr := NewEntry () ;
1881 endCall := IsCall (End) ;
1882 endGoto := IsGoto (End) ;
1883 endCond := IsConditional (End) ;
1884 topOfLoop := IsBackReference (Start) ;
1886 indexBB := high + 1 ;
1893 DetectTrash (bbPtr) ;
1894 Indexing.PutIndice (bbArray, high + 1, bbPtr)
1902 PROCEDURE DumpAlias (array: Index; aliasIndex: CARDINAL) ;
1906 sa := Indexing.GetIndice (array, aliasIndex) ;
1907 printf2 ("keySym = %d: alias = %d\n", sa^.keySym, sa^.alias)
1915 PROCEDURE doDumpAliases (array: Index) ;
1920 n := Indexing.HighIndice (array) ;
1922 DumpAlias (array, i) ;
1932 PROCEDURE DumpAliases ;
1936 printf0 ("LArray\n") ;
1937 doDumpAliases (LArray) ;
1938 printf0 ("IndirectArray\n") ;
1939 doDumpAliases (IndirectArray)
1948 PROCEDURE newAlias () : symAlias ;
1957 freeList := freeList^.next
1967 PROCEDURE initAlias (sym: CARDINAL) : symAlias ;
1985 PROCEDURE killAlias (sa: symAlias) ;
1987 sa^.next := freeList ;
1996 PROCEDURE initBlock ;
1998 LArray := Indexing.InitIndex (1) ;
1999 IndirectArray := Indexing.InitIndex (1) ;
2000 InitList (ignoreList)
2008 PROCEDURE killBlock ;
2010 doKillBlock (LArray) ;
2011 doKillBlock (IndirectArray) ;
2012 KillList (ignoreList)
2016 PROCEDURE doKillBlock (VAR array: Index) ;
2021 n := Indexing.HighIndice (array) ;
2023 killAlias (Indexing.GetIndice (array, i)) ;
2026 array := Indexing.KillIndex (array)
2034 PROCEDURE addAlias (array: Index; sym: CARDINAL; aliased: CARDINAL) ;
2040 n := Indexing.HighIndice (array) ;
2042 sa := Indexing.GetIndice (array, i) ;
2045 sa^.alias := aliased ;
2050 sa := initAlias (sym) ;
2051 Indexing.IncludeIndiceIntoIndex (array, sa) ;
2052 sa^.alias := aliased
2060 PROCEDURE lookupAlias (array: Index; sym: CARDINAL) : symAlias ;
2066 n := Indexing.HighIndice (array) ;
2068 sa := Indexing.GetIndice (array, i) ;
2083 PROCEDURE doGetAlias (array: Index; sym: CARDINAL) : CARDINAL ;
2087 sa := lookupAlias (array, sym) ;
2088 IF (sa # NIL) AND (sa^.alias # NulSym)
2097 getLAlias - attempts to looks up an alias which is not a temporary variable.
2100 PROCEDURE getLAlias (sym: CARDINAL) : CARDINAL ;
2108 type := GetSType (sym) ;
2109 IF (IsTemporary (sym) AND (GetMode (sym) = LeftValue)) OR
2110 ((type # NulSym) AND IsReallyPointer (type))
2112 nsym := doGetAlias (LArray, sym)
2116 UNTIL nsym = NulSym ;
2125 PROCEDURE SetupLAlias (des, exp: CARDINAL) ;
2129 ((GetMode (des) = LeftValue) OR IsReallyPointer (GetSType (des))))
2131 addAlias (LArray, des, exp) ;
2141 PROCEDURE SetupIndr (ptr, content: CARDINAL) ;
2143 addAlias (IndirectArray, ptr, content) ;
2148 getContent - attempts to return the content pointed to by ptr.
2149 sym is the original symbol and ptr will be the equivalent lvalue.
2152 PROCEDURE getContent (ptr: CARDINAL; sym: CARDINAL; tok: CARDINAL) : CARDINAL ;
2157 "attempting to dereference {%1Wad} which will be a {%kNIL} pointer",
2161 RETURN doGetAlias (IndirectArray, ptr)
2174 InitList (errorList)