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