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