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 /*@only@*/ static constraintList fcnConstraints = NULL;
60 static /*@only@*/ constraintList implicitFcnConstraints = NULL;
63 //static constraintList fcnPreConditions = NULL;
65 static void clabstract_prepareFunction (uentry p_e) /*@modifies p_e@*/ ;
66 static bool fcnNoGlobals = FALSE;
67 static bool ProcessingVars = FALSE;
68 static bool ProcessingParams = FALSE;
69 static bool ProcessingGlobals = FALSE;
70 static bool ProcessingTypedef = FALSE;
71 static bool ProcessingIterVars = FALSE;
72 static /*@only@*/ qtype processingType = qtype_undefined;
73 static uentry currentIter = uentry_undefined;
74 static /*@dependent@*/ uentryList saveParamList; /* for old style functions */
75 static /*@owned@*/ uentry saveFunction = uentry_undefined;
76 static int saveIterParamNo;
77 static idDecl fixStructDecl (/*@returned@*/ idDecl p_d);
78 static void checkTypeDecl (uentry p_e, ctype p_rep);
79 static /*@dependent@*/ fileloc saveStoreLoc = fileloc_undefined;
80 static storageClassCode storageClass = SCNONE;
81 static void declareEnumList (/*@temp@*/ enumNameList p_el, ctype p_c, fileloc p_loc);
82 static void resetGlobals (void);
83 static /*@null@*/ qual specialFunctionCode;
84 static bool argsUsed = FALSE;
86 extern void clabstract_initMod ()
88 specialFunctionCode = qual_createUnknown ();
89 DPRINTF (("Initialized: %s", qual_unparse (specialFunctionCode)));
92 static bool hasSpecialCode (void)
94 return (!qual_isUnknown (specialFunctionCode));
97 extern void setArgsUsed (void)
103 cstring_makeLiteral ("Multiple ARGSUSED comments for one function"),
110 static void reflectArgsUsed (uentry ue)
114 if (uentry_isFunction (ue))
116 uentryList params = uentry_getParams (ue);
118 uentryList_elements (params, el)
120 uentry_setUsed (el, fileloc_undefined);
121 } end_uentryList_elements ;
128 extern void setSpecialFunction (qual qu)
130 if (!qual_isUnknown (specialFunctionCode))
132 voptgenerror (FLG_SYNTAX,
133 message ("Multiple special function codes: %s, %s "
134 "(first code is ignored)",
135 qual_unparse (specialFunctionCode),
140 specialFunctionCode = qu;
143 static void reflectSpecialCode (uentry ue)
145 if (qual_isUnknown (specialFunctionCode)) {
147 } else if (qual_isPrintfLike (specialFunctionCode)) {
148 uentry_setPrintfLike (ue);
149 } else if (qual_isScanfLike (specialFunctionCode)) {
150 uentry_setScanfLike (ue);
151 } else if (qual_isMessageLike (specialFunctionCode)) {
152 uentry_setMessageLike (ue);
157 specialFunctionCode = qual_createUnknown ();
160 static void resetStorageClass (void)
162 qtype_free (processingType);
163 processingType = qtype_undefined;
164 storageClass = SCNONE;
167 static void reflectStorageClass (uentry u)
169 if (storageClass == SCSTATIC)
171 uentry_setStatic (u);
173 else if (storageClass == SCEXTERN)
175 uentry_setExtern (u);
179 ; /* no storage class */
186 saveStoreLoc = g_currentloc;
189 void setFunctionNoGlobals (void)
194 static void reflectGlobalQualifiers (sRef sr, qualList quals)
196 DPRINTF (("Reflect global qualifiers: %s / %s",
197 sRef_unparseFull (sr), qualList_unparse (quals)));
199 qualList_elements (quals, qel)
201 if (qual_isGlobalQual (qel)) /* undef, killed */
203 sstate oldstate = sRef_getDefState (sr);
204 sstate defstate = sstate_fromQual (qel);
206 if ((oldstate == SS_UNDEFGLOB && defstate == SS_KILLED)
207 || (oldstate == SS_KILLED && defstate == SS_UNDEFGLOB))
209 defstate = SS_UNDEFKILLED;
216 sRef_setDefState (sr, defstate, fileloc_undefined);
217 DPRINTF (("State: %s", sRef_unparseFull (sr)));
219 else if (qual_isAllocQual (qel)) /* out, partial, reldef, etc. */
221 ctype realType = sRef_getType (sr);
222 sstate defstate = sstate_fromQual (qel);
224 if (qual_isRelDef (qel))
226 ; /* okay anywhere */
230 if (!ctype_isAP (realType)
231 && !ctype_isSU (realType)
232 && !ctype_isUnknown (realType)
233 && !ctype_isAbstract (sRef_getType (sr)))
237 message ("Qualifier %s used on non-pointer or struct: %q",
238 qual_unparse (qel), sRef_unparse (sr)));
243 sRef_setDefState (sr, defstate, fileloc_undefined);
245 else if (qual_isNull (qel))
247 sRef_setNullState (sr, NS_POSNULL, fileloc_undefined);
249 else if (qual_isRelNull (qel))
251 sRef_setNullState (sr, NS_RELNULL, fileloc_undefined);
253 else if (qual_isNotNull (qel))
255 sRef_setNullState (sr, NS_MNOTNULL, fileloc_undefined);
259 if (qual_isCQual (qel))
266 message ("Qualifier %s cannot be used in a globals list",
267 qual_unparse (qel)));
270 } end_qualList_elements;
273 sRef clabstract_createGlobal (sRef sr, qualList quals)
277 if (sRef_isValid (sr))
279 res = sRef_copy (sr);
280 DPRINTF (("Reflecting quals: %s / %s", sRef_unparse (sr), qualList_unparse (quals)));
281 reflectGlobalQualifiers (res, quals);
282 DPRINTF (("==> %s", sRef_unparseFull (res)));
286 res = sRef_undefined;
289 qualList_free (quals);
293 extern void declareCIter (cstring name, /*@owned@*/ uentryList params)
297 ue = uentry_makeIter (name,
298 ctype_makeFunction (ctype_void, params),
299 fileloc_copy (g_currentloc));
301 usymtab_supEntry (uentry_makeEndIter (name, fileloc_copy (g_currentloc)));
302 ue = usymtab_supGlobalEntryReturn (ue);
305 extern void nextIterParam (void)
307 llassert (ProcessingIterVars);
311 extern int iterParamNo (void)
313 llassert (ProcessingIterVars);
314 return saveIterParamNo;
318 ** yucky hacks to put it in the right place
322 makeCurrentParam (idDecl t)
326 saveStoreLoc = fileloc_undefined;
328 /* param number unknown */
330 ue = uentry_makeParam (t, 0);
335 declareUnnamedEnum (enumNameList el)
337 ctype ret = usymtab_enumEnumNameListType (el);
341 if (ctype_isDefined (ret))
344 e = uentry_makeEnumTagLoc (ctype_enumTag (rt), ret);
346 reflectStorageClass (e);
347 usymtab_supGlobalEntry (e);
349 declareEnumList (el, ret, g_currentloc);
350 enumNameList_free (el);
354 ctype ct = ctype_createEnum (fakeTag (), el);
356 e = uentry_makeEnumTagLoc (ctype_enumTag (ctype_realType (ct)), ct);
357 reflectStorageClass (e);
359 e = usymtab_supGlobalEntryReturn (e);
360 rt = uentry_getAbstractType (e);
361 declareEnumList (el, ct, g_currentloc);
368 declareEnum (cstring ename, enumNameList el)
373 llassert (cstring_isDefined (ename));
375 cet = ctype_createEnum (ename, el);
376 e = uentry_makeEnumTagLoc (ename, cet);
377 reflectStorageClass (e);
378 e = usymtab_supGlobalEntryReturn (e);
379 cet = uentry_getType (e);
380 declareEnumList (el, cet, uentry_whereLast (e));
381 return (uentry_getAbstractType (e));
385 declareEnumList (enumNameList el, ctype c, fileloc loc)
387 bool boolnames = FALSE;
388 bool othernames = FALSE;
390 (void) context_getSaveLocation (); /* undefine it */
392 if (context_maybeSet (FLG_NUMENUMMEMBERS))
394 int maxnum = context_getValue (FLG_NUMENUMMEMBERS);
395 int num = enumNameList_size (el);
401 message ("Enumerator %s declared with %d members (limit is set to %d)",
402 ctype_unparse (c), num, maxnum),
407 enumNameList_elements (el, e)
409 uentry ue = usymtab_lookupExposeGlob (e);
410 ctype ct = uentry_getType (ue);
412 llassert (uentry_isEnumConstant (ue));
414 if (ctype_isUnknown (ct))
416 uentry_setType (ue, c);
420 if (cstring_equal (e, context_getFalseName ())
421 || cstring_equal (e, context_getTrueName ()))
427 message ("Enumerator mixes boolean name (%s) with "
430 uentry_whereLast (ue)))
437 uentry_setType (ue, ctype_bool);
438 DPRINTF (("Set type: %s / %s",
439 uentry_unparse (ue), ctype_unparse (ctype_bool)));
447 message ("Enumerator mixes boolean names (%s, %s) with "
448 "non-boolean name: %s",
449 context_getTrueName (),
450 context_getFalseName (),
452 uentry_whereLast (ue)))
461 if (!ctype_match (c, ct))
463 if (ctype_isDirectBool (ct))
465 if (cstring_equal (e, context_getFalseName ())
466 || cstring_equal (e, context_getTrueName ()))
468 DPRINTF (("Here we are!"));
474 message ("Enumerator member %s declared with "
475 "inconsistent type: %s",
476 e, ctype_unparse (c)),
477 uentry_whereLast (ue)))
479 uentry_showWhereSpecifiedExtra
480 (ue, cstring_copy (ctype_unparse (ct)));
488 message ("Enumerator member %s declared with "
489 "inconsistent type: %s",
490 e, ctype_unparse (c)),
491 uentry_whereLast (ue)))
493 uentry_showWhereSpecifiedExtra
494 (ue, cstring_copy (ctype_unparse (ct)));
499 } end_enumNameList_elements;
502 static /*@dependent@*/ uentryList currentParamList;
504 /*drl added 3-28-2001*/
505 /* this function takes a list of paramentar and generates a list
507 Currently the only constraints gnerated are MaxSet(p) >= 0 for all pointers
510 void setImplictfcnConstraints (void)
515 params = currentParamList;
517 if (constraintList_isDefined(implicitFcnConstraints) )
518 constraintList_free(implicitFcnConstraints);
520 implicitFcnConstraints = constraintList_makeNew();
522 uentryList_elements (params, el)
524 DPRINTF((message("setImplictfcnConstraints doing: %s", uentry_unparse(el) ) ));
526 s = uentry_getSref(el);
527 if (sRef_isReference (s) )
529 DPRINTF((message ("%s is a pointer", sRef_unparse(s) ) ));
533 DPRINTF((message ("%s is NOT a pointer", sRef_unparse(s) ) ));
536 chagned this is MaxSet(s) == 0 to MaxSet(s) >= 0 */
538 c = constraint_makeSRefWriteSafeInt (s, 0);
539 // constraint_makeSRefSetBufferSize (s, 0);
540 implicitFcnConstraints = constraintList_add(implicitFcnConstraints , c);
542 end_uentryList_elements;
546 /*@observer@*/ constraintList getImplicitFcnConstraints (void)
548 return implicitFcnConstraints;
551 void setCurrentParams (/*@dependent@*/ uentryList ue)
553 currentParamList = ue;
556 void clearCurrentParams (void)
558 currentParamList = uentryList_undefined;
562 ** requires: uentry_isFunction (e)
563 ** parameter names for current function are in currentParamList
566 static void enterFunctionParams (uentryList params)
570 uentryList_elements (params, current)
572 if (uentry_hasName (current))
574 uentry_setParamNo (current, paramno);
575 usymtab_supEntry (uentry_copy (current));
579 } end_uentryList_elements;
583 extern void enterParamsTemp (void)
585 usymtab_enterScope ();
586 enterFunctionParams (currentParamList);
589 extern void exitParamsTemp (void)
591 usymtab_quietPlainExitScope ();
594 static /*@exposed@*/ uentry clabstract_globalDeclareFunction (idDecl tid)
596 ctype deftype = idDecl_getCtype (tid);
600 DPRINTF (("Global function: %s", idDecl_unparse (tid)));
602 if (ctype_isFunction (deftype))
604 rettype = ctype_getReturnType (deftype);
608 rettype = ctype_unknown;
612 ** check has been moved here...
615 if (ctype_isFunction (idDecl_getCtype (tid)))
617 ue = uentry_makeIdFunction (tid);
618 reflectSpecialCode (ue);
619 reflectArgsUsed (ue);
623 llparseerror (message ("Inconsistent function declaration: %q",
624 idDecl_unparse (tid)));
626 tid = idDecl_replaceCtype
627 (tid, ctype_makeFunction (ctype_unknown, uentryList_undefined));
628 ue = uentry_makeIdFunction (tid);
631 reflectStorageClass (ue);
632 uentry_checkParams (ue);
634 DPRINTF (("Supercede function: %s", uentry_unparseFull (ue)));
636 ue = usymtab_supGlobalEntryReturn (ue);
637 DPRINTF (("After supercede function: %s", uentry_unparseFull (ue)));
639 context_enterFunction (ue);
640 enterFunctionParams (uentry_getParams (ue));
642 resetStorageClass ();
643 DPRINTF (("Function: %s", uentry_unparseFull (ue)));
648 ** for now, no type checking
649 ** (must check later though!)
652 static /*@only@*/ uentry globalDeclareOldStyleFunction (idDecl tid)
657 ** check has been moved here...
660 if (cstring_equalLit (idDecl_observeId (tid), "main"))
662 context_setFlagTemp (FLG_MAINTYPE, FALSE);
665 ue = uentry_makeIdFunction (tid);
666 reflectStorageClass (ue);
667 reflectSpecialCode (ue);
668 reflectArgsUsed (ue);
669 uentry_setDefined (ue, g_currentloc);
670 uentry_checkParams (ue);
671 resetStorageClass ();
675 static void oldStyleDeclareFunction (/*@only@*/ uentry e)
677 uentryList params = saveParamList;
678 ctype rt = uentry_getType (e);
680 llassert (ctype_isFunction (rt));
682 e = usymtab_supGlobalEntryReturn (e);
684 context_enterFunction (e);
685 enterFunctionParams (params);
686 saveParamList = uentryList_undefined;
687 resetStorageClass ();
690 void clabstract_declareFunction (idDecl tid) /*@globals undef saveFunction; @*/
694 DPRINTF (("Declare function: %s", idDecl_unparse (tid)));
696 if (ProcessingParams)
698 ue = globalDeclareOldStyleFunction (tid);
703 saveFunction = uentry_undefined;
705 if (context_inRealFunction ())
707 ue = uentry_makeVariableLoc (idDecl_observeId (tid), ctype_unknown);
709 llparseerror (message ("Function declared inside function: %q",
710 idDecl_unparse (tid)));
712 context_quietExitFunction ();
713 ue = usymtab_supEntryReturn (ue);
717 if (context_inInnerScope ())
719 llparseerror (message ("Declaration in inner context: %q",
720 idDecl_unparse (tid)));
722 sRef_setGlobalScope ();
723 ue = uentry_makeVariableLoc (idDecl_observeId (tid),
725 ue = usymtab_supGlobalEntryReturn (ue);
726 sRef_clearGlobalScope ();
730 ue = clabstract_globalDeclareFunction (tid);
737 resetStorageClass ();
741 void declareStaticFunction (idDecl tid) /*@globals undef saveFunction; @*/
745 DPRINTF (("Declare static funciton: %s", idDecl_unparse (tid)));
747 if (ProcessingParams)
749 ue = globalDeclareOldStyleFunction (tid);
754 saveFunction = uentry_undefined;
756 if (context_inRealFunction ())
758 ue = uentry_makeVariableLoc (idDecl_observeId (tid), ctype_unknown);
760 llparseerror (message ("Function declared inside function: %q",
761 idDecl_unparse (tid)));
763 context_quietExitFunction ();
764 ue = usymtab_supEntryReturn (ue);
768 if (context_inInnerScope ())
770 llparseerror (message ("Declaration in inner context: %q",
771 idDecl_unparse (tid)));
773 sRef_setGlobalScope ();
774 ue = uentry_makeVariableLoc (idDecl_observeId (tid),
776 ue = usymtab_supGlobalEntryReturn (ue);
777 sRef_clearGlobalScope ();
781 ctype deftype = idDecl_getCtype (tid);
784 if (ctype_isFunction (deftype))
786 rettype = ctype_getReturnType (deftype);
790 rettype = ctype_unknown;
794 ** check has been moved here...
797 if (ctype_isFunction (idDecl_getCtype (tid)))
799 ue = uentry_makeIdFunction (tid);
800 reflectSpecialCode (ue);
801 reflectArgsUsed (ue);
805 llparseerror (message ("Inconsistent function declaration: %q",
806 idDecl_unparse (tid)));
808 tid = idDecl_replaceCtype
809 (tid, ctype_makeFunction (ctype_unknown, uentryList_undefined));
810 ue = uentry_makeIdFunction (tid);
813 reflectStorageClass (ue);
814 uentry_setStatic (ue);
816 uentry_checkParams (ue);
818 DPRINTF (("Sub global entry: %s", uentry_unparse (ue)));
819 ue = usymtab_supGlobalEntryReturn (ue);
821 context_enterFunction (ue);
822 enterFunctionParams (uentry_getParams (ue));
823 resetStorageClass ();
830 resetStorageClass ();
835 checkTypeDecl (uentry e, ctype rep)
837 cstring n = uentry_getName (e);
839 DPRINTF (("Check type decl: %s", uentry_unparseFull (e)));
841 if (cstring_equal (context_getBoolName (), n))
843 ctype rrep = ctype_realType (rep);
846 ** for abstract enum types, we need to fix the enum members:
847 ** they should have the abstract type, not the rep type.
850 if (ctype_isEnum (ctype_realType (rrep)))
852 enumNameList el = ctype_elist (rrep);
854 enumNameList_elements (el, ye)
856 if (usymtab_existsGlob (ye))
858 uentry ue = usymtab_lookupSafe (ye);
859 uentry_setType (ue, ctype_bool);
862 if (cstring_equal (context_getTrueName (), ye)
863 || cstring_equal (context_getFalseName (), ye))
871 message ("Member of boolean enumerated type definition "
872 "does not match name set to represent TRUE "
875 message ("Use -boolfalse and -booltrue to set the "
876 "name of false and true boolean values."),
877 uentry_whereDefined (e));
879 } end_enumNameList_elements;
883 if (usymtab_exists (n))
885 usymId llm = usymtab_getId (n);
886 uentry le = usymtab_getTypeEntry (llm);
888 uentry_setDeclared (e, g_currentloc);
889 uentry_setSref (e, sRef_makeGlobal (llm, uentry_getType (le)));
891 DPRINTF (("Here we are: %s / %s",
892 n, context_getBoolName ()));
894 if (uentry_isAbstractDatatype (le))
896 ctype rrep = ctype_realType (rep);
898 DPRINTF (("Abstract type: %s", uentry_unparseFull (le)));
901 ** for abstract enum types, we need to fix the enum members:
902 ** they should have the abstract type, not the rep type.
905 if (ctype_isEnum (ctype_realType (rrep)))
907 ctype at = uentry_getAbstractType (le);
908 enumNameList el = ctype_elist (rrep);
910 enumNameList_elements (el, ye)
912 if (usymtab_existsGlob (ye))
914 uentry ue = usymtab_lookupSafe (ye);
916 llassert (uentry_isEitherConstant (ue));
917 llassertprint (ctype_match (uentry_getType (ue), rrep),
918 ("Bad enum: %s / %s",
920 ctype_unparse (rrep)));
922 uentry_setType (ue, at);
924 } end_enumNameList_elements;
927 if (uentry_isMutableDatatype (le))
929 /* maybe more complicated if abstract and immutable ? */
931 if (!ctype_isRealPointer (rep) && !ctype_isRealAbstract (rep))
935 message ("Mutable abstract type %s declared without pointer "
936 "indirection: %s (violates assignment semantics)",
937 n, ctype_unparse (rep)),
938 uentry_whereDefined (e));
940 uentry_setMutable (e);
947 fileloc fl = uentry_whereDeclared (e);
949 if (context_getFlag (FLG_LIKELYBOOL)
950 && !context_getFlag (FLG_BOOLINT))
952 if ((cstring_equalLit (n, "BOOL")
953 || cstring_equalLit (n, "Bool")
954 || cstring_equalLit (n, "bool")
955 || cstring_equalLit (n, "boolean")
956 || cstring_equalLit (n, "Boolean")
957 || cstring_equalLit (n, "BOOLEAN"))
958 && !(cstring_equal (n, context_getBoolName ())))
960 if (context_setBoolName ()) {
963 message ("Type %s is probably meant as a boolean type, but does "
964 "not match the boolean type name \"%s\".",
966 context_getBoolName ()),
971 message ("Type %s is probably meant as a boolean type, "
972 "but the boolean type name is not set. "
973 "Use -booltype %s to set it.",
980 if (!uentry_isStatic (e)
981 && !ctype_isFunction (uentry_getType (e))
982 && !fileloc_isLib (fl)
983 && !fileloc_isImport (fl)
984 && fileloc_isHeader (fl))
986 voptgenerror (FLG_EXPORTTYPE,
987 message ("Type exported, but not specified: %s\n", n),
996 fixUentryList (idDeclList tl, qtype q)
998 uentryList f = uentryList_new ();
1000 idDeclList_elements (tl, i)
1002 if (idDecl_isDefined (i))
1008 (void) idDecl_fixBase (i, q);
1011 ** implicit annotations
1014 (void) fixStructDecl (i);
1016 ue = uentry_makeIdVariable (i);
1017 rt = ctype_realType (uentry_getType (ue));
1020 ** where is this here???
1022 if (ctype_isArray (rt) || ctype_isSU (rt))
1024 sRef_setAllocated (uentry_getSref (ue), uentry_whereDefined (ue));
1030 if (uentry_isValid (old = uentryList_lookupField (f, uentry_rawName (ue))))
1032 if (optgenerror (FLG_SYNTAX,
1033 message ("Field name reused: %s", uentry_rawName (ue)),
1034 uentry_whereDefined (ue)))
1036 llgenmsg (message ("Previous use of %s", uentry_rawName (ue)),
1037 uentry_whereDefined (old));
1041 f = uentryList_add (f, ue);
1043 } end_idDeclList_elements;
1045 idDeclList_free (tl);
1050 ** This is a hack to support unnamed struct/union fields as done by
1051 ** Microsoft VC++. It is not supported by the ANSI standard.
1053 ** The inner fields are added to the outer structure. This is meaningful
1054 ** for nesting structs inside unions, but lclint does no related
1059 fixUnnamedDecl (qtype q)
1061 ctype ct = ctype_realType (qtype_getType (q));
1063 if (ctype_isStruct (ct) || ctype_isUnion (ct))
1065 uentryList res = ctype_getFields (ct);
1067 return (uentryList_copy (res));
1074 return uentryList_undefined;
1077 void setStorageClass (storageClassCode sc)
1083 setProcessingIterVars (uentry iter)
1085 ProcessingIterVars = TRUE;
1087 saveIterParamNo = 0;
1091 setProcessingGlobalsList ()
1093 ProcessingGlobals = TRUE;
1094 fcnNoGlobals = FALSE;
1097 static bool ProcessingGlobMods = FALSE;
1100 setProcessingGlobMods ()
1102 ProcessingGlobMods = TRUE;
1106 clearProcessingGlobMods ()
1108 ProcessingGlobMods = FALSE;
1112 isProcessingGlobMods ()
1114 return (ProcessingGlobMods);
1117 static void resetGlobals (void)
1119 ProcessingGlobals = FALSE;
1120 fcnNoGlobals = FALSE;
1124 unsetProcessingGlobals ()
1126 ProcessingGlobals = FALSE;
1130 setProcessingVars (/*@only@*/ qtype q)
1132 ProcessingVars = TRUE;
1133 qtype_free (processingType);
1138 setGenericParamList (/*@dependent@*/ uentryList pm)
1140 ProcessingParams = TRUE;
1145 setProcessingTypedef (/*@only@*/ qtype q)
1147 ProcessingTypedef = TRUE;
1149 qtype_free (processingType);
1154 unsetProcessingVars ()
1156 resetStorageClass ();
1157 ProcessingVars = FALSE;
1163 if (ProcessingParams)
1165 if (uentry_isInvalid (saveFunction))
1167 llbuglit ("unsetProcessingVars: no saved function\n");
1171 ctype ct = ctype_getReturnType (uentry_getType (saveFunction));
1172 uentryList params = uentryList_copy (saveParamList);
1173 ctype ct2 = ctype_makeFunction (ct, params);
1175 uentry_setType (saveFunction, ct2);
1176 ProcessingParams = FALSE;
1178 oldStyleDeclareFunction (saveFunction);
1179 saveFunction = uentry_undefined;
1186 ** If the paramlist used a type name, we could be here.
1189 llfatalerror (message ("%q: Old-style function parameter list uses a "
1190 "type name.", fileloc_unparse (g_currentloc)));
1197 if (uentry_isValid (saveFunction))
1200 ** old style declaration
1203 ctype ct = ctype_getReturnType (uentry_getType (saveFunction));
1206 uentryList_elements (saveParamList, current)
1208 uentry_setType (current, ctype_int); /* all params are ints */
1209 } end_uentryList_elements;
1211 ct2 = ctype_makeParamsFunction (ct, uentryList_copy (saveParamList));
1213 uentry_setType (saveFunction, ct2);
1214 ProcessingParams = FALSE;
1216 oldStyleDeclareFunction (saveFunction);
1217 saveFunction = uentry_undefined;
1222 unsetProcessingTypedef ()
1224 ProcessingTypedef = FALSE;
1227 void checkConstant (qtype t, idDecl id)
1231 id = idDecl_fixBase (id, t);
1232 e = uentry_makeIdConstant (id);
1234 reflectStorageClass (e);
1235 resetStorageClass ();
1237 usymtab_supGlobalEntry (e);
1240 void checkValueConstant (qtype t, idDecl id, exprNode e)
1244 id = idDecl_fixBase (id, t);
1245 ue = uentry_makeIdConstant (id);
1246 reflectStorageClass (ue);
1247 resetStorageClass ();
1249 if (exprNode_isDefined (e))
1251 if (!exprNode_matchType (uentry_getType (ue), e))
1254 (exprNode_getType (e), e,
1255 uentry_getType (ue), exprNode_undefined,
1256 message ("Constant %q initialized to type %t, expects %t: %s",
1257 uentry_getName (ue),
1258 exprNode_getType (e),
1259 uentry_getType (ue),
1260 exprNode_unparse (e)),
1265 if (exprNode_hasValue (e))
1267 uentry_mergeConstantValue (ue, multiVal_copy (exprNode_getValue (e)));
1272 usymtab_supGlobalEntry (ue);
1275 void processNamedDecl (idDecl t)
1277 if (qtype_isUndefined (processingType))
1279 llparseerror (message ("No type before declaration name: %q", idDecl_unparse (t)));
1281 processingType = qtype_create (ctype_unknown);
1284 t = idDecl_fixBase (t, processingType);
1286 DPRINTF (("Declare: %s", idDecl_unparse (t)));
1288 if (ProcessingGlobals)
1290 cstring id = idDecl_getName (t);
1291 uentry ue = usymtab_lookupSafe (id);
1293 if (!uentry_isValid (ue))
1295 llerror (FLG_UNRECOG,
1296 message ("Variable used in globals list is undeclared: %s", id));
1300 if (!ctype_match (uentry_getType (ue), idDecl_getCtype (t)))
1304 message ("Variable %s used in globals list declared %s, "
1306 id, ctype_unparse (uentry_getType (ue)),
1307 ctype_unparse (idDecl_getCtype (t))),
1312 sRef sr = sRef_copy (uentry_getSref (ue));
1313 reflectGlobalQualifiers (sr, idDecl_getQuals (t));
1317 else if (ProcessingVars)
1322 ct = ctype_realType (idDecl_getCtype (t));
1324 if (ProcessingParams)
1326 cstring id = idDecl_getName (t);
1327 int paramno = uentryList_lookupRealName (saveParamList, id);
1331 uentry cparam = uentryList_getN (saveParamList, paramno);
1333 uentry_setType (cparam, idDecl_getCtype (t));
1334 uentry_reflectQualifiers (cparam, idDecl_getQuals (t));
1335 uentry_setDeclaredOnly (cparam, context_getSaveLocation ());
1340 (message ("Old style declaration uses unlisted parameter: %s",
1348 if (context_inIterDef ())
1350 cstring pname = makeParam (idDecl_observeId (t));
1351 uentry p = usymtab_lookupSafe (pname);
1353 cstring_free (pname);
1355 if (uentry_isYield (p))
1357 e = uentry_makeParam (t, sRef_getParam (uentry_getSref (p)));
1358 uentry_checkYieldParam (p, e);
1359 usymtab_supEntrySref (e);
1364 if ((hasSpecialCode () || argsUsed)
1365 && ctype_isFunction (idDecl_getCtype (t)))
1367 e = uentry_makeIdFunction (t);
1368 reflectSpecialCode (e);
1369 reflectArgsUsed (e);
1373 e = uentry_makeIdVariable (t);
1376 loc = uentry_whereDeclared (e);
1379 if (context_inGlobalScope ())
1381 uentry_checkParams was here!
1385 if (ctype_isFunction (uentry_getType (e)))
1387 clabstract_prepareFunction (e);
1390 DPRINTF (("Superceding... %s", uentry_unparseFull (e)));
1391 e = usymtab_supEntrySrefReturn (e);
1392 DPRINTF (("After superceding... %s", uentry_unparseFull (e)));
1394 if (uentry_isExtern (e) && !context_inGlobalScope ())
1398 message ("Declaration using extern inside function scope: %q",
1399 uentry_unparse (e)),
1402 uentry_setDefined (e, fileloc_getExternal ());
1403 sRef_setDefined (uentry_getSref (e), fileloc_getExternal ());
1406 if (uentry_isFunction (e))
1408 if (!context_inXHFile ())
1410 checkParamNames (e);
1414 if (uentry_isVar (e) && uentry_isCheckedUnknown (e))
1416 sRef sr = uentry_getSref (e);
1418 if (sRef_isLocalVar (sr))
1420 if (context_getFlag (FLG_IMPCHECKMODINTERNALS))
1422 uentry_setCheckMod (e);
1426 uentry_setUnchecked (e);
1429 else if (sRef_isFileStatic (sr))
1431 if (context_getFlag (FLG_IMPCHECKEDSTRICTSTATICS))
1433 uentry_setCheckedStrict (e);
1435 else if (context_getFlag (FLG_IMPCHECKEDSTATICS))
1437 uentry_setChecked (e);
1439 else if (context_getFlag (FLG_IMPCHECKMODSTATICS))
1441 uentry_setCheckMod (e);
1448 else /* real global */
1450 llassert (sRef_isRealGlobal (sr));
1452 if (context_getFlag (FLG_IMPCHECKEDSTRICTGLOBALS))
1454 uentry_setCheckedStrict (e);
1456 else if (context_getFlag (FLG_IMPCHECKEDGLOBALS))
1458 uentry_setChecked (e);
1460 else if (context_getFlag (FLG_IMPCHECKMODGLOBALS))
1462 uentry_setCheckMod (e);
1472 else if (ProcessingTypedef)
1474 ctype ct = idDecl_getCtype (t);
1477 DPRINTF (("Processing typedef: %s", ctype_unparse (ct)));
1479 e = uentry_makeIdDatatype (t);
1481 if (cstring_equal (idDecl_getName (t), context_getBoolName ())) {
1482 ctype rt = ctype_realType (ct);
1484 if (ctype_isEnum (rt)) {
1487 if (!(ctype_isInt (rt)
1488 || ctype_isUnknown (rt)
1489 || ctype_isChar (rt))) {
1492 message ("Boolean type %s defined using non-standard type %s (integral, char or enum type expected)",
1493 context_getBoolName (),
1494 ctype_unparse (ct)),
1495 uentry_whereLast (e));
1499 uentry_setType (e, ct);
1503 reflectStorageClass (e);
1504 checkTypeDecl (e, ct);
1506 e = usymtab_supReturnTypeEntry (e);
1510 llparseerror (message ("Suspect missing struct or union keyword: %q",
1511 idDecl_unparse (t)));
1517 ** moved from grammar
1520 static idDecl fixStructDecl (/*@returned@*/ idDecl d)
1522 if (ctype_isVisiblySharable (idDecl_getCtype (d))
1523 && context_getFlag (FLG_STRUCTIMPONLY))
1525 if (!qualList_hasAliasQualifier (idDecl_getQuals (d)))
1527 if (qualList_hasExposureQualifier (idDecl_getQuals (d)))
1529 idDecl_addQual (d, qual_createDependent ());
1533 idDecl_addQual (d, qual_createImpOnly ());
1542 declareUnnamedStruct (/*@only@*/ uentryList f)
1544 DPRINTF (("Unnamed struct: %s", uentryList_unparse (f)));
1546 if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1548 int num = uentryList_size (f);
1549 int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1554 (FLG_NUMSTRUCTFIELDS,
1555 message ("Structure declared with %d fields "
1556 "(limit is set to %d)",
1562 return (ctype_createUnnamedStruct (f));
1566 declareUnnamedUnion (/*@only@*/ uentryList f)
1568 if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1570 int num = uentryList_size (f);
1571 int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1576 (FLG_NUMSTRUCTFIELDS,
1577 message ("Union declared with %d fields "
1578 "(limit is set to %d)",
1584 return (ctype_createUnnamedUnion (f));
1587 ctype declareStruct (cstring id, /*@only@*/ uentryList f)
1591 int num = uentryList_size (f);
1593 DPRINTF (("Declare struct: %s / %s", id, uentryList_unparse (f)));
1595 ct = ctype_createStruct (cstring_copy (id), f);
1597 DPRINTF (("Ctype: %s", ctype_unparse (ct)));
1599 ue = uentry_makeStructTagLoc (id, ct);
1601 DPRINTF (("ue: %s", uentry_unparseFull (ue)));
1603 if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1605 int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1610 (FLG_NUMSTRUCTFIELDS,
1611 message ("Structure %q declared with %d fields "
1612 "(limit is set to %d)",
1613 uentry_getName (ue), num, max),
1614 uentry_whereLast (ue));
1618 return (usymtab_supTypeEntry (ue));
1621 ctype declareUnion (cstring id, uentryList f)
1625 int num = uentryList_size (f);
1627 ct = ctype_createUnion (cstring_copy (id), f);
1628 ue = uentry_makeUnionTagLoc (id, ct);
1630 if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1632 int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1637 (FLG_NUMSTRUCTFIELDS,
1638 message ("Union %q declared with %d fields "
1639 "(limit is set to %d)",
1640 uentry_getName (ue), num, max),
1641 uentry_whereLast (ue));
1645 return (usymtab_supTypeEntry (ue));
1648 ctype handleStruct (/*@only@*/ cstring id)
1650 if (usymtab_existsStructTag (id))
1652 ctype ct = uentry_getAbstractType (usymtab_lookupStructTag (id));
1659 return (ctype_createForwardStruct (id));
1663 ctype handleUnion (/*@only@*/ cstring id)
1665 if (usymtab_existsUnionTag (id))
1667 ctype ret = uentry_getAbstractType (usymtab_lookupUnionTag (id));
1673 return (ctype_createForwardUnion (id));
1678 handleEnum (cstring id)
1680 if (usymtab_existsEnumTag (id))
1682 ctype ret = uentry_getAbstractType (usymtab_lookupEnumTag (id));
1688 return (declareEnum (id, enumNameList_new ()));
1692 bool processingIterVars (void)
1694 return ProcessingIterVars;
1697 uentry getCurrentIter (void)
1702 static bool flipOldStyle = FALSE;
1703 static bool flipNewStyle = TRUE;
1705 void setFlipOldStyle () { flipOldStyle = TRUE; }
1706 bool isFlipOldStyle () { return flipOldStyle; }
1707 bool isNewStyle () { return flipNewStyle; }
1708 void setNewStyle () { flipNewStyle = TRUE; }
1710 /*@dependent@*/ uentryList handleParamIdList (/*@dependent@*/ uentryList params)
1715 ** this is a really YUCKY hack to handle old style
1719 voptgenerror (FLG_OLDSTYLE,
1720 cstring_makeLiteral ("Old style function declaration"),
1723 uentryList_elements (params, current)
1725 uentry_setParam (current);
1726 uentry_setSref (current, sRef_makeParam (paramno, ctype_unknown));
1728 } end_uentryList_elements;
1730 setGenericParamList (params);
1731 g_expectingTypeName = TRUE;
1736 /*@dependent@*/ uentryList handleParamTypeList (/*@returned@*/ uentryList params)
1740 uentryList_fixMissingNames (params);
1742 voptgenerror (FLG_OLDSTYLE,
1743 cstring_makeLiteral ("Old style function declaration."),
1746 setGenericParamList (params);
1747 flipOldStyle = FALSE;
1748 g_expectingTypeName = TRUE;
1757 ctype c = ctype_unknown;
1758 cstring id = cstring_makeLiteral ("va_alist");
1761 if (ProcessingParams)
1763 int i = uentryList_lookupRealName (saveParamList, id);
1767 e = uentry_makeVariableSrefParam (id, c, sRef_makeParam (i, c));
1771 e = uentry_undefined; /* suppress gcc message */
1772 llfatalerrorLoc (cstring_makeLiteral ("va_dcl used without va_alist"));
1777 llerror (FLG_SYNTAX, cstring_makeLiteral ("va_dcl used outside of function declaration"));
1778 e = uentry_makeVariableLoc (id, c);
1782 uentry_setUsed (e, g_currentloc);
1783 usymtab_supEntrySref (e);
1786 /*@exposed@*/ sRef modListPointer (/*@exposed@*/ sRef s)
1788 ctype ct = sRef_getType (s);
1789 ctype rt = ctype_realType (ct);
1791 if (ctype_isAP (rt))
1793 if (context_inHeader () && ctype_isAbstract (ct))
1798 ("Modifies clause in header file dereferences abstract "
1799 "type %s (interface modifies clause should not depend "
1800 "on or expose type representation): %q",
1806 return (sRef_constructPointer (s));
1810 if (ctype_isKnown (rt))
1814 message ("Implementation modifies clause dereferences non-pointer (type %s): %q",
1824 /*@exposed@*/ sRef modListFieldAccess (sRef s, cstring f)
1826 ctype ct = sRef_getType (s);
1827 ctype rt = ctype_realType (ct);
1829 if (ctype_isStructorUnion (rt))
1831 uentry tf = uentryList_lookupField (ctype_getFields (rt), f);
1833 if (uentry_isUndefined (tf))
1835 voptgenerror (FLG_TYPE,
1836 message ("Modifies list accesses non-existent "
1837 "field %s of %t: %q", f, ct,
1842 return sRef_undefined;
1846 if (ctype_isAbstract (ct) && context_inHeader ())
1851 ("Modifies clause in header file accesses abstract "
1852 "type %s (interface modifies clause should not depend "
1853 "on or expose type representation): %q",
1860 cstring_markOwned (f);
1861 return (sRef_makeField (s, f));
1867 message ("Modifies clause dereferences non-pointer (type %s): %q",
1877 /*@dependent@*/ sRef clabstract_unrecognizedGlobal (cstring s)
1879 if (cstring_equalLit (s, "nothing"))
1881 return sRef_makeNothing ();
1883 else if (cstring_equalLit (s, "internalState"))
1885 return sRef_makeInternalState ();
1887 else if (cstring_equalLit (s, "fileSystem")
1888 || cstring_equalLit (s, "systemState"))
1890 return sRef_makeSystemState ();
1896 message ("Unrecognized identifier in globals list: %s", s),
1899 return sRef_undefined;
1903 /*@exposed@*/ sRef modListArrowAccess (sRef s, cstring f)
1905 ctype ct = sRef_getType (s);
1906 ctype rt = ctype_realType (ct);
1908 if (ctype_isRealPointer (rt))
1910 ctype b = ctype_baseArrayPtr (rt);
1911 ctype rb = ctype_realType (b);
1913 if (ctype_isStructorUnion (rb))
1915 uentry tf = uentryList_lookupField (ctype_getFields (rb), f);
1917 if (uentry_isUndefined (tf))
1919 voptgenerror (FLG_TYPE,
1920 message ("Modifies list arrow accesses non-existent "
1921 "field %s of %t: %q", f, b,
1926 return sRef_undefined;
1930 if (context_inHeader ())
1932 if (ctype_isAbstract (b))
1937 ("Modifies clause in header file arrow accesses abstract "
1938 "type %s (interface modifies clause should not depend "
1939 "on or expose type representation): %q",
1947 if (ctype_isAbstract (ct))
1952 ("Modifies clause in header file arrow accesses abstract "
1953 "type %s (interface modifies clause should not depend "
1954 "on or expose type representation): %q",
1962 cstring_markOwned (f);
1963 return (sRef_makeArrow (s, f));
1969 message ("Modifies clause arrow accesses pointer to "
1970 "non-structure (type %s): %q",
1980 message ("Modifies clause arrow accesses non-pointer (type %s): %q",
1990 sRef checkStateClausesId (uentry ue)
1992 cstring s = uentry_rawName (ue);
1994 if (sRef_isFileOrGlobalScope (uentry_getSref (ue)))
1998 message ("Global variable %s used special clause. (Global variables "
1999 "are not recognized in special clauses. If there is "
2000 "sufficient interest in support for this, it may be "
2001 "added to a future release. Send mail to "
2002 "lclint@cs.virginia.edu.)",
2006 return sRef_undefined;
2010 if (cstring_equalLit (s, "result"))
2014 message ("Special clause list uses %s which is a variable and has special "
2015 "meaning in a modifies list. (Special meaning assumed.)", s),
2018 uentry_showWhereDeclared (ue);
2022 return uentry_getSref (ue);
2028 don;t know what the real date is...
2034 based on checkSpecClausesId
2038 sRef checkbufferConstraintClausesId (uentry ue)
2040 cstring s = uentry_rawName (ue);
2041 if (cstring_equalLit (s, "result"))
2045 message ("Special clause list uses %s which is a variable and has special "
2046 "meaning in a modifies list. (Special meaning assumed.)", s),
2049 uentry_showWhereDeclared (ue);
2053 return sRef_saveCopy( uentry_getSref (ue) );
2056 void checkModifiesId (uentry ue)
2058 cstring s = uentry_rawName (ue);
2060 if (cstring_equalLit (s, "nothing")
2061 || cstring_equalLit (s, "internalState")
2062 || cstring_equalLit (s, "systemState")
2063 || (cstring_equalLit (s, "fileSystem")))
2067 message ("Modifies list uses %s which is a variable and has special "
2068 "meaning in a modifies list. (Special meaning assumed.)", s),
2071 uentry_showWhereDeclared (ue);
2076 /*@exposed@*/ sRef fixModifiesId (cstring s)
2079 cstring pname = makeParam (s);
2080 uentry ue = usymtab_lookupSafe (pname);
2082 cstring_free (pname);
2084 if (cstring_equalLit (s, "nothing"))
2086 ret = sRef_makeNothing ();
2088 else if (cstring_equalLit (s, "internalState"))
2090 ret = sRef_makeInternalState ();
2092 else if (cstring_equalLit (s, "fileSystem")
2093 || cstring_equalLit (s, "systemState"))
2095 ret = sRef_makeSystemState ();
2099 ret = sRef_undefined;
2102 if (sRef_isValid (ret))
2104 if (uentry_isValid (ue))
2108 message ("Modifies list uses %s which is a parameter and has special "
2109 "meaning in a modifies list. (Special meaning assumed.)", s),
2115 if (uentry_isValid (ue))
2117 ret = uentry_getSref (ue);
2121 fileloc loc = fileloc_decColumn (g_currentloc, cstring_length (s));
2122 ret = sRef_undefined;
2126 message ("Unrecognized identifier in modifies comment: %s", s),
2136 sRef fixStateClausesId (cstring s)
2139 cstring pname = makeParam (s);
2140 uentry ue = usymtab_lookupSafe (pname);
2142 cstring_free (pname);
2144 if (cstring_equalLit (s, "result"))
2146 ret = sRef_makeResult ();
2150 ret = sRef_undefined;
2153 if (sRef_isValid (ret))
2155 if (uentry_isValid (ue))
2159 message ("Function clause uses %s which is a parameter and has special "
2160 "meaning in a function clause. (Special meaning assumed.)", s),
2166 if (uentry_isValid (ue))
2168 ret = uentry_getSref (ue);
2170 if (sRef_isFileOrGlobalScope (ret))
2174 message ("Global variable %s used in function clause. (Global variables "
2175 "are not recognized in function clauses. If there is "
2176 "sufficient interest in support for this, it may be "
2177 "added to a future release. Send mail to "
2178 "lclint@cs.virginia.edu.)",
2182 ret = sRef_undefined;
2187 fileloc loc = fileloc_decColumn (g_currentloc, cstring_length (s));
2188 ret = sRef_undefined;
2192 message ("Unrecognized identifier in function clause: %s", s),
2202 sRef modListArrayFetch (/*@exposed@*/ sRef s, /*@unused@*/ sRef mexp)
2204 ctype ct = sRef_getType (s);
2205 ctype rt = ctype_realType (ct);
2207 if (ctype_isAP (rt))
2209 if (context_inHeader () && ctype_isAbstract (ct))
2214 ("Modifies clause in header file indexes abstract "
2215 "type %s (interface modifies clause should not depend "
2216 "on or expose type representation): %q",
2222 return (sRef_makeAnyArrayFetch (s));
2229 ("Implementation modifies clause uses array fetch on non-array (type %s): %q",
2230 ctype_unparse (ct), sRef_unparse (s)),
2236 static void clabstract_prepareFunction (uentry e)
2238 uentry_checkParams (e);
2239 DPRINTF (("After prepare: %s", uentry_unparseFull (e)));
2242 sRef clabstract_checkGlobal (exprNode e)
2245 llassert (exprNode_isInitializer (e));
2247 s = exprNode_getSref (e);
2248 DPRINTF (("Initializer: %s -> %s", exprNode_unparse (e), sRef_unparse (s)));
2251 return sRef_copy (s);