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)
313 fcnEnsuresConstraints = constraintList_copy (c);
316 void setFunctionConstraints (constraintList c)
319 fcnConstraints = constraintList_copy (c);
323 void setFunctionModifies (sRefSet s)
325 sRefSet_free (fcnModifies);
329 static void reflectGlobalQualifiers (sRef sr, qualList quals)
331 qualList_elements (quals, qel)
333 if (qual_isGlobalQual (qel)) /* undef, killed */
335 sstate oldstate = sRef_getDefState (sr);
336 sstate defstate = sstate_fromQual (qel);
338 if ((oldstate == SS_UNDEFGLOB && defstate == SS_KILLED)
339 || (oldstate == SS_KILLED && defstate == SS_UNDEFGLOB))
341 defstate = SS_UNDEFKILLED;
348 sRef_setDefState (sr, defstate, fileloc_undefined);
350 else if (qual_isAllocQual (qel)) /* out, partial, reldef, etc. */
352 ctype realType = sRef_getType (sr);
353 sstate defstate = sstate_fromQual (qel);
355 if (qual_isRelDef (qel))
357 ; /* okay anywhere */
361 if (!ctype_isAP (realType)
362 && !ctype_isSU (realType)
363 && !ctype_isUnknown (realType)
364 && !ctype_isAbstract (sRef_getType (sr)))
368 message ("Qualifier %s used on non-pointer or struct: %q",
369 qual_unparse (qel), sRef_unparse (sr)));
374 sRef_setDefState (sr, defstate, fileloc_undefined);
376 else if (qual_isNull (qel))
378 sRef_setNullState (sr, NS_POSNULL, fileloc_undefined);
380 else if (qual_isRelNull (qel))
382 sRef_setNullState (sr, NS_RELNULL, fileloc_undefined);
384 else if (qual_isNotNull (qel))
386 sRef_setNullState (sr, NS_MNOTNULL, fileloc_undefined);
390 if (qual_isCQual (qel))
397 message ("Qualifier %s cannot be used in a globals list",
398 qual_unparse (qel)));
401 } end_qualList_elements;
404 void globListAdd (sRef sr, qualList quals)
406 if (sRef_isValid (sr))
408 sRef sc = sRef_copy (sr);
410 reflectGlobalQualifiers (sc, quals);
411 currentGlobals = globSet_insert (currentGlobals, sc);
415 extern void declareCIter (cstring name, /*@owned@*/ uentryList params)
419 ue = uentry_makeIter (name,
420 ctype_makeFunction (ctype_void, params),
421 fileloc_copy (g_currentloc));
423 usymtab_supEntry (uentry_makeEndIter (name, fileloc_copy (g_currentloc)));
425 reflectModGlobs (ue);
427 ue = usymtab_supGlobalEntryReturn (ue);
430 extern void nextIterParam (void)
432 llassert (ProcessingIterVars);
436 extern int iterParamNo (void)
438 llassert (ProcessingIterVars);
439 return saveIterParamNo;
443 ** yucky hacks to put it in the right place
447 makeCurrentParam (idDecl t)
451 saveStoreLoc = fileloc_undefined;
453 /* param number unknown */
455 ue = uentry_makeParam (t, 0);
460 declareUnnamedEnum (enumNameList el)
462 ctype ret = usymtab_enumEnumNameListType (el);
466 if (ctype_isDefined (ret))
469 e = uentry_makeEnumTagLoc (ctype_enumTag (rt), ret);
471 reflectStorageClass (e);
472 usymtab_supGlobalEntry (e);
474 declareEnumList (el, ret, g_currentloc);
475 enumNameList_free (el);
479 ctype ct = ctype_createEnum (fakeTag (), el);
481 e = uentry_makeEnumTagLoc (ctype_enumTag (ctype_realType (ct)), ct);
482 reflectStorageClass (e);
484 e = usymtab_supGlobalEntryReturn (e);
485 rt = uentry_getAbstractType (e);
486 declareEnumList (el, ct, g_currentloc);
493 declareEnum (cstring ename, enumNameList el)
498 llassert (cstring_isDefined (ename));
500 cet = ctype_createEnum (ename, el);
501 e = uentry_makeEnumTagLoc (ename, cet);
502 reflectStorageClass (e);
503 e = usymtab_supGlobalEntryReturn (e);
504 cet = uentry_getType (e);
505 declareEnumList (el, cet, uentry_whereLast (e));
506 return (uentry_getAbstractType (e));
510 declareEnumList (enumNameList el, ctype c, fileloc loc)
512 bool boolnames = FALSE;
513 bool othernames = FALSE;
515 (void) context_getSaveLocation (); /* undefine it */
517 if (context_maybeSet (FLG_NUMENUMMEMBERS))
519 int maxnum = context_getValue (FLG_NUMENUMMEMBERS);
520 int num = enumNameList_size (el);
526 message ("Enumerator %s declared with %d members (limit is set to %d)",
527 ctype_unparse (c), num, maxnum),
532 enumNameList_elements (el, e)
534 uentry ue = usymtab_lookupExposeGlob (e);
535 ctype ct = uentry_getType (ue);
537 llassert (uentry_isEnumConstant (ue));
539 if (ctype_isUnknown (ct))
541 uentry_setType (ue, c);
545 if (cstring_equal (e, context_getFalseName ())
546 || cstring_equal (e, context_getTrueName ()))
552 message ("Enumerator mixes boolean name (%s) with "
555 uentry_whereLast (ue)))
562 uentry_setType (ue, ctype_bool);
563 DPRINTF (("Set type: %s / %s",
564 uentry_unparse (ue), ctype_unparse (ctype_bool)));
572 message ("Enumerator mixes boolean names (%s, %s) with "
573 "non-boolean name: %s",
574 context_getTrueName (),
575 context_getFalseName (),
577 uentry_whereLast (ue)))
586 if (!ctype_match (c, ct))
588 if (ctype_isDirectBool (ct))
590 if (cstring_equal (e, context_getFalseName ())
591 || cstring_equal (e, context_getTrueName ()))
593 DPRINTF (("Here we are!"));
599 message ("Enumerator member %s declared with "
600 "inconsistent type: %s",
601 e, ctype_unparse (c)),
602 uentry_whereLast (ue)))
604 uentry_showWhereSpecifiedExtra
605 (ue, cstring_copy (ctype_unparse (ct)));
613 message ("Enumerator member %s declared with "
614 "inconsistent type: %s",
615 e, ctype_unparse (c)),
616 uentry_whereLast (ue)))
618 uentry_showWhereSpecifiedExtra
619 (ue, cstring_copy (ctype_unparse (ct)));
624 } end_enumNameList_elements;
627 static /*@dependent@*/ uentryList currentParamList;
629 /*drl added 3-28-2001*/
630 /* this function takes a list of paramentar and generates a list
632 Currently the only constraints gnerated are MaxSet(p) >= 0 for all pointers
634 void setImplictfcnConstraints (void)
639 params = currentParamList;
641 implicitFcnConstraints = constraintList_makeNew();
643 uentryList_elements (params, el)
645 DPRINTF((message("setImplictfcnConstraints doing: %s", uentry_unparse(el) ) ));
647 s = uentry_getSref(el);
648 if (sRef_isReference (s) )
650 DPRINTF((message ("%s is a pointer", sRef_unparse(s) ) ));
654 DPRINTF((message ("%s is NOT a pointer", sRef_unparse(s) ) ));
657 chagned this is MaxSet(s) == 0 to MaxSet(s) >= 0 */
659 c = constraint_makeSRefWriteSafeInt (s, 0);
660 // constraint_makeSRefSetBufferSize (s, 0);
661 implicitFcnConstraints = constraintList_add(implicitFcnConstraints , c);
663 end_uentryList_elements;
666 void setCurrentParams (/*@dependent@*/ uentryList ue)
668 currentParamList = ue;
671 void clearCurrentParams (void)
673 currentParamList = uentryList_undefined;
677 ** requires: uentry_isFunction (e)
678 ** parameter names for current function are in currentParamList
681 static void enterFunctionParams (uentryList params)
685 uentryList_elements (params, current)
687 if (uentry_hasName (current))
689 uentry_setParamNo (current, paramno);
690 usymtab_supEntry (uentry_copy (current));
694 } end_uentryList_elements;
698 extern void enterParamsTemp (void)
700 usymtab_enterScope ();
701 enterFunctionParams (currentParamList);
704 extern void exitParamsTemp (void)
706 usymtab_quietPlainExitScope ();
709 static /*@exposed@*/ uentry globalDeclareFunction (idDecl tid)
711 ctype deftype = idDecl_getCtype (tid);
715 DPRINTF (("Global function: %s", idDecl_unparse (tid)));
717 if (ctype_isFunction (deftype))
719 rettype = ctype_returnValue (deftype);
723 rettype = ctype_unknown;
727 ** check has been moved here...
730 if (ctype_isFunction (idDecl_getCtype (tid)))
732 ue = uentry_makeIdFunction (tid);
733 reflectSpecialCode (ue);
734 reflectArgsUsed (ue);
738 llparseerror (message ("Inconsistent function declaration: %q",
739 idDecl_unparse (tid)));
741 tid = idDecl_replaceCtype
742 (tid, ctype_makeFunction (ctype_unknown, uentryList_undefined));
743 ue = uentry_makeIdFunction (tid);
746 reflectStorageClass (ue);
748 uentry_checkParams (ue);
749 reflectModGlobs (ue);
751 ue = usymtab_supGlobalEntryReturn (ue);
752 context_enterFunction (ue);
753 enterFunctionParams (uentry_getParams (ue));
755 resetStorageClass ();
760 ** for now, no type checking
761 ** (must check later though!)
764 static /*@only@*/ uentry globalDeclareOldStyleFunction (idDecl tid)
769 ** check has been moved here...
772 if (cstring_equalLit (idDecl_observeId (tid), "main"))
774 context_setFlagTemp (FLG_MAINTYPE, FALSE);
777 ue = uentry_makeIdFunction (tid);
778 reflectStorageClass (ue);
779 reflectSpecialCode (ue);
780 reflectArgsUsed (ue);
781 uentry_setDefined (ue, g_currentloc);
783 uentry_checkParams (ue);
785 if (ProcessingGlobals)
787 uentry_setGlobals (ue, currentGlobals);
790 resetStorageClass ();
794 static void oldStyleDeclareFunction (/*@only@*/ uentry e)
796 uentryList params = saveParamList;
797 ctype rt = uentry_getType (e);
799 llassert (ctype_isFunction (rt));
801 e = usymtab_supGlobalEntryReturn (e);
803 context_enterFunction (e);
804 enterFunctionParams (params);
805 saveParamList = uentryList_undefined;
806 resetStorageClass ();
809 void declareFunction (idDecl tid) /*@globals undef saveFunction; @*/
813 DPRINTF (("Declare function: %s", idDecl_unparse (tid)));
815 if (ProcessingParams)
817 ue = globalDeclareOldStyleFunction (tid);
822 saveFunction = uentry_undefined;
824 if (context_inRealFunction ())
826 ue = uentry_makeVariableLoc (idDecl_observeId (tid), ctype_unknown);
828 llparseerror (message ("Function declared inside function: %q",
829 idDecl_unparse (tid)));
831 context_quietExitFunction ();
832 ue = usymtab_supEntryReturn (ue);
836 if (context_inInnerScope ())
838 llparseerror (message ("Declaration in inner context: %q",
839 idDecl_unparse (tid)));
841 sRef_setGlobalScope ();
842 ue = uentry_makeVariableLoc (idDecl_observeId (tid),
844 ue = usymtab_supGlobalEntryReturn (ue);
845 sRef_clearGlobalScope ();
849 ue = globalDeclareFunction (tid);
856 resetStorageClass ();
860 void declareStaticFunction (idDecl tid) /*@globals undef saveFunction; @*/
864 DPRINTF (("Declare static funciton: %s", idDecl_unparse (tid)));
866 if (ProcessingParams)
868 ue = globalDeclareOldStyleFunction (tid);
873 saveFunction = uentry_undefined;
875 if (context_inRealFunction ())
877 ue = uentry_makeVariableLoc (idDecl_observeId (tid), ctype_unknown);
879 llparseerror (message ("Function declared inside function: %q",
880 idDecl_unparse (tid)));
882 context_quietExitFunction ();
883 ue = usymtab_supEntryReturn (ue);
887 if (context_inInnerScope ())
889 llparseerror (message ("Declaration in inner context: %q",
890 idDecl_unparse (tid)));
892 sRef_setGlobalScope ();
893 ue = uentry_makeVariableLoc (idDecl_observeId (tid),
895 ue = usymtab_supGlobalEntryReturn (ue);
896 sRef_clearGlobalScope ();
900 ctype deftype = idDecl_getCtype (tid);
903 if (ctype_isFunction (deftype))
905 rettype = ctype_returnValue (deftype);
909 rettype = ctype_unknown;
913 ** check has been moved here...
916 if (ctype_isFunction (idDecl_getCtype (tid)))
918 ue = uentry_makeIdFunction (tid);
919 reflectSpecialCode (ue);
920 reflectArgsUsed (ue);
924 llparseerror (message ("Inconsistent function declaration: %q",
925 idDecl_unparse (tid)));
927 tid = idDecl_replaceCtype
928 (tid, ctype_makeFunction (ctype_unknown, uentryList_undefined));
929 ue = uentry_makeIdFunction (tid);
932 reflectStorageClass (ue);
933 uentry_setStatic (ue);
935 uentry_checkParams (ue);
936 reflectModGlobs (ue);
938 DPRINTF (("Sub global entry: %s", uentry_unparse (ue)));
939 ue = usymtab_supGlobalEntryReturn (ue);
941 context_enterFunction (ue);
942 enterFunctionParams (uentry_getParams (ue));
943 resetStorageClass ();
950 resetStorageClass ();
955 checkTypeDecl (uentry e, ctype rep)
957 cstring n = uentry_getName (e);
959 DPRINTF (("Check type decl: %s", n));
961 if (cstring_equal (context_getBoolName (), n))
963 ctype rrep = ctype_realType (rep);
966 ** for abstract enum types, we need to fix the enum members:
967 ** they should have the abstract type, not the rep type.
970 if (ctype_isEnum (ctype_realType (rrep)))
972 enumNameList el = ctype_elist (rrep);
974 enumNameList_elements (el, ye)
976 if (usymtab_existsGlob (ye))
978 uentry ue = usymtab_lookupSafe (ye);
979 uentry_setType (ue, ctype_bool);
982 if (cstring_equal (context_getTrueName (), ye)
983 || cstring_equal (context_getFalseName (), ye))
991 message ("Member of boolean enumerated type definition "
992 "does not match name set to represent TRUE "
995 message ("Use -boolfalse and -booltrue to set the "
996 "name of false and true boolean values."),
997 uentry_whereDefined (e));
999 } end_enumNameList_elements;
1003 if (usymtab_exists (n))
1005 usymId llm = usymtab_getId (n);
1006 uentry le = usymtab_getTypeEntry (llm);
1008 uentry_setDeclared (e, g_currentloc);
1009 uentry_setSref (e, sRef_makeGlobal (llm, uentry_getType (le)));
1011 DPRINTF (("Here we are: %s / %s",
1012 n, context_getBoolName ()));
1014 if (uentry_isAbstractDatatype (le))
1016 ctype rrep = ctype_realType (rep);
1019 ** for abstract enum types, we need to fix the enum members:
1020 ** they should have the abstract type, not the rep type.
1023 if (ctype_isEnum (ctype_realType (rrep)))
1025 ctype at = uentry_getAbstractType (le);
1026 enumNameList el = ctype_elist (rrep);
1028 enumNameList_elements (el, ye)
1030 if (usymtab_existsGlob (ye))
1032 uentry ue = usymtab_lookupSafe (ye);
1034 llassert (uentry_isEitherConstant (ue));
1035 llassertprint (ctype_match (uentry_getType (ue), rrep),
1036 ("Bad enum: %s / %s",
1037 uentry_unparse (ue),
1038 ctype_unparse (rrep)));
1040 uentry_setType (ue, at);
1042 } end_enumNameList_elements;
1045 if (uentry_isMutableDatatype (le))
1047 /* maybe more complicated if abstract and immutable ? */
1049 if (!ctype_isRealPointer (rep) && !ctype_isRealAbstract (rep))
1053 message ("Mutable abstract type %s declared without pointer "
1054 "indirection: %s (violates assignment semantics)",
1055 n, ctype_unparse (rep)),
1056 uentry_whereDefined (e));
1058 uentry_setMutable (e);
1065 fileloc fl = uentry_whereDeclared (e);
1067 if (context_getFlag (FLG_LIKELYBOOL)
1068 && !context_getFlag (FLG_BOOLINT))
1070 if ((cstring_equalLit (n, "BOOL")
1071 || cstring_equalLit (n, "Bool")
1072 || cstring_equalLit (n, "bool")
1073 || cstring_equalLit (n, "boolean")
1074 || cstring_equalLit (n, "Boolean")
1075 || cstring_equalLit (n, "BOOLEAN"))
1076 && !(cstring_equal (n, context_getBoolName ())))
1078 if (context_setBoolName ()) {
1081 message ("Type %s is probably meant as a boolean type, but does "
1082 "not match the boolean type name \"%s\".",
1084 context_getBoolName ()),
1089 message ("Type %s is probably meant as a boolean type, "
1090 "but the boolean type name is not set. "
1091 "Use -booltype %s to set it.",
1098 if (!uentry_isStatic (e)
1099 && !ctype_isFunction (uentry_getType (e))
1100 && !fileloc_isLib (fl)
1101 && !fileloc_isImport (fl)
1102 && fileloc_isHeader (fl))
1104 voptgenerror (FLG_EXPORTTYPE,
1105 message ("Type exported, but not specified: %s\n", n),
1114 fixUentryList (idDeclList tl, qtype q)
1116 uentryList f = uentryList_new ();
1118 idDeclList_elements (tl, i)
1120 if (idDecl_isDefined (i))
1126 (void) idDecl_fixBase (i, q);
1129 ** implicit annotations
1132 (void) fixStructDecl (i);
1134 ue = uentry_makeIdVariable (i);
1135 rt = ctype_realType (uentry_getType (ue));
1138 ** where is this here???
1140 if (ctype_isArray (rt) || ctype_isSU (rt))
1142 sRef_setAllocated (uentry_getSref (ue), uentry_whereDefined (ue));
1148 if (uentry_isValid (old = uentryList_lookupField (f, uentry_rawName (ue))))
1150 if (optgenerror (FLG_SYNTAX,
1151 message ("Field name reused: %s", uentry_rawName (ue)),
1152 uentry_whereDefined (ue)))
1154 llgenmsg (message ("Previous use of %s", uentry_rawName (ue)),
1155 uentry_whereDefined (old));
1159 f = uentryList_add (f, ue);
1161 } end_idDeclList_elements;
1163 idDeclList_free (tl);
1168 ** This is a hack to support unnamed struct/union fields as done by
1169 ** Microsoft VC++. It is not supported by the ANSI standard.
1171 ** The inner fields are added to the outer structure. This is meaningful
1172 ** for nesting structs inside unions, but lclint does no related
1177 fixUnnamedDecl (qtype q)
1179 ctype ct = ctype_realType (qtype_getType (q));
1181 if (ctype_isStruct (ct) || ctype_isUnion (ct))
1183 uentryList res = ctype_getFields (ct);
1185 return (uentryList_copy (res));
1192 return uentryList_undefined;
1195 void setStorageClass (storageClassCode sc)
1201 setProcessingIterVars (uentry iter)
1203 ProcessingIterVars = TRUE;
1205 saveIterParamNo = 0;
1209 setProcessingGlobalsList ()
1211 ProcessingGlobals = TRUE;
1213 llassert (globSet_isUndefined (currentGlobals));
1214 currentGlobals = globSet_undefined;
1216 llassert (sRefSet_isUndefined (fcnModifies));
1217 fcnModifies = sRefSet_undefined;
1220 ** No, special clauses might have been processed first!
1221 llassert (specialClauses_isUndefined (specClauses));
1222 specClauses = specialClauses_undefined;
1225 fcnNoGlobals = FALSE;
1228 static bool ProcessingGlobMods = FALSE;
1231 setProcessingGlobMods ()
1233 ProcessingGlobMods = TRUE;
1237 clearProcessingGlobMods ()
1239 ProcessingGlobMods = FALSE;
1243 isProcessingGlobMods ()
1245 return (ProcessingGlobMods);
1248 static void resetGlobals (void)
1250 ProcessingGlobals = FALSE;
1251 currentGlobals = globSet_undefined;
1252 llassert (sRefSet_isUndefined (fcnModifies));
1253 fcnModifies = sRefSet_undefined;
1254 fcnNoGlobals = FALSE;
1258 unsetProcessingGlobals ()
1260 ProcessingGlobals = FALSE;
1264 setProcessingVars (/*@only@*/ qtype q)
1266 ProcessingVars = TRUE;
1267 qtype_free (processingType);
1272 setGenericParamList (/*@dependent@*/ uentryList pm)
1274 ProcessingParams = TRUE;
1279 setProcessingTypedef (/*@only@*/ qtype q)
1281 ProcessingTypedef = TRUE;
1283 qtype_free (processingType);
1288 unsetProcessingVars ()
1290 resetStorageClass ();
1291 ProcessingVars = FALSE;
1297 if (ProcessingParams)
1299 if (uentry_isInvalid (saveFunction))
1301 llbuglit ("unsetProcessingVars: no saved function\n");
1303 if (sRefSet_isDefined (fcnModifies)) {
1304 sRefSet_free (fcnModifies);
1305 fcnModifies = sRefSet_undefined;
1310 ctype ct = ctype_returnValue (uentry_getType (saveFunction));
1311 uentryList params = uentryList_copy (saveParamList);
1312 ctype ct2 = ctype_makeFunction (ct, params);
1314 uentry_setType (saveFunction, ct2);
1315 ProcessingParams = FALSE;
1317 reflectModGlobs (saveFunction);
1318 oldStyleDeclareFunction (saveFunction);
1319 saveFunction = uentry_undefined;
1326 ** If the paramlist used a type name, we could be here.
1329 llfatalerror (message ("%q: Old-style function parameter list uses a "
1330 "type name.", fileloc_unparse (g_currentloc)));
1337 if (uentry_isValid (saveFunction))
1340 ** old style declaration
1343 ctype ct = ctype_returnValue (uentry_getType (saveFunction));
1346 uentryList_elements (saveParamList, current)
1348 uentry_setType (current, ctype_int); /* all params are ints */
1349 } end_uentryList_elements;
1351 ct2 = ctype_makeParamsFunction (ct, uentryList_copy (saveParamList));
1353 uentry_setType (saveFunction, ct2);
1354 ProcessingParams = FALSE;
1356 oldStyleDeclareFunction (saveFunction);
1357 saveFunction = uentry_undefined;
1362 unsetProcessingTypedef ()
1364 ProcessingTypedef = FALSE;
1367 void checkConstant (qtype t, idDecl id)
1371 id = idDecl_fixBase (id, t);
1372 e = uentry_makeIdConstant (id);
1374 reflectStorageClass (e);
1375 resetStorageClass ();
1377 usymtab_supGlobalEntry (e);
1380 void checkValueConstant (qtype t, idDecl id, exprNode e)
1384 id = idDecl_fixBase (id, t);
1385 ue = uentry_makeIdConstant (id);
1386 reflectStorageClass (ue);
1387 resetStorageClass ();
1389 if (exprNode_isDefined (e))
1391 if (!exprNode_matchType (uentry_getType (ue), e))
1394 (exprNode_getType (e), e,
1395 uentry_getType (ue), exprNode_undefined,
1396 message ("Constant %q initialized to type %t, expects %t: %s",
1397 uentry_getName (ue),
1398 exprNode_getType (e),
1399 uentry_getType (ue),
1400 exprNode_unparse (e)),
1405 if (exprNode_hasValue (e))
1407 uentry_mergeConstantValue (ue, multiVal_copy (exprNode_getValue (e)));
1412 usymtab_supGlobalEntry (ue);
1416 void processNamedDecl (idDecl t)
1418 if (qtype_isUndefined (processingType))
1420 llparseerror (message ("No type before declaration name: %q", idDecl_unparse (t)));
1422 processingType = qtype_create (ctype_unknown);
1425 t = idDecl_fixBase (t, processingType);
1427 DPRINTF (("Declare: %s", idDecl_unparse (t)));
1429 if (ProcessingGlobals)
1431 cstring id = idDecl_getName (t);
1432 uentry ue = usymtab_lookupSafe (id);
1434 if (!uentry_isValid (ue))
1436 llerror (FLG_UNRECOG,
1437 message ("Variable used in globals list is undeclared: %s", id));
1441 if (!ctype_match (uentry_getType (ue), idDecl_getCtype (t)))
1445 message ("Variable %s used in globals list declared %s, "
1447 id, ctype_unparse (uentry_getType (ue)),
1448 ctype_unparse (idDecl_getCtype (t))),
1453 sRef sr = sRef_copy (uentry_getSref (ue));
1455 reflectGlobalQualifiers (sr, idDecl_getQuals (t));
1457 currentGlobals = globSet_insert (currentGlobals, sr);
1461 else if (ProcessingVars)
1466 ct = ctype_realType (idDecl_getCtype (t));
1468 if (ProcessingParams)
1470 cstring id = idDecl_getName (t);
1471 int paramno = uentryList_lookupRealName (saveParamList, id);
1475 uentry cparam = uentryList_getN (saveParamList, paramno);
1477 uentry_setType (cparam, idDecl_getCtype (t));
1478 uentry_reflectQualifiers (cparam, idDecl_getQuals (t));
1479 uentry_setDeclaredOnly (cparam, context_getSaveLocation ());
1484 (message ("Old style declaration uses unlisted parameter: %s",
1492 if (context_inIterDef ())
1494 cstring pname = makeParam (idDecl_observeId (t));
1495 uentry p = usymtab_lookupSafe (pname);
1497 cstring_free (pname);
1499 if (uentry_isYield (p))
1501 e = uentry_makeParam (t, sRef_getParam (uentry_getSref (p)));
1503 uentry_checkYieldParam (p, e);
1505 usymtab_supEntrySref (e);
1510 if ((hasSpecialCode () || argsUsed)
1511 && ctype_isFunction (idDecl_getCtype (t)))
1513 e = uentry_makeIdFunction (t);
1514 reflectSpecialCode (e);
1515 reflectArgsUsed (e);
1519 e = uentry_makeIdVariable (t);
1522 loc = uentry_whereDeclared (e);
1525 if (context_inGlobalScope ())
1527 uentry_checkParams was here!
1531 if (ctype_isFunction (uentry_getType (e)))
1533 reflectModGlobs (e);
1537 llassert (!globSet_isDefined (currentGlobals)
1538 && !sRefSet_isDefined (fcnModifies));
1541 e = usymtab_supEntrySrefReturn (e);
1543 if (uentry_isExtern (e) && !context_inGlobalScope ())
1547 message ("Declaration using extern inside function scope: %q",
1548 uentry_unparse (e)),
1551 uentry_setDefined (e, fileloc_getExternal ());
1552 sRef_setDefined (uentry_getSref (e), fileloc_getExternal ());
1555 if (uentry_isFunction (e))
1557 uentry_checkParams (e);
1558 checkParamNames (e);
1561 if (uentry_isVar (e)
1562 && uentry_isCheckedUnknown (e))
1564 sRef sr = uentry_getSref (e);
1566 if (sRef_isLocalVar (sr))
1568 if (context_getFlag (FLG_IMPCHECKMODINTERNALS))
1570 uentry_setCheckMod (e);
1574 uentry_setUnchecked (e);
1577 else if (sRef_isFileStatic (sr))
1579 if (context_getFlag (FLG_IMPCHECKEDSTRICTSTATICS))
1581 uentry_setCheckedStrict (e);
1583 else if (context_getFlag (FLG_IMPCHECKEDSTATICS))
1585 uentry_setChecked (e);
1587 else if (context_getFlag (FLG_IMPCHECKMODSTATICS))
1589 uentry_setCheckMod (e);
1596 else /* real global */
1598 llassert (sRef_isRealGlobal (sr));
1600 if (context_getFlag (FLG_IMPCHECKEDSTRICTGLOBALS))
1602 uentry_setCheckedStrict (e);
1604 else if (context_getFlag (FLG_IMPCHECKEDGLOBALS))
1606 uentry_setChecked (e);
1608 else if (context_getFlag (FLG_IMPCHECKMODGLOBALS))
1610 uentry_setCheckMod (e);
1620 else if (ProcessingTypedef)
1622 ctype ct = idDecl_getCtype (t);
1625 DPRINTF (("Processing typedef: %s", ctype_unparse (ct)));
1627 e = uentry_makeIdDatatype (t);
1629 if (cstring_equal (idDecl_getName (t), context_getBoolName ())) {
1630 ctype rt = ctype_realType (ct);
1632 if (ctype_isEnum (rt)) {
1635 if (!(ctype_isInt (rt)
1636 || ctype_isUnknown (rt)
1637 || ctype_isChar (rt))) {
1640 message ("Boolean type %s defined using non-standard type %s (integral, char or enum type expected)",
1641 context_getBoolName (),
1642 ctype_unparse (ct)),
1643 uentry_whereLast (e));
1647 uentry_setType (e, ct);
1651 reflectStorageClass (e);
1652 checkTypeDecl (e, ct);
1654 e = usymtab_supReturnTypeEntry (e);
1656 if (uentry_isMaybeAbstract (e))
1658 if (context_getFlag (FLG_IMPABSTRACT))
1660 uentry_setAbstract (e);
1664 uentry_setConcrete (e);
1670 llparseerror (message ("Suspect missing struct or union keyword: %q",
1671 idDecl_unparse (t)));
1677 ** moved from grammar
1680 static idDecl fixStructDecl (/*@returned@*/ idDecl d)
1682 if (ctype_isVisiblySharable (idDecl_getCtype (d))
1683 && context_getFlag (FLG_STRUCTIMPONLY))
1685 if (!qualList_hasAliasQualifier (idDecl_getQuals (d)))
1687 if (qualList_hasExposureQualifier (idDecl_getQuals (d)))
1689 idDecl_addQual (d, qual_createDependent ());
1693 idDecl_addQual (d, qual_createImpOnly ());
1702 declareUnnamedStruct (/*@only@*/ uentryList f)
1704 if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1706 int num = uentryList_size (f);
1707 int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1712 (FLG_NUMSTRUCTFIELDS,
1713 message ("Structure declared with %d fields "
1714 "(limit is set to %d)",
1720 return (ctype_createUnnamedStruct (f));
1724 declareUnnamedUnion (/*@only@*/ uentryList f)
1726 if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1728 int num = uentryList_size (f);
1729 int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1734 (FLG_NUMSTRUCTFIELDS,
1735 message ("Union declared with %d fields "
1736 "(limit is set to %d)",
1742 return (ctype_createUnnamedUnion (f));
1745 ctype declareStruct (cstring id, /*@only@*/ uentryList f)
1749 int num = uentryList_size (f);
1751 ct = ctype_createStruct (cstring_copy (id), f);
1752 DPRINTF (("Declare struct: %s [%d]", ctype_unparse (ct), ct));
1753 ue = uentry_makeStructTagLoc (id, ct);
1755 if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1757 int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1762 (FLG_NUMSTRUCTFIELDS,
1763 message ("Structure %q declared with %d fields "
1764 "(limit is set to %d)",
1765 uentry_getName (ue), num, max),
1766 uentry_whereLast (ue));
1770 return (usymtab_supTypeEntry (ue));
1773 ctype declareUnion (cstring id, uentryList f)
1777 int num = uentryList_size (f);
1779 ct = ctype_createUnion (cstring_copy (id), f);
1780 ue = uentry_makeUnionTagLoc (id, ct);
1782 if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1784 int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1789 (FLG_NUMSTRUCTFIELDS,
1790 message ("Union %q declared with %d fields "
1791 "(limit is set to %d)",
1792 uentry_getName (ue), num, max),
1793 uentry_whereLast (ue));
1797 return (usymtab_supTypeEntry (ue));
1800 ctype handleStruct (/*@only@*/ cstring id)
1802 if (usymtab_existsStructTag (id))
1804 ctype ct = uentry_getAbstractType (usymtab_lookupStructTag (id));
1811 return (ctype_createForwardStruct (id));
1815 ctype handleUnion (/*@only@*/ cstring id)
1817 if (usymtab_existsUnionTag (id))
1819 ctype ret = uentry_getAbstractType (usymtab_lookupUnionTag (id));
1825 return (ctype_createForwardUnion (id));
1830 handleEnum (cstring id)
1832 if (usymtab_existsEnumTag (id))
1834 ctype ret = uentry_getAbstractType (usymtab_lookupEnumTag (id));
1840 return (declareEnum (id, enumNameList_new ()));
1844 bool processingIterVars (void)
1846 return ProcessingIterVars;
1849 uentry getCurrentIter (void)
1854 static bool flipOldStyle = FALSE;
1855 static bool flipNewStyle = TRUE;
1857 void setFlipOldStyle () { flipOldStyle = TRUE; }
1858 bool isFlipOldStyle () { return flipOldStyle; }
1859 bool isNewStyle () { return flipNewStyle; }
1860 void setNewStyle () { flipNewStyle = TRUE; }
1862 /*@dependent@*/ uentryList handleParamIdList (/*@dependent@*/ uentryList params)
1867 ** this is a really YUCKY hack to handle old style
1871 voptgenerror (FLG_OLDSTYLE,
1872 cstring_makeLiteral ("Old style function declaration"),
1875 uentryList_elements (params, current)
1877 uentry_setParam (current);
1878 uentry_setSref (current, sRef_makeParam (paramno, ctype_unknown));
1880 } end_uentryList_elements;
1882 setGenericParamList (params);
1883 g_expectingTypeName = TRUE;
1888 /*@dependent@*/ uentryList handleParamTypeList (/*@returned@*/ uentryList params)
1892 uentryList_fixMissingNames (params);
1894 voptgenerror (FLG_OLDSTYLE,
1895 cstring_makeLiteral ("Old style function declaration."),
1898 setGenericParamList (params);
1899 flipOldStyle = FALSE;
1900 g_expectingTypeName = TRUE;
1909 ctype c = ctype_unknown;
1910 cstring id = cstring_makeLiteral ("va_alist");
1913 if (ProcessingParams)
1915 int i = uentryList_lookupRealName (saveParamList, id);
1919 e = uentry_makeVariableSrefParam (id, c, sRef_makeParam (i, c));
1923 e = uentry_undefined; /* suppress gcc message */
1924 llfatalerrorLoc (cstring_makeLiteral ("va_dcl used without va_alist"));
1929 llerror (FLG_SYNTAX, cstring_makeLiteral ("va_dcl used outside of function declaration"));
1930 e = uentry_makeVariableLoc (id, c);
1934 uentry_setUsed (e, g_currentloc);
1935 usymtab_supEntrySref (e);
1938 /*@exposed@*/ sRef modListPointer (sRef s)
1940 ctype ct = sRef_getType (s);
1941 ctype rt = ctype_realType (ct);
1943 if (ctype_isAP (rt))
1945 if (context_inHeader () && ctype_isAbstract (ct))
1950 ("Modifies clause in header file dereferences abstract "
1951 "type %s (interface modifies clause should not depend "
1952 "on or expose type representation): %q",
1958 return (sRef_constructPointer (s));
1962 if (ctype_isKnown (rt))
1966 message ("Implementation modifies clause dereferences non-pointer (type %s): %q",
1976 /*@exposed@*/ sRef modListFieldAccess (sRef s, cstring f)
1978 ctype ct = sRef_getType (s);
1979 ctype rt = ctype_realType (ct);
1981 if (ctype_isStructorUnion (rt))
1983 uentry tf = uentryList_lookupField (ctype_getFields (rt), f);
1985 if (uentry_isUndefined (tf))
1987 voptgenerror (FLG_TYPE,
1988 message ("Modifies list accesses non-existent "
1989 "field %s of %t: %q", f, ct,
1994 return sRef_undefined;
1998 if (ctype_isAbstract (ct) && context_inHeader ())
2003 ("Modifies clause in header file accesses abstract "
2004 "type %s (interface modifies clause should not depend "
2005 "on or expose type representation): %q",
2012 cstring_markOwned (f);
2013 return (sRef_makeField (s, f));
2019 message ("Modifies clause dereferences non-pointer (type %s): %q",
2029 sRef globListUnrecognized (cstring s)
2031 if (cstring_equalLit (s, "nothing"))
2033 return sRef_makeNothing ();
2035 else if (cstring_equalLit (s, "internalState"))
2037 return sRef_makeInternalState ();
2039 else if (cstring_equalLit (s, "fileSystem")
2040 || cstring_equalLit (s, "systemState"))
2042 return sRef_makeSystemState ();
2048 message ("Unrecognized identifier in globals list: %s", s),
2051 return sRef_undefined;
2055 /*@exposed@*/ sRef modListArrowAccess (sRef s, cstring f)
2057 ctype ct = sRef_getType (s);
2058 ctype rt = ctype_realType (ct);
2060 if (ctype_isRealPointer (rt))
2062 ctype b = ctype_baseArrayPtr (rt);
2063 ctype rb = ctype_realType (b);
2065 if (ctype_isStructorUnion (rb))
2067 uentry tf = uentryList_lookupField (ctype_getFields (rb), f);
2069 if (uentry_isUndefined (tf))
2071 voptgenerror (FLG_TYPE,
2072 message ("Modifies list arrow accesses non-existent "
2073 "field %s of %t: %q", f, b,
2078 return sRef_undefined;
2082 if (context_inHeader ())
2084 if (ctype_isAbstract (b))
2089 ("Modifies clause in header file arrow accesses abstract "
2090 "type %s (interface modifies clause should not depend "
2091 "on or expose type representation): %q",
2099 if (ctype_isAbstract (ct))
2104 ("Modifies clause in header file arrow accesses abstract "
2105 "type %s (interface modifies clause should not depend "
2106 "on or expose type representation): %q",
2114 cstring_markOwned (f);
2115 return (sRef_makeArrow (s, f));
2121 message ("Modifies clause arrow accesses pointer to "
2122 "non-structure (type %s): %q",
2132 message ("Modifies clause arrow accesses non-pointer (type %s): %q",
2142 sRef checkSpecClausesId (uentry ue)
2144 cstring s = uentry_rawName (ue);
2146 if (sRef_isGlobal (uentry_getSref (ue)))
2150 message ("Global variable %s used special clause. (Global variables "
2151 "are not recognized in special clauses. If there is "
2152 "sufficient interest in support for this, it may be "
2153 "added to a future release. Send mail to "
2154 "lclint@cs.virginia.edu.)",
2158 return sRef_undefined;
2162 if (cstring_equalLit (s, "result"))
2166 message ("Special clause list uses %s which is a variable and has special "
2167 "meaning in a modifies list. (Special meaning assumed.)", s),
2170 uentry_showWhereDeclared (ue);
2174 return uentry_getSref (ue);
2180 don;t know what the real date is...
2186 based on checkSpecClausesId
2189 sRef checkbufferConstraintClausesId (uentry ue)
2191 cstring s = uentry_rawName (ue);
2192 if (cstring_equalLit (s, "result"))
2196 message ("Special clause list uses %s which is a variable and has special "
2197 "meaning in a modifies list. (Special meaning assumed.)", s),
2200 uentry_showWhereDeclared (ue);
2204 return sRef_copy( uentry_getSref (ue) );
2207 void checkModifiesId (uentry ue)
2209 cstring s = uentry_rawName (ue);
2211 if (cstring_equalLit (s, "nothing")
2212 || cstring_equalLit (s, "internalState")
2213 || cstring_equalLit (s, "systemState")
2214 || (cstring_equalLit (s, "fileSystem")))
2218 message ("Modifies list uses %s which is a variable and has special "
2219 "meaning in a modifies list. (Special meaning assumed.)", s),
2222 uentry_showWhereDeclared (ue);
2227 /*@exposed@*/ sRef fixModifiesId (cstring s)
2230 cstring pname = makeParam (s);
2231 uentry ue = usymtab_lookupSafe (pname);
2233 cstring_free (pname);
2235 if (cstring_equalLit (s, "nothing"))
2237 ret = sRef_makeNothing ();
2239 else if (cstring_equalLit (s, "internalState"))
2241 ret = sRef_makeInternalState ();
2243 else if (cstring_equalLit (s, "fileSystem")
2244 || cstring_equalLit (s, "systemState"))
2246 ret = sRef_makeSystemState ();
2250 ret = sRef_undefined;
2253 if (sRef_isValid (ret))
2255 if (uentry_isValid (ue))
2259 message ("Modifies list uses %s which is a parameter and has special "
2260 "meaning in a modifies list. (Special meaning assumed.)", s),
2266 if (uentry_isValid (ue))
2268 ret = uentry_getSref (ue);
2272 fileloc loc = fileloc_decColumn (g_currentloc, cstring_length (s));
2273 ret = sRef_undefined;
2277 message ("Unrecognized identifier in modifies comment: %s", s),
2287 sRef fixSpecClausesId (cstring s)
2290 cstring pname = makeParam (s);
2291 uentry ue = usymtab_lookupSafe (pname);
2293 cstring_free (pname);
2295 if (cstring_equalLit (s, "result"))
2297 ret = sRef_makeResult ();
2301 ret = sRef_undefined;
2304 if (sRef_isValid (ret))
2306 if (uentry_isValid (ue))
2310 message ("Special clause uses %s which is a parameter and has special "
2311 "meaning in a special clause. (Special meaning assumed.)", s),
2317 if (uentry_isValid (ue))
2319 ret = uentry_getSref (ue);
2321 if (sRef_isGlobal (ret))
2325 message ("Global variable %s used special clause. (Global variables "
2326 "are not recognized in special clauses. If there is "
2327 "sufficient interest in support for this, it may be "
2328 "added to a future release. Send mail to "
2329 "lclint@cs.virginia.edu.)",
2333 ret = sRef_undefined;
2338 fileloc loc = fileloc_decColumn (g_currentloc, cstring_length (s));
2339 ret = sRef_undefined;
2343 message ("Unrecognized identifier in special clause: %s", s),
2353 sRef modListArrayFetch (sRef s, /*@unused@*/ sRef mexp)
2355 ctype ct = sRef_getType (s);
2356 ctype rt = ctype_realType (ct);
2358 if (ctype_isAP (rt))
2360 if (context_inHeader () && ctype_isAbstract (ct))
2365 ("Modifies clause in header file indexes abstract "
2366 "type %s (interface modifies clause should not depend "
2367 "on or expose type representation): %q",
2373 return (sRef_makeAnyArrayFetch (s));
2380 ("Implementation modifies clause uses array fetch on non-array (type %s): %q",
2381 ctype_unparse (ct), sRef_unparse (s)),