]> andersk Git - splint.git/blob - src/exprChecks.c
Merged this branch with the one in the splint.sf.net repository.
[splint.git] / src / exprChecks.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 ** exprChecks.c
26 */
27
28 # include "splintMacros.nf"
29 # include "basic.h"
30 # include "cgrammar.h"
31 # include "cgrammar_tokens.h"
32 # include "transferChecks.h"
33 # include "exprChecks.h"
34
35 /*
36 ** for now, allow exprChecks to access exprNode.
37 ** may remove this in future
38 */
39
40 /*@access exprNode@*/
41
42 static bool checkCallModifyAux (/*@exposed@*/ sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err);
43 static bool checkModifyValAux (/*@exposed@*/ sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err);
44 static bool checkModifyAux (/*@exposed@*/ sRef p_s, exprNode p_f, sRef p_alias, exprNode p_err);
45 static void checkSafeReturnExpr (/*@notnull@*/ exprNode p_e);
46
47 /*
48 ** called at end of expression statement
49 **
50 **  of e->kind is not an assign, empty, body or modop
51 **         verify the the value is void
52 **
53 */
54
55 static int inCompoundStatementExpression = 0;
56
57 void
58 exprChecks_inCompoundStatementExpression (void)
59 {
60   inCompoundStatementExpression++;
61 }
62
63 void
64 exprChecks_leaveCompoundStatementExpression (void)
65 {
66   inCompoundStatementExpression--;
67   llassert (inCompoundStatementExpression >= 0);
68 }
69
70 void
71 exprChecks_checkStatementEffect (exprNode e)
72 {
73   bool hasError = FALSE;
74
75   if (inCompoundStatementExpression > 0)
76     {
77       /*
78       ** Okay to have effectless statments in compound statement expression (should check
79       ** it is the last statement, but we don't for now).
80       */
81
82       return;
83     }
84
85   if (!exprNode_isError (e))
86     {
87       exprKind ek = e->kind;
88
89       if (ek == XPR_CALL && !(ctype_isRealVoid (e->typ)))
90         { 
91           if (ctype_isKnown (e->typ))
92             {
93               if (ctype_isManifestBool (ctype_realishType (e->typ)))
94                 {
95                   hasError = optgenerror 
96                     (FLG_RETVALBOOL,
97                      message ("Return value (type %t) ignored: %s",
98                               e->typ,
99                               exprNode_unparseFirst (e)),
100                      e->loc);
101                 }
102               else if (ctype_isDirectInt (e->typ))
103                 {
104                   hasError = optgenerror 
105                     (FLG_RETVALINT,
106                      message ("Return value (type %t) ignored: %s",
107                               e->typ,
108                               exprNode_unparseFirst (e)),
109                      e->loc);
110                 }
111               else
112                 {
113                   hasError = optgenerror 
114                     (FLG_RETVALOTHER,
115                      message ("Return value (type %t) ignored: %s",
116                               e->typ,
117                               exprNode_unparseFirst (e)),
118                      e->loc);
119                 }
120             }
121         }
122
123       if (!hasError && !(exprNode_mayEscape (e))
124           && !(e->canBreak)) /* control changes are effects too! */
125         {
126           if (sRefSet_hasRealElement (e->sets)
127               || sRefSet_hasRealElement (e->msets))
128             {
129               ; /* okay */
130             }
131           else
132             {
133               if (sRefSet_isEmpty (e->sets) && sRefSet_isEmpty (e->msets))
134                 {
135                   voptgenerror
136                     (FLG_NOEFFECT,
137                      message ("Statement has no effect: %s",
138                               exprNode_unparseFirst (e)),
139                      e->loc);
140                 }
141               else
142                 {
143                   if (context_maybeSet (FLG_NOEFFECTUNCON))
144                     {
145                       if (sRefSet_hasUnconstrained (e->sets))
146                         {
147                           voptgenerror
148                             (FLG_NOEFFECTUNCON,
149                              message ("Statement has no effect (possible "
150                                       "undected modification through "
151                                       "call to %q): %s",
152                                       sRefSet_unparseUnconstrained (e->sets),
153                                       exprNode_unparseFirst (e)),
154                              e->loc);
155                         }
156                       else if (sRefSet_hasUnconstrained (e->msets))
157                         {
158                           voptgenerror
159                             (FLG_NOEFFECTUNCON,
160                              message ("Statement has no effect (possible "
161                                       "undected modification through "
162                                       "call to %q): %s",
163                                       sRefSet_unparseUnconstrained (e->msets),
164                                       exprNode_unparseFirst (e)),
165                              e->loc);
166                         }
167                       else
168                         {
169                           ; /* statement has unknown modification */
170                         }
171                     }
172                 }
173             }
174         }
175     }
176 }
177
178 static bool
179 checkRepExposed (sRef base, /*@notnull@*/ exprNode e, sRef alias, 
180                  /*@unused@*/ exprNode unused)
181 {
182   ctype btype;
183
184   if (sRef_isInvalid (alias) || sRef_sameName (base, alias))
185     {
186       btype = sRef_getType (base);
187
188       if (ctype_isAbstract (btype) && ctype_isVisiblySharable (e->typ))
189         {
190           voptgenerror (FLG_RETEXPOSE,
191                         message ("Return value exposes rep of %s: %s",
192                                  ctype_unparse (btype),
193                                  exprNode_unparse (e)),
194                         e->loc);
195           return TRUE;
196         }
197     }
198   else
199     {
200       sRef rbase = sRef_getRootBase (base);
201       btype = sRef_getType (rbase);
202                       
203       if (ctype_isAbstract (btype) && ctype_isVisiblySharable (e->typ))
204         {
205           voptgenerror 
206             (FLG_RETEXPOSE,
207              message ("Return value may expose rep of %s through alias %q: %s",
208                       ctype_unparse (btype),
209                       sRef_unparse (rbase),
210                       exprNode_unparse (e)),
211              e->loc);
212           return TRUE;
213         }
214     }
215
216   return FALSE;
217 }
218
219 static bool
220 checkRefGlobParam (sRef base, /*@notnull@*/ exprNode e,
221                    sRef alias, /*@unused@*/ exprNode unused)
222 {
223   if (sRef_isInvalid (alias) || sRef_sameName (base, alias))
224     {
225       ctype ct = e->typ;
226
227       if (ctype_isUnknown (ct))
228         {
229           ct = sRef_getType (base);
230         }
231  
232       if (ctype_isVisiblySharable (ct))
233         {
234           if (sRef_isFileOrGlobalScope (base))
235             {
236               uentry fcn = context_getHeader ();
237               bool noerror = FALSE;
238
239               if (uentry_isValid (fcn) && uentry_isFunction (fcn))
240                 {
241                   sRef res = uentry_getSref (fcn);
242
243                   /* If result is dependent and global is owned, this is okay... */
244                   if (sRef_isDependent (res)
245                       && sRef_isOwned (base))
246                     {
247                       noerror = TRUE;
248
249                     }
250                 }
251
252               if (!noerror)
253                 {
254                   voptgenerror
255                     (FLG_RETALIAS,
256                      message ("Function returns reference to global %q: %s",
257                               sRef_unparse (base),
258                               exprNode_unparse (e)),
259                      e->loc);
260                 }
261
262               return TRUE;
263             }
264           else if (sRef_isAnyParam (base))
265             {
266               uentryList params = context_getParams ();
267               int paramno = sRef_getParam (base);
268
269               if (paramno < uentryList_size (params))
270                 {
271                   uentry arg = uentryList_getN (params, paramno);
272                   sRef ref = uentry_getSref (arg);
273
274                   if (uentry_isReturned (arg) 
275                       || sRef_isOnly (ref) 
276                       || sRef_isExposed (ref)
277                       || sRef_isRefCounted (ref))
278                     {
279                       ; /* okay */
280                     }
281                   else
282                     {
283                       voptgenerror 
284                         (FLG_RETALIAS,
285                          message ("Function returns reference to parameter %q: %s",
286                                   sRef_unparse (base),
287                                   exprNode_unparse (e)),
288                          e->loc);
289                     }
290                 }
291               else
292                 {
293                   llbuglit ("ret alias: bad paramno");
294                 }
295               
296               return TRUE;
297             }
298           else
299             {
300               return FALSE;
301             }
302         }
303     }
304   else
305     {
306       if (ctype_isVisiblySharable (e->typ))
307         {
308           if (sRef_isFileOrGlobalScope (base))
309             {
310               voptgenerror 
311                 (FLG_RETALIAS,
312                  message ("Function may return reference to global %q through alias %q: %s",
313                           sRef_unparse (alias),
314                           sRef_unparse (base),
315                           exprNode_unparse (e)),
316                  e->loc);
317               return TRUE;
318             }
319           else if (sRef_isAnyParam (base) && !(sRef_isOnly (base)))
320             {
321               uentryList params = context_getParams ();
322               int paramno = sRef_getParam (base);
323               
324               if (paramno < uentryList_size (params))
325                 {
326                   uentry arg = uentryList_getN (params, paramno);
327                   
328                   if (!uentry_isReturned (arg))
329                     {
330                       voptgenerror 
331                         (FLG_RETALIAS,
332                          message 
333                          ("Function may return reference to parameter %q through alias %q: %s",
334                           sRef_unparse (base),
335                           sRef_unparse (alias),
336                           exprNode_unparse (e)),
337                          e->loc);
338                       
339                       return TRUE;
340                     }
341                 }
342               else
343                 {
344                   voptgenerror 
345                     (FLG_RETALIAS,
346                      message 
347                      ("Function may return reference to parameter %q through alias %q: %s",
348                       sRef_unparse (base),
349                       sRef_unparse (alias),
350                       exprNode_unparse (e)),
351                      e->loc);
352                   
353                   return TRUE;
354                 }
355             }
356           else
357             {
358               return FALSE;
359             }
360         }
361     }
362   return FALSE;
363 }
364
365
366 void
367 exprNode_checkModify (exprNode e, exprNode err)
368 {
369   llassert (exprNode_isDefined (e));
370
371   DPRINTF (("Check modify: %s", exprNode_unparse (e)));
372   
373   if (sRef_isValid (e->sref))
374     {
375       sRef_aliasCheckPred (checkModifyAux, sRef_isReference, e->sref, e, err);
376     }
377 }
378
379 void
380 exprNode_checkModifyVal (exprNode e, exprNode err)
381 {
382   llassert (exprNode_isDefined (e));
383   
384   DPRINTF (("Check modify val: %s", exprNode_unparse (e)));
385
386   if (sRef_isValid (e->sref))
387     {
388       sRef_aliasCheckPred (checkModifyValAux, sRef_isReference, e->sref, e, err);
389     }
390 }
391
392 void
393 exprChecks_checkNullReturn (fileloc loc)
394 {
395   if (!context_inRealFunction ())
396     {
397       /*
398       llmsg ("exprChecks_checkNullReturnExpr: not in function context");
399       */
400       return;
401     }
402   else
403     {
404       if (ctype_isFunction (context_currentFunctionType ()))
405         {
406           ctype tr = ctype_getReturnType (context_currentFunctionType ());
407
408           if (!ctype_isFirstVoid (tr))
409             {
410               if (ctype_isUnknown (tr))
411                 {
412                   voptgenerror
413                     (FLG_EMPTYRETURN,
414                      cstring_makeLiteral ("Empty return in function declared to implicitly return int"),
415                      loc);
416                 }
417               else
418                 {
419                   voptgenerror (FLG_EMPTYRETURN,
420                                 message ("Empty return in function declared to return %t", tr),
421                                 loc);
422                 }
423             }
424         }
425     }
426 }
427
428 void
429 exprNode_checkReturn (exprNode e)
430 {
431   if (!exprNode_isError (e))
432     {
433       if (!context_inRealFunction ())
434         {
435           if (context_inMacro ())
436             {
437               llerror (FLG_MACRORETURN,
438                        message ("Macro %s uses return (not functional)",
439                                 context_inFunctionName ()));
440             }
441           else
442             {
443               /*
444                 llbuglit ("exprNode_checkReturn: not in function context");
445                 */
446             }
447         }
448       else
449         {
450           if (ctype_isFunction (context_currentFunctionType ()))
451             {
452               checkSafeReturnExpr (e);
453             }
454           else
455             {
456               ;
457             }
458         }
459     }
460 }
461
462 void
463 exprNode_checkPred (cstring c, exprNode e)
464 {
465   ctype ct;
466
467   if (exprNode_isError (e))
468     return;
469
470   ct = exprNode_getType (e);
471
472   if (exprNode_isAssign (e))
473     {
474       voptgenerror 
475         (FLG_PREDASSIGN,
476          message ("Test expression for %s is assignment expression: %s", 
477                   c, exprNode_unparse (e)),
478          e->loc);
479     }
480
481   if (ctype_isRealBool (ct) || ctype_isUnknown (ct)) 
482          /* evs 2000-12-20 added || ctype_isUnknown to avoid spurious messages */
483     {
484      ;
485     }
486   else if (ctype_isRealPointer (ct))
487     {
488       voptgenerror
489         (FLG_PREDBOOLPTR,
490          message ("Test expression for %s not %s, type %t: %s", c, 
491                   context_printBoolName (), 
492                   ct, exprNode_unparse (e)),
493          e->loc);
494     }
495   else if (ctype_isRealInt (ct))
496     {
497       voptgenerror 
498         (FLG_PREDBOOLINT,
499          message ("Test expression for %s not %s, type %t: %s", c, 
500                   context_printBoolName (), ct, exprNode_unparse (e)),
501          e->loc);
502     }
503   else
504     {
505       voptgenerror 
506         (FLG_PREDBOOLOTHERS,
507          message ("Test expression for %s not %s, type %t: %s", c, 
508                   context_printBoolName (), ct, exprNode_unparse (e)),
509          e->loc);
510     }
511 }
512
513 void
514 exprChecks_checkUsedGlobs (globSet decl, globSet used)
515 {
516   fileloc fl = uentry_whereSpecified (context_getHeader ());
517
518   if (fileloc_isUndefined (fl))
519     {
520       fl = uentry_whereDeclared (context_getHeader ());
521     }
522
523   globSet_allElements (decl, el)
524     {
525       if (!globSet_member (used, el))
526         {
527           if (sRef_isSpecInternalState (el)
528               || sRef_isNothing (el))
529             {
530               ;
531             }
532           else
533             {
534               cstring sname = sRef_unparse (el);
535               
536               if (fileloc_isLib (fl))
537                 {
538                   voptgenerror (FLG_USEALLGLOBS,
539                                 message ("Global %s listed (%q) but not used", 
540                                          sname, fileloc_unparse (fl)),
541                                 g_currentloc);
542                 }               
543               else
544                 {
545                   voptgenerror (FLG_USEALLGLOBS,
546                                 message ("Global %s listed but not used", sname),
547                                 fl);
548                 }
549
550               cstring_free (sname);
551             }
552         }
553     } end_globSet_allElements;
554 }
555
556 void
557 exprNode_checkAllMods (sRefSet mods, uentry ue)
558 {
559   bool realParams = FALSE;
560   uentry le = context_getHeader ();
561   fileloc fl = uentry_whereSpecified (le);
562   uentryList specParamNames = uentryList_undefined;
563   uentryList paramNames = context_getParams ();
564
565   if (uentry_isFunction (le))
566     {
567       specParamNames = uentry_getParams (le);  
568
569       if (uentryList_isUndefined (specParamNames))
570         {
571           ; /* unknown params */
572         }
573       else if (uentryList_size (paramNames) != uentryList_size (specParamNames))
574         {
575           llbug
576             (message ("exprNode_checkAllMods: parameter lists have different sizes: "
577                       "%q (%d) / %q (%d)",
578                       uentryList_unparse (paramNames),
579                       uentryList_size (paramNames),
580                       uentryList_unparse (specParamNames),
581                       uentryList_size (specParamNames)));
582         }
583       else if (uentryList_size (paramNames) > 0 
584                && !uentry_hasRealName (uentryList_getN (specParamNames, 0)))
585         {
586           /* loaded from a library */
587         }
588       else
589         {
590           realParams = TRUE;
591         }
592     }
593
594   sRefSet_allElements (mods, sr)
595     {
596       if (sRef_isNothing (sr) || sRef_isSpecState (sr))
597         {
598           ; /* should report on anything? */
599         }
600       else if (sRef_isInternalState (sr))
601         {
602           if (!sRef_isModified (sr))
603             {
604               if (sRefSet_hasStatic (mods))
605                 {
606                   ; /* okay */
607                 }
608               else
609                 {
610                   if (optgenerror 
611                       (FLG_MUSTMOD,
612                        message
613                        ("Function %s specified to modify internal state "
614                         "but no internal state is modified", 
615                         uentry_rawName (ue)),
616                        uentry_whereLast (ue)))
617                     {
618                       uentry_showWhereSpecified (le);
619                     }
620                 }
621             }
622         }
623       else 
624         {
625           if (!sRef_isModified (sr))
626             {
627               cstring sname = realParams ? sRef_unparse (sr) : sRef_unparse (sr);
628               
629               if (fileloc_isLib (fl) && !realParams)
630                 {
631                   voptgenerror 
632                     (FLG_MUSTMOD,
633                      message ("Suspect object listed (%q) in modifies "
634                               "clause of %s not modified: %s", 
635                               fileloc_unparse (fl),
636                               uentry_rawName (ue),
637                               sname),
638                      uentry_whereLast (ue));
639                 }               
640               else
641                 {
642                   if (optgenerror 
643                       (FLG_MUSTMOD,
644                        message ("Suspect object listed in modifies of %s "
645                                 "not modified: %s", 
646                                 uentry_rawName (ue),
647                                 sname),
648                        uentry_whereLast (ue)))
649                     {
650                       uentry_showWhereSpecified (le);
651                     }
652                 }
653               cstring_free (sname);
654             }
655         }
656     } end_sRefSet_allElements;
657 }
658
659 void exprNode_checkMacroBody (/*@only@*/ exprNode e)
660 {
661   if (!exprNode_isError (e))
662     {
663       uentry hdr;
664
665       if (!(context_inFunctionLike () || context_inMacroConstant ()
666             || context_inUnknownMacro ()))
667         {
668           llcontbug 
669             (message 
670              ("exprNode_checkMacroBody: not in macro function or constant: %q", 
671               context_unparse ()));
672           exprNode_free (e);
673           return;
674         }
675
676       hdr = context_getHeader ();
677       
678       if (e->kind == XPR_STMTLIST || e->kind == XPR_BODY)
679         {
680           voptgenerror 
681             (FLG_MACROSTMT,
682              message 
683              ("Macro %q definition is statement list (recommend "
684               "do { ... } while (0) constuction to ensure multiple "
685               "statement macro is syntactic function)",
686               uentry_getName (hdr)),
687              fileloc_isDefined (e->loc) ? e->loc : g_currentloc);
688         }
689       
690       if (context_inMacroConstant ())
691         {
692           ctype t = uentry_getType (hdr);
693
694           uentry_setDefined (hdr, e->loc);
695           
696           if (!(exprNode_matchType (t, e)))
697             {
698               cstring uname = uentry_getName (hdr);
699
700               if (cstring_equal (uname, context_getTrueName ())
701                   || cstring_equal (uname, context_getFalseName ()))
702                 {
703                   /* 
704                   ** We need to do something special to allow FALSE and TRUE
705                   ** to be defined without reporting errors.  This is a tad
706                   ** bogus, but otherwise lots of things would break.
707                   */
708
709
710                   llassert (ctype_isManifestBool (t));
711                   /* Should also check type of e is a reasonable (?) bool type. */
712                 }
713               else 
714                 {
715                   if (optgenerror 
716                       (FLG_INCONDEFS,
717                        message
718                        ("Constant %q specified as %s, but defined as %s: %s",
719                         uentry_getName (hdr),
720                         ctype_unparse (t),
721                         ctype_unparse (e->typ),
722                         exprNode_unparse (e)),
723                        e->loc))
724                     {
725                       uentry_showWhereSpecified (hdr);
726                     }
727                 }
728
729               cstring_free (uname);
730             }
731           else
732             {
733               if (context_maybeSet (FLG_NULLSTATE)
734                   && ctype_isUA(t) 
735                   && ctype_isRealPointer (t)
736                   && exprNode_isNullValue (e))
737                 {
738                   uentry ue = usymtab_getTypeEntry (ctype_typeId (t));
739                   sRef   sr = uentry_getSref (ue);
740                   
741                   if (!sRef_possiblyNull (sr))
742                     {
743                       vgenhinterror 
744                         (FLG_NULLSTATE,
745                          message ("Constant %q of non-null type %s defined "
746                                   "as null: %s",
747                                   uentry_getName (hdr), ctype_unparse (t),
748                                   exprNode_unparse (e)),
749                          message ("If %s can be null, add a /*@null@*/ "
750                                   "qualifer to its typedef.",
751                                   ctype_unparse (t)),
752                          e->loc);
753                     }
754                   
755                   uentry_mergeConstantValue (hdr, e->val);
756                   e->val = multiVal_undefined;
757                 }
758             }
759         }
760       else if (context_inMacroFunction () || context_inUnknownMacro ())
761         {
762           ctype rettype = context_getRetType ();
763
764           if (context_isMacroMissingParams ())
765             {
766               llassert (context_inMacroFunction ());
767
768               /*
769               ** # define newname oldname
770               **
771               ** newname is a function
772               ** specification of oldname should match
773               ** specification of newname.
774               */
775
776               if (!ctype_isFunction (e->typ))
777                 {
778                   voptgenerror 
779                     (FLG_INCONDEFS,
780                      message ("Function %s defined by unparameterized "
781                               "macro not corresponding to function",
782                               context_inFunctionName ()),
783                      e->loc);
784                 }
785               else
786                 {
787                   uentry ue = exprNode_getUentry (e);
788
789                   if (uentry_isValid (ue))
790                     {
791                       /*
792                       ** Okay, for now --- should check for consistency
793                       */
794                       /*
795                       ** uentry oldue = usymtab_lookup (cfname);
796                       */
797
798                       /* check var conformance here! */
799                     }
800                   else
801                     {
802                       voptgenerror
803                         (FLG_INCONDEFS,
804                          message ("Function %s defined by unparameterized "
805                                   "macro not corresponding to function",
806                                   context_inFunctionName ()),
807                          e->loc);
808                     }
809                   
810                   e->typ = ctype_getReturnType (e->typ);
811                   rettype = e->typ; /* avoid aditional errors */
812                 }
813             }
814
815           if (ctype_isVoid (rettype) || ctype_isUnknown (rettype))
816             {
817              ; /* don't complain when void macros have values */
818             }       
819           else if (!exprNode_matchType (rettype, e))
820             {
821               if (optgenerror 
822                   (FLG_INCONDEFS,
823                    message ("Function %q specified to return %s, "
824                             "implemented as macro having type %s: %s",
825                             uentry_getName (hdr),
826                             ctype_unparse (rettype), ctype_unparse (e->typ),
827                             exprNode_unparse (e)),
828                    e->loc))
829                 {
830                   uentry_showWhereSpecified (hdr);
831                 }
832             }
833           else
834             {
835               switch (e->kind)
836                 {
837                   /* these expressions have values: */
838                 case XPR_PARENS: case XPR_ASSIGN: 
839                 case XPR_EMPTY: case XPR_VAR:
840                 case XPR_OP: case XPR_POSTOP: 
841                 case XPR_PREOP: case XPR_CALL: 
842                 case XPR_SIZEOFT: case XPR_SIZEOF: 
843                 case XPR_ALIGNOFT: case XPR_ALIGNOF: 
844                 case XPR_CAST: case XPR_FETCH: 
845                 case XPR_COMMA: case XPR_COND: 
846                 case XPR_ARROW: case XPR_CONST: 
847                 case XPR_STRINGLITERAL: case XPR_NUMLIT:
848                 case XPR_FACCESS: case XPR_OFFSETOF:
849
850                   transferChecks_return (e, hdr);
851                   break;
852
853                   /* these expressions don't */
854                 case XPR_LABEL:
855                 case XPR_VAARG: case XPR_ITER: 
856                 case XPR_FOR: case XPR_FORPRED:
857                 case XPR_GOTO: case XPR_CONTINUE: 
858                 case XPR_BREAK: case XPR_RETURN:
859                 case XPR_NULLRETURN: case XPR_IF: 
860                 case XPR_IFELSE: case XPR_DOWHILE:
861                 case XPR_WHILE: case XPR_STMT: 
862                 case XPR_STMTLIST: case XPR_SWITCH:
863                 case XPR_INIT: case XPR_BODY: 
864                 case XPR_NODE: case XPR_ITERCALL:
865                 case XPR_TOK: case XPR_CASE: 
866                 case XPR_FTCASE: case XPR_FTDEFAULT:
867                 case XPR_DEFAULT: case XPR_WHILEPRED:
868                 case XPR_BLOCK: case XPR_INITBLOCK:
869                   if (optgenerror 
870                       (FLG_INCONDEFS,
871                        message ("Function %q specified to return %s, "
872                                 "implemented as macro with no result: %s",
873                                 uentry_getName (hdr),
874                                 ctype_unparse (rettype), 
875                                 exprNode_unparse (e)),
876                        e->loc))
877                     {
878                       uentry_showWhereSpecified (hdr);
879                     }
880                 }
881             }
882
883           usymtab_checkFinalScope (FALSE);
884         }
885       else
886         {
887           llbug (message ("exprNode_checkMacroBody: not in macro function: %q", context_unparse ()));
888         }
889
890       exprNode_free (e);
891     }
892
893   context_exitFunction ();
894   return;
895 }
896
897 void exprNode_checkFunctionBody (exprNode body)
898 {
899   if (!exprNode_isError (body))
900     {
901       bool noret = context_getFlag (FLG_NORETURN);
902       bool checkret = exprNode_mustEscape (body);
903
904       if (!checkret 
905           && noret 
906           && !exprNode_errorEscape (body)
907           && context_inRealFunction ()
908           && ctype_isFunction (context_currentFunctionType ()))
909         {
910           ctype tr = ctype_getReturnType (context_currentFunctionType ());
911           
912           if (!ctype_isFirstVoid (tr)) 
913             {
914               if (ctype_isUnknown (tr))
915                 {
916                   voptgenerror 
917                     (FLG_NORETURN,
918                      cstring_makeLiteral ("Path with no return in function declared to implicity return int"), 
919                      g_currentloc);
920                 }
921               else
922                 {
923                   voptgenerror 
924                     (FLG_NORETURN,
925                      message ("Path with no return in function declared to return %t", 
926                               tr),
927                      g_currentloc);
928                 }
929             }
930         }
931       
932       if (!checkret)
933         {
934           context_returnFunction ();
935         }
936     }
937 }
938
939 /* drl added 2/26/2002 */
940 /* prints out a function */
941 void exprNode_spitFunction (/*@unused@*/ uentry ue, exprNode fcnBody)
942 {
943
944   exprNode body;
945
946   body = fcnBody;
947
948   if (context_getFlag(FLG_GENERATECODE) )
949     {
950       cstring outCode;
951
952             /*  //
953
954       cstring locateInfo;
955
956       locateInfo = fileloc_filename (exprNode_getLoc (body) ) ;
957
958       locateInfo = message ("fprintf(stderr,\"%s\");\n",locateInfo);
959
960       
961       if (body->kind == XPR_TOK)
962         {
963           outCode = message( " #include <stdio.h>\n%s\n{\n%s{\n%s\n}\n}\n",
964                              uentry_unparseFunctionHeader (ue),
965                              locateInfo,
966                              exprNode_unparse(body)
967                              );
968         }
969       else
970         {
971           outCode = message( "\n#include <stdio.h>\n%s\n{\n%s{\n%s;\n}\n}\n",
972                              uentry_unparseFunctionHeader (ue),
973                              locateInfo,
974                              exprNode_unparse(body)
975                              );
976         }
977       */
978
979       llassert(exprNode_isDefined(body) );
980       
981       if (body->kind == XPR_TOK)
982         {
983           outCode = message( "%s\n{\n%s\n}\n",
984                              uentry_unparseFunctionHeader (ue),
985                              exprNode_unparse(body)
986                              );
987         }
988       else
989         {
990           outCode = message( "%s\n{\n%s\n}\n",
991                              uentry_unparseFunctionHeader (ue),
992                              exprNode_unparse(body)
993                              );
994         }
995       outputCode(outCode);
996       cstring_free(outCode);
997     }
998 }
999
1000
1001
1002 /*drl modified */
1003
1004 void exprNode_checkFunction (/*@unused@*/ uentry ue, /*@only@*/ exprNode body)
1005 {
1006   constraintList c, t, post;
1007   constraintList c2, fix;
1008   constraintList implicitFcnConstraints;
1009   
1010   context_enterInnerContext ();
1011
1012   
1013   llassert (exprNode_isDefined (body));
1014
1015   /*
1016     if we're not going to be printing any errors for buffer overflows
1017     we can skip the checking to improve performance
1018     
1019     FLG_DEBUGFUNCTIONCONSTRAINT controls wheather we perform the check anyway
1020     in order to find potential problems like assert failures and seg faults...
1021   */
1022
1023   if (!context_getFlag(FLG_DEBUGFUNCTIONCONSTRAINT))
1024     {
1025       /* check if errors will printed */
1026       if (!(context_getFlag(FLG_DEBUGFUNCTIONCONSTRAINT) ||
1027             context_getFlag(FLG_BOUNDSWRITE) ||
1028             context_getFlag(FLG_BOUNDSREAD) ||
1029             context_getFlag(FLG_CHECKPOST)))
1030         {
1031           if ( context_getFlag (FLG_GENERATECODE) )
1032             {
1033               exprNode_spitFunction(ue, body);
1034             }
1035           
1036
1037           exprNode_free (body);
1038           context_exitInnerPlain();
1039           
1040           return;
1041         }
1042     }
1043   
1044   exprNode_generateConstraints (body); /* evans 2002-03-02: this should not be declared to take a
1045                                           dependent... fix it! */
1046   
1047   c =   uentry_getFcnPreconditions (ue);
1048   DPRINTF(("function constraints\n"));
1049   DPRINTF (("\n\n\n\n\n\n\n"));
1050   
1051   if (constraintList_isDefined(c) )
1052     {
1053       DPRINTF ((message ("Function preconditions are %s \n\n\n\n\n", constraintList_printDetailed (c) ) ) );
1054       
1055       body->requiresConstraints = constraintList_reflectChangesFreePre (body->requiresConstraints, c);
1056       
1057       c2  =  constraintList_copy (c);
1058       fix =  constraintList_makeFixedArrayConstraints (body->uses);
1059       c2  =  constraintList_reflectChangesFreePre (c2, fix);
1060       constraintList_free (fix);
1061       
1062       if (context_getFlag (FLG_ORCONSTRAINT))
1063         {
1064           t = constraintList_reflectChangesOr (body->requiresConstraints, c2 );
1065         }
1066       else
1067         {
1068           t = constraintList_reflectChanges(body->requiresConstraints, c2);
1069         }
1070       
1071       constraintList_free (body->requiresConstraints);
1072       DPRINTF ((message ("The body has the required constraints: %s", constraintList_printDetailed (t) ) ) );
1073       
1074       body->requiresConstraints = t;
1075       
1076       t = constraintList_mergeEnsures (c, body->ensuresConstraints);
1077       constraintList_free(body->ensuresConstraints);
1078       
1079       body->ensuresConstraints = t;
1080       
1081       DPRINTF ((message ("The body has the ensures constraints: %s", constraintList_printDetailed (t) ) ) );
1082       constraintList_free(c2);
1083     }
1084   
1085   if (constraintList_isDefined(c))
1086     {
1087       DPRINTF ((message ("The Function %s has the preconditions %s", 
1088                          uentry_unparse(ue), constraintList_printDetailed(c))));
1089     }
1090   else
1091     {
1092       DPRINTF((message ("The Function %s has no preconditions", uentry_unparse(ue))));
1093     }
1094   
1095   implicitFcnConstraints = getImplicitFcnConstraints();
1096   
1097   if (constraintList_isDefined(implicitFcnConstraints) )
1098     {
1099       if (context_getFlag (FLG_IMPLICTCONSTRAINT) )
1100         {
1101           body->requiresConstraints = constraintList_reflectChangesFreePre (body->requiresConstraints, 
1102                                                                             implicitFcnConstraints );
1103         }
1104     }
1105   
1106   body->requiresConstraints = constraintList_sort (body->requiresConstraints);
1107   
1108   constraintList_printError(body->requiresConstraints, g_currentloc);
1109   
1110   post = uentry_getFcnPostconditions (ue);
1111   
1112   if (context_getFlag (FLG_CHECKPOST))
1113     {
1114       if (constraintList_isDefined (post))
1115         {
1116           constraintList post2;
1117           
1118           DPRINTF ((message ("The declared function postconditions are %s \n\n\n\n\n", 
1119                              constraintList_printDetailed (post) ) ) );
1120           
1121           post = constraintList_reflectChangesFreePre (post, body->ensuresConstraints);
1122           
1123           post2  =  constraintList_copy (post);
1124           fix =  constraintList_makeFixedArrayConstraints (body->uses);
1125           post2  =  constraintList_reflectChangesFreePre (post2, fix);
1126           constraintList_free(fix);
1127           if ( context_getFlag (FLG_ORCONSTRAINT) )
1128             {
1129               t = constraintList_reflectChangesOr (post2, body->ensuresConstraints);
1130             }
1131           else
1132             {
1133               t = constraintList_reflectChanges(post2, body->ensuresConstraints);
1134             }
1135           
1136           constraintList_free(post2);
1137           constraintList_free(post);
1138           post = t;
1139
1140           printf("Unresolved post conditions\n");
1141           constraintList_printErrorPostConditions(post, g_currentloc);
1142         }
1143     }
1144   
1145   if (constraintList_isDefined (post))
1146     {
1147       constraintList_free (post);
1148     }
1149    
1150    body->ensuresConstraints = constraintList_sort(body->ensuresConstraints);
1151
1152    if ( context_getFlag (FLG_FUNCTIONPOST) )
1153      {
1154        constraintList_printError(body->ensuresConstraints, g_currentloc);
1155      }
1156    
1157    /*   ConPrint (message ("Unable to resolve function constraints:\n%s", constraintList_printDetailed(body->requiresConstraints) ), g_currentloc);
1158
1159         ConPrint (message ("Splint has found function post conditions:\n%s", constraintList_printDetailed(body->ensuresConstraints) ), g_currentloc);
1160   
1161         printf ("The required constraints are:\n%s", constraintList_printDetailed(body->requiresConstraints) );
1162         printf ("The ensures constraints are:\n%s", constraintList_printDetailed(body->ensuresConstraints) );
1163    */
1164    
1165    if (constraintList_isDefined(c) )
1166      constraintList_free(c);
1167
1168    context_exitInnerPlain();
1169
1170    if ( context_getFlag (FLG_GENERATECODE) )
1171      {
1172        exprNode_spitFunction(ue, body);
1173      }
1174   
1175
1176    /*is it okay not to free this?*/
1177   exprNode_free (body);
1178   }
1179
1180 void exprChecks_checkEmptyMacroBody (void)
1181 {
1182   uentry hdr;
1183   
1184   if (!(context_inFunctionLike () || context_inMacroConstant ()
1185         || context_inUnknownMacro ()))
1186     {
1187       llcontbug 
1188         (message ("exprNode_checkEmptyMacroBody: not in macro function or constant: %q", 
1189                   context_unparse ()));
1190       return;
1191     }
1192   
1193   hdr = context_getHeader ();
1194   
1195   beginLine ();
1196   
1197   if (uentry_isFunction (hdr))
1198     {
1199       voptgenerror 
1200         (FLG_MACROEMPTY,
1201          message 
1202          ("Macro definition for %q is empty", uentry_getName (hdr)),
1203          g_currentloc);
1204
1205       usymtab_checkFinalScope (FALSE);
1206     }
1207
1208   context_exitFunction ();
1209   return;
1210 }
1211
1212 void exprNode_checkIterBody (/*@only@*/ exprNode body)
1213 {
1214   context_exitAllClauses ();
1215
1216   context_exitFunction ();
1217   exprNode_free (body);
1218 }
1219
1220 void exprNode_checkIterEnd (/*@only@*/ exprNode body)
1221 {
1222   context_exitAllClauses ();
1223   context_exitFunction ();
1224   exprNode_free (body);
1225 }
1226
1227 static
1228 bool checkModifyAuxAux (/*@exposed@*/ sRef s, exprNode f, sRef alias, exprNode err)
1229 {
1230   bool hasMods = context_hasMods ();
1231   flagcode errCode = hasMods ? FLG_MODIFIES : FLG_MODNOMODS;
1232
1233   if (exprNode_isDefined (f))
1234     {
1235       f->sets = sRefSet_insert (f->sets, s); 
1236     }
1237
1238   if (context_getFlag (FLG_MODIFIES) 
1239       && (hasMods || context_getFlag (FLG_MODNOMODS)))
1240     {
1241       sRefSet mods = context_modList ();
1242
1243       if (!sRef_canModify (s, mods))
1244         {
1245           sRef rb = sRef_getRootBase (s);
1246           
1247           
1248           if (sRef_isFileOrGlobalScope (rb))
1249             {
1250               if (!context_checkGlobMod (rb))
1251                 {
1252                   return FALSE;
1253                 }
1254             }
1255           
1256           if (sRef_isInvalid (alias) || sRef_sameName (s, alias))
1257             {
1258               if (sRef_isLocalVar (sRef_getRootBase (s)))
1259                 {
1260                   voptgenerror 
1261                     (errCode,
1262                      message 
1263                      ("Undocumented modification of internal state (%q): %s", 
1264                       sRef_unparse (s), exprNode_unparse (err)), 
1265                      exprNode_isDefined (f) ? f->loc : g_currentloc);
1266                 }
1267               else
1268                 {
1269                   if (sRef_isSystemState (s))
1270                     {
1271                       if (errCode == FLG_MODNOMODS) 
1272                         {
1273                           if (context_getFlag (FLG_MODNOMODS))
1274                             {
1275                               errCode = FLG_MODFILESYSTEM;
1276                             }
1277                         }
1278                       else
1279                         {
1280                           errCode = FLG_MODFILESYSTEM;
1281                         }
1282                     }
1283
1284                   voptgenerror 
1285                     (errCode,
1286                      message ("Undocumented modification of %q: %s", 
1287                               sRef_unparse (s), exprNode_unparse (err)), 
1288                      exprNode_isDefined (f) ? f->loc : g_currentloc);
1289                 }
1290               
1291               return TRUE;
1292             }
1293           else
1294             {
1295               if (sRef_isReference (s) && !sRef_isAddress (alias))
1296                 {
1297                   voptgenerror 
1298                     (errCode,
1299                      message
1300                      ("Possible undocumented modification of %q through alias %q: %s", 
1301                       sRef_unparse (s),
1302                       sRef_unparse (alias),
1303                       exprNode_unparse (err)),
1304                      exprNode_isDefined (f) ? f->loc : g_currentloc);
1305                   return TRUE;
1306                 }
1307             }
1308         }
1309     }
1310   else
1311     {
1312       if (context_maybeSet (FLG_MUSTMOD))
1313         {
1314           (void) sRef_canModify (s, context_modList ());
1315         }
1316       
1317       if (sRef_isRefsField (s))
1318         {
1319           sRef_setModified (s);
1320         }
1321     }
1322   
1323   return FALSE;
1324 }
1325
1326 static
1327 bool checkModifyAux (/*@exposed@*/ sRef s, exprNode f, sRef alias, exprNode err)
1328 {
1329   DPRINTF (("Check modify aux: %s", sRef_unparseFull (s)));
1330
1331   if (sRef_isReference (s) && sRef_isObserver (s) 
1332       && context_maybeSet (FLG_MODOBSERVER))
1333     {    
1334       cstring sname;
1335       
1336       if (sRef_isPointer (s)) 
1337         {
1338           sRef base = sRef_getBase (s);
1339           sname = sRef_unparse (base);
1340         }
1341       else 
1342         {
1343           if (sRef_isAddress (s))
1344             {
1345               sRef p = sRef_constructPointer (s);
1346               sname = sRef_unparse (p);
1347             }
1348           else
1349             {
1350               sname = sRef_unparse (s);
1351             }
1352         }
1353       
1354       if (!sRef_isValid (alias) || sRef_sameName (s, alias))
1355         {
1356           if (sRef_isMeaningful (s))
1357             {
1358               if (optgenerror 
1359                   (FLG_MODOBSERVER,
1360                    message ("Suspect modification of observer %s: %s", 
1361                             sname, exprNode_unparse (err)), 
1362                    exprNode_isDefined (f) ? f->loc : g_currentloc))
1363                 {
1364                   sRef_showExpInfo (s);
1365                 }
1366             }
1367           else
1368             {
1369               voptgenerror 
1370                 (FLG_MODOBSERVER,
1371                  message ("Suspect modification of observer returned by "
1372                           "function call: %s", 
1373                           exprNode_unparse (err)), 
1374                  exprNode_isDefined (f) ? f->loc : g_currentloc);
1375             }
1376         }
1377       else
1378         {
1379           if (optgenerror
1380               (FLG_MODOBSERVER,
1381                message ("Suspect modification of observer %s through alias %q: %s", 
1382                         sname, sRef_unparse (alias), exprNode_unparse (err)), 
1383                exprNode_isDefined (f) ? f->loc : g_currentloc))
1384             {
1385               sRef_showExpInfo (s);
1386             }
1387         }
1388       
1389       cstring_free (sname);
1390     }
1391   
1392   (void) checkModifyAuxAux (s, f, alias, err);
1393   return FALSE;
1394 }
1395
1396 static
1397 bool checkModifyValAux (/*@exposed@*/ sRef s, exprNode f, sRef alias, exprNode err)
1398 {
1399   (void) checkModifyAuxAux (s, f, alias, err);
1400   return FALSE;
1401 }
1402
1403 static
1404 bool checkCallModifyAux (/*@exposed@*/ sRef s, exprNode f, sRef alias, exprNode err)
1405 {
1406   bool result = FALSE;
1407
1408   DPRINTF (("Check modify aux: %s / %s",
1409             sRef_unparse (s), sRef_unparse (alias)));
1410
1411   if (sRef_isObserver (s) && context_maybeSet (FLG_MODOBSERVER))
1412     {    
1413       sRef p = sRef_isAddress (s) ? sRef_constructPointer (s) : s;
1414       cstring sname = sRef_unparse (p);
1415
1416       if (!sRef_isValid (alias) || sRef_sameName (s, alias))
1417         {
1418           if (sRef_isMeaningful (s))
1419             {
1420               result = optgenerror 
1421                 (FLG_MODOBSERVER,
1422                  message ("Suspect modification of observer %s: %s", 
1423                           sname, exprNode_unparse (err)), 
1424                  exprNode_isDefined (f) ? f->loc : g_currentloc);
1425             }
1426           else
1427             {
1428               result = optgenerror 
1429                 (FLG_MODOBSERVER,
1430                  message ("Suspect modification of observer returned by "
1431                           "function call: %s", 
1432                           exprNode_unparse (err)), 
1433                  exprNode_isDefined (f) ? f->loc : g_currentloc);
1434             }
1435         }
1436       else
1437         {
1438           result = optgenerror 
1439             (FLG_MODOBSERVER,
1440              message
1441              ("Suspect modification of observer %s through alias %q: %s", 
1442               sname, sRef_unparse (alias), exprNode_unparse (err)), 
1443              exprNode_isDefined (f) ? f->loc : g_currentloc);
1444         }
1445       
1446       cstring_free (sname);
1447     }
1448   else if (context_maybeSet (FLG_MODIFIES))
1449     {
1450       DPRINTF (("can modify: %s / %s",
1451                 sRef_unparse (s),
1452                 sRefSet_unparse (context_modList ())));
1453
1454       if (!(sRef_canModifyVal (s, context_modList ())))
1455         {
1456           sRef p = sRef_isAddress (s) ? sRef_constructPointer (s) : s;
1457           cstring sname = sRef_unparse (p);
1458           bool hasMods = context_hasMods ();
1459           sRef rb = sRef_getRootBase (s);
1460           flagcode errCode = hasMods ? FLG_MODIFIES : FLG_MODNOMODS;
1461           bool check = TRUE;
1462
1463           DPRINTF (("Can't modify! %s", sRef_unparse (s)));
1464
1465           if (sRef_isFileOrGlobalScope (rb))
1466             {
1467               uentry ue = sRef_getUentry (rb);
1468               
1469               /* be more specific here! */
1470               if (!uentry_isCheckedModify (ue))
1471                 {
1472                   check = FALSE;
1473                 }
1474             }
1475           
1476           if (check)
1477             {
1478               if (!sRef_isValid (alias) || sRef_sameName (s, alias))
1479                 {
1480                   if (sRef_isLocalVar (sRef_getRootBase (s)))
1481                     {
1482                       voptgenerror 
1483                         (errCode,
1484                          message 
1485                          ("Undocumented modification of internal "
1486                           "state (%q) through call to %s: %s", 
1487                           sRef_unparse (s), exprNode_unparse (f),
1488                           exprNode_unparse (err)), 
1489                          exprNode_isDefined (f) ? f->loc : g_currentloc);
1490                     }
1491                   else
1492                     {
1493                       if (sRef_isSystemState (s))
1494                         {
1495                           if (errCode == FLG_MODNOMODS) 
1496                             {
1497                               if (context_getFlag (FLG_MODNOMODS))
1498                                 {
1499                                   errCode = FLG_MODFILESYSTEM;
1500                                 }
1501                             }
1502                           else
1503                             {
1504                               errCode = FLG_MODFILESYSTEM;
1505                             }
1506                         }
1507                       
1508                       result = optgenerror 
1509                         (errCode,
1510                          message ("Undocumented modification of %s "
1511                                   "possible from call to %s: %s", 
1512                                   sname,
1513                                   exprNode_unparse (f),
1514                                   exprNode_unparse (err)),
1515                          exprNode_isDefined (f) ? f->loc : g_currentloc);
1516                     }
1517                 }
1518               else
1519                 {
1520                   result = optgenerror
1521                     (errCode,
1522                      message ("Undocumented modification of %s possible "
1523                               "from call to %s (through alias %q): %s", 
1524                               sname,
1525                               exprNode_unparse (f), 
1526                               sRef_unparse (alias), 
1527                               exprNode_unparse (err)),
1528                      exprNode_isDefined (f) ? f->loc : g_currentloc);
1529                 }
1530             }
1531           cstring_free (sname);
1532         }
1533     }
1534   else
1535     {
1536       if (context_maybeSet (FLG_MUSTMOD))
1537         {
1538           (void) sRef_canModifyVal (s, context_modList ());
1539         }
1540     }
1541
1542   return result;
1543 }
1544
1545 void exprNode_checkCallModifyVal (sRef s, exprNodeList args, exprNode f, exprNode err)
1546 {
1547   s = sRef_fixBaseParam (s, args);
1548   DPRINTF (("Check call modify: %s", sRef_unparse (s)));
1549   sRef_aliasCheckPred (checkCallModifyAux, NULL, s, f, err);
1550 }
1551
1552 void
1553 exprChecks_checkExport (uentry e)
1554 {
1555   if (context_checkExport (e))
1556     {
1557       fileloc fl = uentry_whereDeclared (e);
1558       
1559       if (fileloc_isHeader (fl) && !fileloc_isLib (fl) 
1560           && !fileloc_isImport (fl) && !uentry_isStatic (e))
1561         {
1562           if (uentry_isFunction (e) || 
1563               (uentry_isVariable (e) && ctype_isFunction (uentry_getType (e))))
1564             {
1565               voptgenerror 
1566                 (FLG_EXPORTFCN,
1567                  message ("Function exported, but not specified: %q", 
1568                           uentry_getName (e)),
1569                  fl);
1570             }
1571           else if (uentry_isExpandedMacro (e))
1572             {
1573               voptgenerror
1574                 (FLG_EXPORTMACRO,
1575                  message ("Expanded macro exported, but not specified: %q", 
1576                           uentry_getName (e)),
1577                  fl);
1578             }
1579           else if (uentry_isVariable (e) && !uentry_isParam (e)) 
1580             {
1581               voptgenerror 
1582                 (FLG_EXPORTVAR,
1583                  message ("Variable exported, but not specified: %q", 
1584                           uentry_getName (e)),
1585                  fl);
1586             }
1587           else if (uentry_isEitherConstant (e))
1588             {
1589               voptgenerror 
1590                 (FLG_EXPORTCONST,
1591                  message ("Constant exported, but not specified: %q", 
1592                           uentry_getName (e)),
1593                  fl);
1594             }
1595           else if (uentry_isIter (e) || uentry_isEndIter (e))
1596             {
1597               voptgenerror 
1598                 (FLG_EXPORTITER,
1599                  message ("Iterator exported, but not specified: %q", 
1600                           uentry_getName (e)),
1601                  fl);
1602             }
1603
1604           else if (uentry_isDatatype (e))
1605             {
1606               ; /* error already reported */
1607             }
1608           else
1609             {
1610               BADEXIT;
1611             }
1612         }
1613     }
1614 }
1615
1616 static void checkSafeReturnExpr (/*@notnull@*/ exprNode e)
1617 {
1618   ctype tr = ctype_getReturnType (context_currentFunctionType ());
1619   ctype te = exprNode_getType (e);
1620
1621   /* evans 2001-08-21: added test to warn about void returns from void functions */
1622   if (ctype_isVoid (tr))
1623     {
1624       (void) gentypeerror
1625         (te, e, tr, exprNode_undefined,
1626          message ("Return expression from function declared void: %s", exprNode_unparse (e)),
1627          e->loc);
1628       return;
1629     }
1630
1631   if (!ctype_forceMatch (tr, te) && !exprNode_matchLiteral (tr, e))
1632     {
1633       (void) gentypeerror
1634         (te, e, tr, exprNode_undefined,
1635          message ("Return value type %t does not match declared type %t: %s",
1636                   te, tr, exprNode_unparse (e)),
1637          e->loc);
1638     }
1639   else
1640     {
1641       sRef ret = e->sref;
1642       uentry rval = context_getHeader ();
1643       sRef resultref = uentry_getSref (rval);
1644
1645       DPRINTF (("Check return: %s / %s / %s",
1646                 exprNode_unparse (e),
1647                 sRef_unparseFull (e->sref),
1648                 uentry_unparse (rval)));
1649
1650       transferChecks_return (e, rval);
1651
1652       DPRINTF (("After return: %s / %s / %s",
1653                 exprNode_unparse (e),
1654                 sRef_unparseFull (e->sref),
1655                 uentry_unparse (rval)));
1656
1657       if (!(sRef_isExposed (uentry_getSref (context_getHeader ()))
1658             || sRef_isObserver (uentry_getSref (context_getHeader ())))
1659           && (context_getFlag (FLG_RETALIAS) 
1660               || context_getFlag (FLG_RETEXPOSE)))
1661         {
1662           sRef base = sRef_getRootBase (ret);
1663           ctype rtype = e->typ;
1664
1665           if (ctype_isUnknown (rtype))
1666             {
1667               rtype = tr;
1668             }
1669
1670           if (ctype_isVisiblySharable (rtype))
1671             {
1672               if (context_getFlag (FLG_RETALIAS))
1673                 {
1674                   sRef_aliasCheckPred (checkRefGlobParam, NULL, base, 
1675                                        e, exprNode_undefined);
1676                 }
1677               
1678               if (context_getFlag (FLG_RETEXPOSE) && sRef_isIReference (ret) 
1679                   && !sRef_isExposed (resultref) && !sRef_isObserver (resultref))
1680                 {
1681                   sRef_aliasCheckPred (checkRepExposed, NULL, base, e, 
1682                                        exprNode_undefined);
1683                 }
1684             }
1685         }
1686     }
1687 }
1688
1689
1690
1691
1692
This page took 0.468903 seconds and 5 git commands to generate.