]> andersk Git - splint.git/blob - src/clabstract.c
Moved doc/lclint.1 to doc/splint.1
[splint.git] / src / clabstract.c
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2002 University of Virginia,
4 **         Massachusetts Institute of Technology
5 **
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.
10 ** 
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.
15 ** 
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.
19 **
20 ** For information on splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
23 */
24 /*
25 ** clabstract.c
26 **
27 ** ASTs for C grammar
28 **
29 */
30
31 # include "splintMacros.nf"
32 # include "llbasic.h"
33 # include "cgrammar.h"
34
35 # ifndef NOLCL
36 # include "usymtab_interface.h"
37 # endif
38
39 # include "structNames.h"
40 # include "nameChecks.h"
41
42 # ifdef SANITIZER
43 # include "sgrammar_tokens.h"
44 # else
45 # include "cgrammar_tokens.h"
46 # endif
47
48 /*
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.
52 */
53
54 /*drl*/
55 static /*@only@*/ constraintList implicitFcnConstraints = NULL;
56
57 static void clabstract_prepareFunction (uentry p_e) /*@modifies p_e@*/ ;
58 static bool fcnNoGlobals = FALSE;
59 static bool ProcessingVars = FALSE;
60 static bool ProcessingParams = FALSE;
61 static bool ProcessingGlobals = FALSE;
62 static bool ProcessingTypedef = FALSE;
63 static bool ProcessingIterVars = FALSE;
64 static /*@only@*/ qtype processingType = qtype_undefined;
65 static uentry currentIter = uentry_undefined;
66 static /*@dependent@*/ uentryList saveParamList;  /* for old style functions */
67 static /*@owned@*/ uentry saveFunction = uentry_undefined;
68 static int saveIterParamNo;
69 static idDecl fixStructDecl (/*@returned@*/ idDecl p_d);
70 static void checkTypeDecl (uentry p_e, ctype p_rep);
71 static /*@dependent@*/ fileloc saveStoreLoc = fileloc_undefined;
72 static storageClassCode storageClass = SCNONE;
73 static void declareEnumList (/*@temp@*/ enumNameList p_el, ctype p_c, fileloc p_loc);
74 static void resetGlobals (void);
75 static /*@null@*/ qual specialFunctionCode;
76 static bool argsUsed = FALSE;
77
78 extern void clabstract_initMod () 
79 {
80   specialFunctionCode = qual_createUnknown ();
81   DPRINTF (("Initialized: %s", qual_unparse (specialFunctionCode)));
82 }
83
84 static bool hasSpecialCode (void)
85 {
86   return (!qual_isUnknown (specialFunctionCode));
87 }
88
89 extern void setArgsUsed (void)
90 {
91   if (argsUsed)
92     {
93       voptgenerror
94         (FLG_SYNTAX,
95          cstring_makeLiteral ("Multiple ARGSUSED comments for one function"),
96          g_currentloc);
97     }
98
99   argsUsed = TRUE;
100 }
101
102 static void reflectArgsUsed (uentry ue)
103 {
104   if (argsUsed)
105     {
106       if (uentry_isFunction (ue))
107         {
108           uentryList params = uentry_getParams (ue);
109
110           uentryList_elements (params, el)
111             {
112               uentry_setUsed (el, fileloc_undefined);
113             } end_uentryList_elements ;
114         }
115
116       argsUsed = FALSE;
117     }
118 }
119               
120 extern void setSpecialFunction (qual qu)
121 {
122   if (!qual_isUnknown (specialFunctionCode))
123     {
124       voptgenerror (FLG_SYNTAX,
125                     message ("Multiple special function codes: %s, %s "
126                              "(first code is ignored)",
127                              qual_unparse (specialFunctionCode),
128                              qual_unparse (qu)),
129                     g_currentloc);
130     }
131
132   specialFunctionCode = qu;
133 }
134
135 static void reflectSpecialCode (uentry ue)
136 {
137   if (qual_isUnknown (specialFunctionCode)) {
138     ;
139   } else if (qual_isPrintfLike (specialFunctionCode)) {
140     uentry_setPrintfLike (ue);
141   } else if (qual_isScanfLike (specialFunctionCode)) {
142     uentry_setScanfLike (ue);
143   } else if (qual_isMessageLike (specialFunctionCode)) {
144     uentry_setMessageLike (ue);
145   } else {
146     BADBRANCH;
147   }
148
149   specialFunctionCode = qual_createUnknown ();
150 }
151
152 static void resetStorageClass (void)
153 {
154   qtype_free (processingType);
155   processingType = qtype_undefined;
156   storageClass = SCNONE;
157 }
158
159 static void reflectStorageClass (uentry u)
160 {
161   if (storageClass == SCSTATIC)
162     {
163       uentry_setStatic (u);
164     }
165   else if (storageClass == SCEXTERN)
166     {
167       uentry_setExtern (u);
168     }
169   else
170     {
171       ; /* no storage class */
172     }
173
174   }
175
176 void storeLoc ()
177 {
178   saveStoreLoc = g_currentloc;
179 }
180
181 void setFunctionNoGlobals (void)
182 {
183   fcnNoGlobals = TRUE;
184 }
185
186 static void reflectGlobalQualifiers (sRef sr, qualList quals)
187 {
188   DPRINTF (("Reflect global qualifiers: %s / %s", 
189             sRef_unparseFull (sr), qualList_unparse (quals)));
190
191   qualList_elements (quals, qel)
192     {
193       if (qual_isGlobalQual (qel)) /* undef, killed */
194         {
195           sstate oldstate = sRef_getDefState (sr);
196           sstate defstate = sstate_fromQual (qel);
197           
198           if ((oldstate == SS_UNDEFGLOB && defstate == SS_KILLED)
199               || (oldstate == SS_KILLED && defstate == SS_UNDEFGLOB))
200             {
201               defstate = SS_UNDEFKILLED;
202             }
203           else 
204             {
205               ; /* any errors? */
206             }
207           
208           sRef_setDefState (sr, defstate, fileloc_undefined);
209           DPRINTF (("State: %s", sRef_unparseFull (sr)));
210         }
211       else if (qual_isAllocQual (qel)) /* out, partial, reldef, etc. */
212         {
213           ctype realType = sRef_getType (sr);
214           sstate defstate = sstate_fromQual (qel);
215           
216           if (qual_isRelDef (qel))
217             {
218               ; /* okay anywhere */
219             }
220           else
221             {
222               if (!ctype_isAP (realType) 
223                   && !ctype_isSU (realType)
224                   && !ctype_isUnknown (realType)
225                   && !ctype_isAbstract (sRef_getType (sr)))
226                 {
227                   llerror 
228                     (FLG_SYNTAX, 
229                      message ("Qualifier %s used on non-pointer or struct: %q",
230                               qual_unparse (qel), sRef_unparse (sr)));
231                   
232                 }
233             }
234           
235           sRef_setDefState (sr, defstate, fileloc_undefined);
236         }
237       else if (qual_isNull (qel))
238         {
239           sRef_setNullState (sr, NS_POSNULL, fileloc_undefined);
240         }
241       else if (qual_isRelNull (qel))
242         {
243           sRef_setNullState (sr, NS_RELNULL, fileloc_undefined);
244         }
245       else if (qual_isNotNull (qel))
246         {
247           sRef_setNullState (sr, NS_MNOTNULL, fileloc_undefined);
248         }
249       else
250         {
251           if (qual_isCQual (qel))
252             {
253               ; /* okay */
254             }
255           else
256             {
257               llerror (FLG_SYNTAX,
258                        message ("Qualifier %s cannot be used in a globals list",
259                                 qual_unparse (qel)));
260             }
261         }
262     } end_qualList_elements;
263 }
264
265 sRef clabstract_createGlobal (sRef sr, qualList quals)
266 {
267   sRef res;
268
269   if (sRef_isValid (sr))
270     {
271       res = sRef_copy (sr);
272       DPRINTF (("Reflecting quals: %s / %s", sRef_unparse (sr), qualList_unparse (quals)));
273       reflectGlobalQualifiers (res, quals);
274       DPRINTF (("==> %s", sRef_unparseFull (res)));
275     }
276   else
277     {
278       res = sRef_undefined;
279     }
280
281   qualList_free (quals);
282   return res;
283 }
284
285 extern void declareCIter (cstring name, /*@owned@*/ uentryList params)
286 {
287   uentry ue;
288
289   ue = uentry_makeIter (name, 
290                         ctype_makeFunction (ctype_void, params), 
291                         fileloc_copy (g_currentloc));
292
293   usymtab_supEntry (uentry_makeEndIter (name, fileloc_copy (g_currentloc)));
294   ue = usymtab_supGlobalEntryReturn (ue);
295 }
296
297 extern void nextIterParam (void)
298 {
299   llassert (ProcessingIterVars);
300   saveIterParamNo++;
301 }
302
303 extern int iterParamNo (void)
304 {
305   llassert (ProcessingIterVars);
306   return saveIterParamNo;
307 }
308
309 /*
310 ** yucky hacks to put it in the right place
311 */
312
313 /*@only@*/ uentry 
314 makeCurrentParam (idDecl t)
315 {
316   uentry ue;
317
318   saveStoreLoc = fileloc_undefined;
319
320   /* param number unknown */
321
322   ue = uentry_makeParam (t, 0);
323   return ue;
324 }
325
326 ctype
327 declareUnnamedEnum (enumNameList el)
328 {
329   ctype ret = usymtab_enumEnumNameListType (el);
330   ctype rt;
331   uentry e;
332
333   if (ctype_isDefined (ret))
334     {
335       rt = ret;
336       e = uentry_makeEnumTagLoc (ctype_enumTag (rt), ret);
337
338       reflectStorageClass (e);
339       usymtab_supGlobalEntry (e);
340       
341       declareEnumList (el, ret, g_currentloc);    
342       enumNameList_free (el);
343     }
344   else
345     {
346       ctype ct = ctype_createEnum (fakeTag (), el);
347
348       e = uentry_makeEnumTagLoc (ctype_enumTag (ctype_realType (ct)), ct);
349       reflectStorageClass (e);
350
351       e = usymtab_supGlobalEntryReturn (e);
352       rt = uentry_getAbstractType (e);
353       declareEnumList (el, ct, g_currentloc);    
354     }
355   
356   return (rt);
357 }
358
359 ctype
360 declareEnum (cstring ename, enumNameList el)
361 {
362   ctype cet;
363   uentry e;
364
365   llassert (cstring_isDefined (ename));
366
367   cet = ctype_createEnum (ename, el);
368   e = uentry_makeEnumTagLoc (ename, cet);
369   reflectStorageClass (e);
370   e = usymtab_supGlobalEntryReturn (e);
371   cet = uentry_getType (e);
372   declareEnumList (el, cet, uentry_whereLast (e));    
373   return (uentry_getAbstractType (e));
374 }
375
376 static void
377 declareEnumList (enumNameList el, ctype c, fileloc loc)
378 {
379   bool boolnames = FALSE;
380   bool othernames = FALSE;
381
382   (void) context_getSaveLocation (); /* undefine it */
383
384   if (context_maybeSet (FLG_NUMENUMMEMBERS))
385     {
386       int maxnum = context_getValue (FLG_NUMENUMMEMBERS);
387       int num = enumNameList_size (el);
388
389       if (num > maxnum)
390         {
391           voptgenerror 
392             (FLG_NUMENUMMEMBERS,
393              message ("Enumerator %s declared with %d members (limit is set to %d)",
394                       ctype_unparse (c), num, maxnum),
395              loc);
396         }
397     }
398
399   enumNameList_elements (el, e)
400     {
401       uentry ue = usymtab_lookupExposeGlob (e);
402       ctype ct = uentry_getType (ue);
403
404       llassert (uentry_isEnumConstant (ue));
405
406       if (ctype_isUnknown (ct))
407         {
408           uentry_setType (ue, c);
409         }
410       else
411         {
412           if (cstring_equal (e, context_getFalseName ())
413               || cstring_equal (e, context_getTrueName ()))
414             {
415               if (othernames) 
416                 {
417                   if (optgenerror 
418                       (FLG_INCONDEFS,
419                        message ("Enumerator mixes boolean name (%s) with "
420                                 "non-boolean names",
421                                 e),
422                        uentry_whereLast (ue)))
423                     {
424                       ;
425                     }
426                 }
427               
428               boolnames = TRUE;
429               uentry_setType (ue, ctype_bool);
430               DPRINTF (("Set type: %s / %s",
431                         uentry_unparse (ue), ctype_unparse (ctype_bool)));
432             }
433           else 
434             {
435               if (boolnames) 
436                 {
437                   if (optgenerror 
438                       (FLG_INCONDEFS,
439                        message ("Enumerator mixes boolean names (%s, %s) with "
440                                 "non-boolean name: %s",
441                                 context_getTrueName (),
442                                 context_getFalseName (),
443                                 e),
444                        uentry_whereLast (ue)))
445                     {
446                       ;
447                     }
448                 }
449
450               othernames = TRUE;
451             }
452
453           if (!ctype_match (c, ct))
454             {
455               if (ctype_isDirectBool (ct))
456                 {
457                   if (cstring_equal (e, context_getFalseName ())
458                       || cstring_equal (e, context_getTrueName ()))
459                     {
460                       DPRINTF (("Here we are!"));
461                     }
462                   else
463                     {
464                       if (optgenerror 
465                           (FLG_INCONDEFS,
466                            message ("Enumerator member %s declared with "
467                                     "inconsistent type: %s",
468                                     e, ctype_unparse (c)),
469                            uentry_whereLast (ue)))
470                         {
471                           uentry_showWhereSpecifiedExtra 
472                             (ue, cstring_copy (ctype_unparse (ct)));
473                         }
474                     }
475                 }
476               else
477                 {
478                   if (optgenerror 
479                       (FLG_INCONDEFS,
480                        message ("Enumerator member %s declared with "
481                                 "inconsistent type: %s",
482                                 e, ctype_unparse (c)),
483                        uentry_whereLast (ue)))
484                     {
485                       uentry_showWhereSpecifiedExtra 
486                         (ue, cstring_copy (ctype_unparse (ct)));
487                     }
488                 }
489             }
490         }
491     } end_enumNameList_elements;
492 }
493
494 static /*@dependent@*/ uentryList currentParamList;
495
496 /*drl added 3-28-2002*/
497 /* this function takes a list of paramentar and generates a list
498    of constraints.
499    Currently the only constraints gnerated are MaxSet(p) >= 0 for all pointers
500 */
501
502 void  setImplictfcnConstraints (void)
503 {
504   uentryList params;
505   sRef s;
506   constraint c;
507   params = currentParamList;
508
509   if (constraintList_isDefined(implicitFcnConstraints) )
510     constraintList_free(implicitFcnConstraints);
511    
512   implicitFcnConstraints  = constraintList_makeNew();
513   
514   uentryList_elements (params, el)
515     {
516       DPRINTF((message("setImplictfcnConstraints doing: %s", uentry_unparse(el) ) ));
517       
518       s = uentry_getSref(el);
519       if (sRef_isReference (s) )
520         {
521           DPRINTF((message ("%s is a pointer", sRef_unparse(s) ) ));
522         }
523       else
524         {
525           DPRINTF((message ("%s is NOT a pointer", sRef_unparse(s) ) ));
526         }
527       /*drl 4/26/01
528         chagned this is MaxSet(s) == 0 to MaxSet(s) >= 0 */
529       
530       c = constraint_makeSRefWriteSafeInt (s, 0);
531       /* constraint_makeSRefSetBufferSize (s, 0); */
532       implicitFcnConstraints = constraintList_add(implicitFcnConstraints , c);
533     }
534   end_uentryList_elements;
535 }
536
537
538 /*@observer@*/ constraintList  getImplicitFcnConstraints (void)
539 {
540   return implicitFcnConstraints;
541 }
542
543 void setCurrentParams (/*@dependent@*/ uentryList ue)
544 {
545   currentParamList = ue;
546 }
547
548 void clearCurrentParams (void)
549 {
550     currentParamList = uentryList_undefined;
551 }
552
553 /*
554 ** requires: uentry_isFunction (e)
555 **           parameter names for current function are in currentParamList
556 */
557
558 static void enterFunctionParams (uentryList params)
559 {
560   int paramno = 0;
561
562   uentryList_elements (params, current)
563     {
564       if (uentry_hasName (current)) 
565         {
566           uentry_setParamNo (current, paramno);
567           usymtab_supEntry (uentry_copy (current));
568         }
569       
570       paramno++;
571     } end_uentryList_elements; 
572 }
573  
574
575 extern void enterParamsTemp (void)
576 {
577   usymtab_enterScope ();
578   enterFunctionParams (currentParamList);
579 }
580
581 extern void exitParamsTemp (void)
582 {
583   usymtab_quietPlainExitScope ();
584 }
585
586 static /*@exposed@*/ uentry clabstract_globalDeclareFunction (idDecl tid) 
587 {
588   ctype deftype = idDecl_getCtype (tid);
589   ctype rettype;
590   uentry ue;
591   
592   DPRINTF (("Global function: %s", idDecl_unparse (tid)));
593
594   if (ctype_isFunction (deftype))
595     {
596       rettype = ctype_getReturnType (deftype);
597     }
598   else
599     {
600       rettype = ctype_unknown;
601     }
602
603   /*
604   ** check has been moved here...
605   */
606
607   if (ctype_isFunction (idDecl_getCtype (tid)))
608     {
609       ue = uentry_makeIdFunction (tid);
610       reflectSpecialCode (ue);
611       reflectArgsUsed (ue);
612     }
613   else
614     {    
615       llparseerror (message ("Inconsistent function declaration: %q",
616                              idDecl_unparse (tid)));
617
618       tid = idDecl_replaceCtype 
619         (tid, ctype_makeFunction (ctype_unknown, uentryList_undefined));
620       ue = uentry_makeIdFunction (tid);
621     }
622
623   reflectStorageClass (ue);
624   uentry_checkParams (ue);
625
626   DPRINTF (("Supercede function: %s", uentry_unparseFull (ue)));
627
628   ue = usymtab_supGlobalEntryReturn (ue);
629   DPRINTF (("After supercede function: %s", uentry_unparseFull (ue)));
630
631   DPRINTF (("Enter function: %s", uentry_unparseFull (ue)));
632   context_enterFunction (ue);
633   enterFunctionParams (uentry_getParams (ue));
634
635   resetStorageClass ();
636   DPRINTF (("Function: %s", uentry_unparseFull (ue)));
637   return (ue);
638 }
639
640 /*
641 ** for now, no type checking
642 ** (must check later though!)
643 */
644
645 static /*@only@*/ uentry globalDeclareOldStyleFunction (idDecl tid)
646 {
647   uentry ue;
648
649   /*
650   ** check has been moved here...
651   */
652
653   if (cstring_equalLit (idDecl_observeId (tid), "main"))
654     {
655       context_setFlagTemp (FLG_MAINTYPE, FALSE);
656     }
657
658   ue = uentry_makeIdFunction (tid);
659   reflectStorageClass (ue);
660   reflectSpecialCode (ue);
661   reflectArgsUsed (ue);
662   uentry_setDefined (ue, g_currentloc);
663   uentry_checkParams (ue);
664   resetStorageClass ();
665
666   /* context_enterOldStyleScope (); */
667
668   return (ue);
669 }
670
671 static void oldStyleDeclareFunction (/*@only@*/ uentry e)
672 {
673   uentryList params = saveParamList;
674   ctype rt = uentry_getType (e);
675
676   llassert (ctype_isFunction (rt));
677
678   if (uentry_hasStateClauseList (e) 
679       || uentry_hasConditions (e))
680     {
681       llfatalerror (message ("%q: Old-style function declaration uses a clause (rewrite with function parameters): %q",
682                              fileloc_unparse (g_currentloc), uentry_unparse (e)));
683     }
684
685   e = usymtab_supGlobalEntryReturn (e);
686
687   context_enterFunction (e);
688   enterFunctionParams (params);
689   saveParamList = uentryList_undefined;
690   resetStorageClass ();
691 }
692
693 static void oldStyleCompleteFunction (/*@only@*/ uentry e)
694 {
695   uentryList params = saveParamList;
696   ctype rt = uentry_getType (e);
697
698   llassert (ctype_isFunction (rt));
699
700   if (uentry_hasStateClauseList (e) 
701       || uentry_hasConditions (e))
702     {
703       llfatalerror (message ("%q: Old-style function declaration uses a clause (rewrite with function parameters): %q",
704                              fileloc_unparse (g_currentloc), uentry_unparse (e)));
705     }
706
707   e = usymtab_supGlobalEntryReturn (e);
708
709   context_completeOldStyleFunction (e);
710   enterFunctionParams (params);
711   saveParamList = uentryList_undefined;
712   resetStorageClass ();
713 }
714
715 void clabstract_declareFunction (idDecl tid) /*@globals undef saveFunction; @*/
716 {
717   uentry ue;
718
719   DPRINTF (("Declare function: %s", idDecl_unparse (tid)));
720   
721   if (ProcessingParams)
722     {
723       ue = globalDeclareOldStyleFunction (tid);
724       saveFunction = ue;
725       DPRINTF (("Set save function: %s", uentry_unparseFull (ue)));
726     }
727   else
728     {
729       saveFunction = uentry_undefined;
730
731       if (context_inRealFunction ())
732         {
733           ue = uentry_makeVariableLoc (idDecl_observeId (tid), ctype_unknown);
734
735           llparseerror (message ("Function declared inside function: %q",
736                                  idDecl_unparse (tid)));
737           
738           context_quietExitFunction ();
739           ue = usymtab_supEntryReturn (ue);
740         }
741       else
742         {
743           if (context_inInnerScope ())
744             {
745               llparseerror (message ("Declaration in inner context: %q",
746                                      idDecl_unparse (tid)));
747               
748               sRef_setGlobalScope ();
749               ue = uentry_makeVariableLoc (idDecl_observeId (tid), 
750                                            ctype_unknown);
751               ue = usymtab_supGlobalEntryReturn (ue);
752               sRef_clearGlobalScope ();
753             }
754           else
755             {
756               ue = clabstract_globalDeclareFunction (tid);
757             }
758         }
759       
760       resetGlobals ();
761     }
762
763   resetStorageClass ();
764   idDecl_free (tid);
765 }
766
767 void declareStaticFunction (idDecl tid) /*@globals undef saveFunction; @*/
768 {
769   uentry ue;
770
771   DPRINTF (("Declare static funciton: %s", idDecl_unparse (tid)));
772
773   if (ProcessingParams)
774     {
775       ue = globalDeclareOldStyleFunction (tid);
776       saveFunction = ue;
777     }
778   else
779     {
780       saveFunction = uentry_undefined;
781
782       if (context_inRealFunction ())
783         {
784           ue = uentry_makeVariableLoc (idDecl_observeId (tid), ctype_unknown);
785
786           llparseerror (message ("Function declared inside function: %q",
787                                  idDecl_unparse (tid)));
788           
789           context_quietExitFunction ();
790           ue = usymtab_supEntryReturn (ue);
791         }
792       else
793         {
794           if (context_inInnerScope ())
795             {
796               llparseerror (message ("Declaration in inner context: %q",
797                                      idDecl_unparse (tid)));
798               
799               sRef_setGlobalScope ();
800               ue = uentry_makeVariableLoc (idDecl_observeId (tid), 
801                                            ctype_unknown);
802               ue = usymtab_supGlobalEntryReturn (ue);
803               sRef_clearGlobalScope ();
804             }
805           else
806             {
807               ctype deftype = idDecl_getCtype (tid);
808               ctype rettype;
809               
810               if (ctype_isFunction (deftype))
811                 {
812                   rettype = ctype_getReturnType (deftype);
813                 }
814               else
815                 {
816                   rettype = ctype_unknown;
817                 }
818               
819               /*
820               ** check has been moved here...
821               */
822               
823               if (ctype_isFunction (idDecl_getCtype (tid)))
824                 {
825                   ue = uentry_makeIdFunction (tid);
826                   reflectSpecialCode (ue);
827                   reflectArgsUsed (ue);
828                 }
829               else
830                 {    
831                   llparseerror (message ("Inconsistent function declaration: %q",
832                                          idDecl_unparse (tid)));
833                   
834                   tid = idDecl_replaceCtype 
835                     (tid, ctype_makeFunction (ctype_unknown, uentryList_undefined));
836                   ue = uentry_makeIdFunction (tid);
837                 }
838               
839               reflectStorageClass (ue);
840               uentry_setStatic (ue);
841
842               uentry_checkParams (ue);
843         
844               DPRINTF (("Sub global entry: %s", uentry_unparse (ue)));
845               ue = usymtab_supGlobalEntryReturn (ue);
846
847               context_enterFunction (ue);
848               enterFunctionParams (uentry_getParams (ue));
849               resetStorageClass ();
850             }
851         }
852       
853       resetGlobals ();
854     }
855   
856   resetStorageClass ();
857   idDecl_free (tid);
858 }
859
860 void
861 checkTypeDecl (uentry e, ctype rep)
862 {
863   cstring n = uentry_getName (e);
864
865   DPRINTF (("Check type decl: %s", uentry_unparseFull (e)));
866
867   if (cstring_equal (context_getBoolName (), n))
868     {
869       ctype rrep = ctype_realType (rep);
870       
871       /*
872       ** for abstract enum types, we need to fix the enum members:
873       ** they should have the abstract type, not the rep type.
874       */
875       
876       if (ctype_isEnum (ctype_realType (rrep)))
877         {
878           enumNameList el = ctype_elist (rrep);
879           
880           enumNameList_elements (el, ye)
881             {
882               if (usymtab_existsGlob (ye))
883                 {
884                   uentry ue = usymtab_lookupSafe (ye);
885                   uentry_setType (ue, ctype_bool);
886                 }
887
888               if (cstring_equal (context_getTrueName (), ye)
889                   || cstring_equal (context_getFalseName (), ye))
890                 {
891                   ;
892                 }
893               else
894                 {
895                   vgenhinterror 
896                     (FLG_SYNTAX,
897                      message ("Member of boolean enumerated type definition "
898                               "does not match name set to represent TRUE "
899                               "or FALSE: %s",
900                               ye),
901                      message ("Use -boolfalse and -booltrue to set the "
902                               "name of false and true boolean values."),
903                      uentry_whereDefined (e));
904                 }
905             } end_enumNameList_elements;
906         }
907     }
908
909   if (usymtab_exists (n))
910     {
911       usymId llm = usymtab_getId (n);
912       uentry le  = usymtab_getTypeEntry (llm);
913
914       uentry_setDeclared (e, g_currentloc); 
915       uentry_setSref (e, sRef_makeGlobal (llm, uentry_getType (le), stateInfo_currentLoc ()));
916
917       DPRINTF (("Here we are: %s / %s",
918                 n, context_getBoolName ()));
919       
920       if (uentry_isAbstractDatatype (le))
921         {
922           ctype rrep = ctype_realType (rep);
923
924           DPRINTF (("Abstract type: %s", uentry_unparseFull (le)));
925
926           /*
927           ** for abstract enum types, we need to fix the enum members:
928           ** they should have the abstract type, not the rep type.
929           */
930
931           if (ctype_isEnum (ctype_realType (rrep)))
932             {
933               ctype at = uentry_getAbstractType (le);
934               enumNameList el = ctype_elist (rrep);
935
936               enumNameList_elements (el, ye)
937                 {
938                   if (usymtab_existsGlob (ye))
939                     {
940                       uentry ue = usymtab_lookupSafe (ye);
941
942                       llassert (uentry_isEitherConstant (ue));
943                       llassertprint (ctype_match (uentry_getType (ue), rrep),
944                                      ("Bad enum: %s / %s",
945                                       uentry_unparse (ue),
946                                       ctype_unparse (rrep)));
947                       
948                       uentry_setType (ue, at);
949                     }
950                 } end_enumNameList_elements;
951             }
952           
953           if (uentry_isMutableDatatype (le))
954             {
955               /* maybe more complicated if abstract and immutable ? */
956
957               if (!ctype_isRealPointer (rep) && !ctype_isRealAbstract (rep))
958                 {
959                   voptgenerror 
960                     (FLG_MUTREP,
961                      message ("Mutable abstract type %s declared without pointer "
962                               "indirection: %s (violates assignment semantics)",
963                               n, ctype_unparse (rep)),
964                      uentry_whereDefined (e));
965                   
966                   uentry_setMutable (e);
967                 }
968             }
969         }
970     }
971   else
972     {
973       fileloc fl = uentry_whereDeclared (e);
974
975       if (context_getFlag (FLG_LIKELYBOOL)
976           && !context_getFlag (FLG_BOOLINT))
977         {
978           if ((cstring_equalLit (n, "BOOL")
979                || cstring_equalLit (n, "Bool")
980                || cstring_equalLit (n, "bool")
981                || cstring_equalLit (n, "boolean")
982                || cstring_equalLit (n, "Boolean")
983                || cstring_equalLit (n, "BOOLEAN"))
984               && !(cstring_equal (n, context_getBoolName ())))
985             {
986               if (context_setBoolName ()) {
987                 voptgenerror 
988                   (FLG_LIKELYBOOL,
989                    message ("Type %s is probably meant as a boolean type, but does "
990                             "not match the boolean type name \"%s\".",
991                             n,
992                             context_getBoolName ()),
993                    fl);
994               } else
995                 voptgenerror 
996                   (FLG_LIKELYBOOL,
997                    message ("Type %s is probably meant as a boolean type, "
998                             "but the boolean type name is not set. "
999                             "Use -booltype %s to set it.",
1000                             n,
1001                             n),
1002                    fl);
1003                 }
1004         }
1005
1006       if (!uentry_isStatic (e)
1007           && !ctype_isFunction (uentry_getType (e)) 
1008           && !fileloc_isLib (fl) 
1009           && !fileloc_isImport (fl)
1010           && fileloc_isHeader (fl))
1011         {
1012           voptgenerror (FLG_EXPORTTYPE,
1013                         message ("Type exported, but not specified: %s\n", n),
1014                         fl);
1015         }
1016     }
1017
1018   cstring_free (n);
1019 }
1020
1021 uentryList
1022 fixUentryList (idDeclList tl, qtype q)
1023 {
1024   uentryList f = uentryList_new ();
1025   
1026   idDeclList_elements (tl, i)
1027   {
1028     if (idDecl_isDefined (i))
1029       {
1030         uentry ue;
1031         uentry old;
1032         ctype rt;
1033
1034         (void) idDecl_fixBase (i, q);
1035
1036         /*
1037         ** implicit annotations 
1038         */
1039
1040         (void) fixStructDecl (i);
1041
1042         ue = uentry_makeIdVariable (i);
1043         rt = ctype_realType (uentry_getType (ue));
1044
1045         /*
1046         ** where is this here???
1047
1048         if (ctype_isArray (rt) || ctype_isSU (rt))
1049           {
1050             sRef_setAllocated (uentry_getSref (ue), uentry_whereDefined (ue));
1051           }
1052
1053         **
1054         */
1055
1056         if (uentry_isValid (old = uentryList_lookupField (f, uentry_rawName (ue))))
1057           {
1058             if (optgenerror (FLG_SYNTAX,
1059                              message ("Field name reused: %s", uentry_rawName (ue)),
1060                              uentry_whereDefined (ue)))
1061               {
1062                 llgenmsg (message ("Previous use of %s", uentry_rawName (ue)),
1063                           uentry_whereDefined (old));
1064               }
1065           }
1066         
1067         f = uentryList_add (f, ue);
1068       }
1069   } end_idDeclList_elements;
1070
1071   idDeclList_free (tl);
1072   return (f);
1073 }
1074
1075 /*
1076 ** This is a hack to support unnamed struct/union fields as done by
1077 ** Microsoft VC++.  It is not supported by the ANSI standard.  
1078 **
1079 ** The inner fields are added to the outer structure.  This is meaningful
1080 ** for nesting structs inside unions, but Splint does no related 
1081 ** checking.
1082 */
1083
1084 uentryList
1085 fixUnnamedDecl (qtype q)
1086 {
1087   ctype ct = ctype_realType (qtype_getType (q));
1088
1089   if (ctype_isStruct (ct) || ctype_isUnion (ct))
1090     {
1091       uentryList res = ctype_getFields (ct);
1092
1093       return (uentryList_copy (res));
1094     }
1095   else
1096     {      
1097       BADBRANCHCONT;
1098     }
1099
1100   return uentryList_undefined;
1101 }
1102
1103 void setStorageClass (storageClassCode sc)
1104 {
1105   storageClass = sc;
1106 }
1107
1108 void
1109 setProcessingIterVars (uentry iter)
1110 {
1111   ProcessingIterVars = TRUE;
1112   currentIter = iter;
1113   saveIterParamNo = 0;
1114 }
1115
1116 void
1117 setProcessingGlobalsList ()
1118 {
1119   ProcessingGlobals = TRUE;
1120   fcnNoGlobals = FALSE;
1121 }
1122
1123 static bool ProcessingGlobMods = FALSE;
1124
1125 void
1126 setProcessingGlobMods ()
1127 {
1128   ProcessingGlobMods = TRUE;
1129 }
1130
1131 void
1132 clearProcessingGlobMods ()
1133 {
1134   ProcessingGlobMods = FALSE;
1135 }
1136
1137 bool
1138 isProcessingGlobMods ()
1139 {
1140   return (ProcessingGlobMods);
1141 }
1142
1143 static void resetGlobals (void)
1144 {
1145   ProcessingGlobals = FALSE;
1146   fcnNoGlobals = FALSE;
1147 }
1148
1149 void
1150 unsetProcessingGlobals ()
1151 {
1152   ProcessingGlobals = FALSE;
1153 }
1154
1155 void
1156 setProcessingVars (/*@only@*/ qtype q)
1157 {
1158   ProcessingVars = TRUE;
1159   qtype_free (processingType);
1160   processingType = q;
1161 }
1162
1163 static void
1164 setGenericParamList (/*@dependent@*/ uentryList pm)
1165 {
1166   ProcessingParams = TRUE;
1167   saveParamList = pm;
1168 }
1169
1170 void
1171 setProcessingTypedef (qtype q)
1172 {
1173   ProcessingTypedef = TRUE;
1174
1175   qtype_free (processingType);
1176   processingType = q;
1177 }
1178
1179 void
1180 unsetProcessingVars ()
1181 {
1182   resetStorageClass ();
1183   ProcessingVars = FALSE;
1184 }
1185
1186 void 
1187 oldStyleDoneParams ()
1188 {  
1189   if (ProcessingParams)
1190     {
1191       if (uentry_isInvalid (saveFunction))
1192         {
1193           llbuglit ("unsetProcessingVars: no saved function\n");
1194         }
1195       else
1196         {
1197           ctype ct = ctype_getReturnType (uentry_getType (saveFunction));
1198           uentryList params = uentryList_copy (saveParamList);
1199           ctype ct2 = ctype_makeFunction (ct, params);
1200
1201           uentry_setType (saveFunction, ct2);
1202           ProcessingParams = FALSE;
1203
1204           oldStyleCompleteFunction (saveFunction);
1205           saveFunction = uentry_undefined;
1206           resetGlobals ();
1207         }
1208     }
1209   else
1210     {
1211       /*
1212       ** If the paramlist used a type name, we could be here.
1213       */
1214
1215       llfatalerror (message ("%q: Old-style function parameter list uses a "
1216                              "type name.", fileloc_unparse (g_currentloc)));
1217     }
1218 }
1219
1220 void 
1221 checkDoneParams ()
1222 {
1223   if (uentry_isValid (saveFunction))
1224     {
1225       /*
1226       ** old style declaration
1227       */
1228
1229       ctype ct = ctype_getReturnType (uentry_getType (saveFunction));
1230       ctype ct2;
1231
1232       DPRINTF (("save function: %s", uentry_unparseFull (saveFunction)));
1233
1234       uentryList_elements (saveParamList, current)
1235         {
1236           uentry_setType (current, ctype_int); /* all params are ints */
1237         } end_uentryList_elements; 
1238
1239       ct2 = ctype_makeParamsFunction (ct, uentryList_copy (saveParamList));
1240       
1241       uentry_setType (saveFunction, ct2);
1242       ProcessingParams = FALSE;
1243       
1244       oldStyleDeclareFunction (saveFunction);
1245       saveFunction = uentry_undefined;
1246     }
1247 }
1248
1249 void clabstract_declareType (/*@only@*/ exprNodeList decls, /*@only@*/ warnClause warn)
1250 {
1251   llassert (ProcessingTypedef);
1252
1253   if (warnClause_isDefined (warn))
1254     {
1255       exprNodeList_elements (decls, el)
1256         {
1257           uentry ue = exprNode_getUentry (el);
1258           cstring uname = uentry_getName (ue);
1259
1260           DPRINTF (("Entry: %s", exprNode_unparse (el)));
1261
1262           /*
1263           ** Need to lookup again to make sure we have the right one...
1264           */
1265
1266           ue = usymtab_lookupExposeGlob (uname);
1267
1268           llassert (uentry_isValid (ue));
1269           llassert (uentry_isDatatype (ue));
1270
1271           DPRINTF (("Warning for %s: %s",
1272                     uentry_unparse (ue), warnClause_unparse (warn)));
1273
1274           uentry_addWarning (ue, warnClause_copy (warn));
1275           cstring_free (uname);
1276         } end_exprNodeList_elements;
1277     }
1278
1279   warnClause_free (warn);
1280   exprNodeList_free (decls);
1281   unsetProcessingTypedef ();
1282 }
1283
1284 void
1285 unsetProcessingTypedef ()
1286 {
1287   ProcessingTypedef = FALSE;
1288 }
1289
1290 void checkConstant (qtype t, idDecl id) 
1291 {
1292   uentry e;
1293   
1294   id = idDecl_fixBase (id, t);
1295   e = uentry_makeIdConstant (id);
1296   
1297   reflectStorageClass (e);
1298   resetStorageClass ();
1299
1300   DPRINTF (("Constant: %s", uentry_unparseFull (e)));
1301   usymtab_supGlobalEntry (e);
1302 }
1303
1304 void checkValueConstant (qtype t, idDecl id, exprNode e) 
1305 {
1306   uentry ue;
1307
1308   id = idDecl_fixBase (id, t);
1309   ue = uentry_makeIdConstant (id);
1310   reflectStorageClass (ue);
1311   resetStorageClass ();
1312
1313   if (exprNode_isDefined (e))
1314     {
1315       if (!exprNode_matchType (uentry_getType (ue), e))
1316         {
1317           (void) gentypeerror 
1318             (exprNode_getType (e), e,
1319              uentry_getType (ue), exprNode_undefined,
1320              message ("Constant %q initialized to type %t, expects %t: %s",
1321                       uentry_getName (ue),  
1322                       exprNode_getType (e), 
1323                       uentry_getType (ue),
1324                       exprNode_unparse (e)),
1325              exprNode_loc (e));
1326         }
1327       else
1328         {
1329           if (exprNode_hasValue (e))
1330             {
1331               uentry_mergeConstantValue (ue, multiVal_copy (exprNode_getValue (e)));
1332             }
1333           else
1334             {
1335               DPRINTF (("No value: %s", exprNode_unparse (e)));
1336             }
1337         }
1338     }
1339
1340   DPRINTF (("Constant value: %s", uentry_unparseFull (ue)));
1341   usymtab_supGlobalEntry (ue);
1342 }
1343
1344 void processNamedDecl (idDecl t)
1345 {
1346   if (qtype_isUndefined (processingType))
1347     {
1348       llparseerror (message ("No type before declaration name: %q", idDecl_unparse (t)));
1349
1350       processingType = qtype_create (ctype_unknown);
1351     }
1352
1353   t = idDecl_fixBase (t, processingType);
1354
1355   DPRINTF (("Declare: %s", idDecl_unparse (t)));
1356   
1357   if (ProcessingGlobals)
1358     {
1359       cstring id = idDecl_getName (t);
1360       uentry ue = usymtab_lookupSafe (id);
1361       
1362       if (!uentry_isValid (ue))
1363         {
1364           llerror (FLG_UNRECOG,
1365                    message ("Variable used in globals list is undeclared: %s", id));
1366         }
1367       else
1368         {
1369           if (!ctype_match (uentry_getType (ue), idDecl_getCtype (t)))
1370             {
1371               voptgenerror 
1372                 (FLG_INCONDEFS,
1373                  message ("Variable %s used in globals list declared %s, "
1374                           "but listed as %s", 
1375                           id, ctype_unparse (uentry_getType (ue)), 
1376                           ctype_unparse (idDecl_getCtype (t))),
1377                  g_currentloc);
1378             }
1379           else
1380             {
1381               sRef sr = sRef_copy (uentry_getSref (ue));
1382               reflectGlobalQualifiers (sr, idDecl_getQuals (t));
1383             }
1384         }
1385     }
1386   else if (ProcessingVars)
1387     {
1388       uentry e;
1389       ctype ct;
1390       
1391       ct = ctype_realType (idDecl_getCtype (t));
1392
1393       if (ProcessingParams)
1394         {
1395           cstring id = idDecl_getName (t);
1396           int paramno = uentryList_lookupRealName (saveParamList, id);
1397
1398           if (paramno >= 0)
1399             {
1400               uentry cparam = uentryList_getN (saveParamList, paramno);
1401
1402               DPRINTF (("Processing param: %s", uentry_unparseFull (cparam)));
1403               uentry_setType (cparam, idDecl_getCtype (t));
1404               uentry_reflectQualifiers (cparam, idDecl_getQuals (t));
1405               uentry_setDeclaredOnly (cparam, context_getSaveLocation ());
1406               DPRINTF (("Processing param: %s", uentry_unparseFull (cparam)));
1407             }
1408           else
1409             {
1410               llfatalerrorLoc
1411                 (message ("Old style declaration uses unlisted parameter: %s", 
1412                           id));
1413             }
1414         }
1415       else
1416         {
1417           fileloc loc;
1418
1419           if (context_inIterDef ())
1420             {
1421               cstring pname = makeParam (idDecl_observeId (t));
1422               uentry p = usymtab_lookupSafe (pname);
1423
1424               cstring_free (pname);
1425
1426               if (uentry_isYield (p))
1427                   {
1428                       e = uentry_makeParam (t, sRef_getParam (uentry_getSref (p)));
1429                       uentry_checkYieldParam (p, e);
1430                       usymtab_supEntrySref (e);
1431                       return;
1432                   }
1433             }
1434           
1435           if ((hasSpecialCode () || argsUsed)
1436               && ctype_isFunction (idDecl_getCtype (t)))
1437               {
1438               e = uentry_makeIdFunction (t);
1439               reflectSpecialCode (e);
1440               reflectArgsUsed (e);
1441               }
1442           else
1443               {
1444                   e = uentry_makeIdVariable (t);
1445               }
1446           
1447           loc = uentry_whereDeclared (e);
1448           
1449           /*
1450             if (context_inGlobalScope ())
1451             {
1452             uentry_checkParams was here!
1453             }
1454           */
1455           
1456           if (ctype_isFunction (uentry_getType (e)))
1457             {
1458               clabstract_prepareFunction (e);
1459             }
1460           
1461           DPRINTF (("Superceding... %s", uentry_unparseFull (e)));
1462           e = usymtab_supEntrySrefReturn (e);
1463           DPRINTF (("After superceding... %s", uentry_unparseFull (e)));          
1464           
1465           if (uentry_isExtern (e) && !context_inGlobalScope ())
1466             {
1467               voptgenerror 
1468                 (FLG_NESTEDEXTERN,
1469                  message ("Declaration using extern inside function scope: %q",
1470                           uentry_unparse (e)),
1471                  g_currentloc);
1472               
1473               uentry_setDefined (e, fileloc_getExternal ());
1474               sRef_setDefined (uentry_getSref (e), fileloc_getExternal ());
1475             }
1476           
1477           if (uentry_isFunction (e))
1478             {
1479               if (!context_inXHFile ())
1480                 {
1481                   checkParamNames (e);
1482                 }
1483             }
1484           
1485           if (uentry_isVar (e) && uentry_isCheckedUnknown (e))
1486             {
1487               sRef sr = uentry_getSref (e);
1488               
1489               if (sRef_isLocalVar (sr))
1490                 {
1491                   if (context_getFlag (FLG_IMPCHECKMODINTERNALS))
1492                     {
1493                       uentry_setCheckMod (e);
1494                     }
1495                   else
1496                     {
1497                       uentry_setUnchecked (e);
1498                     }
1499                 }
1500               else if (sRef_isFileStatic (sr))
1501                 {
1502                   if (context_getFlag (FLG_IMPCHECKEDSTRICTSTATICS))
1503                     {
1504                       uentry_setCheckedStrict (e);
1505                     }
1506                   else if (context_getFlag (FLG_IMPCHECKEDSTATICS))
1507                     {
1508                       uentry_setChecked (e);
1509                     }
1510                   else if (context_getFlag (FLG_IMPCHECKMODSTATICS))
1511                     {
1512                       uentry_setCheckMod (e);
1513                     }
1514                   else
1515                     {
1516                       ;
1517                     }
1518                 }
1519               else /* real global */
1520                 {
1521                   llassert (sRef_isRealGlobal (sr));
1522                   
1523                   if (context_getFlag (FLG_IMPCHECKEDSTRICTGLOBALS))
1524                     {
1525                       uentry_setCheckedStrict (e);
1526                     }
1527                   else if (context_getFlag (FLG_IMPCHECKEDGLOBALS))
1528                     {
1529                       uentry_setChecked (e);
1530                     }
1531                   else if (context_getFlag (FLG_IMPCHECKMODGLOBALS))
1532                     {
1533                       uentry_setCheckMod (e);
1534                     }
1535                   else
1536                     {
1537                       ;
1538                     }
1539                 }
1540             }
1541         }
1542     }
1543   else if (ProcessingTypedef)
1544     {
1545       ctype ct = idDecl_getCtype (t);
1546       uentry e;
1547       
1548       DPRINTF (("Processing typedef: %s", ctype_unparse (ct)));
1549       
1550       e = uentry_makeIdDatatype (t);
1551
1552       if (cstring_equal (idDecl_getName (t), context_getBoolName ())) {
1553         ctype rt = ctype_realType (ct);
1554         
1555         if (ctype_isEnum (rt)) {
1556           ;
1557         } else {
1558           if (!(ctype_isInt (rt)
1559                 || ctype_isUnknown (rt)
1560                 || ctype_isChar (rt))) {
1561             (void) llgenerror
1562               (FLG_BOOLTYPE, 
1563                message ("Boolean type %s defined using non-standard type %s (integral, char or enum type expected)",
1564                         context_getBoolName (),
1565                         ctype_unparse (ct)),
1566                uentry_whereLast (e));
1567           }
1568           
1569           ct = ctype_bool;
1570           uentry_setType (e, ct);
1571         }
1572       }
1573
1574       reflectStorageClass (e);
1575       checkTypeDecl (e, ct);
1576       
1577       e = usymtab_supReturnTypeEntry (e);
1578     }
1579   else
1580     {
1581       llparseerror (message ("Suspect missing struct or union keyword: %q",
1582                              idDecl_unparse (t)));
1583     }
1584
1585   }
1586
1587 /*
1588 ** moved from grammar
1589 */
1590
1591 static idDecl fixStructDecl (/*@returned@*/ idDecl d)
1592 {
1593   if (ctype_isVisiblySharable (idDecl_getCtype (d)) 
1594       && context_getFlag (FLG_STRUCTIMPONLY))
1595     {
1596       if (!qualList_hasAliasQualifier (idDecl_getQuals (d)))
1597         {
1598           if (qualList_hasExposureQualifier (idDecl_getQuals (d)))
1599             {
1600               idDecl_addQual (d, qual_createDependent ());
1601             }
1602           else
1603             {
1604               idDecl_addQual (d, qual_createImpOnly ());
1605             }
1606         }
1607     }
1608
1609   return d;
1610 }
1611
1612 ctype
1613 declareUnnamedStruct (/*@only@*/ uentryList f)
1614 {
1615   DPRINTF (("Unnamed struct: %s", uentryList_unparse (f)));
1616
1617   if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1618     {
1619       int num = uentryList_size (f);
1620       int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1621
1622       if (num > max)
1623         {
1624           voptgenerror 
1625             (FLG_NUMSTRUCTFIELDS,
1626              message ("Structure declared with %d fields "
1627                       "(limit is set to %d)",
1628                       num, max),
1629              g_currentloc);
1630         }
1631     }
1632
1633   return (ctype_createUnnamedStruct (f));
1634 }
1635
1636 ctype
1637 declareUnnamedUnion (/*@only@*/ uentryList f)
1638 {
1639   if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1640     {
1641       int num = uentryList_size (f);
1642       int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1643
1644       if (num > max)
1645         {
1646           voptgenerror 
1647             (FLG_NUMSTRUCTFIELDS,
1648              message ("Union declared with %d fields "
1649                       "(limit is set to %d)",
1650                       num, max),
1651              g_currentloc);
1652         }
1653     }
1654
1655   return (ctype_createUnnamedUnion (f));
1656 }
1657
1658 ctype declareStruct (cstring id, /*@only@*/ uentryList f)
1659 {
1660   ctype ct; 
1661   uentry ue;
1662   int num = uentryList_size (f);
1663
1664   DPRINTF (("Declare struct: %s / %s", id, uentryList_unparse (f)));
1665
1666   ct = ctype_createStruct (cstring_copy (id), f);
1667
1668   DPRINTF (("Ctype: %s", ctype_unparse (ct)));
1669
1670   ue = uentry_makeStructTagLoc (id, ct);
1671
1672   DPRINTF (("ue: %s", uentry_unparseFull (ue)));
1673
1674   if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1675     {
1676       int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1677
1678       if (num > max)
1679         {
1680           voptgenerror 
1681             (FLG_NUMSTRUCTFIELDS,
1682              message ("Structure %q declared with %d fields "
1683                       "(limit is set to %d)",
1684                       uentry_getName (ue), num, max),
1685              uentry_whereLast (ue));
1686         }
1687     }
1688
1689   return (usymtab_supTypeEntry (ue));
1690 }
1691
1692 ctype declareUnion (cstring id, uentryList f)
1693 {
1694   ctype ct; 
1695   uentry ue;
1696   int num = uentryList_size (f);
1697
1698   ct = ctype_createUnion (cstring_copy (id), f);
1699   ue = uentry_makeUnionTagLoc (id, ct);
1700
1701   if (context_maybeSet (FLG_NUMSTRUCTFIELDS))
1702     {
1703       int max = context_getValue (FLG_NUMSTRUCTFIELDS);
1704
1705       if (num > max)
1706         {
1707           voptgenerror 
1708             (FLG_NUMSTRUCTFIELDS,
1709              message ("Union %q declared with %d fields "
1710                       "(limit is set to %d)",
1711                       uentry_getName (ue), num, max),
1712              uentry_whereLast (ue));
1713         }
1714     }
1715
1716   return (usymtab_supTypeEntry (ue));
1717 }
1718
1719 ctype handleStruct (/*@only@*/ cstring id)
1720 {
1721   if (usymtab_existsStructTag (id))
1722     {
1723       ctype ct = uentry_getAbstractType (usymtab_lookupStructTag (id));
1724
1725       cstring_free (id);
1726       return ct;
1727     }
1728   else
1729     {
1730       return (ctype_createForwardStruct (id));
1731     }
1732 }
1733
1734 ctype handleUnion (/*@only@*/ cstring id)
1735 {
1736   if (usymtab_existsUnionTag (id))
1737     {
1738       ctype ret = uentry_getAbstractType (usymtab_lookupUnionTag (id));
1739       cstring_free (id);
1740       return (ret);
1741     }
1742   else
1743     {
1744       return (ctype_createForwardUnion (id));
1745     }
1746 }
1747
1748 ctype
1749 handleEnum (cstring id)
1750 {
1751   if (usymtab_existsEnumTag (id))
1752     {
1753       ctype ret = uentry_getAbstractType (usymtab_lookupEnumTag (id));
1754       cstring_free (id);
1755       return ret;
1756     }
1757   else
1758     {
1759       return (declareEnum (id, enumNameList_new ()));
1760     }
1761 }
1762
1763 bool processingIterVars (void) 
1764
1765   return ProcessingIterVars; 
1766 }
1767
1768 uentry getCurrentIter (void) 
1769 {
1770   return currentIter; 
1771 }
1772
1773 static bool flipOldStyle = FALSE;
1774 static bool flipNewStyle = TRUE;
1775
1776 void setFlipOldStyle ()          { flipOldStyle = TRUE; }
1777 bool isFlipOldStyle ()           { return flipOldStyle; }
1778 bool isNewStyle ()               { return flipNewStyle; }
1779 void setNewStyle ()              { flipNewStyle = TRUE; }
1780
1781 /*@dependent@*/ uentryList handleParamIdList (/*@dependent@*/ uentryList params)
1782 {  
1783   int paramno = 0;
1784
1785   /*
1786   ** this is a really YUCKY hack to handle old style
1787   ** declarations.
1788   */
1789   
1790   voptgenerror (FLG_OLDSTYLE,
1791                 cstring_makeLiteral ("Old style function declaration"),
1792                 g_currentloc); 
1793
1794   DPRINTF (("Handle old style params: %s", uentryList_unparseFull (params)));
1795
1796   uentryList_elements (params, current)
1797     {
1798       uentry_setParam (current);
1799       uentry_setSref (current, sRef_makeParam (paramno, ctype_unknown, stateInfo_makeLoc (uentry_whereLast (current))));
1800       paramno++;
1801     } end_uentryList_elements;
1802
1803   setGenericParamList (params);
1804   g_expectingTypeName = TRUE; 
1805
1806   return params;
1807 }
1808
1809 /*@dependent@*/ uentryList handleParamTypeList (/*@returned@*/ uentryList params)
1810 {
1811   if (flipOldStyle)
1812     {
1813       uentryList_fixMissingNames (params);
1814
1815       voptgenerror (FLG_OLDSTYLE, 
1816                     cstring_makeLiteral ("Old style function declaration."), 
1817                     g_currentloc); 
1818       
1819       setGenericParamList (params);
1820       flipOldStyle = FALSE;
1821       g_expectingTypeName = TRUE; 
1822     }
1823  
1824   return (params); 
1825 }
1826
1827 void
1828 doVaDcl ()
1829 {
1830   ctype c = ctype_unknown;
1831   cstring id = cstring_makeLiteral ("va_alist");
1832   uentry e;
1833
1834   if (ProcessingParams)
1835     {
1836       int i = uentryList_lookupRealName (saveParamList, id);
1837       
1838       if (i >= 0)
1839         {
1840           fileloc loc = context_getSaveLocation ();
1841           e = uentry_makeVariableSrefParam (id, c, loc, sRef_makeParam (i, c, stateInfo_makeLoc (loc)));
1842         }
1843       else
1844         {
1845           e = uentry_undefined; /* suppress gcc message */
1846           llfatalerrorLoc (cstring_makeLiteral ("va_dcl used without va_alist"));
1847         }
1848     }
1849   else
1850     {    
1851       llerror (FLG_SYNTAX, cstring_makeLiteral ("va_dcl used outside of function declaration"));
1852       e = uentry_makeVariableLoc (id, c);
1853     }
1854
1855   cstring_free (id);
1856   uentry_setUsed (e, g_currentloc);  
1857   usymtab_supEntrySref (e);
1858 }
1859
1860 /*@exposed@*/ sRef modListPointer (/*@exposed@*/ sRef s)
1861 {
1862   ctype ct = sRef_getType (s);
1863   ctype rt = ctype_realType (ct);
1864   
1865   if (ctype_isAP (rt))
1866     {
1867       if (context_inHeader () && ctype_isAbstract (ct))
1868         {
1869           voptgenerror 
1870             (FLG_ABSTRACT,
1871              message
1872              ("Modifies clause in header file dereferences abstract "
1873               "type %s (interface modifies clause should not depend "
1874               "on or expose type representation): %q",
1875               ctype_unparse (ct),
1876               sRef_unparse (s)),
1877              g_currentloc);
1878         }
1879
1880       return (sRef_constructPointer (s));
1881     }
1882   else
1883     {
1884       if (ctype_isKnown (rt))
1885         {
1886           voptgenerror 
1887             (FLG_TYPE,
1888              message ("Implementation modifies clause dereferences non-pointer (type %s): %q",
1889                       ctype_unparse (rt),
1890                       sRef_unparse (s)),
1891              g_currentloc);
1892         }
1893
1894       return s;
1895     }
1896 }
1897
1898 /*@exposed@*/ sRef modListFieldAccess (sRef s, cstring f)
1899 {
1900   ctype ct = sRef_getType (s);
1901   ctype rt = ctype_realType (ct);
1902   
1903   if (ctype_isStructorUnion (rt))
1904     {
1905       uentry tf = uentryList_lookupField (ctype_getFields (rt), f);
1906       
1907       if (uentry_isUndefined (tf))
1908         {
1909           voptgenerror (FLG_TYPE,
1910                         message ("Modifies list accesses non-existent "
1911                                  "field %s of %t: %q", f, ct, 
1912                                  sRef_unparse (s)),
1913                         g_currentloc);
1914           
1915           cstring_free (f);
1916           return sRef_undefined;
1917         }
1918       else 
1919         {
1920           if (ctype_isAbstract (ct) && context_inHeader ())
1921             {
1922               voptgenerror 
1923                 (FLG_ABSTRACT,
1924                  message
1925                  ("Modifies clause in header file accesses abstract "
1926                   "type %s (interface modifies clause should not depend "
1927                   "on or expose type representation): %q",
1928                   ctype_unparse (ct),
1929                   sRef_unparse (s)),
1930                  g_currentloc);
1931             }
1932         }
1933       
1934       cstring_markOwned (f);
1935       return (sRef_makeField (s, f));
1936     }
1937   else
1938     {
1939       voptgenerror 
1940         (FLG_TYPE,
1941          message ("Modifies clause dereferences non-pointer (type %s): %q",
1942                   ctype_unparse (rt),
1943                   sRef_unparse (s)),
1944          g_currentloc);
1945       
1946       cstring_free (f);
1947       return s;
1948     }
1949 }
1950
1951 /*@dependent@*/ sRef clabstract_unrecognizedGlobal (cstring s)
1952 {
1953   if (cstring_equalLit (s, "nothing"))
1954     {
1955       return sRef_makeNothing ();
1956     }
1957   else if (cstring_equalLit (s, "internalState"))
1958     {
1959       return sRef_makeInternalState ();
1960     }
1961   else if (cstring_equalLit (s, "fileSystem")
1962            || cstring_equalLit (s, "systemState"))
1963     {
1964       return sRef_makeSystemState ();
1965     }
1966   else
1967     {
1968       voptgenerror 
1969         (FLG_UNRECOG, 
1970          message ("Unrecognized identifier in globals list: %s", s), 
1971          g_currentloc);
1972       
1973       return sRef_undefined;
1974     }
1975 }
1976
1977 /*@exposed@*/ sRef modListArrowAccess (sRef s, cstring f)
1978 {
1979   ctype ct = sRef_getType (s);
1980   ctype rt = ctype_realType (ct);
1981
1982   if (ctype_isRealPointer (rt))
1983     {
1984       ctype b = ctype_baseArrayPtr (rt);
1985       ctype rb = ctype_realType (b);
1986
1987       if (ctype_isStructorUnion (rb))
1988         {
1989           uentry tf = uentryList_lookupField (ctype_getFields (rb), f);
1990       
1991           if (uentry_isUndefined (tf))
1992             {
1993               voptgenerror (FLG_TYPE,
1994                             message ("Modifies list arrow accesses non-existent "
1995                                      "field %s of %t: %q", f, b, 
1996                                      sRef_unparse (s)),
1997                             g_currentloc);
1998               
1999               cstring_free (f);
2000               return sRef_undefined;
2001             }
2002           else 
2003             {
2004               if (context_inHeader ())
2005                 {
2006                   if (ctype_isAbstract (b))
2007                     {
2008                       voptgenerror 
2009                         (FLG_ABSTRACT,
2010                          message
2011                          ("Modifies clause in header file arrow accesses abstract "
2012                           "type %s (interface modifies clause should not depend "
2013                           "on or expose type representation): %q",
2014                           ctype_unparse (b),
2015                           sRef_unparse (s)),
2016                          g_currentloc);
2017                     }
2018                 }
2019               else 
2020                 {
2021                   if (ctype_isAbstract (rt))
2022                     {
2023                       voptgenerror 
2024                         (FLG_ABSTRACT,
2025                          message
2026                          ("Modifies clause arrow accesses inaccessible abstract "
2027                           "type %s (interface modifies clause should not depend "
2028                           "on or expose type representation): %q",
2029                           ctype_unparse (rt),
2030                           sRef_unparse (s)),
2031                          g_currentloc);
2032                     }
2033                 }
2034             }
2035
2036           cstring_markOwned (f);
2037           return (sRef_makeArrow (s, f));
2038         }
2039       else
2040         {
2041           voptgenerror 
2042             (FLG_TYPE,
2043              message ("Modifies clause arrow accesses pointer to "
2044                       "non-structure (type %s): %q",
2045                       ctype_unparse (rt),
2046                       sRef_unparse (s)),
2047              g_currentloc);
2048         }
2049     }
2050   else
2051     {
2052       voptgenerror 
2053         (FLG_TYPE,
2054          message ("Modifies clause arrow accesses non-pointer (type %s): %q",
2055                   ctype_unparse (rt),
2056                   sRef_unparse (s)),
2057          g_currentloc);
2058     }
2059
2060   cstring_free (f);
2061   return s;
2062 }
2063
2064 sRef checkStateClausesId (uentry ue)
2065 {
2066   cstring s = uentry_rawName (ue);
2067
2068   if (sRef_isFileOrGlobalScope (uentry_getSref (ue)))
2069     {
2070       voptgenerror 
2071         (FLG_COMMENTERROR,
2072          message ("Global variable %s used state clause.  (Global variables "
2073                   "are not recognized in state clauses.  If there is "
2074                   "sufficient interest in support for this, it may be "
2075                   "added to a future release.  Send mail to "
2076                   "info@splint.org.)",
2077                   s),
2078          g_currentloc);
2079       
2080       return sRef_undefined;
2081     }
2082   else
2083     {
2084       if (cstring_equalLit (s, "result"))
2085         {
2086           if (optgenerror 
2087               (FLG_SYNTAX, 
2088                message ("Special clause list uses %s which is a variable and has special "
2089                         "meaning in a modifies list.  (Special meaning assumed.)", s), 
2090                g_currentloc))
2091             {
2092               uentry_showWhereDeclared (ue);
2093             }
2094         }
2095
2096       return uentry_getSref (ue);
2097     }
2098 }
2099 /*drl:1/19/2001
2100   oops to 1/8/2000
2101   date is wronge ..
2102   don;t know what the real date is...
2103   
2104 */
2105
2106 /*drl
2107   added 1/8/2000
2108   based on checkSpecClausesId
2109   called by grammar
2110 */
2111
2112 sRef checkbufferConstraintClausesId (uentry ue)
2113 {
2114   cstring s = uentry_rawName (ue);
2115
2116   if (cstring_equalLit (s, "result"))
2117     {
2118       if (optgenerror 
2119           (FLG_SYNTAX, 
2120            message ("Function clause list uses %s which is a variable and has special "
2121                     "meaning in a modifies list.  (Special meaning assumed.)", s), 
2122            g_currentloc))
2123         {
2124           uentry_showWhereDeclared (ue);
2125         }
2126     }
2127   
2128   DPRINTF (("constrant id: %s", uentry_unparseFull (ue)));
2129   return sRef_saveCopy (uentry_getSref (ue)); /*@i523 why the saveCopy? */
2130 }
2131
2132 void checkModifiesId (uentry ue)
2133 {
2134   cstring s = uentry_rawName (ue);
2135
2136   if (cstring_equalLit (s, "nothing")
2137       || cstring_equalLit (s, "internalState")
2138       || cstring_equalLit (s, "systemState")
2139       || (cstring_equalLit (s, "fileSystem")))
2140     {
2141       if (optgenerror 
2142           (FLG_SYNTAX, 
2143            message ("Modifies list uses %s which is a variable and has special "
2144                     "meaning in a modifies list.  (Special meaning assumed.)", s), 
2145            g_currentloc))
2146         {
2147           uentry_showWhereDeclared (ue);
2148         }
2149     }
2150 }
2151
2152 /*@exposed@*/ sRef fixModifiesId (cstring s) 
2153 {
2154   sRef ret;
2155   cstring pname = makeParam (s);
2156   uentry ue = usymtab_lookupSafe (pname);
2157
2158   cstring_free (pname);
2159
2160   if (cstring_equalLit (s, "nothing"))
2161     {
2162       ret = sRef_makeNothing ();
2163     }
2164   else if (cstring_equalLit (s, "internalState"))
2165     {
2166       ret = sRef_makeInternalState ();
2167     }
2168   else if (cstring_equalLit (s, "fileSystem")
2169            || cstring_equalLit (s, "systemState"))
2170     {
2171       ret = sRef_makeSystemState ();
2172     }
2173   else
2174     {
2175       ret = sRef_undefined;
2176     }
2177
2178   if (sRef_isValid (ret))
2179     {
2180       if (uentry_isValid (ue))
2181         {
2182           voptgenerror 
2183             (FLG_SYNTAX, 
2184              message ("Modifies list uses %s which is a parameter and has special "
2185                       "meaning in a modifies list.  (Special meaning assumed.)", s), 
2186              g_currentloc);
2187         }
2188     }
2189   else
2190     {
2191       if (uentry_isValid (ue))
2192         {
2193           ret = uentry_getSref (ue);
2194         }
2195       else
2196         {
2197           fileloc loc = fileloc_decColumn (g_currentloc, cstring_length (s));
2198           ret = sRef_undefined;
2199
2200           voptgenerror 
2201             (FLG_UNRECOG, 
2202              message ("Unrecognized identifier in modifies comment: %s", s), 
2203              loc);
2204
2205           fileloc_free (loc);
2206         }
2207     }
2208   
2209   return ret;
2210 }
2211
2212 sRef fixStateClausesId (cstring s) 
2213 {
2214   sRef ret;
2215   cstring pname = makeParam (s);
2216   uentry ue = usymtab_lookupSafe (pname);
2217
2218   cstring_free (pname);
2219
2220   if (cstring_equalLit (s, "result"))
2221     {
2222       ret = sRef_makeResult (ctype_unknown);
2223     }
2224   else
2225     {
2226       ret = sRef_undefined;
2227     }
2228
2229   if (sRef_isValid (ret))
2230     {
2231       if (uentry_isValid (ue))
2232         {
2233           voptgenerror 
2234             (FLG_SYNTAX, 
2235              message ("Function clause uses %s which is a parameter and has special "
2236                       "meaning in a function clause.  (Special meaning assumed.)", s), 
2237              g_currentloc);
2238         }
2239     }
2240   else
2241     {
2242       if (uentry_isValid (ue))
2243         {
2244           ret = uentry_getSref (ue);
2245
2246           if (sRef_isFileOrGlobalScope (ret))
2247             {
2248               voptgenerror 
2249                 (FLG_SYNTAX, 
2250                  message ("Global variable %s used in function clause.  (Global variables "
2251                           "are not recognized in function clauses.  If there is "
2252                           "sufficient interest in support for this, it may be "
2253                           "added to a future release.  Send mail to "
2254                           "info@splint.org.)",
2255                           s), 
2256                  g_currentloc);
2257               
2258               ret = sRef_undefined;
2259             }
2260         }
2261       else
2262         {
2263           /*@i222@*/
2264           /*drl handle structure invariant */
2265
2266           /*@i222@*/
2267           /*check that we're in a structure */
2268 # if 0\r
2269                   /*@unused@*/    uentryList ueL;
2270           /*@unused@*/ uentry ue2;
2271           /*@unused@*/ ctype ct;\r
2272 # endif
2273           fileloc loc = fileloc_decColumn (g_currentloc, cstring_length (s));
2274           ret = sRef_undefined; 
2275 # if 0
2276           /*drl commenting this out for now 
2277           ct = context_getLastStruct ( ct );
2278
2279           llassert( ctype_isStruct(ct) );
2280
2281           ueL =  ctype_getFields (ct);
2282
2283           ue2 = uentryList_lookupField (ueL, s);
2284
2285           if (!uentry_isUndefined(ue2) )
2286             {
2287               ret = uentry_getSref(ue2);
2288               
2289               DPRINTF((
2290                        message("Got field in structure in the annotation constraint: %s (or sref: %s)", s, sRef_unparse(ret) )
2291                        ));
2292               
2293               return ret;
2294             }
2295           */\r
2296 # endif\r
2297
2298           voptgenerror 
2299             (FLG_UNRECOG, 
2300              message ("Unrecognized identifier in function clause: %s", s), 
2301              loc);
2302
2303           fileloc_free (loc);
2304         }
2305     }
2306   
2307   return ret;
2308 }
2309
2310 sRef modListArrayFetch (/*@exposed@*/ sRef s, /*@unused@*/ sRef mexp)
2311 {
2312   ctype ct = sRef_getType (s);
2313   ctype rt = ctype_realType (ct);
2314
2315   if (ctype_isAP (rt))
2316     {
2317       if (context_inHeader () && ctype_isAbstract (ct))
2318         {
2319           voptgenerror 
2320             (FLG_ABSTRACT,
2321              message
2322              ("Modifies clause in header file indexes abstract "
2323               "type %s (interface modifies clause should not depend "
2324               "on or expose type representation): %q",
2325               ctype_unparse (ct),
2326               sRef_unparse (s)),
2327              g_currentloc);
2328         }
2329       
2330       return (sRef_makeAnyArrayFetch (s));
2331     }
2332   else
2333     {
2334       voptgenerror
2335         (FLG_TYPE,
2336          message
2337          ("Implementation modifies clause uses array fetch on non-array (type %s): %q",
2338           ctype_unparse (ct), sRef_unparse (s)),
2339          g_currentloc);
2340       return s;
2341     }
2342 }
2343
2344 static void clabstract_prepareFunction (uentry e)
2345 {
2346   uentry_checkParams (e);
2347   DPRINTF (("After prepare: %s", uentry_unparseFull (e)));
2348 }
2349
2350 sRef clabstract_checkGlobal (exprNode e)
2351 {
2352   sRef s;
2353   llassert (exprNode_isInitializer (e));
2354
2355   s = exprNode_getSref (e);
2356   DPRINTF (("Initializer: %s -> %s", exprNode_unparse (e), sRef_unparse (s)));
2357
2358   exprNode_free (e);
2359   return sRef_copy (s);
2360 }
This page took 0.344872 seconds and 5 git commands to generate.