2 ** LCLint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2000 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;
57 /*@only@*/ static constraintList fcnEnsuresConstraints = NULL;
61 /*@only@*/ constraintList implicitFcnConstraints = NULL;
64 //static constraintList fcnPreConditions = NULL;
67 static /*@only@*/ sRefSet fcnModifies = sRefSet_undefined;
68 static /*@only@*/ /*@null@*/ specialClauses specClauses = specialClauses_undefined;
69 static bool fcnNoGlobals = FALSE;
70 static bool ProcessingVars = FALSE;
71 static bool ProcessingParams = FALSE;
72 static bool ProcessingGlobals = FALSE;
73 static bool ProcessingTypedef = FALSE;
74 static bool ProcessingIterVars = FALSE;
75 static /*@only@*/ qtype processingType = qtype_undefined;
76 static uentry currentIter = uentry_undefined;
77 static globSet currentGlobals = globSet_undefined;
78 static /*@dependent@*/ uentryList saveParamList; /* for old style functions */
79 static /*@owned@*/ uentry saveFunction = uentry_undefined;
80 static int saveIterParamNo;
81 static idDecl fixStructDecl (/*@returned@*/ idDecl p_d);
82 static void checkTypeDecl (uentry p_e, ctype p_rep);
83 static /*@dependent@*/ fileloc saveStoreLoc = fileloc_undefined;
84 static storageClassCode storageClass = SCNONE;
85 static void declareEnumList (/*@temp@*/ enumNameList p_el, ctype p_c, fileloc p_loc);
86 static void resetGlobals (void);
87 static qual specialFunctionCode = QU_UNKNOWN;
88 static bool argsUsed = FALSE;
90 static bool hasSpecialCode (void)
92 return (specialFunctionCode != QU_UNKNOWN);
95 extern void setArgsUsed (void)
101 cstring_makeLiteral ("Multiple ARGSUSED comments for one function"),
108 static void reflectArgsUsed (uentry ue)
112 if (uentry_isFunction (ue))
114 uentryList params = uentry_getParams (ue);
116 uentryList_elements (params, el)
118 uentry_setUsed (el, fileloc_undefined);
119 } end_uentryList_elements ;
126 extern void setSpecialFunction (qual qu)
128 if (specialFunctionCode != QU_UNKNOWN)
130 voptgenerror (FLG_SYNTAX,
131 message ("Multiple special function codes: %s, %s "
132 "(first code is ignored)",
133 qual_unparse (specialFunctionCode),
138 specialFunctionCode = qu;
141 static void reflectSpecialCode (uentry ue)
143 switch (specialFunctionCode)
145 case QU_UNKNOWN: break;
147 uentry_setPrintfLike (ue);
150 uentry_setScanfLike (ue);
153 uentry_setMessageLike (ue);
158 specialFunctionCode = QU_UNKNOWN;
161 static void resetStorageClass (void)
163 qtype_free (processingType);
164 processingType = qtype_undefined;
165 storageClass = SCNONE;
168 static void reflectModGlobs (uentry ue)
172 llassert (globSet_isUndefined (currentGlobals));
174 uentry_setGlobals (ue, globSet_undefined);
175 fcnNoGlobals = FALSE;
177 else if (globSet_isDefined (currentGlobals))
179 uentry_setGlobals (ue, currentGlobals);
180 currentGlobals = globSet_undefined;
187 if (sRefSet_isDefined (fcnModifies))
189 uentry_setModifies (ue, fcnModifies);
190 fcnModifies = sRefSet_undefined;
195 uentry_setPreconditions (ue, fcnConstraints);
196 fcnConstraints = constraintList_undefined;
199 if (fcnEnsuresConstraints)
201 uentry_setPostconditions (ue, fcnEnsuresConstraints);
202 fcnEnsuresConstraints = constraintList_undefined;
206 if (uentry_isFunction (ue))
208 uentry_setSpecialClauses (ue, specClauses);
210 DPRINTF (("Done with spec clauses"));
214 static void reflectStorageClass (uentry u)
216 if (storageClass == SCSTATIC)
218 uentry_setStatic (u);
220 else if (storageClass == SCEXTERN)
222 uentry_setExtern (u);
226 ; /* no storage class */
233 saveStoreLoc = g_currentloc;
236 void setFunctionNoGlobals (void)
238 llassert (globSet_isUndefined (currentGlobals));
243 setFunctionStateSpecialClause (lltok stok, specialClauseKind kind,
245 /*@unused@*/ lltok etok)
247 int tok = lltok_getTok (stok);
252 specClauses = specialClauses_add (specClauses,
253 specialClause_create (TK_BEFORE, kind, s));
256 specClauses = specialClauses_add (specClauses,
257 specialClause_create (TK_AFTER, kind, s));
264 DPRINTF (("Added to specclauses: %s", specialClauses_unparse (specClauses)));
267 void setFunctionSpecialClause (lltok stok, sRefSet s,
268 /*@unused@*/ lltok etok)
270 int tok = lltok_getTok (stok);
275 specClauses = specialClauses_add (specClauses, specialClause_createUses (s));
278 specClauses = specialClauses_add (specClauses, specialClause_createDefines (s));
281 specClauses = specialClauses_add (specClauses, specialClause_createAllocates (s));
284 specClauses = specialClauses_add (specClauses, specialClause_createSets (s));
287 specClauses = specialClauses_add (specClauses, specialClause_createReleases (s));
294 DPRINTF (("Added to specclauses: %s", specialClauses_unparse (specClauses)));
299 constraintList getFunctionConstraints (void)
301 return constraintList_copy (fcnConstraints);
305 constraintList getEnsuresConstraints (void)
307 return constraintList_copy (fcnEnsuresConstraints);
310 void setEnsuresConstraints (constraintList c)
312 if (fcnEnsuresConstraints != NULL)
313 constraintList_free(fcnEnsuresConstraints);
314 fcnEnsuresConstraints = constraintList_copy (c);
317 void setFunctionConstraints (constraintList c)
319 if (fcnConstraints != NULL)
320 constraintList_free(fcnConstraints);
321 fcnConstraints = constraintList_copy (c);
325 void setFunctionModifies (sRefSet s)
327 sRefSet_free (fcnModifies);
331 static void reflectGlobalQualifiers (sRef sr, qualList quals)
333 qualList_elements (quals, qel)
335 if (qual_isGlobalQual (qel)) /* undef, killed */
337 sstate oldstate = sRef_getDefState (sr);
338 sstate defstate = sstate_fromQual (qel);
340 if ((oldstate == SS_UNDEFGLOB && defstate == SS_KILLED)
341 || (oldstate == SS_KILLED && defstate == SS_UNDEFGLOB))
343 defstate = SS_UNDEFKILLED;
350 sRef_setDefState (sr, defstate, fileloc_undefined);
352 else if (qual_isAllocQual (qel)) /* out, partial, reldef, etc. */
354 ctype realType = sRef_getType (sr);
355 sstate defstate = sstate_fromQual (qel);
357 if (qual_isRelDef (qel))
359 ; /* okay anywhere */
363 if (!ctype_isAP (realType)
364 && !ctype_isSU (realType)
365 && !ctype_isUnknown (realType)
366 && !ctype_isAbstract (sRef_getType (sr)))
370 message ("Qualifier %s used on non-pointer or struct: %q",
371 qual_unparse (qel), sRef_unparse (sr)));
376 sRef_setDefState (sr, defstate, fileloc_undefined);
378 else if (qual_isNull (qel))
380 sRef_setNullState (sr, NS_POSNULL, fileloc_undefined);
382 else if (qual_isRelNull (qel))
384 sRef_setNullState (sr, NS_RELNULL, fileloc_undefined);
386 else if (qual_isNotNull (qel))
388 sRef_setNullState (sr, NS_MNOTNULL, fileloc_undefined);
392 if (qual_isCQual (qel))
399 message ("Qualifier %s cannot be used in a globals list",
400 qual_unparse (qel)));
403 } end_qualList_elements;
406 void globListAdd (sRef sr, qualList quals)
408 if (sRef_isValid (sr))
410 sRef sc = sRef_copy (sr);
412 reflectGlobalQualifiers (sc, quals);
413 currentGlobals = globSet_insert (currentGlobals, sc);
417 extern void declareCIter (cstring name, /*@owned@*/ uentryList params)
421 ue = uentry_makeIter (name,
422 ctype_makeFunction (ctype_void, params),
423 fileloc_copy (g_currentloc));
425 usymtab_supEntry (uentry_makeEndIter (name, fileloc_copy (g_currentloc)));
427 reflectModGlobs (ue);
429 ue = usymtab_supGlobalEntryReturn (ue);
432 extern void nextIterParam (void)
434 llassert (ProcessingIterVars);
438 extern int iterParamNo (void)
440 llassert (ProcessingIterVars);
441 return saveIterParamNo;
445 ** yucky hacks to put it in the right place
449 makeCurrentParam (idDecl t)
453 saveStoreLoc = fileloc_undefined;
455 /* param number unknown */
457 ue = uentry_makeParam (t, 0);
462 declareUnnamedEnum (enumNameList el)
464 ctype ret = usymtab_enumEnumNameListType (el);
468 if (ctype_isDefined (ret))
471 e = uentry_makeEnumTagLoc (ctype_enumTag (rt), ret);
473 reflectStorageClass (e);
474 usymtab_supGlobalEntry (e);
476 declareEnumList (el, ret, g_currentloc);
477 enumNameList_free (el);
481 ctype ct = ctype_createEnum (fakeTag (), el);
483 e = uentry_makeEnumTagLoc (ctype_enumTag (ctype_realType (ct)), ct);
484 reflectStorageClass (e);
486 e = usymtab_supGlobalEntryReturn (e);
487 rt = uentry_getAbstractType (e);
488 declareEnumList (el, ct, g_currentloc);
495 declareEnum (cstring ename, enumNameList el)
500 llassert (cstring_isDefined (ename));
502 cet = ctype_createEnum (ename, el);
503 e = uentry_makeEnumTagLoc (ename, cet);
504 reflectStorageClass (e);
505 e = usymtab_supGlobalEntryReturn (e);
506 cet = uentry_getType (e);
507 declareEnumList (el, cet, uentry_whereLast (e));
508 return (uentry_getAbstractType (e));
512 declareEnumList (enumNameList el, ctype c, fileloc loc)
514 bool boolnames = FALSE;
515 bool othernames = FALSE;
517 (void) context_getSaveLocation (); /* undefine it */
519 if (context_maybeSet (FLG_NUMENUMMEMBERS))
521 int maxnum = context_getValue (FLG_NUMENUMMEMBERS);
522 int num = enumNameList_size (el);
528 message ("Enumerator %s declared with %d members (limit is set to %d)",
529 ctype_unparse (c), num, maxnum),
534 enumNameList_elements (el, e)
536 uentry ue = usymtab_lookupExposeGlob (e);
537 ctype ct = uentry_getType (ue);
539 llassert (uentry_isEnumConstant (ue));
541 if (ctype_isUnknown (ct))
543 uentry_setType (ue, c);
547 if (cstring_equal (e, context_getFalseName ())
548 || cstring_equal (e, context_getTrueName ()))
554 message ("Enumerator mixes boolean name (%s) with "
557 uentry_whereLast (ue)))
564 uentry_setType (ue, ctype_bool);
565 DPRINTF (("Set type: %s / %s",
566 uentry_unparse (ue), ctype_unparse (ctype_bool)));
574 message ("Enumerator mixes boolean names (%s, %s) with "
575 "non-boolean name: %s",
576 context_getTrueName (),
577 context_getFalseName (),
579 uentry_whereLast (ue)))
588 if (!ctype_match (c, ct))
590 if (ctype_isDirectBool (ct))
592 if (cstring_equal (e, context_getFalseName ())
593 || cstring_equal (e, context_getTrueName ()))
595 DPRINTF (("Here we are!"));
601 message ("Enumerator member %s declared with "
602 "inconsistent type: %s",
603 e, ctype_unparse (c)),
604 uentry_whereLast (ue)))
606 uentry_showWhereSpecifiedExtra
607 (ue, cstring_copy (ctype_unparse (ct)));
615 message ("Enumerator member %s declared with "
616 "inconsistent type: %s",
617 e, ctype_unparse (c)),
618 uentry_whereLast (ue)))
620 uentry_showWhereSpecifiedExtra
621 (ue, cstring_copy (ctype_unparse (ct)));
626 } end_enumNameList_elements;
629 static /*@dependent@*/ uentryList currentParamList;
631 /*drl added 3-28-2001*/
632 /* this function takes a list of paramentar and generates a list
634 Currently the only constraints gnerated are MaxSet(p) >= 0 for all pointers
636 void setImplictfcnConstraints (void)
641 params = currentParamList;
643 if (implicitFcnConstraints != NULL)
644 constraintList_free(implicitFcnConstraints);
646 implicitFcnConstraints = constraintList_makeNew();
648 uentryList_elements (params, el)
650 DPRINTF((message("setImplictfcnConstraints doing: %s", uentry_unparse(el) ) ));
652 s = uentry_getSref(el);
653 if (sRef_isReference (s) )
655 DPRINTF((message ("%s is a pointer", sRef_unparse(s) ) ));
659 DPRINTF((message ("%s is NOT a pointer", sRef_unparse(s) ) ));
662 chagned this is MaxSet(s) == 0 to MaxSet(s) >= 0 */
664 c = constraint_makeSRefWriteSafeInt (s, 0);
665 // constraint_makeSRefSetBufferSize (s, 0);
666 implicitFcnConstraints = constraintList_add(implicitFcnConstraints , c);
668 end_uentryList_elements;
671 void setCurrentParams (/*@dependent@*/ uentryList ue)
673 currentParamList = ue;
676 void clearCurrentParams (void)
678 currentParamList = uentryList_undefined;
682 ** requires: uentry_isFunction (e)
683 ** parameter names for current function are in currentParamList
686 static void enterFunctionParams (uentryList params)
690 uentryList_elements (params, current)
692 if (uentry_hasName (current))
694 uentry_setParamNo (current, paramno);
695 usymtab_supEntry (uentry_copy (current));
699 } end_uentryList_elements;
703 extern void enterParamsTemp (void)
705 usymtab_enterScope ();
706 enterFunctionParams (currentParamList);
709 extern void exitParamsTemp (void)
711 usymtab_quietPlainExitScope ();
714 static /*@exposed@*/ uentry globalDeclareFunction (idDecl tid)
716 ctype deftype = idDecl_getCtype (tid);
720 DPRINTF (("Global function: %s", idDecl_unparse (tid)));
722 if (ctype_isFunction (deftype))
724 rettype = ctype_returnValue (deftype);
728 rettype = ctype_unknown;
732 ** check has been moved here...
735 if (ctype_isFunction (idDecl_getCtype (tid)))
737 ue = uentry_makeIdFunction (tid);
738 reflectSpecialCode (ue);
739 reflectArgsUsed (ue);
743 llparseerror (message ("Inconsistent function declaration: %q",
744 idDecl_unparse (tid)));
746 tid = idDecl_replaceCtype
747 (tid, ctype_makeFunction (ctype_unknown, uentryList_undefined));
748 ue = uentry_makeIdFunction (tid);
751 reflectStorageClass (ue);
753 uentry_checkParams (ue);
754 reflectModGlobs (ue);
756 ue = usymtab_supGlobalEntryReturn (ue);
757 context_enterFunction (ue);
758 enterFunctionParams (uentry_getParams (ue));
760 resetStorageClass ();
765 ** for now, no type checking
766 ** (must check later though!)
769 static /*@only@*/ uentry globalDeclareOldStyleFunction (idDecl tid)
774 ** check has been moved here...
777 if (cstring_equalLit (idDecl_observeId (tid), "main"))
779 context_setFlagTemp (FLG_MAINTYPE, FALSE);
782 ue = uentry_makeIdFunction (tid);
783 reflectStorageClass (ue);
784 reflectSpecialCode (ue);
785 reflectArgsUsed (ue);
786 uentry_setDefined (ue, g_currentloc);
788 uentry_checkParams (ue);
790 if (ProcessingGlobals)
792 uentry_setGlobals (ue, currentGlobals);
795 resetStorageClass ();
799 static void oldStyleDeclareFunction (/*@only@*/ uentry e)
801 uentryList params = saveParamList;
802 ctype rt = uentry_getType (e);
804 llassert (ctype_isFunction (rt));
806 e = usymtab_supGlobalEntryReturn (e);
808 context_enterFunction (e);
809 enterFunctionParams (params);
810 saveParamList = uentryList_undefined;
811 resetStorageClass ();
814 void declareFunction (idDecl tid) /*@globals undef saveFunction; @*/
818 DPRINTF (("Declare function: %s", idDecl_unparse (tid)));
820 if (ProcessingParams)
822 ue = globalDeclareOldStyleFunction (tid);
827 saveFunction = uentry_undefined;
829 if (context_inRealFunction ())
831 ue = uentry_makeVariableLoc (idDecl_observeId (tid), ctype_unknown);
833 llparseerror (message ("Function declared inside function: %q",
834 idDecl_unparse (tid)));
836 context_quietExitFunction ();
837 ue = usymtab_supEntryReturn (ue);
841 if (context_inInnerScope ())
843 llparseerror (message ("Declaration in inner context: %q",
844 idDecl_unparse (tid)));
846 sRef_setGlobalScope ();
847 ue = uentry_makeVariableLoc (idDecl_observeId (tid),
849 ue = usymtab_supGlobalEntryReturn (ue);
850 sRef_clearGlobalScope ();
854 ue = globalDeclareFunction (tid);
861 resetStorageClass ();
865 void declareStaticFunction (idDecl tid) /*@globals undef saveFunction; @*/
869 DPRINTF (("Declare static funciton: %s", idDecl_unparse (tid)));
871 if (ProcessingParams)
873 ue = globalDeclareOldStyleFunction (tid);
878 saveFunction = uentry_undefined;
880 if (context_inRealFunction ())
882 ue = uentry_makeVariableLoc (idDecl_observeId (tid), ctype_unknown);
884 llparseerror (message ("Function declared inside function: %q",
885 idDecl_unparse (tid)));
887 context_quietExitFunction ();
888 ue = usymtab_supEntryReturn (ue);
892 if (context_inInnerScope ())
894 llparseerror (message ("Declaration in inner context: %q",
895 idDecl_unparse (tid)));
897 sRef_setGlobalScope ();
898 ue = uentry_makeVariableLoc (idDecl_observeId (tid),
900 ue = usymtab_supGlobalEntryReturn (ue);
901 sRef_clearGlobalScope ();
905 ctype deftype = idDecl_getCtype (tid);
908 if (ctype_isFunction (deftype))
910 rettype = ctype_returnValue (deftype);
914 rettype = ctype_unknown;
918 ** check has been moved here...
921 if (ctype_isFunction (idDecl_getCtype (tid)))
923 ue = uentry_makeIdFunction (tid);
924 reflectSpecialCode (ue);
925 reflectArgsUsed (ue);
929 llparseerror (message ("Inconsistent function declaration: %q",
930 idDecl_unparse (tid)));
932 tid = idDecl_replaceCtype
933 (tid, ctype_makeFunction (ctype_unknown, uentryList_undefined));
934 ue = uentry_makeIdFunction (tid);
937 reflectStorageClass (ue);
938 uentry_setStatic (ue);
940 uentry_checkParams (ue);
941 reflectModGlobs (ue);
943 DPRINTF (("Sub global entry: %s", uentry_unparse (ue)));
944 ue = usymtab_supGlobalEntryReturn (ue);
946 context_enterFunction (ue);
947 enterFunctionParams (uentry_getParams (ue));
948 resetStorageClass ();
955 resetStorageClass ();
960 checkTypeDecl (uentry e, ctype rep)
962 cstring n = uentry_getName (e);
964 DPRINTF (("Check type decl: %s", n));
966 if (cstring_equal (context_getBoolName (), n))
968 ctype rrep = ctype_realType (rep);
971 ** for abstract enum types, we need to fix the enum members:
972 ** they should have the abstract type, not the rep type.
975 if (ctype_isEnum (ctype_realType (rrep)))
977 enumNameList el = ctype_elist (rrep);
979 enumNameList_elements (el, ye)
981 if (usymtab_existsGlob (ye))
983 uentry ue = usymtab_lookupSafe (ye);
984 uentry_setType (ue, ctype_bool);
987 if (cstring_equal (context_getTrueName (), ye)
988 || cstring_equal (context_getFalseName (), ye))
996 message ("Member of boolean enumerated type definition "
997 "does not match name set to represent TRUE "
1000 message ("Use -boolfalse and -booltrue to set the "
1001 "name of false and true boolean values."),
1002 uentry_whereDefined (e));
1004 } end_enumNameList_elements;
1008 if (usymtab_exists (n))
1010 usymId llm = usymtab_getId (n);
1011 uentry le = usymtab_getTypeEntry (llm);
1013 uentry_setDeclared (e, g_currentloc);
1014 uentry_setSref (e, sRef_makeGlobal (llm, uentry_getType (le)));
1016 DPRINTF (("Here we are: %s / %s",
1017 n, context_getBoolName ()));
1019 if (uentry_isAbstractDatatype (le))
1021 ctype rrep = ctype_realType (rep);
1024 ** for abstract enum types, we need to fix the enum members:
1025 ** they should have the abstract type, not the rep type.
1028 if (ctype_isEnum (ctype_realType (rrep)))
1030 ctype at = uentry_getAbstractType (le);
1031 enumNameList el = ctype_elist (rrep);
1033 enumNameList_elements (el, ye)
1035 if (usymtab_existsGlob (ye))
1037 uentry ue = usymtab_lookupSafe (ye);
1039 llassert (uentry_isEitherConstant (ue));
1040 llassertprint (ctype_match (uentry_getType (ue), rrep),
1041 ("Bad enum: %s / %s",
1042 uentry_unparse (ue),
1043 ctype_unparse (rrep)));
1045 uentry_setType (ue, at);
1047 } end_enumNameList_elements;
1050 if (uentry_isMutableDatatype (le))
1052 /* maybe more complicated if abstract and immutable ? */
1054 if (!ctype_isRealPointer (rep) && !ctype_isRealAbstract (rep))
1058 message ("Mutable abstract type %s declared without pointer "
1059 "indirection: %s (violates assignment semantics)",
1060 n, ctype_unparse (rep)),
1061 uentry_whereDefined (e));
1063 uentry_setMutable (e);
1070 fileloc fl = uentry_whereDeclared (e);
1072 if (context_getFlag (FLG_LIKELYBOOL)
1073 && !context_getFlag (FLG_BOOLINT))
1075 if ((cstring_equalLit (n, "BOOL")
1076 || cstring_equalLit (n, "Bool")
1077 || cstring_equalLit (n, "bool")
1078 || cstring_equalLit (n, "boolean")
1079 || cstring_equalLit (n, "Boolean")
1080 || cstring_equalLit (n, "BOOLEAN"))
1081 && !(cstring_equal (n, context_getBoolName ())))
1083 if (context_setBoolName ()) {
1086 message ("Type %s is probably meant as a boolean type, but does "
1087 "not match the boolean type name \"%s\".",
1089 context_getBoolName ()),
1094 message ("Type %s is probably meant as a boolean type, "
1095 "but the boolean type name is not set. "
1096 "Use -booltype %s to set it.",
1103 if (!uentry_isStatic (e)
1104 && !ctype_isFunction (uentry_getType (e))
1105 && !fileloc_isLib (fl)
1106 && !fileloc_isImport (fl)
1107 && fileloc_isHeader (fl))
1109 voptgenerror (FLG_EXPORTTYPE,
1110 message ("Type exported, but not specified: %s\n", n),
1119 fixUentryList (idDeclList tl, qtype q)
1121 uentryList f = uentryList_new ();
1123 idDeclList_elements (tl, i)
1125 if (idDecl_isDefined (i))
1131 (void) idDecl_fixBase (i, q);
1134 ** implicit annotations
1137 (void) fixStructDecl (i);
1139 ue = uentry_makeIdVariable (i);
1140 rt = ctype_realType (uentry_getType (ue));
1143 ** where is this here???
1145 if (ctype_isArray (rt) || ctype_isSU (rt))
1147 sRef_setAllocated (uentry_getSref (ue), uentry_whereDefined (ue));
1153 if (uentry_isValid (old = uentryList_lookupField (f, uentry_rawName (ue))))
1155 if (optgenerror (FLG_SYNTAX,
1156 message ("Field name reused: %s", uentry_rawName (ue)),
1157 uentry_whereDefined (ue)))
1159 llgenmsg (message ("Previous use of %s", uentry_rawName (ue)),
1160 uentry_whereDefined (old));
1164 f = uentryList_add (f, ue);
1166 } end_idDeclList_elements;
1168 idDeclList_free (tl);
1173 ** This is a hack to support unnamed struct/union fields as done by
1174 ** Microsoft VC++. It is not supported by the ANSI standard.
1176 ** The inner fields are added to the outer structure. This is meaningful
1177 ** for nesting structs inside unions, but lclint does no related
1182 fixUnnamedDecl (qtype q)
1184 ctype ct = ctype_realType (qtype_getType (q));
1186 if (ctype_isStruct (ct) || ctype_isUnion (ct))
1188 uentryList res = ctype_getFields (ct);
1190 return (uentryList_copy (res));
1197 return uentryList_undefined;
1200 void setStorageClass (storageClassCode sc)
1206 setProcessingIterVars (uentry iter)
1208 ProcessingIterVars = TRUE;
1210 saveIterParamNo = 0;
1214 setProcessingGlobalsList ()
1216 ProcessingGlobals = TRUE;
1218 llassert (globSet_isUndefined (currentGlobals));
1219 currentGlobals = globSet_undefined;
1221 llassert (sRefSet_isUndefined (fcnModifies));
1222 fcnModifies = sRefSet_undefined;
1225 ** No, special clauses might have been processed first!
1226 llassert (specialClauses_isUndefined (specClauses));
1227 specClauses = specialClauses_undefined;
1230 fcnNoGlobals = FALSE;
1233 static bool ProcessingGlobMods = FALSE;
1236 setProcessingGlobMods ()
1238 ProcessingGlobMods = TRUE;
1242 clearProcessingGlobMods ()
1244 ProcessingGlobMods = FALSE;
1248 isProcessingGlobMods ()
1250 return (ProcessingGlobMods);
1253 static void resetGlobals (void)
1255 ProcessingGlobals = FALSE;
1256 currentGlobals = globSet_undefined;
1257 llassert (sRefSet_isUndefined (fcnModifies));
1258 fcnModifies = sRefSet_undefined;
1259 fcnNoGlobals = FALSE;
1263 unsetProcessingGlobals ()
1265 ProcessingGlobals = FALSE;
1269 setProcessingVars (/*@only@*/ qtype q)
1271 ProcessingVars = TRUE;
1272 qtype_free (processingType);
1277 setGenericParamList (/*@dependent@*/ uentryList pm)
1279 ProcessingParams = TRUE;
1284 setProcessingTypedef (/*@only@*/ qtype q)
1286 ProcessingTypedef = TRUE;
1288 qtype_free (processingType);
1293 unsetProcessingVars ()
1295 resetStorageClass ();
1296 ProcessingVars = FALSE;
1302 if (ProcessingParams)
1304 if (uentry_isInvalid (saveFunction))
1306 llbuglit ("unsetProcessingVars: no saved function\n");
1308 if (sRefSet_isDefined (fcnModifies)) {
1309 sRefSet_free (fcnModifies);
1310 fcnModifies = sRefSet_undefined;
1315 ctype ct = ctype_returnValue (uentry_getType (saveFunction));
1316 uentryList params = uentryList_copy (saveParamList);
1317 ctype ct2 = ctype_makeFunction (ct, params);
1319 uentry_setType (saveFunction, ct2);
1320 ProcessingParams = FALSE;
1322 reflectModGlobs (saveFunction);
1323 oldStyleDeclareFunction (saveFunction);
1324 saveFunction = uentry_undefined;
1331 ** If the paramlist used a type name, we could be here.
1334 llfatalerror (message ("%q: Old-style function parameter list uses a "
1335 "type name.", fileloc_unparse (g_currentloc)));
1342 if (uentry_isValid (saveFunction))
1345 ** old style declaration
1348 ctype ct = ctype_returnValue (uentry_getType (saveFunction));
1351 uentryList_elements (saveParamList, current)
1353 uentry_setType (current, ctype_int); /* all params are ints */
1354 } end_uentryList_elements;
1356 ct2 = ctype_makeParamsFunction (ct, uentryList_copy (saveParamList));
1358 uentry_setType (saveFunction, ct2);
1359 ProcessingParams = FALSE;
1361 oldStyleDeclareFunction (saveFunction);
1362 saveFunction = uentry_undefined;
1367 unsetProcessingTypedef ()
1369 ProcessingTypedef = FALSE;
1372 void checkConstant (qtype t, idDecl id)
1376 id = idDecl_fixBase (id, t);
1377 e = uentry_makeIdConstant (id);
1379 reflectStorageClass (e);
1380 resetStorageClass ();
1382 usymtab_supGlobalEntry (e);
1385 void checkValueConstant (qtype t, idDecl id, exprNode e)
1389 id = idDecl_fixBase (id, t);
1390 ue = uentry_makeIdConstant (id);
1391 reflectStorageClass (ue);
1392 resetStorageClass ();
1394 if (exprNode_isDefined (e))
1396 if (!exprNode_matchType (uentry_getType (ue), e))
1399 (exprNode_getType (e), e,
1400 uentry_getType (ue), exprNode_undefined,
1401 message ("Constant %q initialized to type %t, expects %t: %s",
1402 uentry_getName (ue),
1403 exprNode_getType (e),
1404 uentry_getType (ue),
1405 exprNode_unparse (e)),
1410 if (exprNode_hasValue (e))
1412 uentry_mergeConstantValue (ue, multiVal_copy (exprNode_getValue (e)));
1417 usymtab_supGlobalEntry (ue);
1421 void processNamedDecl (idDecl t)
1423 if (qtype_isUndefined (processingType))
1425 llparseerror (message ("No type before declaration name: %q", idDecl_unparse (t)));
1427 processingType = qtype_create (ctype_unknown);
1430 t = idDecl_fixBase (t, processingType);
1432 DPRINTF (("Declare: %s", idDecl_unparse (t)));
1434 if (ProcessingGlobals)
1436 cstring id = idDecl_getName (t);
1437 uentry ue = usymtab_lookupSafe (id);
1439 if (!uentry_isValid (ue))
1441 llerror (FLG_UNRECOG,
1442 message ("Variable used in globals list is undeclared: %s", id));
1446 if (!ctype_match (uentry_getType (ue), idDecl_getCtype (t)))
1450 message ("Variable %s used in globals list declared %s, "
1452 id, ctype_unparse (uentry_getType (ue)),
1453 ctype_unparse (idDecl_getCtype (t))),
1458 sRef sr = sRef_copy (uentry_getSref (ue));
1460 reflectGlobalQualifiers (sr, idDecl_getQuals (t));
1462 currentGlobals = globSet_insert (currentGlobals, sr);
1466 else if (ProcessingVars)
1471 ct = ctype_realType (idDecl_getCtype (t));
1473 if (ProcessingParams)
1475 cstring id = idDecl_getName (t);
1476 int paramno = uentryList_lookupRealName (saveParamList, id);
1480 uentry cparam = uentryList_getN (saveParamList, paramno);
1482 uentry_setType (cparam, idDecl_getCtype (t));
1483 uentry_reflectQualifiers (cparam, idDecl_getQuals (t));
1484 uentry_setDeclaredOnly (cparam, context_getSaveLocation ());
1489 (message ("Old style declaration uses unlisted parameter: %s",
1497 if (context_inIterDef ())
1499 cstring pname = makeParam (idDecl_observeId (t));
1500 uentry p = usymtab_lookupSafe (pname);
1502 cstring_free (pname);
1504 if (uentry_isYield (p))
1506 e = uentry_makeParam (t, sRef_getParam (uentry_getSref (p)));
1508 uentry_checkYieldParam (p, e);
1510 usymtab_supEntrySref (e);
1515 if ((hasSpecialCode () || argsUsed)
1516 && ctype_isFunction (idDecl_getCtype (t)))
1518 e = uentry_makeIdFunction (t);
1519 reflectSpecialCode (e);
1520 reflectArgsUsed (e);
1524 e = uentry_makeIdVariable (t);
1527 loc = uentry_whereDeclared (e);
1530 if (context_inGlobalScope ())
1532 uentry_checkParams was here!
1536 if (ctype_isFunction (uentry_getType (e)))
1538 reflectModGlobs (e);
1542 llassert (!globSet_isDefined (currentGlobals)
1543 && !sRefSet_isDefined (fcnModifies));
1546 e = usymtab_supEntrySrefReturn (e);
1548 if (uentry_isExtern (e) && !context_inGlobalScope ())
1552 message ("Declaration using extern inside function scope: %q",
1553 uentry_unparse (e)),
1556 uentry_setDefined (e, fileloc_getExternal ());
1557 sRef_setDefined (uentry_getSref (e), fileloc_getExternal ());
1560 if (uentry_isFunction (e))
1562 uentry_checkParams (e);
1563 checkParamNames (e);
1566 if (uentry_isVar (e)
1567 && uentry_isCheckedUnknown (e))
1569 sRef sr = uentry_getSref (e);
1571 if (sRef_isLocalVar (sr))
1573 if (context_getFlag (FLG_IMPCHECKMODINTERNALS))
1575 uentry_setCheckMod (e);
1579 uentry_setUnchecked (e);
1582 else if (sRef_isFileStatic (sr))
1584 if (context_getFlag (FLG_IMPCHECKEDSTRICTSTATICS))
1586 uentry_setCheckedStrict (e);
1588 else if (context_getFlag (FLG_IMPCHECKEDSTATICS))
1590 uentry_setChecked (e);
1592 else if (context_getFlag (FLG_IMPCHECKMODSTATICS))
1594 uentry_setCheckMod (e);
1601 else /* real global */
1603 llassert (sRef_isRealGlobal (sr));
1605 if (context_getFlag (FLG_IMPCHECKEDSTRICTGLOBALS))
1607 uentry_setCheckedStrict (e);
1609 else if (context_getFlag (FLG_IMPCHECKEDGLOBALS))
1611 uentry_setChecked (e);
1613 else if (context_getFlag (FLG_IMPCHECKMODGLOBALS))
1615 uentry_setCheckMod (e);
1625 else if (ProcessingTypedef)
1627 ctype ct = idDecl_getCtype (t);
1630 DPRINTF (("Processing typedef: %s", ctype_unparse (ct)));
1632 e = uentry_makeIdDatatype (t);
1634 if (cstring_equal (idDecl_getName (t), context_getBoolName ())) {
1635 ctype rt = ctype_realType (ct);
1637 if (ctype_isEnum (rt)) {
1640 if (!(ctype_isInt (rt)
1641 || ctype_isUnknown (rt)
1642 || ctype_isChar (rt))) {
1645 message ("Boolean type %s defined using non-standard type %s (integral, char or enum type expected)",
1646 context_getBoolName (),
1647 ctype_unparse (ct)),
1648 uentry_whereLast (e));
1652 uentry_setType (e, ct);
1656 reflectStorageClass (e);
1657 checkTypeDecl (e, ct);
1659 e = usymtab_supReturnTypeEntry (e);
1661 if (uentry_isMaybeAbstract (e))
1663 if (context_getFlag (FLG_IMPABSTRACT))
1665 uentry_setAbstract (e);
1669 uentry_setConcrete (e);
1675 llparseerror (message ("Suspect missing struct or union keyword: %q",
1676 idDecl_unparse (t)));
1682 ** moved from grammar
1685 static idDecl fixStructDecl (/*@returned@*/ idDecl d)
1687 if (ctype_isVisiblySharable (idDecl_getCtype (d))
1688 && context_getFlag (FLG_STRUCTIMPONLY))
1690 if (!qualList_hasAliasQualifier (idDecl_getQuals (d)))
1692 if (qualList_hasExposureQualifier (idDecl_getQuals (d)))
1694 idDecl_addQual (d, qual_createDependent ());
1698 idDecl_addQual (d, qual_createImpOnly ());
1707 declareUnnamedStruct (/*@only@*/ uentryList f)
1709 if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1711 int num = uentryList_size (f);
1712 int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1717 (FLG_NUMSTRUCTFIELDS,
1718 message ("Structure declared with %d fields "
1719 "(limit is set to %d)",
1725 return (ctype_createUnnamedStruct (f));
1729 declareUnnamedUnion (/*@only@*/ uentryList f)
1731 if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1733 int num = uentryList_size (f);
1734 int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1739 (FLG_NUMSTRUCTFIELDS,
1740 message ("Union declared with %d fields "
1741 "(limit is set to %d)",
1747 return (ctype_createUnnamedUnion (f));
1750 ctype declareStruct (cstring id, /*@only@*/ uentryList f)
1754 int num = uentryList_size (f);
1756 ct = ctype_createStruct (cstring_copy (id), f);
1757 DPRINTF (("Declare struct: %s [%d]", ctype_unparse (ct), ct));
1758 ue = uentry_makeStructTagLoc (id, ct);
1760 if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1762 int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1767 (FLG_NUMSTRUCTFIELDS,
1768 message ("Structure %q declared with %d fields "
1769 "(limit is set to %d)",
1770 uentry_getName (ue), num, max),
1771 uentry_whereLast (ue));
1775 return (usymtab_supTypeEntry (ue));
1778 ctype declareUnion (cstring id, uentryList f)
1782 int num = uentryList_size (f);
1784 ct = ctype_createUnion (cstring_copy (id), f);
1785 ue = uentry_makeUnionTagLoc (id, ct);
1787 if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1789 int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1794 (FLG_NUMSTRUCTFIELDS,
1795 message ("Union %q declared with %d fields "
1796 "(limit is set to %d)",
1797 uentry_getName (ue), num, max),
1798 uentry_whereLast (ue));
1802 return (usymtab_supTypeEntry (ue));
1805 ctype handleStruct (/*@only@*/ cstring id)
1807 if (usymtab_existsStructTag (id))
1809 ctype ct = uentry_getAbstractType (usymtab_lookupStructTag (id));
1816 return (ctype_createForwardStruct (id));
1820 ctype handleUnion (/*@only@*/ cstring id)
1822 if (usymtab_existsUnionTag (id))
1824 ctype ret = uentry_getAbstractType (usymtab_lookupUnionTag (id));
1830 return (ctype_createForwardUnion (id));
1835 handleEnum (cstring id)
1837 if (usymtab_existsEnumTag (id))
1839 ctype ret = uentry_getAbstractType (usymtab_lookupEnumTag (id));
1845 return (declareEnum (id, enumNameList_new ()));
1849 bool processingIterVars (void)
1851 return ProcessingIterVars;
1854 uentry getCurrentIter (void)
1859 static bool flipOldStyle = FALSE;
1860 static bool flipNewStyle = TRUE;
1862 void setFlipOldStyle () { flipOldStyle = TRUE; }
1863 bool isFlipOldStyle () { return flipOldStyle; }
1864 bool isNewStyle () { return flipNewStyle; }
1865 void setNewStyle () { flipNewStyle = TRUE; }
1867 /*@dependent@*/ uentryList handleParamIdList (/*@dependent@*/ uentryList params)
1872 ** this is a really YUCKY hack to handle old style
1876 voptgenerror (FLG_OLDSTYLE,
1877 cstring_makeLiteral ("Old style function declaration"),
1880 uentryList_elements (params, current)
1882 uentry_setParam (current);
1883 uentry_setSref (current, sRef_makeParam (paramno, ctype_unknown));
1885 } end_uentryList_elements;
1887 setGenericParamList (params);
1888 g_expectingTypeName = TRUE;
1893 /*@dependent@*/ uentryList handleParamTypeList (/*@returned@*/ uentryList params)
1897 uentryList_fixMissingNames (params);
1899 voptgenerror (FLG_OLDSTYLE,
1900 cstring_makeLiteral ("Old style function declaration."),
1903 setGenericParamList (params);
1904 flipOldStyle = FALSE;
1905 g_expectingTypeName = TRUE;
1914 ctype c = ctype_unknown;
1915 cstring id = cstring_makeLiteral ("va_alist");
1918 if (ProcessingParams)
1920 int i = uentryList_lookupRealName (saveParamList, id);
1924 e = uentry_makeVariableSrefParam (id, c, sRef_makeParam (i, c));
1928 e = uentry_undefined; /* suppress gcc message */
1929 llfatalerrorLoc (cstring_makeLiteral ("va_dcl used without va_alist"));
1934 llerror (FLG_SYNTAX, cstring_makeLiteral ("va_dcl used outside of function declaration"));
1935 e = uentry_makeVariableLoc (id, c);
1939 uentry_setUsed (e, g_currentloc);
1940 usymtab_supEntrySref (e);
1943 /*@exposed@*/ sRef modListPointer (sRef s)
1945 ctype ct = sRef_getType (s);
1946 ctype rt = ctype_realType (ct);
1948 if (ctype_isAP (rt))
1950 if (context_inHeader () && ctype_isAbstract (ct))
1955 ("Modifies clause in header file dereferences abstract "
1956 "type %s (interface modifies clause should not depend "
1957 "on or expose type representation): %q",
1963 return (sRef_constructPointer (s));
1967 if (ctype_isKnown (rt))
1971 message ("Implementation modifies clause dereferences non-pointer (type %s): %q",
1981 /*@exposed@*/ sRef modListFieldAccess (sRef s, cstring f)
1983 ctype ct = sRef_getType (s);
1984 ctype rt = ctype_realType (ct);
1986 if (ctype_isStructorUnion (rt))
1988 uentry tf = uentryList_lookupField (ctype_getFields (rt), f);
1990 if (uentry_isUndefined (tf))
1992 voptgenerror (FLG_TYPE,
1993 message ("Modifies list accesses non-existent "
1994 "field %s of %t: %q", f, ct,
1999 return sRef_undefined;
2003 if (ctype_isAbstract (ct) && context_inHeader ())
2008 ("Modifies clause in header file accesses abstract "
2009 "type %s (interface modifies clause should not depend "
2010 "on or expose type representation): %q",
2017 cstring_markOwned (f);
2018 return (sRef_makeField (s, f));
2024 message ("Modifies clause dereferences non-pointer (type %s): %q",
2034 sRef globListUnrecognized (cstring s)
2036 if (cstring_equalLit (s, "nothing"))
2038 return sRef_makeNothing ();
2040 else if (cstring_equalLit (s, "internalState"))
2042 return sRef_makeInternalState ();
2044 else if (cstring_equalLit (s, "fileSystem")
2045 || cstring_equalLit (s, "systemState"))
2047 return sRef_makeSystemState ();
2053 message ("Unrecognized identifier in globals list: %s", s),
2056 return sRef_undefined;
2060 /*@exposed@*/ sRef modListArrowAccess (sRef s, cstring f)
2062 ctype ct = sRef_getType (s);
2063 ctype rt = ctype_realType (ct);
2065 if (ctype_isRealPointer (rt))
2067 ctype b = ctype_baseArrayPtr (rt);
2068 ctype rb = ctype_realType (b);
2070 if (ctype_isStructorUnion (rb))
2072 uentry tf = uentryList_lookupField (ctype_getFields (rb), f);
2074 if (uentry_isUndefined (tf))
2076 voptgenerror (FLG_TYPE,
2077 message ("Modifies list arrow accesses non-existent "
2078 "field %s of %t: %q", f, b,
2083 return sRef_undefined;
2087 if (context_inHeader ())
2089 if (ctype_isAbstract (b))
2094 ("Modifies clause in header file arrow accesses abstract "
2095 "type %s (interface modifies clause should not depend "
2096 "on or expose type representation): %q",
2104 if (ctype_isAbstract (ct))
2109 ("Modifies clause in header file arrow accesses abstract "
2110 "type %s (interface modifies clause should not depend "
2111 "on or expose type representation): %q",
2119 cstring_markOwned (f);
2120 return (sRef_makeArrow (s, f));
2126 message ("Modifies clause arrow accesses pointer to "
2127 "non-structure (type %s): %q",
2137 message ("Modifies clause arrow accesses non-pointer (type %s): %q",
2147 sRef checkSpecClausesId (uentry ue)
2149 cstring s = uentry_rawName (ue);
2151 if (sRef_isGlobal (uentry_getSref (ue)))
2155 message ("Global variable %s used special clause. (Global variables "
2156 "are not recognized in special clauses. If there is "
2157 "sufficient interest in support for this, it may be "
2158 "added to a future release. Send mail to "
2159 "lclint@cs.virginia.edu.)",
2163 return sRef_undefined;
2167 if (cstring_equalLit (s, "result"))
2171 message ("Special clause list uses %s which is a variable and has special "
2172 "meaning in a modifies list. (Special meaning assumed.)", s),
2175 uentry_showWhereDeclared (ue);
2179 return uentry_getSref (ue);
2185 don;t know what the real date is...
2191 based on checkSpecClausesId
2194 sRef checkbufferConstraintClausesId (uentry ue)
2196 cstring s = uentry_rawName (ue);
2197 if (cstring_equalLit (s, "result"))
2201 message ("Special clause list uses %s which is a variable and has special "
2202 "meaning in a modifies list. (Special meaning assumed.)", s),
2205 uentry_showWhereDeclared (ue);
2209 return sRef_copy( uentry_getSref (ue) );
2212 void checkModifiesId (uentry ue)
2214 cstring s = uentry_rawName (ue);
2216 if (cstring_equalLit (s, "nothing")
2217 || cstring_equalLit (s, "internalState")
2218 || cstring_equalLit (s, "systemState")
2219 || (cstring_equalLit (s, "fileSystem")))
2223 message ("Modifies list uses %s which is a variable and has special "
2224 "meaning in a modifies list. (Special meaning assumed.)", s),
2227 uentry_showWhereDeclared (ue);
2232 /*@exposed@*/ sRef fixModifiesId (cstring s)
2235 cstring pname = makeParam (s);
2236 uentry ue = usymtab_lookupSafe (pname);
2238 cstring_free (pname);
2240 if (cstring_equalLit (s, "nothing"))
2242 ret = sRef_makeNothing ();
2244 else if (cstring_equalLit (s, "internalState"))
2246 ret = sRef_makeInternalState ();
2248 else if (cstring_equalLit (s, "fileSystem")
2249 || cstring_equalLit (s, "systemState"))
2251 ret = sRef_makeSystemState ();
2255 ret = sRef_undefined;
2258 if (sRef_isValid (ret))
2260 if (uentry_isValid (ue))
2264 message ("Modifies list uses %s which is a parameter and has special "
2265 "meaning in a modifies list. (Special meaning assumed.)", s),
2271 if (uentry_isValid (ue))
2273 ret = uentry_getSref (ue);
2277 fileloc loc = fileloc_decColumn (g_currentloc, cstring_length (s));
2278 ret = sRef_undefined;
2282 message ("Unrecognized identifier in modifies comment: %s", s),
2292 sRef fixSpecClausesId (cstring s)
2295 cstring pname = makeParam (s);
2296 uentry ue = usymtab_lookupSafe (pname);
2298 cstring_free (pname);
2300 if (cstring_equalLit (s, "result"))
2302 ret = sRef_makeResult ();
2306 ret = sRef_undefined;
2309 if (sRef_isValid (ret))
2311 if (uentry_isValid (ue))
2315 message ("Special clause uses %s which is a parameter and has special "
2316 "meaning in a special clause. (Special meaning assumed.)", s),
2322 if (uentry_isValid (ue))
2324 ret = uentry_getSref (ue);
2326 if (sRef_isGlobal (ret))
2330 message ("Global variable %s used special clause. (Global variables "
2331 "are not recognized in special clauses. If there is "
2332 "sufficient interest in support for this, it may be "
2333 "added to a future release. Send mail to "
2334 "lclint@cs.virginia.edu.)",
2338 ret = sRef_undefined;
2343 fileloc loc = fileloc_decColumn (g_currentloc, cstring_length (s));
2344 ret = sRef_undefined;
2348 message ("Unrecognized identifier in special clause: %s", s),
2358 sRef modListArrayFetch (sRef s, /*@unused@*/ sRef mexp)
2360 ctype ct = sRef_getType (s);
2361 ctype rt = ctype_realType (ct);
2363 if (ctype_isAP (rt))
2365 if (context_inHeader () && ctype_isAbstract (ct))
2370 ("Modifies clause in header file indexes abstract "
2371 "type %s (interface modifies clause should not depend "
2372 "on or expose type representation): %q",
2378 return (sRef_makeAnyArrayFetch (s));
2385 ("Implementation modifies clause uses array fetch on non-array (type %s): %q",
2386 ctype_unparse (ct), sRef_unparse (s)),