2 ** LCLint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2001 University of Virginia,
4 ** Massachusetts Institute of Technology
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** General Public License for more details.
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
20 ** For information on lclint: lclint-request@cs.virginia.edu
21 ** To report a bug: lclint-bug@cs.virginia.edu
22 ** For more information: http://lclint.cs.virginia.edu
31 # include "lclintMacros.nf"
33 # include "cgrammar.h"
36 # include "usymtab_interface.h"
39 # include "structNames.h"
40 # include "nameChecks.h"
43 # include "sgrammar_tokens.h"
45 # include "cgrammar_tokens.h"
49 ** Lots of variables are needed because of interactions with the
50 ** parser. This is easier than restructuring the grammar so the
51 ** right values are available in the right place.
55 static /*@only@*/ constraintList implicitFcnConstraints = NULL;
58 //static constraintList fcnPreConditions = NULL;
60 static void clabstract_prepareFunction (uentry p_e) /*@modifies p_e@*/ ;
61 static bool fcnNoGlobals = FALSE;
62 static bool ProcessingVars = FALSE;
63 static bool ProcessingParams = FALSE;
64 static bool ProcessingGlobals = FALSE;
65 static bool ProcessingTypedef = FALSE;
66 static bool ProcessingIterVars = FALSE;
67 static /*@only@*/ qtype processingType = qtype_undefined;
68 static uentry currentIter = uentry_undefined;
69 static /*@dependent@*/ uentryList saveParamList; /* for old style functions */
70 static /*@owned@*/ uentry saveFunction = uentry_undefined;
71 static int saveIterParamNo;
72 static idDecl fixStructDecl (/*@returned@*/ idDecl p_d);
73 static void checkTypeDecl (uentry p_e, ctype p_rep);
74 static /*@dependent@*/ fileloc saveStoreLoc = fileloc_undefined;
75 static storageClassCode storageClass = SCNONE;
76 static void declareEnumList (/*@temp@*/ enumNameList p_el, ctype p_c, fileloc p_loc);
77 static void resetGlobals (void);
78 static /*@null@*/ qual specialFunctionCode;
79 static bool argsUsed = FALSE;
81 extern void clabstract_initMod ()
83 specialFunctionCode = qual_createUnknown ();
84 DPRINTF (("Initialized: %s", qual_unparse (specialFunctionCode)));
87 static bool hasSpecialCode (void)
89 return (!qual_isUnknown (specialFunctionCode));
92 extern void setArgsUsed (void)
98 cstring_makeLiteral ("Multiple ARGSUSED comments for one function"),
105 static void reflectArgsUsed (uentry ue)
109 if (uentry_isFunction (ue))
111 uentryList params = uentry_getParams (ue);
113 uentryList_elements (params, el)
115 uentry_setUsed (el, fileloc_undefined);
116 } end_uentryList_elements ;
123 extern void setSpecialFunction (qual qu)
125 if (!qual_isUnknown (specialFunctionCode))
127 voptgenerror (FLG_SYNTAX,
128 message ("Multiple special function codes: %s, %s "
129 "(first code is ignored)",
130 qual_unparse (specialFunctionCode),
135 specialFunctionCode = qu;
138 static void reflectSpecialCode (uentry ue)
140 if (qual_isUnknown (specialFunctionCode)) {
142 } else if (qual_isPrintfLike (specialFunctionCode)) {
143 uentry_setPrintfLike (ue);
144 } else if (qual_isScanfLike (specialFunctionCode)) {
145 uentry_setScanfLike (ue);
146 } else if (qual_isMessageLike (specialFunctionCode)) {
147 uentry_setMessageLike (ue);
152 specialFunctionCode = qual_createUnknown ();
155 static void resetStorageClass (void)
157 qtype_free (processingType);
158 processingType = qtype_undefined;
159 storageClass = SCNONE;
162 static void reflectStorageClass (uentry u)
164 if (storageClass == SCSTATIC)
166 uentry_setStatic (u);
168 else if (storageClass == SCEXTERN)
170 uentry_setExtern (u);
174 ; /* no storage class */
181 saveStoreLoc = g_currentloc;
184 void setFunctionNoGlobals (void)
189 static void reflectGlobalQualifiers (sRef sr, qualList quals)
191 DPRINTF (("Reflect global qualifiers: %s / %s",
192 sRef_unparseFull (sr), qualList_unparse (quals)));
194 qualList_elements (quals, qel)
196 if (qual_isGlobalQual (qel)) /* undef, killed */
198 sstate oldstate = sRef_getDefState (sr);
199 sstate defstate = sstate_fromQual (qel);
201 if ((oldstate == SS_UNDEFGLOB && defstate == SS_KILLED)
202 || (oldstate == SS_KILLED && defstate == SS_UNDEFGLOB))
204 defstate = SS_UNDEFKILLED;
211 sRef_setDefState (sr, defstate, fileloc_undefined);
212 DPRINTF (("State: %s", sRef_unparseFull (sr)));
214 else if (qual_isAllocQual (qel)) /* out, partial, reldef, etc. */
216 ctype realType = sRef_getType (sr);
217 sstate defstate = sstate_fromQual (qel);
219 if (qual_isRelDef (qel))
221 ; /* okay anywhere */
225 if (!ctype_isAP (realType)
226 && !ctype_isSU (realType)
227 && !ctype_isUnknown (realType)
228 && !ctype_isAbstract (sRef_getType (sr)))
232 message ("Qualifier %s used on non-pointer or struct: %q",
233 qual_unparse (qel), sRef_unparse (sr)));
238 sRef_setDefState (sr, defstate, fileloc_undefined);
240 else if (qual_isNull (qel))
242 sRef_setNullState (sr, NS_POSNULL, fileloc_undefined);
244 else if (qual_isRelNull (qel))
246 sRef_setNullState (sr, NS_RELNULL, fileloc_undefined);
248 else if (qual_isNotNull (qel))
250 sRef_setNullState (sr, NS_MNOTNULL, fileloc_undefined);
254 if (qual_isCQual (qel))
261 message ("Qualifier %s cannot be used in a globals list",
262 qual_unparse (qel)));
265 } end_qualList_elements;
268 sRef clabstract_createGlobal (sRef sr, qualList quals)
272 if (sRef_isValid (sr))
274 res = sRef_copy (sr);
275 DPRINTF (("Reflecting quals: %s / %s", sRef_unparse (sr), qualList_unparse (quals)));
276 reflectGlobalQualifiers (res, quals);
277 DPRINTF (("==> %s", sRef_unparseFull (res)));
281 res = sRef_undefined;
284 qualList_free (quals);
288 extern void declareCIter (cstring name, /*@owned@*/ uentryList params)
292 ue = uentry_makeIter (name,
293 ctype_makeFunction (ctype_void, params),
294 fileloc_copy (g_currentloc));
296 usymtab_supEntry (uentry_makeEndIter (name, fileloc_copy (g_currentloc)));
297 ue = usymtab_supGlobalEntryReturn (ue);
300 extern void nextIterParam (void)
302 llassert (ProcessingIterVars);
306 extern int iterParamNo (void)
308 llassert (ProcessingIterVars);
309 return saveIterParamNo;
313 ** yucky hacks to put it in the right place
317 makeCurrentParam (idDecl t)
321 saveStoreLoc = fileloc_undefined;
323 /* param number unknown */
325 ue = uentry_makeParam (t, 0);
330 declareUnnamedEnum (enumNameList el)
332 ctype ret = usymtab_enumEnumNameListType (el);
336 if (ctype_isDefined (ret))
339 e = uentry_makeEnumTagLoc (ctype_enumTag (rt), ret);
341 reflectStorageClass (e);
342 usymtab_supGlobalEntry (e);
344 declareEnumList (el, ret, g_currentloc);
345 enumNameList_free (el);
349 ctype ct = ctype_createEnum (fakeTag (), el);
351 e = uentry_makeEnumTagLoc (ctype_enumTag (ctype_realType (ct)), ct);
352 reflectStorageClass (e);
354 e = usymtab_supGlobalEntryReturn (e);
355 rt = uentry_getAbstractType (e);
356 declareEnumList (el, ct, g_currentloc);
363 declareEnum (cstring ename, enumNameList el)
368 llassert (cstring_isDefined (ename));
370 cet = ctype_createEnum (ename, el);
371 e = uentry_makeEnumTagLoc (ename, cet);
372 reflectStorageClass (e);
373 e = usymtab_supGlobalEntryReturn (e);
374 cet = uentry_getType (e);
375 declareEnumList (el, cet, uentry_whereLast (e));
376 return (uentry_getAbstractType (e));
380 declareEnumList (enumNameList el, ctype c, fileloc loc)
382 bool boolnames = FALSE;
383 bool othernames = FALSE;
385 (void) context_getSaveLocation (); /* undefine it */
387 if (context_maybeSet (FLG_NUMENUMMEMBERS))
389 int maxnum = context_getValue (FLG_NUMENUMMEMBERS);
390 int num = enumNameList_size (el);
396 message ("Enumerator %s declared with %d members (limit is set to %d)",
397 ctype_unparse (c), num, maxnum),
402 enumNameList_elements (el, e)
404 uentry ue = usymtab_lookupExposeGlob (e);
405 ctype ct = uentry_getType (ue);
407 llassert (uentry_isEnumConstant (ue));
409 if (ctype_isUnknown (ct))
411 uentry_setType (ue, c);
415 if (cstring_equal (e, context_getFalseName ())
416 || cstring_equal (e, context_getTrueName ()))
422 message ("Enumerator mixes boolean name (%s) with "
425 uentry_whereLast (ue)))
432 uentry_setType (ue, ctype_bool);
433 DPRINTF (("Set type: %s / %s",
434 uentry_unparse (ue), ctype_unparse (ctype_bool)));
442 message ("Enumerator mixes boolean names (%s, %s) with "
443 "non-boolean name: %s",
444 context_getTrueName (),
445 context_getFalseName (),
447 uentry_whereLast (ue)))
456 if (!ctype_match (c, ct))
458 if (ctype_isDirectBool (ct))
460 if (cstring_equal (e, context_getFalseName ())
461 || cstring_equal (e, context_getTrueName ()))
463 DPRINTF (("Here we are!"));
469 message ("Enumerator member %s declared with "
470 "inconsistent type: %s",
471 e, ctype_unparse (c)),
472 uentry_whereLast (ue)))
474 uentry_showWhereSpecifiedExtra
475 (ue, cstring_copy (ctype_unparse (ct)));
483 message ("Enumerator member %s declared with "
484 "inconsistent type: %s",
485 e, ctype_unparse (c)),
486 uentry_whereLast (ue)))
488 uentry_showWhereSpecifiedExtra
489 (ue, cstring_copy (ctype_unparse (ct)));
494 } end_enumNameList_elements;
497 static /*@dependent@*/ uentryList currentParamList;
499 /*drl added 3-28-2001*/
500 /* this function takes a list of paramentar and generates a list
502 Currently the only constraints gnerated are MaxSet(p) >= 0 for all pointers
505 void setImplictfcnConstraints (void)
510 params = currentParamList;
512 if (constraintList_isDefined(implicitFcnConstraints) )
513 constraintList_free(implicitFcnConstraints);
515 implicitFcnConstraints = constraintList_makeNew();
517 uentryList_elements (params, el)
519 DPRINTF((message("setImplictfcnConstraints doing: %s", uentry_unparse(el) ) ));
521 s = uentry_getSref(el);
522 if (sRef_isReference (s) )
524 DPRINTF((message ("%s is a pointer", sRef_unparse(s) ) ));
528 DPRINTF((message ("%s is NOT a pointer", sRef_unparse(s) ) ));
531 chagned this is MaxSet(s) == 0 to MaxSet(s) >= 0 */
533 c = constraint_makeSRefWriteSafeInt (s, 0);
534 // constraint_makeSRefSetBufferSize (s, 0);
535 implicitFcnConstraints = constraintList_add(implicitFcnConstraints , c);
537 end_uentryList_elements;
541 /*@observer@*/ constraintList getImplicitFcnConstraints (void)
543 return implicitFcnConstraints;
546 void setCurrentParams (/*@dependent@*/ uentryList ue)
548 currentParamList = ue;
551 void clearCurrentParams (void)
553 currentParamList = uentryList_undefined;
557 ** requires: uentry_isFunction (e)
558 ** parameter names for current function are in currentParamList
561 static void enterFunctionParams (uentryList params)
565 uentryList_elements (params, current)
567 if (uentry_hasName (current))
569 uentry_setParamNo (current, paramno);
570 usymtab_supEntry (uentry_copy (current));
574 } end_uentryList_elements;
578 extern void enterParamsTemp (void)
580 usymtab_enterScope ();
581 enterFunctionParams (currentParamList);
584 extern void exitParamsTemp (void)
586 usymtab_quietPlainExitScope ();
589 static /*@exposed@*/ uentry clabstract_globalDeclareFunction (idDecl tid)
591 ctype deftype = idDecl_getCtype (tid);
595 DPRINTF (("Global function: %s", idDecl_unparse (tid)));
597 if (ctype_isFunction (deftype))
599 rettype = ctype_getReturnType (deftype);
603 rettype = ctype_unknown;
607 ** check has been moved here...
610 if (ctype_isFunction (idDecl_getCtype (tid)))
612 ue = uentry_makeIdFunction (tid);
613 reflectSpecialCode (ue);
614 reflectArgsUsed (ue);
618 llparseerror (message ("Inconsistent function declaration: %q",
619 idDecl_unparse (tid)));
621 tid = idDecl_replaceCtype
622 (tid, ctype_makeFunction (ctype_unknown, uentryList_undefined));
623 ue = uentry_makeIdFunction (tid);
626 reflectStorageClass (ue);
627 uentry_checkParams (ue);
629 DPRINTF (("Supercede function: %s", uentry_unparseFull (ue)));
631 ue = usymtab_supGlobalEntryReturn (ue);
632 DPRINTF (("After supercede function: %s", uentry_unparseFull (ue)));
634 context_enterFunction (ue);
635 enterFunctionParams (uentry_getParams (ue));
637 resetStorageClass ();
638 DPRINTF (("Function: %s", uentry_unparseFull (ue)));
643 ** for now, no type checking
644 ** (must check later though!)
647 static /*@only@*/ uentry globalDeclareOldStyleFunction (idDecl tid)
652 ** check has been moved here...
655 if (cstring_equalLit (idDecl_observeId (tid), "main"))
657 context_setFlagTemp (FLG_MAINTYPE, FALSE);
660 ue = uentry_makeIdFunction (tid);
661 reflectStorageClass (ue);
662 reflectSpecialCode (ue);
663 reflectArgsUsed (ue);
664 uentry_setDefined (ue, g_currentloc);
665 uentry_checkParams (ue);
666 resetStorageClass ();
670 static void oldStyleDeclareFunction (/*@only@*/ uentry e)
672 uentryList params = saveParamList;
673 ctype rt = uentry_getType (e);
675 llassert (ctype_isFunction (rt));
677 e = usymtab_supGlobalEntryReturn (e);
679 context_enterFunction (e);
680 enterFunctionParams (params);
681 saveParamList = uentryList_undefined;
682 resetStorageClass ();
685 void clabstract_declareFunction (idDecl tid) /*@globals undef saveFunction; @*/
689 DPRINTF (("Declare function: %s", idDecl_unparse (tid)));
691 if (ProcessingParams)
693 ue = globalDeclareOldStyleFunction (tid);
698 saveFunction = uentry_undefined;
700 if (context_inRealFunction ())
702 ue = uentry_makeVariableLoc (idDecl_observeId (tid), ctype_unknown);
704 llparseerror (message ("Function declared inside function: %q",
705 idDecl_unparse (tid)));
707 context_quietExitFunction ();
708 ue = usymtab_supEntryReturn (ue);
712 if (context_inInnerScope ())
714 llparseerror (message ("Declaration in inner context: %q",
715 idDecl_unparse (tid)));
717 sRef_setGlobalScope ();
718 ue = uentry_makeVariableLoc (idDecl_observeId (tid),
720 ue = usymtab_supGlobalEntryReturn (ue);
721 sRef_clearGlobalScope ();
725 ue = clabstract_globalDeclareFunction (tid);
732 resetStorageClass ();
736 void declareStaticFunction (idDecl tid) /*@globals undef saveFunction; @*/
740 DPRINTF (("Declare static funciton: %s", idDecl_unparse (tid)));
742 if (ProcessingParams)
744 ue = globalDeclareOldStyleFunction (tid);
749 saveFunction = uentry_undefined;
751 if (context_inRealFunction ())
753 ue = uentry_makeVariableLoc (idDecl_observeId (tid), ctype_unknown);
755 llparseerror (message ("Function declared inside function: %q",
756 idDecl_unparse (tid)));
758 context_quietExitFunction ();
759 ue = usymtab_supEntryReturn (ue);
763 if (context_inInnerScope ())
765 llparseerror (message ("Declaration in inner context: %q",
766 idDecl_unparse (tid)));
768 sRef_setGlobalScope ();
769 ue = uentry_makeVariableLoc (idDecl_observeId (tid),
771 ue = usymtab_supGlobalEntryReturn (ue);
772 sRef_clearGlobalScope ();
776 ctype deftype = idDecl_getCtype (tid);
779 if (ctype_isFunction (deftype))
781 rettype = ctype_getReturnType (deftype);
785 rettype = ctype_unknown;
789 ** check has been moved here...
792 if (ctype_isFunction (idDecl_getCtype (tid)))
794 ue = uentry_makeIdFunction (tid);
795 reflectSpecialCode (ue);
796 reflectArgsUsed (ue);
800 llparseerror (message ("Inconsistent function declaration: %q",
801 idDecl_unparse (tid)));
803 tid = idDecl_replaceCtype
804 (tid, ctype_makeFunction (ctype_unknown, uentryList_undefined));
805 ue = uentry_makeIdFunction (tid);
808 reflectStorageClass (ue);
809 uentry_setStatic (ue);
811 uentry_checkParams (ue);
813 DPRINTF (("Sub global entry: %s", uentry_unparse (ue)));
814 ue = usymtab_supGlobalEntryReturn (ue);
816 context_enterFunction (ue);
817 enterFunctionParams (uentry_getParams (ue));
818 resetStorageClass ();
825 resetStorageClass ();
830 checkTypeDecl (uentry e, ctype rep)
832 cstring n = uentry_getName (e);
834 DPRINTF (("Check type decl: %s", uentry_unparseFull (e)));
836 if (cstring_equal (context_getBoolName (), n))
838 ctype rrep = ctype_realType (rep);
841 ** for abstract enum types, we need to fix the enum members:
842 ** they should have the abstract type, not the rep type.
845 if (ctype_isEnum (ctype_realType (rrep)))
847 enumNameList el = ctype_elist (rrep);
849 enumNameList_elements (el, ye)
851 if (usymtab_existsGlob (ye))
853 uentry ue = usymtab_lookupSafe (ye);
854 uentry_setType (ue, ctype_bool);
857 if (cstring_equal (context_getTrueName (), ye)
858 || cstring_equal (context_getFalseName (), ye))
866 message ("Member of boolean enumerated type definition "
867 "does not match name set to represent TRUE "
870 message ("Use -boolfalse and -booltrue to set the "
871 "name of false and true boolean values."),
872 uentry_whereDefined (e));
874 } end_enumNameList_elements;
878 if (usymtab_exists (n))
880 usymId llm = usymtab_getId (n);
881 uentry le = usymtab_getTypeEntry (llm);
883 uentry_setDeclared (e, g_currentloc);
884 uentry_setSref (e, sRef_makeGlobal (llm, uentry_getType (le)));
886 DPRINTF (("Here we are: %s / %s",
887 n, context_getBoolName ()));
889 if (uentry_isAbstractDatatype (le))
891 ctype rrep = ctype_realType (rep);
893 DPRINTF (("Abstract type: %s", uentry_unparseFull (le)));
896 ** for abstract enum types, we need to fix the enum members:
897 ** they should have the abstract type, not the rep type.
900 if (ctype_isEnum (ctype_realType (rrep)))
902 ctype at = uentry_getAbstractType (le);
903 enumNameList el = ctype_elist (rrep);
905 enumNameList_elements (el, ye)
907 if (usymtab_existsGlob (ye))
909 uentry ue = usymtab_lookupSafe (ye);
911 llassert (uentry_isEitherConstant (ue));
912 llassertprint (ctype_match (uentry_getType (ue), rrep),
913 ("Bad enum: %s / %s",
915 ctype_unparse (rrep)));
917 uentry_setType (ue, at);
919 } end_enumNameList_elements;
922 if (uentry_isMutableDatatype (le))
924 /* maybe more complicated if abstract and immutable ? */
926 if (!ctype_isRealPointer (rep) && !ctype_isRealAbstract (rep))
930 message ("Mutable abstract type %s declared without pointer "
931 "indirection: %s (violates assignment semantics)",
932 n, ctype_unparse (rep)),
933 uentry_whereDefined (e));
935 uentry_setMutable (e);
942 fileloc fl = uentry_whereDeclared (e);
944 if (context_getFlag (FLG_LIKELYBOOL)
945 && !context_getFlag (FLG_BOOLINT))
947 if ((cstring_equalLit (n, "BOOL")
948 || cstring_equalLit (n, "Bool")
949 || cstring_equalLit (n, "bool")
950 || cstring_equalLit (n, "boolean")
951 || cstring_equalLit (n, "Boolean")
952 || cstring_equalLit (n, "BOOLEAN"))
953 && !(cstring_equal (n, context_getBoolName ())))
955 if (context_setBoolName ()) {
958 message ("Type %s is probably meant as a boolean type, but does "
959 "not match the boolean type name \"%s\".",
961 context_getBoolName ()),
966 message ("Type %s is probably meant as a boolean type, "
967 "but the boolean type name is not set. "
968 "Use -booltype %s to set it.",
975 if (!uentry_isStatic (e)
976 && !ctype_isFunction (uentry_getType (e))
977 && !fileloc_isLib (fl)
978 && !fileloc_isImport (fl)
979 && fileloc_isHeader (fl))
981 voptgenerror (FLG_EXPORTTYPE,
982 message ("Type exported, but not specified: %s\n", n),
991 fixUentryList (idDeclList tl, qtype q)
993 uentryList f = uentryList_new ();
995 idDeclList_elements (tl, i)
997 if (idDecl_isDefined (i))
1003 (void) idDecl_fixBase (i, q);
1006 ** implicit annotations
1009 (void) fixStructDecl (i);
1011 ue = uentry_makeIdVariable (i);
1012 rt = ctype_realType (uentry_getType (ue));
1015 ** where is this here???
1017 if (ctype_isArray (rt) || ctype_isSU (rt))
1019 sRef_setAllocated (uentry_getSref (ue), uentry_whereDefined (ue));
1025 if (uentry_isValid (old = uentryList_lookupField (f, uentry_rawName (ue))))
1027 if (optgenerror (FLG_SYNTAX,
1028 message ("Field name reused: %s", uentry_rawName (ue)),
1029 uentry_whereDefined (ue)))
1031 llgenmsg (message ("Previous use of %s", uentry_rawName (ue)),
1032 uentry_whereDefined (old));
1036 f = uentryList_add (f, ue);
1038 } end_idDeclList_elements;
1040 idDeclList_free (tl);
1045 ** This is a hack to support unnamed struct/union fields as done by
1046 ** Microsoft VC++. It is not supported by the ANSI standard.
1048 ** The inner fields are added to the outer structure. This is meaningful
1049 ** for nesting structs inside unions, but lclint does no related
1054 fixUnnamedDecl (qtype q)
1056 ctype ct = ctype_realType (qtype_getType (q));
1058 if (ctype_isStruct (ct) || ctype_isUnion (ct))
1060 uentryList res = ctype_getFields (ct);
1062 return (uentryList_copy (res));
1069 return uentryList_undefined;
1072 void setStorageClass (storageClassCode sc)
1078 setProcessingIterVars (uentry iter)
1080 ProcessingIterVars = TRUE;
1082 saveIterParamNo = 0;
1086 setProcessingGlobalsList ()
1088 ProcessingGlobals = TRUE;
1089 fcnNoGlobals = FALSE;
1092 static bool ProcessingGlobMods = FALSE;
1095 setProcessingGlobMods ()
1097 ProcessingGlobMods = TRUE;
1101 clearProcessingGlobMods ()
1103 ProcessingGlobMods = FALSE;
1107 isProcessingGlobMods ()
1109 return (ProcessingGlobMods);
1112 static void resetGlobals (void)
1114 ProcessingGlobals = FALSE;
1115 fcnNoGlobals = FALSE;
1119 unsetProcessingGlobals ()
1121 ProcessingGlobals = FALSE;
1125 setProcessingVars (/*@only@*/ qtype q)
1127 ProcessingVars = TRUE;
1128 qtype_free (processingType);
1133 setGenericParamList (/*@dependent@*/ uentryList pm)
1135 ProcessingParams = TRUE;
1140 setProcessingTypedef (/*@only@*/ qtype q)
1142 ProcessingTypedef = TRUE;
1144 qtype_free (processingType);
1149 unsetProcessingVars ()
1151 resetStorageClass ();
1152 ProcessingVars = FALSE;
1158 if (ProcessingParams)
1160 if (uentry_isInvalid (saveFunction))
1162 llbuglit ("unsetProcessingVars: no saved function\n");
1166 ctype ct = ctype_getReturnType (uentry_getType (saveFunction));
1167 uentryList params = uentryList_copy (saveParamList);
1168 ctype ct2 = ctype_makeFunction (ct, params);
1170 uentry_setType (saveFunction, ct2);
1171 ProcessingParams = FALSE;
1173 oldStyleDeclareFunction (saveFunction);
1174 saveFunction = uentry_undefined;
1181 ** If the paramlist used a type name, we could be here.
1184 llfatalerror (message ("%q: Old-style function parameter list uses a "
1185 "type name.", fileloc_unparse (g_currentloc)));
1192 if (uentry_isValid (saveFunction))
1195 ** old style declaration
1198 ctype ct = ctype_getReturnType (uentry_getType (saveFunction));
1201 uentryList_elements (saveParamList, current)
1203 uentry_setType (current, ctype_int); /* all params are ints */
1204 } end_uentryList_elements;
1206 ct2 = ctype_makeParamsFunction (ct, uentryList_copy (saveParamList));
1208 uentry_setType (saveFunction, ct2);
1209 ProcessingParams = FALSE;
1211 oldStyleDeclareFunction (saveFunction);
1212 saveFunction = uentry_undefined;
1217 unsetProcessingTypedef ()
1219 ProcessingTypedef = FALSE;
1222 void checkConstant (qtype t, idDecl id)
1226 id = idDecl_fixBase (id, t);
1227 e = uentry_makeIdConstant (id);
1229 reflectStorageClass (e);
1230 resetStorageClass ();
1232 usymtab_supGlobalEntry (e);
1235 void checkValueConstant (qtype t, idDecl id, exprNode e)
1239 id = idDecl_fixBase (id, t);
1240 ue = uentry_makeIdConstant (id);
1241 reflectStorageClass (ue);
1242 resetStorageClass ();
1244 if (exprNode_isDefined (e))
1246 if (!exprNode_matchType (uentry_getType (ue), e))
1249 (exprNode_getType (e), e,
1250 uentry_getType (ue), exprNode_undefined,
1251 message ("Constant %q initialized to type %t, expects %t: %s",
1252 uentry_getName (ue),
1253 exprNode_getType (e),
1254 uentry_getType (ue),
1255 exprNode_unparse (e)),
1260 if (exprNode_hasValue (e))
1262 uentry_mergeConstantValue (ue, multiVal_copy (exprNode_getValue (e)));
1267 usymtab_supGlobalEntry (ue);
1270 void processNamedDecl (idDecl t)
1272 if (qtype_isUndefined (processingType))
1274 llparseerror (message ("No type before declaration name: %q", idDecl_unparse (t)));
1276 processingType = qtype_create (ctype_unknown);
1279 t = idDecl_fixBase (t, processingType);
1281 DPRINTF (("Declare: %s", idDecl_unparse (t)));
1283 if (ProcessingGlobals)
1285 cstring id = idDecl_getName (t);
1286 uentry ue = usymtab_lookupSafe (id);
1288 if (!uentry_isValid (ue))
1290 llerror (FLG_UNRECOG,
1291 message ("Variable used in globals list is undeclared: %s", id));
1295 if (!ctype_match (uentry_getType (ue), idDecl_getCtype (t)))
1299 message ("Variable %s used in globals list declared %s, "
1301 id, ctype_unparse (uentry_getType (ue)),
1302 ctype_unparse (idDecl_getCtype (t))),
1307 sRef sr = sRef_copy (uentry_getSref (ue));
1308 reflectGlobalQualifiers (sr, idDecl_getQuals (t));
1312 else if (ProcessingVars)
1317 ct = ctype_realType (idDecl_getCtype (t));
1319 if (ProcessingParams)
1321 cstring id = idDecl_getName (t);
1322 int paramno = uentryList_lookupRealName (saveParamList, id);
1326 uentry cparam = uentryList_getN (saveParamList, paramno);
1328 uentry_setType (cparam, idDecl_getCtype (t));
1329 uentry_reflectQualifiers (cparam, idDecl_getQuals (t));
1330 uentry_setDeclaredOnly (cparam, context_getSaveLocation ());
1335 (message ("Old style declaration uses unlisted parameter: %s",
1343 if (context_inIterDef ())
1345 cstring pname = makeParam (idDecl_observeId (t));
1346 uentry p = usymtab_lookupSafe (pname);
1348 cstring_free (pname);
1350 if (uentry_isYield (p))
1352 e = uentry_makeParam (t, sRef_getParam (uentry_getSref (p)));
1353 uentry_checkYieldParam (p, e);
1354 usymtab_supEntrySref (e);
1359 if ((hasSpecialCode () || argsUsed)
1360 && ctype_isFunction (idDecl_getCtype (t)))
1362 e = uentry_makeIdFunction (t);
1363 reflectSpecialCode (e);
1364 reflectArgsUsed (e);
1368 e = uentry_makeIdVariable (t);
1371 loc = uentry_whereDeclared (e);
1374 if (context_inGlobalScope ())
1376 uentry_checkParams was here!
1380 if (ctype_isFunction (uentry_getType (e)))
1382 clabstract_prepareFunction (e);
1385 DPRINTF (("Superceding... %s", uentry_unparseFull (e)));
1386 e = usymtab_supEntrySrefReturn (e);
1387 DPRINTF (("After superceding... %s", uentry_unparseFull (e)));
1389 if (uentry_isExtern (e) && !context_inGlobalScope ())
1393 message ("Declaration using extern inside function scope: %q",
1394 uentry_unparse (e)),
1397 uentry_setDefined (e, fileloc_getExternal ());
1398 sRef_setDefined (uentry_getSref (e), fileloc_getExternal ());
1401 if (uentry_isFunction (e))
1403 if (!context_inXHFile ())
1405 checkParamNames (e);
1409 if (uentry_isVar (e) && uentry_isCheckedUnknown (e))
1411 sRef sr = uentry_getSref (e);
1413 if (sRef_isLocalVar (sr))
1415 if (context_getFlag (FLG_IMPCHECKMODINTERNALS))
1417 uentry_setCheckMod (e);
1421 uentry_setUnchecked (e);
1424 else if (sRef_isFileStatic (sr))
1426 if (context_getFlag (FLG_IMPCHECKEDSTRICTSTATICS))
1428 uentry_setCheckedStrict (e);
1430 else if (context_getFlag (FLG_IMPCHECKEDSTATICS))
1432 uentry_setChecked (e);
1434 else if (context_getFlag (FLG_IMPCHECKMODSTATICS))
1436 uentry_setCheckMod (e);
1443 else /* real global */
1445 llassert (sRef_isRealGlobal (sr));
1447 if (context_getFlag (FLG_IMPCHECKEDSTRICTGLOBALS))
1449 uentry_setCheckedStrict (e);
1451 else if (context_getFlag (FLG_IMPCHECKEDGLOBALS))
1453 uentry_setChecked (e);
1455 else if (context_getFlag (FLG_IMPCHECKMODGLOBALS))
1457 uentry_setCheckMod (e);
1467 else if (ProcessingTypedef)
1469 ctype ct = idDecl_getCtype (t);
1472 DPRINTF (("Processing typedef: %s", ctype_unparse (ct)));
1474 e = uentry_makeIdDatatype (t);
1476 if (cstring_equal (idDecl_getName (t), context_getBoolName ())) {
1477 ctype rt = ctype_realType (ct);
1479 if (ctype_isEnum (rt)) {
1482 if (!(ctype_isInt (rt)
1483 || ctype_isUnknown (rt)
1484 || ctype_isChar (rt))) {
1487 message ("Boolean type %s defined using non-standard type %s (integral, char or enum type expected)",
1488 context_getBoolName (),
1489 ctype_unparse (ct)),
1490 uentry_whereLast (e));
1494 uentry_setType (e, ct);
1498 reflectStorageClass (e);
1499 checkTypeDecl (e, ct);
1501 e = usymtab_supReturnTypeEntry (e);
1505 llparseerror (message ("Suspect missing struct or union keyword: %q",
1506 idDecl_unparse (t)));
1512 ** moved from grammar
1515 static idDecl fixStructDecl (/*@returned@*/ idDecl d)
1517 if (ctype_isVisiblySharable (idDecl_getCtype (d))
1518 && context_getFlag (FLG_STRUCTIMPONLY))
1520 if (!qualList_hasAliasQualifier (idDecl_getQuals (d)))
1522 if (qualList_hasExposureQualifier (idDecl_getQuals (d)))
1524 idDecl_addQual (d, qual_createDependent ());
1528 idDecl_addQual (d, qual_createImpOnly ());
1537 declareUnnamedStruct (/*@only@*/ uentryList f)
1539 DPRINTF (("Unnamed struct: %s", uentryList_unparse (f)));
1541 if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1543 int num = uentryList_size (f);
1544 int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1549 (FLG_NUMSTRUCTFIELDS,
1550 message ("Structure declared with %d fields "
1551 "(limit is set to %d)",
1557 return (ctype_createUnnamedStruct (f));
1561 declareUnnamedUnion (/*@only@*/ uentryList f)
1563 if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1565 int num = uentryList_size (f);
1566 int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1571 (FLG_NUMSTRUCTFIELDS,
1572 message ("Union declared with %d fields "
1573 "(limit is set to %d)",
1579 return (ctype_createUnnamedUnion (f));
1582 ctype declareStruct (cstring id, /*@only@*/ uentryList f)
1586 int num = uentryList_size (f);
1588 DPRINTF (("Declare struct: %s / %s", id, uentryList_unparse (f)));
1590 ct = ctype_createStruct (cstring_copy (id), f);
1592 DPRINTF (("Ctype: %s", ctype_unparse (ct)));
1594 ue = uentry_makeStructTagLoc (id, ct);
1596 DPRINTF (("ue: %s", uentry_unparseFull (ue)));
1598 if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1600 int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1605 (FLG_NUMSTRUCTFIELDS,
1606 message ("Structure %q declared with %d fields "
1607 "(limit is set to %d)",
1608 uentry_getName (ue), num, max),
1609 uentry_whereLast (ue));
1613 return (usymtab_supTypeEntry (ue));
1616 ctype declareUnion (cstring id, uentryList f)
1620 int num = uentryList_size (f);
1622 ct = ctype_createUnion (cstring_copy (id), f);
1623 ue = uentry_makeUnionTagLoc (id, ct);
1625 if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1627 int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1632 (FLG_NUMSTRUCTFIELDS,
1633 message ("Union %q declared with %d fields "
1634 "(limit is set to %d)",
1635 uentry_getName (ue), num, max),
1636 uentry_whereLast (ue));
1640 return (usymtab_supTypeEntry (ue));
1643 ctype handleStruct (/*@only@*/ cstring id)
1645 if (usymtab_existsStructTag (id))
1647 ctype ct = uentry_getAbstractType (usymtab_lookupStructTag (id));
1654 return (ctype_createForwardStruct (id));
1658 ctype handleUnion (/*@only@*/ cstring id)
1660 if (usymtab_existsUnionTag (id))
1662 ctype ret = uentry_getAbstractType (usymtab_lookupUnionTag (id));
1668 return (ctype_createForwardUnion (id));
1673 handleEnum (cstring id)
1675 if (usymtab_existsEnumTag (id))
1677 ctype ret = uentry_getAbstractType (usymtab_lookupEnumTag (id));
1683 return (declareEnum (id, enumNameList_new ()));
1687 bool processingIterVars (void)
1689 return ProcessingIterVars;
1692 uentry getCurrentIter (void)
1697 static bool flipOldStyle = FALSE;
1698 static bool flipNewStyle = TRUE;
1700 void setFlipOldStyle () { flipOldStyle = TRUE; }
1701 bool isFlipOldStyle () { return flipOldStyle; }
1702 bool isNewStyle () { return flipNewStyle; }
1703 void setNewStyle () { flipNewStyle = TRUE; }
1705 /*@dependent@*/ uentryList handleParamIdList (/*@dependent@*/ uentryList params)
1710 ** this is a really YUCKY hack to handle old style
1714 voptgenerror (FLG_OLDSTYLE,
1715 cstring_makeLiteral ("Old style function declaration"),
1718 uentryList_elements (params, current)
1720 uentry_setParam (current);
1721 uentry_setSref (current, sRef_makeParam (paramno, ctype_unknown));
1723 } end_uentryList_elements;
1725 setGenericParamList (params);
1726 g_expectingTypeName = TRUE;
1731 /*@dependent@*/ uentryList handleParamTypeList (/*@returned@*/ uentryList params)
1735 uentryList_fixMissingNames (params);
1737 voptgenerror (FLG_OLDSTYLE,
1738 cstring_makeLiteral ("Old style function declaration."),
1741 setGenericParamList (params);
1742 flipOldStyle = FALSE;
1743 g_expectingTypeName = TRUE;
1752 ctype c = ctype_unknown;
1753 cstring id = cstring_makeLiteral ("va_alist");
1756 if (ProcessingParams)
1758 int i = uentryList_lookupRealName (saveParamList, id);
1762 e = uentry_makeVariableSrefParam (id, c, sRef_makeParam (i, c));
1766 e = uentry_undefined; /* suppress gcc message */
1767 llfatalerrorLoc (cstring_makeLiteral ("va_dcl used without va_alist"));
1772 llerror (FLG_SYNTAX, cstring_makeLiteral ("va_dcl used outside of function declaration"));
1773 e = uentry_makeVariableLoc (id, c);
1777 uentry_setUsed (e, g_currentloc);
1778 usymtab_supEntrySref (e);
1781 /*@exposed@*/ sRef modListPointer (/*@exposed@*/ sRef s)
1783 ctype ct = sRef_getType (s);
1784 ctype rt = ctype_realType (ct);
1786 if (ctype_isAP (rt))
1788 if (context_inHeader () && ctype_isAbstract (ct))
1793 ("Modifies clause in header file dereferences abstract "
1794 "type %s (interface modifies clause should not depend "
1795 "on or expose type representation): %q",
1801 return (sRef_constructPointer (s));
1805 if (ctype_isKnown (rt))
1809 message ("Implementation modifies clause dereferences non-pointer (type %s): %q",
1819 /*@exposed@*/ sRef modListFieldAccess (sRef s, cstring f)
1821 ctype ct = sRef_getType (s);
1822 ctype rt = ctype_realType (ct);
1824 if (ctype_isStructorUnion (rt))
1826 uentry tf = uentryList_lookupField (ctype_getFields (rt), f);
1828 if (uentry_isUndefined (tf))
1830 voptgenerror (FLG_TYPE,
1831 message ("Modifies list accesses non-existent "
1832 "field %s of %t: %q", f, ct,
1837 return sRef_undefined;
1841 if (ctype_isAbstract (ct) && context_inHeader ())
1846 ("Modifies clause in header file accesses abstract "
1847 "type %s (interface modifies clause should not depend "
1848 "on or expose type representation): %q",
1855 cstring_markOwned (f);
1856 return (sRef_makeField (s, f));
1862 message ("Modifies clause dereferences non-pointer (type %s): %q",
1872 /*@dependent@*/ sRef clabstract_unrecognizedGlobal (cstring s)
1874 if (cstring_equalLit (s, "nothing"))
1876 return sRef_makeNothing ();
1878 else if (cstring_equalLit (s, "internalState"))
1880 return sRef_makeInternalState ();
1882 else if (cstring_equalLit (s, "fileSystem")
1883 || cstring_equalLit (s, "systemState"))
1885 return sRef_makeSystemState ();
1891 message ("Unrecognized identifier in globals list: %s", s),
1894 return sRef_undefined;
1898 /*@exposed@*/ sRef modListArrowAccess (sRef s, cstring f)
1900 ctype ct = sRef_getType (s);
1901 ctype rt = ctype_realType (ct);
1903 if (ctype_isRealPointer (rt))
1905 ctype b = ctype_baseArrayPtr (rt);
1906 ctype rb = ctype_realType (b);
1908 if (ctype_isStructorUnion (rb))
1910 uentry tf = uentryList_lookupField (ctype_getFields (rb), f);
1912 if (uentry_isUndefined (tf))
1914 voptgenerror (FLG_TYPE,
1915 message ("Modifies list arrow accesses non-existent "
1916 "field %s of %t: %q", f, b,
1921 return sRef_undefined;
1925 if (context_inHeader ())
1927 if (ctype_isAbstract (b))
1932 ("Modifies clause in header file arrow accesses abstract "
1933 "type %s (interface modifies clause should not depend "
1934 "on or expose type representation): %q",
1942 if (ctype_isAbstract (ct))
1947 ("Modifies clause in header file arrow accesses abstract "
1948 "type %s (interface modifies clause should not depend "
1949 "on or expose type representation): %q",
1957 cstring_markOwned (f);
1958 return (sRef_makeArrow (s, f));
1964 message ("Modifies clause arrow accesses pointer to "
1965 "non-structure (type %s): %q",
1975 message ("Modifies clause arrow accesses non-pointer (type %s): %q",
1985 sRef checkStateClausesId (uentry ue)
1987 cstring s = uentry_rawName (ue);
1989 if (sRef_isFileOrGlobalScope (uentry_getSref (ue)))
1993 message ("Global variable %s used special clause. (Global variables "
1994 "are not recognized in special clauses. If there is "
1995 "sufficient interest in support for this, it may be "
1996 "added to a future release. Send mail to "
1997 "lclint@cs.virginia.edu.)",
2001 return sRef_undefined;
2005 if (cstring_equalLit (s, "result"))
2009 message ("Special clause list uses %s which is a variable and has special "
2010 "meaning in a modifies list. (Special meaning assumed.)", s),
2013 uentry_showWhereDeclared (ue);
2017 return uentry_getSref (ue);
2023 don;t know what the real date is...
2029 based on checkSpecClausesId
2033 sRef checkbufferConstraintClausesId (uentry ue)
2035 cstring s = uentry_rawName (ue);
2037 if (cstring_equalLit (s, "result"))
2041 message ("Function clause list uses %s which is a variable and has special "
2042 "meaning in a modifies list. (Special meaning assumed.)", s),
2045 uentry_showWhereDeclared (ue);
2049 return sRef_saveCopy (uentry_getSref (ue)); /*@i523 why the saveCopy? */
2052 void checkModifiesId (uentry ue)
2054 cstring s = uentry_rawName (ue);
2056 if (cstring_equalLit (s, "nothing")
2057 || cstring_equalLit (s, "internalState")
2058 || cstring_equalLit (s, "systemState")
2059 || (cstring_equalLit (s, "fileSystem")))
2063 message ("Modifies list uses %s which is a variable and has special "
2064 "meaning in a modifies list. (Special meaning assumed.)", s),
2067 uentry_showWhereDeclared (ue);
2072 /*@exposed@*/ sRef fixModifiesId (cstring s)
2075 cstring pname = makeParam (s);
2076 uentry ue = usymtab_lookupSafe (pname);
2078 cstring_free (pname);
2080 if (cstring_equalLit (s, "nothing"))
2082 ret = sRef_makeNothing ();
2084 else if (cstring_equalLit (s, "internalState"))
2086 ret = sRef_makeInternalState ();
2088 else if (cstring_equalLit (s, "fileSystem")
2089 || cstring_equalLit (s, "systemState"))
2091 ret = sRef_makeSystemState ();
2095 ret = sRef_undefined;
2098 if (sRef_isValid (ret))
2100 if (uentry_isValid (ue))
2104 message ("Modifies list uses %s which is a parameter and has special "
2105 "meaning in a modifies list. (Special meaning assumed.)", s),
2111 if (uentry_isValid (ue))
2113 ret = uentry_getSref (ue);
2117 fileloc loc = fileloc_decColumn (g_currentloc, cstring_length (s));
2118 ret = sRef_undefined;
2122 message ("Unrecognized identifier in modifies comment: %s", s),
2132 sRef fixStateClausesId (cstring s)
2135 cstring pname = makeParam (s);
2136 uentry ue = usymtab_lookupSafe (pname);
2138 cstring_free (pname);
2140 if (cstring_equalLit (s, "result"))
2142 ret = sRef_makeResult ();
2146 ret = sRef_undefined;
2149 if (sRef_isValid (ret))
2151 if (uentry_isValid (ue))
2155 message ("Function clause uses %s which is a parameter and has special "
2156 "meaning in a function clause. (Special meaning assumed.)", s),
2162 if (uentry_isValid (ue))
2164 ret = uentry_getSref (ue);
2166 if (sRef_isFileOrGlobalScope (ret))
2170 message ("Global variable %s used in function clause. (Global variables "
2171 "are not recognized in function clauses. If there is "
2172 "sufficient interest in support for this, it may be "
2173 "added to a future release. Send mail to "
2174 "lclint@cs.virginia.edu.)",
2178 ret = sRef_undefined;
2183 fileloc loc = fileloc_decColumn (g_currentloc, cstring_length (s));
2184 ret = sRef_undefined;
2188 message ("Unrecognized identifier in function clause: %s", s),
2198 sRef modListArrayFetch (/*@exposed@*/ sRef s, /*@unused@*/ sRef mexp)
2200 ctype ct = sRef_getType (s);
2201 ctype rt = ctype_realType (ct);
2203 if (ctype_isAP (rt))
2205 if (context_inHeader () && ctype_isAbstract (ct))
2210 ("Modifies clause in header file indexes abstract "
2211 "type %s (interface modifies clause should not depend "
2212 "on or expose type representation): %q",
2218 return (sRef_makeAnyArrayFetch (s));
2225 ("Implementation modifies clause uses array fetch on non-array (type %s): %q",
2226 ctype_unparse (ct), sRef_unparse (s)),
2232 static void clabstract_prepareFunction (uentry e)
2234 uentry_checkParams (e);
2235 DPRINTF (("After prepare: %s", uentry_unparseFull (e)));
2238 sRef clabstract_checkGlobal (exprNode e)
2241 llassert (exprNode_isInitializer (e));
2243 s = exprNode_getSref (e);
2244 DPRINTF (("Initializer: %s -> %s", exprNode_unparse (e), sRef_unparse (s)));
2247 return sRef_copy (s);