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 constExpr, overflowChecking : BOOLEAN ;
577 GetQuadOtok (quad, qtok, op, op1, op2, op3,
578 overflowChecking, constExpr,
579 op1tok, op2tok, op3tok) ;
580 IF IsUniqueWarning (qtok)
582 op1tok := DefaultTokPos (op1tok, qtok) ;
583 op2tok := DefaultTokPos (op2tok, qtok) ;
584 op3tok := DefaultTokPos (op3tok, qtok) ;
589 s := InitString ('depending upon the result of {%1Oad} ') ;
590 s := ConCat (s, Mark (GetM2OperatorDesc (op))) ;
591 s := ConCat (s, InitString (' {%2ad}')) ;
592 MetaErrorStringT2 (qtok, s, op1, op2)
594 END IssueConditional ;
601 PROCEDURE GenerateNoteFlow (n: CARDINAL; warning: BOOLEAN) ;
609 (* Only issue flow messages for non warnings. *)
612 iPtr := Indexing.GetIndice (bbArray, i) ;
617 ip1Ptr := Indexing.GetIndice (bbArray, i+1) ;
618 IssueConditional (iPtr^.end, iPtr^.condBB = ip1Ptr^.indexBB)
624 END GenerateNoteFlow ;
628 IssueWarning - issue a warning or note at tok location.
631 PROCEDURE IssueWarning (tok: CARDINAL;
632 before, after: ARRAY OF CHAR;
633 sym: CARDINAL; warning: BOOLEAN) ;
637 s := InitString (before) ;
640 s := ConCat (s, Mark (InitString ('{%1Wad}')))
642 s := ConCat (s, Mark (InitString ('{%1Oad}')))
644 s := ConCat (s, Mark (InitString (after))) ;
645 MetaErrorStringT1 (tok, s, sym)
650 IsUniqueWarning - return TRUE if a warning has not been issued at tok.
651 It remembers tok and subsequent calls will always return FALSE.
654 PROCEDURE IsUniqueWarning (tok: CARDINAL) : BOOLEAN ;
656 IF NOT IsItemInList (errorList, tok)
658 IncludeItemIntoList (errorList, tok) ;
663 END IsUniqueWarning ;
667 CheckDeferredRecordAccess -
670 PROCEDURE CheckDeferredRecordAccess (tok: CARDINAL;
672 canDereference, warning: BOOLEAN;
681 Trace ("CheckDeferredRecordAccess %d\n", sym) ;
685 printf1 ("checkReadInit (%d, true)\n", sym)
687 printf1 ("checkReadInit (%d, false)\n", sym)
692 Trace ("checkReadInit sym is a parameter or not a local variable (%d)", sym) ;
693 (* We assume parameters have been initialized. *)
694 PutVarInitialized (sym, LeftValue) ;
695 PutVarInitialized (sym, RightValue)
696 (* SetVarInitialized (sym, TRUE) *)
697 ELSIF IsUnbounded (GetSType (sym))
699 SetVarInitialized (sym, TRUE, tok)
700 ELSIF IsComponent (sym)
702 Trace ("checkReadInit IsComponent (%d) is true)", sym) ;
703 IF (NOT GetVarComponentInitialized (sym, tok)) AND IsUniqueWarning (tok)
705 GenerateNoteFlow (i, warning) ;
707 'attempting to access ',
708 ' before it has been initialized',
711 ELSIF (GetMode (sym) = LeftValue) AND canDereference
713 Trace ("checkReadInit GetMode (%d) = LeftValue and canDereference (LeftValue and RightValue VarCheckReadInit)", sym) ;
715 IF NOT VarCheckReadInit (sym, LeftValue)
717 unique := IsUniqueWarning (tok) ;
720 GenerateNoteFlow (i, warning) ;
722 'attempting to access the address of ',
723 ' before it has been initialized',
727 IF NOT VarCheckReadInit (sym, RightValue)
731 GenerateNoteFlow (i, warning) ;
733 'attempting to access ', ' before it has been initialized',
738 Trace ("checkReadInit call VarCheckReadInit using GetMode (%d)", sym) ;
739 IF (NOT VarCheckReadInit (sym, GetMode (sym))) AND IsUniqueWarning (tok)
741 GenerateNoteFlow (i, warning) ;
743 'attempting to access ',
744 ' before it has been initialized',
749 END CheckDeferredRecordAccess ;
753 SetVarUninitialized - resets variable init state.
756 PROCEDURE SetVarUninitialized (sym: CARDINAL) ;
760 IF NOT IsUnbounded (GetSType (sym))
765 END SetVarUninitialized ;
772 PROCEDURE ComponentFindVar (sym: CARDINAL;
774 tok: CARDINAL) : CARDINAL ;
781 nsym := GetNth (sym, i) ;
782 lvalue := GetMode (nsym) = LeftValue ;
783 nsym := getLAlias (nsym) ;
787 "attempting to dereference {%1Wad} which will be a {%kNIL} pointer",
790 ELSIF (nsym # NulSym) AND IsVar (nsym)
792 IF (nsym # sym) AND IsComponent (nsym)
794 RETURN ComponentFindVar (nsym, lvalue, tok)
800 UNTIL nsym = NulSym ;
802 END ComponentFindVar ;
806 ComponentCreateFieldList - builds a list of fields accessed by the component var.
807 Each item in the list will be a field of incremental levels
808 though a nested record. It is not a list of fields
818 { v, x } for example and not { v, w }
821 PROCEDURE ComponentCreateFieldList (sym: CARDINAL) : List ;
826 IF IsVar (sym) AND IsComponent (sym)
828 ComponentBuildFieldList (lst, sym)
831 END ComponentCreateFieldList ;
834 PROCEDURE ComponentBuildFieldList (lst: List; sym: CARDINAL) ;
840 nsym := GetNth (sym, i) ;
843 IF IsComponent (nsym)
845 ComponentBuildFieldList (lst, nsym)
846 ELSIF IsRecordField (nsym)
848 IncludeItemIntoList (lst, nsym)
853 END ComponentBuildFieldList ;
860 PROCEDURE deRefComponent (component: CARDINAL; lvalue: BOOLEAN;
861 sym: CARDINAL; tok: CARDINAL) : CARDINAL ;
865 RETURN getContent (component, sym, tok)
873 SetVarComponentInitialized -
876 PROCEDURE SetVarComponentInitialized (sym: CARDINAL; tok: CARDINAL) ;
884 vsym := ComponentFindVar (sym, lvalue, tok) ;
885 vsym := deRefComponent (vsym, lvalue, sym, tok) ;
890 printf0 ("*************** vsym is: ") ;
893 (* Build list accessing the field. *)
894 lst := ComponentCreateFieldList (sym) ;
897 printf2 ("sym = %d, vsym = %d, fields:", sym, vsym)
899 (* Now mark this field in the record variable as initialized. *)
900 IF PutVarFieldInitialized (vsym, RightValue, lst)
905 n := NoOfItemsInList (lst) ;
907 fsym := GetItemFromList (lst, i) ;
908 printf1 (" %d", fsym) ;
911 printf0 (" is initialized\n")
915 printf0 (" vsym is not a var\n")
919 END SetVarComponentInitialized ;
923 GetVarComponentInitialized -
926 PROCEDURE GetVarComponentInitialized (sym: CARDINAL; tok: CARDINAL) : BOOLEAN ;
934 component := ComponentFindVar (sym, lvalue, tok) ;
935 IF IsItemInList (ignoreList, component) OR IsExempt (component)
940 vsym := deRefComponent (component, lvalue, sym, tok) ;
947 (* Create list representing how the field is accessed. *)
948 lst := ComponentCreateFieldList (sym) ;
949 (* Now obtain the mark indicating whether this field was initialized. *)
950 init := GetVarFieldInitialized (vsym, RightValue, lst) ;
956 END GetVarComponentInitialized ;
963 PROCEDURE Trace (message: ARRAY OF CHAR; sym: CARDINAL) ;
967 printf1 (message, sym) ;
974 SetVarInitialized - if the variable has a left mode and can be dereferenced
975 then set the left and right initialization state.
978 PROCEDURE SetVarInitialized (sym: CARDINAL; canDereference: BOOLEAN;
983 RemoveItemFromList (ignoreList, sym) ;
986 Trace ("SetVarInitialized sym %d is a component and calling SetVarComponentInitialized", sym);
987 SetVarComponentInitialized (sym, tok)
988 ELSIF (GetMode (sym) = LeftValue) AND canDereference
990 Trace ("SetVarInitialized sym %d is LeftValue and canDeference and calling PutVarInitialized LeftValue and RightValue", sym);
991 PutVarInitialized (sym, LeftValue) ;
992 PutVarInitialized (sym, RightValue)
994 Trace ("SetVarInitialized sym %d calling PutVarInitialized with its mode", sym);
995 PutVarInitialized (sym, GetMode (sym))
1002 END SetVarInitialized ;
1006 doGetVarInitialized -
1009 PROCEDURE doGetVarInitialized (sym: CARDINAL; tok: CARDINAL) : BOOLEAN ;
1013 IF IsUnbounded (GetSType (sym))
1016 ELSIF IsComponent (sym)
1018 RETURN GetVarComponentInitialized (sym, tok)
1020 RETURN VarCheckReadInit (sym, GetMode (sym))
1022 RETURN IsConst (sym) AND IsConstString (sym)
1023 END doGetVarInitialized ;
1030 PROCEDURE GetVarInitialized (sym: CARDINAL; tok: CARDINAL) : BOOLEAN ;
1034 init := doGetVarInitialized (sym, tok) ;
1039 Trace ("GetVarInitialized (sym = %d) returning TRUE", sym)
1041 Trace ("GetVarInitialized (sym = %d) returning FALSE", sym)
1045 END GetVarInitialized ;
1049 IsExempt - returns TRUE if sym is a global variable or a parameter or
1050 a variable with a variant record type.
1053 PROCEDURE IsExempt (sym: CARDINAL) : BOOLEAN ;
1055 RETURN (sym # NulSym) AND IsVar (sym) AND
1056 (IsGlobalVar (sym) OR
1057 (* (IsVarAParam (sym) AND (GetMode (sym) = LeftValue)) OR *)
1058 ContainsVariant (sym) OR
1059 IsArray (GetSType (sym)) OR IsSet (GetSType (sym)) OR
1060 IsUnbounded (GetSType (sym)) OR IsVarArrayRef (sym) OR
1061 IsItemInList (ignoreList, sym))
1069 PROCEDURE CheckBinary (op1tok, op1,
1071 op3tok, op3: CARDINAL; warning: BOOLEAN;
1074 CheckDeferredRecordAccess (op2tok, op2, FALSE, warning, i) ;
1075 CheckDeferredRecordAccess (op3tok, op3, FALSE, warning, i) ;
1076 SetVarInitialized (op1, FALSE, op1tok)
1084 PROCEDURE CheckUnary (lhstok, lhs,
1085 rhstok, rhs: CARDINAL; warning: BOOLEAN;
1088 CheckDeferredRecordAccess (rhstok, rhs, FALSE, warning, i) ;
1089 SetVarInitialized (lhs, FALSE, lhstok)
1097 PROCEDURE CheckXIndr (lhstok, lhs, type,
1098 rhstok, rhs: CARDINAL; warning: BOOLEAN;
1104 CheckDeferredRecordAccess (rhstok, rhs, FALSE, warning, i) ;
1105 CheckDeferredRecordAccess (lhstok, lhs, FALSE, warning, i) ;
1106 (* Now see if we know what lhs is pointing to and set fields if necessary. *)
1107 content := getContent (getLAlias (lhs), lhs, lhstok) ;
1108 IF (content # NulSym) AND (content # lhs) AND (GetSType (content) = type)
1110 IF IsReallyPointer (rhs)
1112 SetupLAlias (content, rhs)
1116 (* Set all fields of content as initialized. *)
1117 SetVarInitialized (content, FALSE, lhstok)
1119 (* Set only the field assigned in vsym as initialized. *)
1120 lst := ComponentCreateFieldList (rhs) ;
1121 IF PutVarFieldInitialized (content, RightValue, lst)
1134 PROCEDURE CheckIndrX (lhstok, lhs, rhstok, rhs: CARDINAL;
1140 CheckDeferredRecordAccess (rhstok, rhs, FALSE, warning, i) ;
1141 content := getContent (getLAlias (rhs), rhs, rhstok) ;
1144 IncludeItemIntoList (ignoreList, lhs)
1146 CheckDeferredRecordAccess (rhstok, content, TRUE, warning, i) ;
1147 SetVarInitialized (lhs, VarCheckReadInit (content, RightValue), lhstok) ;
1148 IF IsReallyPointer (content)
1150 SetupLAlias (lhs, content)
1160 PROCEDURE CheckRecordField (op1: CARDINAL) ;
1162 PutVarInitialized (op1, LeftValue)
1163 END CheckRecordField ;
1170 PROCEDURE CheckBecomes (destok, des, exprtok, expr: CARDINAL;
1171 warning: BOOLEAN; i: CARDINAL) ;
1177 CheckDeferredRecordAccess (exprtok, expr, FALSE, warning, i) ;
1178 SetupLAlias (des, expr) ;
1179 SetVarInitialized (des, FALSE, destok) ;
1180 (* Now see if we know what lhs is pointing to and set fields if necessary. *)
1181 IF IsComponent (des)
1183 vsym := ComponentFindVar (des, lvalue, destok) ;
1184 vsym := deRefComponent (vsym, lvalue, des, destok) ;
1187 (* Set only the field assigned in vsym as initialized. *)
1188 lst := ComponentCreateFieldList (des) ;
1189 IF PutVarFieldInitialized (vsym, RightValue, lst)
1202 PROCEDURE CheckComparison (op1tok, op1, op2tok, op2: CARDINAL;
1203 warning: BOOLEAN; i: CARDINAL) ;
1205 CheckDeferredRecordAccess (op1tok, op1, FALSE, warning, i) ;
1206 CheckDeferredRecordAccess (op2tok, op2, FALSE, warning, i)
1207 END CheckComparison ;
1214 PROCEDURE CheckAddr (ptrtok, ptr, contenttok, content: CARDINAL) ;
1216 SetVarInitialized (ptr, GetVarInitialized (content, contenttok), ptrtok) ;
1217 SetupIndr (ptr, content)
1225 PROCEDURE DefaultTokPos (preferredPos, defaultPos: CARDINAL) : CARDINAL ;
1227 IF preferredPos = UnknownTokenNo
1244 CheckReadBeforeInitQuad -
1247 PROCEDURE CheckReadBeforeInitQuad (procSym: CARDINAL; quad: CARDINAL;
1248 warning: BOOLEAN; i: CARDINAL) : BOOLEAN ;
1251 op1, op2, op3 : CARDINAL ;
1252 op1tok, op2tok, op3tok, qtok: CARDINAL ;
1253 constExpr, overflowChecking : BOOLEAN ;
1261 printf1 ("CheckReadBeforeInitQuad (quad %d)\n", quad) ;
1263 ForeachLocalSymDo (procSym, PrintSym) ;
1264 printf0 ("***********************************\n")
1266 GetQuadOtok (quad, qtok, op, op1, op2, op3,
1267 overflowChecking, constExpr,
1268 op1tok, op2tok, op3tok) ;
1269 op1tok := DefaultTokPos (op1tok, qtok) ;
1270 op2tok := DefaultTokPos (op2tok, qtok) ;
1271 op3tok := DefaultTokPos (op3tok, qtok) ;
1274 (* Jumps, calls and branches. *)
1282 IfGreEquOp : CheckComparison (op1tok, op1, op2tok, op2, warning, i) |
1288 GotoOp : RETURN TRUE | (* End of basic block. *)
1290 (* Variable references. *)
1293 ExclOp : CheckDeferredRecordAccess (op1tok, op1, FALSE, warning, i) ;
1294 CheckDeferredRecordAccess (op1tok, op1, TRUE, warning, i) ;
1295 CheckDeferredRecordAccess (op3tok, op3, FALSE, warning, i) |
1296 NegateOp : CheckUnary (op1tok, op1, op3tok, op3, warning, i) |
1297 BecomesOp : CheckBecomes (op1tok, op1, op3tok, op3, warning, i) |
1302 SizeOp : SetVarInitialized (op1, FALSE, op1tok) |
1303 AddrOp : CheckAddr (op1tok, op1, op3tok, op3) |
1304 ReturnValueOp : SetVarInitialized (op1, FALSE, op1tok) |
1306 ParamOp : CheckDeferredRecordAccess (op2tok, op2, FALSE, warning, i) ;
1307 CheckDeferredRecordAccess (op3tok, op3, FALSE, warning, i) ;
1308 IF (op1 > 0) AND (op1 <= NoOfParam (op2)) AND
1309 IsVarParam (op2, op1)
1311 SetVarInitialized (op3, TRUE, op3tok)
1313 ArrayOp : CheckDeferredRecordAccess (op3tok, op3, FALSE, warning, i) ;
1314 SetVarInitialized (op1, TRUE, op1tok) |
1315 RecordFieldOp : CheckRecordField (op1) |
1336 DivTruncOp : CheckBinary (op1tok, op1, op2tok, op2, op3tok, op3, warning, i) |
1337 XIndrOp : CheckXIndr (op1tok, op1, op2, op3tok, op3, warning, i) |
1338 IndrXOp : CheckIndrX (op1tok, op1, op3tok, op3, warning, i) |
1339 SaveExceptionOp : SetVarInitialized (op1, FALSE, op1tok) |
1340 RestoreExceptionOp: CheckDeferredRecordAccess (op1tok, op1, FALSE, warning, i) |
1343 SubrangeHighOp : InternalError ('quadruples should have been resolved') |
1345 BuiltinConstOp, (* Nothing to do, it is assigning a constant to op1 (also a const). *)
1346 BuiltinTypeInfoOp, (* Likewise assigning op1 (const) with a type. *)
1347 StringConvertCnulOp,
1348 StringConvertM2nulOp,
1381 END CheckReadBeforeInitQuad ;
1385 FilterCheckReadBeforeInitQuad -
1388 PROCEDURE FilterCheckReadBeforeInitQuad (procSym: CARDINAL; start: CARDINAL;
1390 i: CARDINAL) : BOOLEAN ;
1393 Op1, Op2, Op3: CARDINAL ;
1395 GetQuad (start, Op, Op1, Op2, Op3) ;
1396 IF (Op # RangeCheckOp) AND (Op # StatementNoteOp)
1398 RETURN CheckReadBeforeInitQuad (procSym, start, warning, i)
1401 END FilterCheckReadBeforeInitQuad ;
1405 CheckReadBeforeInitFirstBasicBlock -
1408 PROCEDURE CheckReadBeforeInitFirstBasicBlock (procSym: CARDINAL;
1409 start, end: CARDINAL;
1414 IF FilterCheckReadBeforeInitQuad (procSym, start, warning, i)
1421 start := GetNextQuad (start)
1424 END CheckReadBeforeInitFirstBasicBlock ;
1431 PROCEDURE bbArrayKill ;
1436 h := Indexing.HighIndice (bbArray) ;
1439 bbPtr := Indexing.GetIndice (bbArray, i) ;
1440 bbPtr^.next := bbFreeList ;
1441 bbFreeList := bbPtr ;
1444 bbArray := Indexing.KillIndex (bbArray)
1452 PROCEDURE DumpBBEntry (bbPtr: bbEntry; procSym: CARDINAL) ;
1454 printf4 ("bb %d: scope %d: quads: %d .. %d",
1455 bbPtr^.indexBB, procSym, bbPtr^.start, bbPtr^.end) ;
1462 printf0 (" endcall")
1466 printf0 (" endgoto")
1470 printf0 (" endcond")
1474 printf0 (" topofloop")
1476 IF bbPtr^.condBB # 0
1478 printf1 (" cond %d", bbPtr^.condBB)
1480 IF bbPtr^.nextBB # 0
1482 printf1 (" next %d", bbPtr^.nextBB)
1492 PROCEDURE DumpBBArray (procSym: CARDINAL) ;
1498 n := Indexing.HighIndice (bbArray) ;
1500 bbPtr := Indexing.GetIndice (bbArray, i) ;
1501 DumpBBEntry (bbPtr, procSym) ;
1506 bbPtr := Indexing.GetIndice (bbArray, i) ;
1507 printf4 ("bb %d: scope %d: quads: %d .. %d\n",
1508 bbPtr^.indexBB, procSym, bbPtr^.start, bbPtr^.end) ;
1509 DisplayQuadRange (procSym, bbPtr^.start, bbPtr^.end) ;
1519 PROCEDURE DumpBBSequence (lst: List) ;
1522 listindex, n: CARDINAL ;
1524 n := NoOfItemsInList (lst) ;
1526 printf0 ("=============\n");
1527 printf0 (" checking sequence:");
1528 WHILE listindex <= n DO
1529 arrayindex := GetItemFromList (lst, listindex) ;
1530 printf2 (" lst[%d] -> %d", listindex, arrayindex) ;
1534 END DumpBBSequence ;
1541 PROCEDURE trashParam (trashQuad: CARDINAL) ;
1544 op1, proc, param, paramValue : CARDINAL ;
1545 op1tok, op2tok, paramtok, qtok: CARDINAL ;
1546 constExpr, overflowChecking : BOOLEAN ;
1547 heapValue, ptrToHeap : CARDINAL ;
1551 GetQuadOtok (trashQuad, qtok, op, op1, proc, param,
1552 overflowChecking, constExpr,
1553 op1tok, op2tok, paramtok) ;
1554 heapValue := GetQuadTrash (trashQuad) ;
1557 printf1 ("heapValue = %d\n", heapValue)
1559 IF heapValue # NulSym
1561 SetVarInitialized (param, FALSE, paramtok) ;
1562 paramValue := getLAlias (param) ;
1563 ptrToHeap := getContent (paramValue, param, paramtok) ;
1564 IF ptrToHeap # NulSym
1566 IF IsDeallocate (proc)
1568 SetupLAlias (ptrToHeap, Nil) ;
1569 SetVarInitialized (ptrToHeap, FALSE, paramtok)
1571 SetupIndr (ptrToHeap, heapValue) ;
1572 SetVarInitialized (ptrToHeap, TRUE, paramtok)
1582 SetVarLRInitialized - this sets up an alias between the parameter
1583 value and the pointer for the case:
1585 procedure foo (var shadow: PtrToType) ;
1587 which allows shadow to be statically analyzed
1588 once it is re-assigned.
1591 PROCEDURE SetVarLRInitialized (param: CARDINAL) ;
1596 Assert (IsParameter (param)) ;
1597 shadow := GetParameterShadowVar (param) ;
1600 IncludeItemIntoList (ignoreList, shadow)
1602 heap := GetParameterHeapVar (param) ;
1603 IF (shadow # NulSym) AND (heap # NulSym)
1605 PutVarInitialized (shadow, GetMode (shadow)) ;
1606 PutVarInitialized (heap, GetMode (heap)) ;
1607 SetupIndr (shadow, heap) ;
1608 IncludeItemIntoList (ignoreList, heap)
1610 END SetVarLRInitialized ;
1617 PROCEDURE TestBBSequence (procSym: CARDINAL; lst: List) ;
1622 warning: BOOLEAN ; (* Should we issue a warning rather than a note? *)
1626 DumpBBSequence (lst)
1629 ForeachLocalSymDo (procSym, SetVarUninitialized) ;
1630 ForeachParamSymDo (procSym, SetVarLRInitialized) ;
1631 n := NoOfItemsInList (lst) ;
1635 bbi := GetItemFromList (lst, i) ;
1636 bbPtr := Indexing.GetIndice (bbArray, bbi) ;
1637 CheckReadBeforeInitFirstBasicBlock (procSym,
1638 bbPtr^.start, bbPtr^.end,
1642 (* Check to see if we are moving into an conditional block in which case
1643 we will issue a note. *)
1645 ELSIF bbPtr^.endCall AND (bbPtr^.trashQuad # 0)
1647 trashParam (bbPtr^.trashQuad)
1652 END TestBBSequence ;
1656 CreateBBPermultations -
1659 PROCEDURE CreateBBPermultations (procSym: CARDINAL; i: CARDINAL; lst: List) ;
1666 TestBBSequence (procSym, lst)
1668 iPtr := Indexing.GetIndice (bbArray, i) ;
1671 TestBBSequence (procSym, lst)
1673 duplst := DuplicateList (lst) ;
1674 IncludeItemIntoList (duplst, i) ;
1675 IF iPtr^.endCall AND (iPtr^.trashQuad = 0)
1677 TestBBSequence (procSym, duplst)
1680 CreateBBPermultations (procSym, iPtr^.nextBB, duplst)
1681 ELSIF UninitVariableConditionalChecking AND iPtr^.endCond
1683 CreateBBPermultations (procSym, iPtr^.nextBB, duplst) ;
1684 CreateBBPermultations (procSym, iPtr^.condBB, duplst)
1687 TestBBSequence (procSym, duplst)
1690 CreateBBPermultations (procSym, iPtr^.nextBB, duplst)
1695 END CreateBBPermultations ;
1699 ScopeBlockVariableAnalysis - checks to see whether a variable is
1700 read before it has been initialized.
1703 PROCEDURE ScopeBlockVariableAnalysis (Scope: CARDINAL;
1704 Start, End: CARDINAL) ;
1709 IF UninitVariableChecking
1711 bbArray := Indexing.InitIndex (1) ;
1712 bb := InitBasicBlocksFromRange (Scope, Start, End) ;
1713 ForeachBasicBlockDo (bb, AppendEntry) ;
1714 KillBasicBlocks (bb) ;
1721 DumpBBArray (Scope) ;
1722 IF UninitVariableConditionalChecking
1724 printf0 ("UninitVariableConditionalChecking is TRUE\n")
1727 CreateBBPermultations (Scope, 1, lst) ;
1732 END ScopeBlockVariableAnalysis ;
1739 PROCEDURE GetOp3 (quad: CARDINAL) : CARDINAL ;
1742 op1, op2, op3: CARDINAL ;
1744 GetQuad (quad, op, op1, op2, op3) ;
1750 getBBindex - return the basic block index which starts with quad.
1753 PROCEDURE getBBindex (quad: CARDINAL) : CARDINAL ;
1759 high := Indexing.HighIndice (bbArray) ;
1761 iPtr := Indexing.GetIndice (bbArray, i) ;
1762 IF iPtr^.start = quad
1764 RETURN iPtr^.indexBB
1776 PROCEDURE GenerateCFG ;
1783 high := Indexing.HighIndice (bbArray) ;
1785 iPtr := Indexing.GetIndice (bbArray, i) ;
1786 IF IsKillLocalVar (iPtr^.end) OR IsReturn (iPtr^.end)
1788 (* Nothing to do as we have reached the end of this scope. *)
1790 next := GetNextQuad (iPtr^.end) ;
1791 iPtr^.nextQuad := next ;
1792 iPtr^.nextBB := getBBindex (next) ;
1795 iPtr^.condQuad := GetOp3 (iPtr^.end) ;
1796 iPtr^.condBB := getBBindex (iPtr^.condQuad)
1808 PROCEDURE NewEntry () : bbEntry ;
1816 bbPtr := bbFreeList ;
1817 bbFreeList := bbFreeList^.next
1824 IsAllocate - return TRUE is sym is ALLOCATE.
1827 PROCEDURE IsAllocate (sym: CARDINAL) : BOOLEAN ;
1829 RETURN IsProcedure (sym) AND (GetSymName (sym) = MakeKey('ALLOCATE'))
1834 IsDeallocate - return TRUE is sym is DEALLOCATE.
1837 PROCEDURE IsDeallocate (sym: CARDINAL) : BOOLEAN ;
1839 RETURN IsProcedure (sym) AND (GetSymName (sym) = MakeKey('DEALLOCATE'))
1847 PROCEDURE DetectTrash (bbPtr: bbEntry) ;
1851 op1, op2, op3: CARDINAL ;
1857 GetQuad (i, op, op1, op2, op3) ;
1858 IF (op = ParamOp) AND (op1 = 1) AND (IsAllocate (op2) OR IsDeallocate (op2))
1860 bbPtr^.trashQuad := i
1866 i := GetNextQuad (i)
1876 PROCEDURE AppendEntry (Start, End: CARDINAL) ;
1881 high := Indexing.HighIndice (bbArray) ;
1882 bbPtr := NewEntry () ;
1887 endCall := IsCall (End) ;
1888 endGoto := IsGoto (End) ;
1889 endCond := IsConditional (End) ;
1890 topOfLoop := IsBackReference (Start) ;
1892 indexBB := high + 1 ;
1899 DetectTrash (bbPtr) ;
1900 Indexing.PutIndice (bbArray, high + 1, bbPtr)
1908 PROCEDURE DumpAlias (array: Index; aliasIndex: CARDINAL) ;
1912 sa := Indexing.GetIndice (array, aliasIndex) ;
1913 printf2 ("keySym = %d: alias = %d\n", sa^.keySym, sa^.alias)
1921 PROCEDURE doDumpAliases (array: Index) ;
1926 n := Indexing.HighIndice (array) ;
1928 DumpAlias (array, i) ;
1938 PROCEDURE DumpAliases ;
1942 printf0 ("LArray\n") ;
1943 doDumpAliases (LArray) ;
1944 printf0 ("IndirectArray\n") ;
1945 doDumpAliases (IndirectArray)
1954 PROCEDURE newAlias () : symAlias ;
1963 freeList := freeList^.next
1973 PROCEDURE initAlias (sym: CARDINAL) : symAlias ;
1991 PROCEDURE killAlias (sa: symAlias) ;
1993 sa^.next := freeList ;
2002 PROCEDURE initBlock ;
2004 LArray := Indexing.InitIndex (1) ;
2005 IndirectArray := Indexing.InitIndex (1) ;
2006 InitList (ignoreList)
2014 PROCEDURE killBlock ;
2016 doKillBlock (LArray) ;
2017 doKillBlock (IndirectArray) ;
2018 KillList (ignoreList)
2022 PROCEDURE doKillBlock (VAR array: Index) ;
2027 n := Indexing.HighIndice (array) ;
2029 killAlias (Indexing.GetIndice (array, i)) ;
2032 array := Indexing.KillIndex (array)
2040 PROCEDURE addAlias (array: Index; sym: CARDINAL; aliased: CARDINAL) ;
2046 n := Indexing.HighIndice (array) ;
2048 sa := Indexing.GetIndice (array, i) ;
2051 sa^.alias := aliased ;
2056 sa := initAlias (sym) ;
2057 Indexing.IncludeIndiceIntoIndex (array, sa) ;
2058 sa^.alias := aliased
2066 PROCEDURE lookupAlias (array: Index; sym: CARDINAL) : symAlias ;
2072 n := Indexing.HighIndice (array) ;
2074 sa := Indexing.GetIndice (array, i) ;
2089 PROCEDURE doGetAlias (array: Index; sym: CARDINAL) : CARDINAL ;
2093 sa := lookupAlias (array, sym) ;
2094 IF (sa # NIL) AND (sa^.alias # NulSym)
2103 getLAlias - attempts to looks up an alias which is not a temporary variable.
2106 PROCEDURE getLAlias (sym: CARDINAL) : CARDINAL ;
2114 type := GetSType (sym) ;
2115 IF (IsTemporary (sym) AND (GetMode (sym) = LeftValue)) OR
2116 ((type # NulSym) AND IsReallyPointer (type))
2118 nsym := doGetAlias (LArray, sym)
2122 UNTIL nsym = NulSym ;
2131 PROCEDURE SetupLAlias (des, exp: CARDINAL) ;
2135 ((GetMode (des) = LeftValue) OR IsReallyPointer (GetSType (des))))
2137 addAlias (LArray, des, exp) ;
2147 PROCEDURE SetupIndr (ptr, content: CARDINAL) ;
2149 addAlias (IndirectArray, ptr, content) ;
2154 getContent - attempts to return the content pointed to by ptr.
2155 sym is the original symbol and ptr will be the equivalent lvalue.
2158 PROCEDURE getContent (ptr: CARDINAL; sym: CARDINAL; tok: CARDINAL) : CARDINAL ;
2163 "attempting to dereference {%1Wad} which will be a {%kNIL} pointer",
2167 RETURN doGetAlias (IndirectArray, ptr)
2180 InitList (errorList)