Various minor fixes for compiler/linter (other then splint itself) warnings.
[splint-patched.git] / src / exprNode.c
blobcf04f2032b5da778ddf2039cedef60afd8295c12
1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 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.
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
25 ** exprNode.c
28 # include "splintMacros.nf"
29 # include "basic.h"
31 # include "cscannerHelp.h"
32 # include "cgrammar.h"
34 # include "exprChecks.h"
35 # include "transferChecks.h"
36 # include "exprNodeSList.h"
38 static bool exprNode_sameStorage (exprNode p_e1, exprNode p_e2) /*@*/ ;
39 static bool exprNode_isEmptyStatement (exprNode p_e);
40 static /*@exposed@*/ exprNode exprNode_firstStatement (/*@returned@*/ exprNode p_e);
41 static bool exprNode_isFalseConstant (exprNode p_e) /*@*/ ;
42 static bool exprNode_isStatement (exprNode p_e);
43 static /*@falsewhennull@*/ bool exprNode_isBlock (exprNode p_e) /*@*/ ;
44 static void checkGlobUse (uentry p_glob, bool p_isCall, /*@notnull@*/ exprNode p_e);
45 static void exprNode_addUse (exprNode p_e, /*@exposed@*/ sRef p_s);
46 static bool exprNode_matchArgType (ctype p_ct, exprNode p_e);
47 static exprNode exprNode_fakeCopy (exprNode p_e) /*@*/ ;
48 static exprNode exprNode_statementError (/*@only@*/ exprNode p_e, /*@only@*/ lltok p_t);
49 static bool exprNode_matchTypes (exprNode p_e1, exprNode p_e2);
50 static void checkUniqueParams (exprNode p_fcn,
51 /*@notnull@*/ exprNode p_current, exprNodeList p_args,
52 int p_paramno, uentry p_ucurrent);
53 static void updateAliases (/*@notnull@*/ exprNode p_e1, /*@notnull@*/ exprNode p_e2);
54 static bool abstractOpError (ctype p_tr1, ctype p_tr2, lltok p_op,
55 /*@notnull@*/ exprNode p_e1, /*@notnull@*/ exprNode p_e2,
56 fileloc p_loc1, fileloc p_loc2)
57 /*@modifies g_warningstream@*/ ;
58 static ctype checkNumerics (ctype p_tr1, ctype p_tr2, ctype p_te1, ctype p_te2,
59 /*@notnull@*/ exprNode p_e1, /*@notnull@*/ exprNode p_e2, lltok p_op);
60 static void doAssign (/*@notnull@*/ exprNode p_e1, /*@notnull@*/ exprNode p_e2, bool p_isInit);
61 static void checkSafeUse (exprNode p_e, /*@exposed@*/ sRef p_s);
62 static void reflectNullTest (/*@notnull@*/ exprNode p_e, bool p_isnull);
63 static void checkMacroParen (exprNode p_e);
64 static exprNodeSList exprNode_flatten (/*@dependent@*/ exprNode p_e);
65 static void exprNode_checkSetAny (exprNode p_e, /*@dependent@*/ cstring p_name);
66 static void exprNode_checkUse (exprNode p_e, /*@exposed@*/ sRef p_s, fileloc p_loc);
67 static void exprNode_mergeUSs (exprNode p_res, exprNode p_other);
68 static void exprNode_mergeCondUSs (exprNode p_res, exprNode p_other1, exprNode p_other2);
69 static /*@only@*/ /*@notnull@*/ exprNode exprNode_fromIdentifierAux (/*@observer@*/ uentry p_c);
70 static void checkAnyCall (/*@notnull@*/ /*@dependent@*/ exprNode p_fcn,
71 /*@dependent@*/ cstring p_fname,
72 uentryList p_pn, exprNodeList p_args,
73 bool p_hasMods, sRefSet p_mods, bool p_isSpec,
74 int p_specialArgs);
75 static void checkOneArg (uentry p_ucurrent, /*@notnull@*/ exprNode p_current,
76 /*@dependent@*/ exprNode p_fcn, bool p_isSpec, int p_argno, int p_totargs);
77 static void
78 checkUnspecCall (/*@notnull@*/ /*@dependent@*/ exprNode p_fcn, uentryList p_params, exprNodeList p_args);
80 static /*@only@*/ exprNode exprNode_effect (exprNode p_e)
81 /*@globals internalState@*/ ;
82 static /*@only@*/ cstring exprNode_doUnparse (exprNode p_e);
83 static /*@observer@*/ cstring exprNode_rootVarName (exprNode p_e);
84 static /*@exposed@*/ exprNode
85 exprNode_lastStatement (/*@returned@*/ exprNode p_e);
87 static /*@only@*/ exprNode s_mustExitNode = exprNode_undefined;
89 static int checkArgsReal (uentry p_fcn, /*@dependent@*/ exprNode p_f,
90 uentryList p_cl,
91 exprNodeList p_args, bool p_isIter, exprNode p_ret);
93 static bool inEffect = FALSE;
94 static int nowalloc = 0;
95 static int totalloc = 0;
96 static int maxalloc = 0;
98 static /*@only@*/ uentry regArg;
99 static /*@only@*/ uentry outArg;
100 static /*@only@*/ uentry outStringArg;
101 static /*@exposed@*/ sRef stdinRef;
102 static /*@exposed@*/ sRef stdoutRef;
103 static /*@only@*/ uentry csArg;
104 static /*@only@*/ uentry csOnlyArg;
105 static ctype cstringType;
106 static ctype ctypeType;
107 static ctype filelocType;
108 static bool initMod = FALSE;
110 /*@function void exprNode_swap (sef exprNode, sef exprNode)@*/
111 /*@-macroassign@*/
112 # define exprNode_swap(e1,e2) do { exprNode m_tmp = (e1); (e1) = (e2); (e2) = m_tmp; } while (FALSE)
113 /*@=macroassign@*/
115 static void exprNode_defineConstraints(/*@sef@*/ /*@special@*/ /*@notnull@*/ exprNode e)
116 /*@defines e->requiresConstraints, e->ensuresConstraints,
117 e->trueEnsuresConstraints, e->falseEnsuresConstraints @*/
119 e->requiresConstraints = constraintList_makeNew ();
120 e->ensuresConstraints = constraintList_makeNew ();
121 e->trueEnsuresConstraints = constraintList_makeNew ();
122 e->falseEnsuresConstraints = constraintList_makeNew ();
126 ** must occur after library has been read
129 void exprNode_initMod (void)
130 /*@globals undef regArg, undef outArg, undef outStringArg,
131 undef csOnlyArg, undef csArg;
134 uentry ue;
135 idDecl tmp;
137 initMod = TRUE;
138 cstringType = ctype_unknown;
139 ctypeType = ctype_unknown;
140 filelocType = ctype_unknown;
142 if (usymtab_existsType (cstring_makeLiteralTemp ("cstring")))
144 cstringType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("cstring"));
147 if (usymtab_existsType (cstring_makeLiteralTemp ("ctype")))
149 ctypeType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("ctype"));
152 if (usymtab_existsType (cstring_makeLiteralTemp ("fileloc")))
154 filelocType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("fileloc"));
157 if (usymtab_existsGlob (cstring_makeLiteralTemp ("stdin")))
159 ue = usymtab_lookupGlob (cstring_makeLiteralTemp ("stdin"));
161 else /* define stdin */
163 ue = uentry_makeVariable (cstring_makeLiteralTemp ("stdin"),
164 ctype_unknown,
165 fileloc_getBuiltin (),
166 FALSE);
167 uentry_setHasNameError (ue);
168 ue = usymtab_supGlobalEntryReturn (ue);
171 stdinRef = sRef_makePointer (uentry_getSref (ue));
173 if (usymtab_existsGlob (cstring_makeLiteralTemp ("stdout")))
175 ue = usymtab_lookupGlob (cstring_makeLiteralTemp ("stdout"));
177 else
179 ue = uentry_makeVariable (cstring_makeLiteralTemp ("stdout"),
180 ctype_unknown,
181 fileloc_getBuiltin (),
182 FALSE);
183 uentry_setHasNameError (ue);
184 ue = usymtab_supGlobalEntryReturn (ue);
187 stdoutRef = sRef_makePointer (uentry_getSref (ue));
189 tmp = idDecl_create (cstring_undefined, qtype_create (ctype_unknown));
191 regArg = uentry_makeParam (tmp, PARAMUNKNOWN);
193 idDecl_setTyp (tmp,
194 qtype_addQual (qtype_create (ctype_makePointer (ctype_unknown)),
195 qual_createOut ()));
197 outArg = uentry_makeParam (tmp, PARAMUNKNOWN);
199 idDecl_setTyp (tmp, qtype_addQual (qtype_create (ctype_string),
200 qual_createOut ()));
202 outStringArg = uentry_makeParam (tmp, PARAMUNKNOWN);
204 idDecl_setTyp (tmp, qtype_addQual (qtype_addQual (qtype_create (cstringType),
205 qual_createOnly ()),
206 qual_createNull ()));
208 csOnlyArg = uentry_makeParam (tmp, PARAMUNKNOWN);
210 idDecl_setTyp (tmp, qtype_addQual (qtype_create (cstringType), qual_createNull ()));
211 csArg = uentry_makeParam (tmp, PARAMUNKNOWN);
213 idDecl_free (tmp);
216 void
217 exprNode_destroyMod (void)
218 /*@globals killed regArg, killed outArg, killed outStringArg,
219 killed s_mustExitNode, initMod @*/
221 if (initMod)
223 /* evans 2002-07-12: changed uentry_free to uentry_freeComplete */
224 uentry_freeComplete (regArg);
225 uentry_freeComplete (outArg);
226 uentry_freeComplete (outStringArg);
228 exprNode_free (s_mustExitNode);
229 initMod = FALSE;
230 /*@-branchstate@*/
232 /*@=branchstate@*/
235 static void exprNode_resetSref (/*@notnull@*/ exprNode e)
237 e->sref = sRef_undefined;
240 exprNode exprNode_fakeCopy (exprNode e)
242 /*@-temptrans@*/ /*@-retalias@*/
243 return e;
244 /*@=temptrans@*/ /*@=retalias@*/
247 static bool isFlagKey (char key)
249 return (key == '-' || key == '+' || key == ' ' || key == '#');
252 static void exprNode_combineControl (/*@notnull@*/ exprNode ret,
253 /*@notnull@*/ exprNode ifclause,
254 /*@notnull@*/ exprNode elseclause)
256 ret->canBreak = ifclause->canBreak || elseclause->canBreak;
258 ret->mustBreak =
259 (ifclause->mustBreak || exprNode_mustEscape (ifclause))
260 && (elseclause->mustBreak || exprNode_mustEscape (elseclause));
262 ret->exitCode = exitkind_combine (ifclause->exitCode,
263 elseclause->exitCode);
268 ** For exprNode's returned by exprNode_effect.
271 static bool shallowKind (exprKind kind)
273 return (kind == XPR_STRINGLITERAL
274 || kind == XPR_NUMLIT
275 || kind == XPR_EMPTY
276 || kind == XPR_BODY
277 || kind == XPR_NODE);
280 static void
281 exprNode_freeIniter (/*@only@*/ exprNode e)
283 if (!exprNode_isError (e))
285 switch (e->kind)
287 case XPR_FACCESS:
289 ** Its a fake copy, don't free the field->rec and field->field
290 ** fields.
293 /*@-compdestroy@*/
294 sfree (e->edata->field);
295 /*@=compdestroy@*/
297 sfree (e->edata);
298 break;
299 case XPR_FETCH:
300 exprNode_free (e->edata->op->b);
301 /*@-compdestroy@*/ sfree (e->edata->op); /*@=compdestroy@*/
302 sfree (e->edata);
303 break;
304 default:
305 llbug (message ("other: %s", exprNode_unparse (e)));
308 multiVal_free (e->val);
309 cstring_free (e->etext);
310 fileloc_free (e->loc);
311 sRefSet_free (e->uses);
312 sRefSet_free (e->sets);
313 sRefSet_free (e->msets);
314 guardSet_free (e->guards);
316 constraintList_free(e->requiresConstraints);
317 constraintList_free(e->ensuresConstraints);
318 constraintList_free(e->trueEnsuresConstraints);
319 constraintList_free(e->falseEnsuresConstraints);
321 e->requiresConstraints = NULL;
322 e->ensuresConstraints = NULL;
323 e->trueEnsuresConstraints = NULL;
324 e->falseEnsuresConstraints = NULL;
326 sfree (e);
330 void
331 exprNode_freeShallow (/*@only@*/ exprNode e)
333 if (!exprNode_isError (e))
335 if (shallowKind (e->kind))
338 else
340 if (!inEffect)
342 if (e->kind == XPR_EMPTY
343 || e->kind == XPR_BODY
344 || e->kind == XPR_STRINGLITERAL
345 || e->kind == XPR_NUMLIT
346 || e->kind == XPR_NODE
347 || e->kind == XPR_OFFSETOF
348 || e->kind == XPR_ALIGNOFT
349 || e->kind == XPR_ALIGNOF
350 || e->kind == XPR_SIZEOFT
351 || e->kind == XPR_SIZEOF)
353 /* don't free anything */
355 else
357 /* multiVal_free (e->val); */
358 cstring_free (e->etext);
359 fileloc_free (e->loc);
360 sRefSet_free (e->uses);
361 sRefSet_free (e->sets);
362 sRefSet_free (e->msets);
363 guardSet_free (e->guards);
364 exprData_freeShallow (e->edata, e->kind);
365 nowalloc--;
366 /*@-compdestroy@*/ sfree (e); /*@=compdestroy@*/
367 /*@-branchstate@*/
370 } /*@=branchstate@*/
374 void
375 exprNode_free (exprNode e)
377 if (!exprNode_isError (e))
379 if (!inEffect)
381 multiVal_free (e->val);
382 cstring_free (e->etext);
383 fileloc_free (e->loc);
384 sRefSet_free (e->uses);
385 sRefSet_free (e->sets);
386 sRefSet_free (e->msets);
387 guardSet_free (e->guards);
388 exprData_free (e->edata, e->kind);
390 constraintList_free(e->requiresConstraints);
391 constraintList_free(e->ensuresConstraints);
392 constraintList_free(e->trueEnsuresConstraints);
393 constraintList_free(e->falseEnsuresConstraints);
395 e->requiresConstraints = NULL;
396 e->ensuresConstraints = NULL;
397 e->trueEnsuresConstraints = NULL;
398 e->falseEnsuresConstraints = NULL;
400 nowalloc--;
401 sfree (e);
402 /*@-branchstate@*/
403 } /*@=branchstate@*/
407 exprNode
408 exprNode_makeError (void)
410 return exprNode_undefined;
413 static /*@out@*/ /*@only@*/ /*@notnull@*/ exprNode
414 exprNode_new (void)
416 exprNode ret = (exprNode) dmalloc (sizeof (*ret));
417 /* static int lastexpnodes = 0; */
419 nowalloc++;
420 totalloc++;
422 if (nowalloc > maxalloc)
424 maxalloc = nowalloc;
427 return ret;
430 static /*@notnull@*/ /*@special@*/ exprNode
431 exprNode_createPlain (ctype c)
432 /*@defines result@*/
433 /*@ensures isnull result->edata, result->loc, result->val, result->guards,
434 result->uses, result->sets, result->msets, result->etext @*/
435 /*@*/
437 exprNode e = exprNode_new ();
439 e->typ = c;
440 e->kind = XPR_EMPTY;
441 e->val = multiVal_undefined;
442 e->sref = sRef_undefined;
443 e->etext = cstring_undefined;
444 e->loc = fileloc_undefined;
445 e->guards = guardSet_undefined;
446 e->uses = sRefSet_undefined;
447 e->sets = sRefSet_undefined;
448 e->msets = sRefSet_undefined;
449 e->edata = exprData_undefined;
450 e->exitCode = XK_NEVERESCAPE;
451 e->canBreak = FALSE;
452 e->mustBreak = FALSE;
453 e->isJumpPoint = FALSE;
455 exprNode_defineConstraints(e);
457 return (e);
460 /*@observer@*/ exprNode exprNode_makeMustExit (void)
462 if (exprNode_isUndefined (s_mustExitNode))
464 s_mustExitNode = exprNode_createPlain (ctype_unknown);
465 s_mustExitNode->exitCode = XK_MUSTEXIT;
468 return s_mustExitNode;
472 static /*@notnull@*/ /*@special@*/ exprNode exprNode_create (ctype c)
473 /*@defines result@*/
474 /*@post:isnull result->edata, result->guards, result->val,
475 result->uses, result->sets, result->msets@*/
476 /*@*/
478 exprNode e = exprNode_createPlain (c);
479 e->loc = fileloc_copy (g_currentloc);
480 return (e);
483 static /*@notnull@*/ /*@special@*/ exprNode exprNode_createUnknown (void)
484 /*@defines result@*/
485 /*@post:isnull result->edata, result->guards,
486 result->uses, result->sets, result->msets@*/
487 /*@*/
489 return (exprNode_create (ctype_unknown));
492 static /*@notnull@*/ /*@special@*/ exprNode
493 exprNode_createLoc (ctype c, /*@keep@*/ fileloc loc)
494 /*@defines result@*/
495 /*@post:isnull result->edata, result->guards, result->val,
496 result->uses, result->sets, result->msets@*/
497 /*@*/
499 exprNode e = exprNode_createPlain (c);
500 e->loc = loc;
501 return (e);
504 static void
505 exprNode_copySets (/*@special@*/ /*@notnull@*/ exprNode ret, exprNode e)
506 /*@defines ret->guards, ret->uses, ret->sets, ret->msets@*/
508 if (exprNode_isDefined (e))
510 ret->guards = guardSet_copy (e->guards);
511 ret->uses = sRefSet_newCopy (e->uses);
512 ret->sets = sRefSet_newCopy (e->sets);
513 ret->msets = sRefSet_newCopy (e->msets);
515 else
517 ret->guards = guardSet_undefined;
518 ret->uses = sRefSet_undefined;
519 ret->sets = sRefSet_undefined;
520 ret->msets = sRefSet_undefined;
524 static /*@notnull@*/ /*@special@*/ exprNode
525 exprNode_createPartialLocCopy (exprNode e, /*@only@*/ fileloc loc)
526 /*@defines result@*/
527 /*@post:isnull result->edata, result->etext@*/
528 /*@*/
530 exprNode ret = exprNode_new ();
532 if (exprNode_isError (e))
534 ret->typ = ctype_unknown;
535 ret->val = multiVal_undefined;
536 ret->loc = loc;
537 ret->guards = guardSet_undefined;
538 ret->uses = sRefSet_undefined;
539 ret->sets = sRefSet_undefined;
540 ret->msets = sRefSet_undefined;
542 else
544 ret->typ = e->typ;
545 ret->val = multiVal_copy (e->val);
546 ret->loc = loc;
547 ret->guards = guardSet_copy (e->guards);
548 ret->uses = sRefSet_newCopy (e->uses);
549 ret->sets = sRefSet_newCopy (e->sets);
550 ret->msets = sRefSet_newCopy (e->msets);
553 ret->kind = XPR_EMPTY;
554 ret->sref = sRef_undefined;
555 ret->etext = cstring_undefined;
556 ret->exitCode = XK_NEVERESCAPE;
557 ret->canBreak = FALSE;
558 ret->mustBreak = FALSE;
559 ret->isJumpPoint = FALSE;
560 ret->edata = exprData_undefined;
562 exprNode_defineConstraints(ret);
564 return (ret);
568 static /*@notnull@*/ /*@special@*/ exprNode
569 exprNode_createPartialCopy (exprNode e)
570 /*@defines result@*/
571 /*@post:isnull result->edata, result->etext@*/
572 /*@*/
574 return (exprNode_createPartialLocCopy (e, fileloc_copy (exprNode_loc (e))));
577 static /*@notnull@*/ /*@special@*/ exprNode
578 exprNode_createPartialNVCopy (exprNode e)
579 /*@defines result@*/
580 /*@post:isnull result->edata, result->etext, result->val @*/
581 /*@*/
583 exprNode ret = exprNode_new ();
585 if (exprNode_isError (e))
587 ret->typ = ctype_unknown;
588 ret->loc = fileloc_undefined;
589 ret->guards = guardSet_undefined;
590 ret->uses = sRefSet_undefined;
591 ret->sets = sRefSet_undefined;
592 ret->msets = sRefSet_undefined;
594 else
596 ret->typ = e->typ;
597 ret->loc = fileloc_copy (e->loc);
598 ret->guards = guardSet_copy (e->guards);
599 ret->uses = sRefSet_newCopy (e->uses);
600 ret->sets = sRefSet_newCopy (e->sets);
601 ret->msets = sRefSet_newCopy (e->msets);
604 ret->val = multiVal_undefined;
605 ret->kind = XPR_EMPTY;
606 ret->sref = sRef_undefined;
607 ret->etext = cstring_undefined;
608 ret->exitCode = XK_NEVERESCAPE;
609 ret->canBreak = FALSE;
610 ret->mustBreak = FALSE;
611 ret->isJumpPoint = FALSE;
612 ret->edata = exprData_undefined;
614 exprNode_defineConstraints(ret);
616 return (ret);
619 static /*@notnull@*/ /*@special@*/ exprNode
620 exprNode_createSemiCopy (exprNode e)
621 /*@defines result@*/
622 /*@post:isnull result->edata, result->etext, result->sets,
623 result->msets, result->uses, result->guards@*/
624 /*@*/
626 if (exprNode_isError (e))
628 return exprNode_createPlain (ctype_unknown);
630 else
632 exprNode ret = exprNode_new ();
634 ret->typ = e->typ;
635 ret->val = multiVal_copy (e->val);
636 ret->loc = fileloc_copy (e->loc);
637 ret->guards = guardSet_undefined;
638 ret->uses = sRefSet_undefined;
639 ret->sets = sRefSet_undefined;
640 ret->msets = sRefSet_undefined;
642 ret->kind = XPR_EMPTY;
643 ret->sref = sRef_undefined;
644 ret->etext = cstring_undefined;
645 ret->exitCode = XK_NEVERESCAPE;
646 ret->canBreak = FALSE;
647 ret->mustBreak = FALSE;
648 ret->isJumpPoint = FALSE;
649 ret->edata = exprData_undefined;
651 exprNode_defineConstraints(ret);
653 return (ret);
657 bool
658 exprNode_isNullValue (exprNode e)
660 if (exprNode_isDefined (e))
662 multiVal m = exprNode_getValue (e);
664 if (multiVal_isInt (m))
666 return (multiVal_forceInt (m) == 0);
670 return FALSE;
673 static bool
674 exprNode_isUnknownConstant (/*@notnull@*/ exprNode e)
676 while (e->kind == XPR_PARENS)
678 e = exprData_getUopNode (e->edata);
680 if (!exprNode_isDefined (e))
682 return FALSE;
685 /* evans 2002-02-05: was llassert (exprNode_isDefined (e)); but this can fail */
688 if (e->kind == XPR_CONST)
690 multiVal m = exprNode_getValue (e);
692 if (multiVal_isUnknown (m))
694 return TRUE;
698 return FALSE;
701 /*@only@*/ exprNode
702 exprNode_numLiteral (ctype c, /*@temp@*/ cstring t,
703 /*@only@*/ fileloc loc, long val)
705 exprNode e = exprNode_createLoc (c, loc);
707 e->kind = XPR_NUMLIT;
709 llassert (multiVal_isUndefined (e->val));
710 e->val = multiVal_makeInt (val);
711 e->edata = exprData_makeLiteral (cstring_copy (t));
713 if (val == 0)
715 e->sref = sRef_makeUnknown ();
716 sRef_setDefNull (e->sref, e->loc);
719 DPRINTF (("Num lit: %s / %s", exprNode_unparse (e), ctype_unparse (exprNode_getType (e))));
720 return (e);
723 /*@only@*/ exprNode
724 exprNode_charLiteral (char c, cstring text, /*@only@*/ fileloc loc)
726 exprNode e = exprNode_createLoc (ctype_char, loc);
728 if (context_getFlag (FLG_CHARINTLITERAL))
730 e->typ = ctype_makeConj (ctype_char, ctype_int);
733 e->kind = XPR_NUMLIT;
734 e->val = multiVal_makeChar (c);
736 e->edata = exprData_makeLiteral (cstring_copy (text));
737 return (e);
740 /*@only@*/ exprNode
741 exprNode_floatLiteral (double d, ctype ct, cstring text, /*@only@*/ fileloc loc)
743 exprNode e = exprNode_createLoc (ct, loc);
745 e->kind = XPR_NUMLIT;
746 e->val = multiVal_makeDouble (d);
747 e->edata = exprData_makeLiteral (cstring_copy (text));
748 return (e);
751 multiVal exprNode_getValue (exprNode e)
753 while (exprNode_isInParens (e)) {
754 if (e->edata != NULL) {
755 e = exprData_getUopNode (e->edata);
756 } else {
757 break;
761 if (exprNode_isDefined (e)) {
762 return e->val;
763 } else {
764 return multiVal_undefined;
768 /*@only@*/ exprNode
769 exprNode_combineLiterals (exprNode e, exprNode rest)
771 cstring ns;
773 /* Both must be string literals. */
775 if (exprNode_isUndefined (rest) || exprNode_isUndefined (e))
777 exprNode_free (rest);
778 return e;
781 if (!exprNode_isStringLiteral (e))
783 voptgenerror
784 (FLG_SYNTAX,
785 message ("Constant concatentation is ungrammatical: %s %s", exprNode_unparse (e),
786 exprNode_unparse (rest)),
787 e->loc);
788 exprNode_free (rest);
789 return e;
792 if (!exprNode_isStringLiteral (rest))
794 voptgenerror
795 (FLG_SYNTAX,
796 message ("Constant concatentation is ungrammatical: %s %s", exprNode_unparse (e), exprNode_unparse (rest)),
797 rest->loc);
799 exprNode_free (rest);
800 return e;
803 ns = cstring_concat (multiVal_forceString (exprNode_getValue (e)),
804 multiVal_forceString (exprNode_getValue (rest)));
806 multiVal_free (e->val);
807 exprData_free (e->edata, e->kind);
808 e->edata = exprData_makeLiteral (cstring_copy (ns));
809 e->val = multiVal_makeString (ns);
810 exprNode_free (rest);
811 return e;
814 static /*@notnull@*/ /*@only@*/ exprNode
815 exprNode_rawStringLiteral (/*@only@*/ cstring t, /*@only@*/ fileloc loc)
817 exprNode e = exprNode_createLoc (ctype_string, loc);
818 size_t len = cstring_length (t);
820 if (context_getFlag (FLG_STRINGLITERALLEN))
822 if (len > size_fromInt (context_getValue (FLG_STRINGLITERALLEN)))
824 voptgenerror (FLG_STRINGLITERALLEN,
825 message
826 ("String literal length (%d) exceeds maximum "
827 "length (%d): \"%s\"",
828 size_toInt (len),
829 context_getValue (FLG_STRINGLITERALLEN),
831 e->loc);
835 e->kind = XPR_STRINGLITERAL;
836 e->val = multiVal_makeString (cstring_copy (t));
837 e->edata = exprData_makeLiteral (t);
838 e->sref = sRef_makeConst (ctype_string);
840 if (context_getFlag (FLG_READONLYSTRINGS))
842 sRef_setAliasKind (e->sref, AK_STATIC, fileloc_undefined);
843 sRef_setExKind (e->sref, XO_OBSERVER, loc);
845 else
847 sRef_setAliasKind (e->sref, AK_ERROR, fileloc_undefined);
850 return (e); /* s released */
853 /*@only@*/ exprNode
854 exprNode_wideStringLiteral (/*@only@*/ cstring t, /*@only@*/ fileloc loc)
856 exprNode res = exprNode_stringLiteral (t, loc);
857 res->typ = ctype_makeWideString ();
858 return res;
861 /*@only@*/ exprNode
862 exprNode_stringLiteral (/*@only@*/ cstring t, /*@only@*/ fileloc loc)
864 size_t len = size_fromInt (size_toInt (cstring_length (t)) - 2);
865 char *ts = cstring_toCharsSafe (t);
866 char *s = cstring_toCharsSafe (cstring_create (len + 1));
868 llassert (*ts == '\"' && *(ts + len + 1) == '\"');
869 strncpy (s, ts+1, len);
870 *(s + len) = '\0';
871 cstring_free (t);
872 return exprNode_rawStringLiteral (cstring_fromCharsO (s), loc);
875 exprNode exprNode_fromUIO (cstring c)
877 fileloc loc = context_getSaveLocation ();
878 exprNode e = exprNode_createPlain (ctype_unknown);
880 e->kind = XPR_VAR;
882 if (fileloc_isUndefined (loc))
884 loc = fileloc_copy (g_currentloc);
887 e->loc = loc; /* save loc was mangled */
888 e->sref = sRef_undefined;
890 if (usymtab_exists (c))
892 uentry ue = usymtab_lookupEither (c);
894 if (uentry_isDatatype (ue)
895 && uentry_isSpecified (ue))
897 llfatalerror
898 (message ("%q: Specified datatype %s used in code, but not defined. "
899 "(Cannot continue reasonably from this error.)",
900 fileloc_unparse (e->loc), c));
902 else
904 BADBRANCH;
908 llassertprint (!usymtab_exists (c), ("Entry exists: %s", c));
911 ** was supercedeGlobalEntry...is this better?
914 if (!context_inIterEnd ())
916 if (context_inMacro ())
918 if (context_getFlag (FLG_UNRECOG))
920 voptgenerror
921 (FLG_MACROUNDEF,
922 message ("Unrecognized identifier in macro definition: %s", c), e->loc);
924 else
926 flagcode_recordSuppressed (FLG_UNRECOG);
929 else
931 voptgenerror
932 (FLG_UNRECOG, message ("Unrecognized identifier: %s", c), e->loc);
936 e->edata = exprData_makeId (uentry_makeUnrecognized (c, fileloc_copy (loc)));
938 /* No alias errors for unrecognized identifiers */
939 sRef_setAliasKind (e->sref, AK_ERROR, loc);
941 return (e);
944 exprNode exprNode_makeConstantString (cstring c, /*@only@*/ fileloc loc)
946 exprNode e = exprNode_createPlain (ctype_unknown);
947 e->kind = XPR_VAR;
948 e->loc = loc;
949 e->sref = sRef_makeConst (ctype_string);
950 e->edata = exprData_makeId (uentry_makeUnrecognized (c, fileloc_copy (loc)));
951 e->typ = ctype_string;
953 /* No alias errors for unrecognized identifiers */
954 sRef_setAliasKind (e->sref, AK_STATIC, loc);
955 sRef_setExKind (e->sref, XO_OBSERVER, loc);
957 return (e);
960 exprNode exprNode_createId (/*@observer@*/ uentry c)
962 if (uentry_isValid (c))
964 exprNode e = exprNode_new ();
966 DPRINTF (("create id: %s", uentry_unparse (c)));
968 e->typ = uentry_getType (c);
970 if (uentry_isFunction (c)
971 && !sRef_isLocalVar (uentry_getSref (c)))
973 e->sref = sRef_undefined;
975 else
977 e->sref = uentry_getSref (c);
980 if (sRef_isStateUnknown (e->sref) && uentry_isNonLocal (c))
982 sRef_setDefined (e->sref, fileloc_undefined);
986 ** yoikes! leaving this out was a heinous bug...that would have been
987 ** caught if i had splint working first. gag!
990 e->etext = cstring_undefined;
992 if (uentry_isEitherConstant (c))
994 e->kind = XPR_CONST;
995 e->val = multiVal_copy (uentry_getConstantValue (c));
997 else
999 e->kind = XPR_VAR;
1000 e->val = multiVal_unknown ();
1003 e->edata = exprData_makeId (c);
1004 e->loc = context_getSaveLocation ();
1006 if (fileloc_isUndefined (e->loc))
1008 fileloc_free (e->loc);
1009 e->loc = fileloc_copy (g_currentloc);
1012 e->guards = guardSet_new ();
1014 e->sets = sRefSet_new ();
1015 e->msets = sRefSet_new ();
1016 e->uses = sRefSet_new ();
1018 /*> missing fields, detected by splint <*/
1019 e->exitCode = XK_NEVERESCAPE;
1020 e->isJumpPoint = FALSE;
1021 e->canBreak = FALSE;
1022 e->mustBreak = FALSE;
1024 exprNode_defineConstraints (e);
1025 return e;
1027 else
1029 return exprNode_createUnknown ();
1033 /*@notnull@*/ exprNode
1034 exprNode_fromIdentifier (/*@observer@*/ uentry c)
1036 exprNode ret;
1038 if (context_justPopped ()) /* watch out! c could be dead */
1040 uentry ce = usymtab_lookupSafe (cscannerHelp_observeLastIdentifier ());
1042 if (uentry_isValid (ce))
1044 c = ce;
1046 else
1048 llbuglit ("Looks like Aunt Millie forgot to walk to dog again.");
1052 ret = exprNode_fromIdentifierAux (c);
1053 return ret;
1056 static void exprNode_checkStringLiteralLength (ctype t1, exprNode e2)
1058 multiVal mval = exprNode_getValue (e2);
1059 cstring slit;
1060 size_t len;
1062 if (ctype_isFixedArray (t1))
1064 size_t nelements = ctype_getArraySize (t1);
1066 llassert (multiVal_isString (mval));
1067 slit = multiVal_forceString (mval);
1069 len = cstring_lengthExpandEscapes (slit);
1071 llassert (exprNode_isDefined (e2));
1073 if (len == nelements)
1075 mstring temp;
1077 temp = cstring_expandEscapes (slit);
1079 if (temp[len-1] == '\0')
1081 voptgenerror
1082 (FLG_STRINGLITNOROOMFINALNULL,
1083 message ("String literal with %d character%& "
1084 "is assigned to %s (no room for final null terminator): %s",
1085 size_toInt (len + 1),
1086 ctype_unparse (t1),
1087 exprNode_unparse (e2)),
1088 e2->loc);
1090 else
1092 voptgenerror
1093 (FLG_STRINGLITNOROOM,
1094 message ("String literal with %d character%& "
1095 "is assigned to %s (no room for null terminator): %s",
1096 size_toInt (len + 1),
1097 ctype_unparse (t1),
1098 exprNode_unparse (e2)),
1099 e2->loc);
1102 else if (len > nelements)
1104 voptgenerror
1105 (FLG_STRINGLITTOOLONG,
1106 message ("String literal with %d character%& (counting null terminator) "
1107 "is assigned to %s (insufficient storage available): %s",
1108 size_toInt (len + 1),
1109 ctype_unparse (t1),
1110 exprNode_unparse (e2)),
1111 e2->loc);
1113 else if (len < nelements - 1)
1115 voptgenerror
1116 (FLG_STRINGLITSMALLER,
1117 message ("String literal with %d character%& is assigned to %s (possible waste of storage): %s",
1118 size_toInt (len + 1),
1119 ctype_unparse (t1),
1120 exprNode_unparse (e2)),
1121 e2->loc);
1123 else
1125 ; /* okay */
1130 static /*@only@*/ /*@notnull@*/ exprNode
1131 exprNode_fromIdentifierAux (/*@observer@*/ uentry c)
1133 exprNode e = exprNode_createId (c);
1134 sRef sr = e->sref;
1136 uentry_setUsed (c, e->loc);
1138 if (uentry_isVar (c) && sRef_isFileOrGlobalScope (sr))
1140 checkGlobUse (c, FALSE, e);
1143 return (e);
1146 static bool
1147 exprNode_isZero (exprNode e)
1149 if (exprNode_isDefined (e))
1151 multiVal m = exprNode_getValue (e);
1153 if (multiVal_isInt (m))
1155 return (multiVal_forceInt (m) == 0);
1159 return FALSE;
1162 static bool
1163 exprNode_isNonNegative (exprNode e)
1165 if (exprNode_isDefined (e))
1167 multiVal m = exprNode_getValue (e);
1169 if (multiVal_isInt (m))
1171 return (multiVal_forceInt (m) >= 0);
1175 ** This is not always true if programmer defines enum
1176 ** values, but then the constant should be known.
1179 if (ctype_isEnum (ctype_realType (e->typ)))
1181 return TRUE;
1185 return FALSE;
1189 ** a[x] - uses a but NOT a[]
1190 ** result sref = a[] (set/use in assignment)
1192 ** The syntax x[a] is also legal in C, and has the same
1193 ** semantics. If ind is an array, and arr is an int, flip
1194 ** the arguments.
1197 /*@only@*/ exprNode
1198 exprNode_arrayFetch (/*@only@*/ exprNode e1, /*@only@*/ exprNode e2)
1201 ** error in arr, error propagates (no new messages)
1202 ** error in ind, assume valid and continue
1205 DPRINTF (("Array fetch: %s / %s",
1206 exprNode_unparse (e1), exprNode_unparse (e2)));
1208 if (exprNode_isError (e1))
1210 exprNode_free (e2);
1211 return (exprNode_makeError ());
1213 else
1215 exprNode arr;
1216 exprNode ind;
1217 ctype carr = exprNode_getType (e1);
1218 ctype crarr = ctype_realType (carr);
1221 ** this sets up funny aliasing, that leads to spurious
1222 ** splint errors. Hence, the i2 comments.
1225 /* evans 2001-09-09 added ctype_isKnown so there is no swap when e1 type is unknown */
1226 if (ctype_isKnown (crarr)
1227 && !ctype_isRealArray (crarr)
1228 && ctype_isRealNumeric (crarr)
1229 && !exprNode_isError (e2)
1230 && ctype_isRealAP (exprNode_getType (e2))) /* fetch like 3[a] */
1232 arr = e2;
1233 ind = e1;
1235 carr = exprNode_getType (arr);
1236 crarr = ctype_realType (carr);
1238 else
1240 arr = e1;
1241 ind = e2;
1244 DPRINTF (("arr: %s", exprNode_unparse (arr)));
1246 if (sRef_possiblyNull (arr->sref))
1248 if (!usymtab_isGuarded (arr->sref))
1250 if (!context_inSizeof() )
1252 if (optgenerror (FLG_NULLDEREF,
1253 message ("Index of %s pointer %q: %s",
1254 sRef_nullMessage (arr->sref),
1255 sRef_unparse (arr->sref),
1256 exprNode_unparse (arr)),
1257 arr->loc))
1259 DPRINTF (("ref: %s", sRef_unparseFull (arr->sref)));
1260 sRef_showNullInfo (arr->sref);
1262 /* suppress future messages */
1263 sRef_setNullError (arr->sref);
1269 if (exprNode_isError (ind))
1271 if ((ctype_isArrayPtr (crarr)
1272 && !ctype_isFunction (crarr))
1273 || ctype_isUnknown (carr))
1275 exprNode ret = exprNode_createPartialCopy (arr);
1277 if (ctype_isKnown (carr))
1279 ret->typ = ctype_baseArrayPtr (crarr);
1281 else
1283 ret->typ = ctype_unknown;
1286 ret->sref = sRef_makeArrayFetch (arr->sref);
1288 ret->kind = XPR_FETCH;
1291 ** Because of funny aliasing (when arr and ind are
1292 ** flipped) spurious errors would be reported here.
1295 /*@i2@*/ ret->edata = exprData_makePair (arr, ind);
1296 checkSafeUse (ret, arr->sref);
1297 return (ret);
1299 else
1301 voptgenerror (FLG_TYPE,
1302 message ("Array fetch from non-array (%t): %s[%s]", carr,
1303 exprNode_unparse (e1), exprNode_unparse (e2)),
1304 arr->loc);
1305 exprNode_free (arr);
1306 return (exprNode_makeError ());
1309 else
1311 if (!ctype_isForceRealInt (&(ind->typ)))
1313 ctype rt = ctype_realType (ind->typ);
1315 if (ctype_isChar (rt))
1317 vnoptgenerror
1318 (FLG_CHARINDEX,
1319 message ("Array fetch using non-integer, %t: %s[%s]",
1320 ind->typ,
1321 exprNode_unparse (e1), exprNode_unparse (e2)),
1322 arr->loc);
1324 else if (ctype_isEnum (rt))
1326 vnoptgenerror
1327 (FLG_ENUMINDEX,
1328 message ("Array fetch using non-integer, %t: %s[%s]",
1329 ind->typ,
1330 exprNode_unparse (e1), exprNode_unparse (e2)),
1331 arr->loc);
1333 else if (ctype_isNumAbstract (rt))
1335 vnoptgenerror
1336 (FLG_NUMABSTRACTINDEX,
1337 message ("Array fetch using numabstract type, %t: %s[%s]",
1338 ind->typ,
1339 exprNode_unparse (e1), exprNode_unparse (e2)),
1340 arr->loc);
1342 else
1344 voptgenerror
1345 (FLG_TYPE,
1346 message ("Array fetch using non-integer, %t: %s[%s]",
1347 ind->typ,
1348 exprNode_unparse (e1), exprNode_unparse (e2)),
1349 arr->loc);
1352 multiVal_free (ind->val);
1353 ind->val = multiVal_unknown ();
1356 if (ctype_isArrayPtr (crarr) && !ctype_isFunction (crarr))
1358 exprNode ret = exprNode_createSemiCopy (arr);
1359 multiVal m = exprNode_getValue (ind);
1361 ret->typ = ctype_baseArrayPtr (crarr);
1362 ret->kind = XPR_FETCH;
1364 if (multiVal_isInt (m))
1366 int i = (int) multiVal_forceInt (m);
1368 if (sRef_isValid (arr->sref)) {
1369 ret->sref = sRef_makeArrayFetchKnown (arr->sref, i);
1370 } else {
1371 ret->sref = sRef_undefined;
1374 else
1376 ret->sref = sRef_makeArrayFetch (arr->sref);
1379 ret->sets = sRefSet_realNewUnion (arr->sets, ind->sets);
1380 ret->msets = sRefSet_realNewUnion (arr->msets, ind->msets);
1381 ret->uses = sRefSet_realNewUnion (arr->uses, ind->uses);
1383 /* (see comment on spurious errors above) */
1384 /*@i2@*/ ret->edata = exprData_makePair (arr, ind);
1386 exprNode_checkUse (ret, ind->sref, ind->loc);
1387 exprNode_checkUse (ret, arr->sref, arr->loc);
1389 return (ret);
1391 else
1393 if (ctype_isUnknown (carr))
1395 exprNode ret = exprNode_createPartialCopy (arr);
1397 ret->kind = XPR_FETCH;
1398 ret->typ = ctype_unknown;
1399 ret->sets = sRefSet_union (ret->sets, ind->sets);
1400 ret->msets = sRefSet_union (ret->msets, ind->msets);
1401 ret->uses = sRefSet_union (ret->uses, ind->uses);
1403 /* (see comment on spurious errors above) */
1404 /*@i2@*/ ret->edata = exprData_makePair (arr, ind);
1406 exprNode_checkUse (ret, ind->sref, ind->loc);
1407 exprNode_checkUse (ret, arr->sref, arr->loc);
1408 return (ret);
1410 else
1412 voptgenerror
1413 (FLG_TYPE,
1414 message ("Array fetch from non-array (%t): %s[%s]", carr,
1415 exprNode_unparse (e1), exprNode_unparse (e2)),
1416 arr->loc);
1418 exprNode_free (arr);
1419 exprNode_free (ind);
1421 return (exprNode_makeError ());
1426 BADEXIT;
1430 static int
1431 checkArgs (uentry fcn, /*@dependent@*/ exprNode f, ctype t,
1432 exprNodeList args, exprNode ret)
1434 return (checkArgsReal (fcn, f, ctype_argsFunction (t), args, FALSE, ret));
1438 ** checkPrintfArgs --- checks arguments for printf-like functions
1439 ** Arguments before ... have already been checked.
1440 ** The argument before the ... is a char *.
1441 ** argno is the format string argument.
1444 static void
1445 checkPrintfArgs (/*@notnull@*/ /*@dependent@*/ exprNode f, uentry fcn,
1446 exprNodeList args, exprNode ret, int argno)
1449 ** the last argument before the elips is the format string
1452 int i = argno;
1453 fileloc formatloc;
1454 uentryList params = uentry_getParams (fcn);
1455 exprNode a;
1458 ** These should be ensured by checkSpecialFunction
1461 llassert (uentryList_size (params) == argno + 1);
1462 llassert (uentry_isElipsisMarker (uentryList_getN (params, argno)));
1464 a = exprNodeList_getN (args, argno - 1);
1465 formatloc = fileloc_copy (exprNode_loc (a));
1467 if (exprNode_isDefined (a) && exprNode_isStringLiteral (a)
1468 && exprNode_knownStringValue (a))
1470 char *format = cstring_toCharsSafe (multiVal_forceString (exprNode_getValue (a)));
1471 char *code = format;
1472 char *ocode = code;
1473 int nargs = exprNodeList_size (args);
1475 while ((code = strchr (code, '%')) != NULL)
1477 char *origcode = code;
1478 cstring codetext = cstring_newEmpty ();
1479 char key = *(++code);
1480 ctype modtype = ctype_int;
1481 bool modified = FALSE;
1483 fileloc_addColumn (formatloc, code - ocode);
1485 codetext = cstring_appendChar (codetext, key);
1487 /* ignore flags */
1488 while (isFlagKey (key))
1490 key = *(++code);
1491 codetext = cstring_appendChar (codetext, key);
1492 fileloc_incColumn (formatloc);
1495 if (key == 'm') /* skipped in syslog */
1497 continue;
1500 /* ignore field width */
1501 while (isdigit ((int) key) != 0)
1503 key = *(++code);
1504 codetext = cstring_appendChar (codetext, key);
1505 fileloc_incColumn (formatloc);
1508 /* ignore precision */
1509 if (key == '.')
1511 key = *(++code);
1512 codetext = cstring_appendChar (codetext, key);
1513 fileloc_incColumn (formatloc);
1516 ** In printf, '*' means: read the next arg as an int for the
1517 ** field width. This seems to be missing from my copy of the
1518 ** standard x3.159-1989. Setion 4.9.6.1 refers to * (described
1519 ** later) but never does.
1522 if (key == '*')
1524 ; /* don't do anything --- handle later */
1526 else
1528 while (isdigit ((int) key) != 0)
1530 key = *(++code);
1531 codetext = cstring_appendChar (codetext, key);
1532 fileloc_incColumn (formatloc);
1537 if (key == 'h')
1539 modtype = ctype_sint; /* short */
1540 key = *(++code);
1541 codetext = cstring_appendChar (codetext, key);
1542 fileloc_incColumn (formatloc);
1544 else if (key == 'l' || key == 'L')
1546 modtype = ctype_lint; /* long */
1547 key = *(++code);
1548 codetext = cstring_appendChar (codetext, key);
1549 fileloc_incColumn (formatloc);
1551 if (key == 'l' || key == 'L') {
1552 modtype = ctype_llint; /* long long */
1553 key = *(++code);
1554 codetext = cstring_appendChar (codetext, key);
1555 fileloc_incColumn (formatloc);
1558 else
1560 ; /* no modifier */
1563 /* now, key = type of conversion to apply */
1564 ++code;
1565 fileloc_incColumn (formatloc);
1567 if (key != '%')
1569 if (i >= nargs)
1571 if (optgenerror
1572 (FLG_TYPE,
1573 message ("No argument corresponding to %q format "
1574 "code %d (%%%s): \"%s\"",
1575 uentry_getName (fcn),
1576 i, codetext,
1577 cstring_fromChars (format)),
1578 f->loc))
1580 if (fileloc_isDefined (formatloc)
1581 && context_getFlag (FLG_SHOWCOL))
1583 llgenindentmsg (cstring_makeLiteral ("Corresponding format code"),
1584 formatloc);
1587 i++;
1589 else
1591 a = exprNodeList_getN (args, i);
1592 i++;
1594 if (!exprNode_isError (a))
1596 ctype expecttype;
1598 switch (key)
1600 case '*': /* int argument for fieldwidth */
1601 expecttype = ctype_int;
1602 *(--code) = '%'; /* convert it for next code */
1603 fileloc_subColumn (formatloc, 1);
1604 /*@switchbreak@*/ break;
1605 case 'u':
1606 case 'o':
1607 expecttype = ctype_combine (ctype_uint, modtype);
1608 /*@switchbreak@*/ break;
1610 case 'i': /* int argument */
1611 case 'd':
1612 expecttype = ctype_combine (ctype_int, modtype);
1613 /*@switchbreak@*/ break;
1615 case 'x': /* unsigned int */
1616 case 'X':
1617 expecttype = ctype_combine (ctype_uint, modtype);
1619 /*@switchbreak@*/ break;
1621 case 'e':
1622 case 'E':
1623 case 'g':
1624 case 'G':
1625 case 'f': /* double */
1626 expecttype = ctype_combine (ctype_double, modtype);
1627 /*@switchbreak@*/ break;
1629 case 'c': /* int converted to char (check its a char?) */
1630 expecttype = ctype_makeConj (ctype_int,
1631 ctype_makeConj (ctype_char,
1632 ctype_uchar));
1633 /* evans 2001-10-05 - changed to reflect correct ISO spec:
1634 int converted to char */
1636 /*@switchbreak@*/ break;
1638 case 's': /* string */
1639 expecttype = ctype_string;
1640 /*@switchbreak@*/ break;
1641 case '[':
1642 /* skip to ']' */
1643 while (((key = *(++code)) != ']')
1644 && (key != '\0'))
1646 codetext = cstring_appendChar (codetext, key);
1647 fileloc_incColumn (formatloc);
1650 if (key == '\0')
1652 llfatalerrorLoc
1653 (message ("Bad character set format: %s",
1654 cstring_fromChars (origcode)));
1657 expecttype = ctype_string;
1658 /*@switchbreak@*/ break;
1660 case 'p': /* pointer */
1661 expecttype = ctype_makePointer (ctype_void);
1662 /* need not be defined */
1663 uentry_setDefState (regArg, SS_RELDEF);
1664 sRef_setPosNull (uentry_getSref (regArg),
1665 fileloc_undefined);
1666 /* could be null */
1667 /*@switchbreak@*/ break;
1669 case 'n': /* pointer to int, modified by call! */
1670 expecttype = ctype_combine (ctype_makePointer (ctype_int), modtype);
1671 modified = TRUE;
1672 uentry_setDefState (regArg, SS_ALLOCATED); /* corresponds to out */
1673 /*@switchbreak@*/ break;
1675 case 'm': /* in a syslog, it doesn't consume an argument */
1676 /* should check we're really doing syslog */
1678 /*@switchbreak@*/ break;
1681 default:
1682 expecttype = ctype_unknown;
1684 voptgenerror
1685 (FLG_FORMATCODE,
1686 message ("Unrecognized format code: %s",
1687 cstring_fromChars (origcode)),
1688 fileloc_isDefined (formatloc)
1689 ? formatloc : g_currentloc);
1691 /*@switchbreak@*/ break;
1694 if (!(exprNode_matchArgType (expecttype, a)))
1696 if (ctype_isVoidPointer (expecttype)
1697 && ctype_isRealAbstract (a->typ)
1698 && (context_getFlag (FLG_ABSTVOIDP)))
1702 else
1704 if (llgenformattypeerror
1705 (expecttype, exprNode_undefined,
1706 a->typ, a,
1707 message ("Format argument %d to %q (%%%s) expects "
1708 "%t gets %t: %s",
1709 i - argno,
1710 uentry_getName (fcn),
1711 codetext,
1712 expecttype,
1713 a->typ, exprNode_unparse (a)),
1714 a->loc))
1716 if (fileloc_isDefined (formatloc)
1717 && context_getFlag (FLG_SHOWCOL))
1719 llgenindentmsg
1720 (cstring_makeLiteral
1721 ("Corresponding format code"),
1722 formatloc);
1728 uentry_setType (regArg, expecttype);
1729 checkOneArg (regArg, a, f, FALSE, i+1, nargs);
1731 if (ctype_equal (expecttype, ctype_string))
1733 exprNode_checkUse (a, sRef_makePointer (a->sref), a->loc);
1736 uentry_setType (regArg, ctype_unknown);
1737 uentry_fixupSref (regArg);
1739 if (modified)
1741 exprNode_checkCallModifyVal (a->sref, args, f, ret);
1744 else
1751 ocode = code;
1752 cstring_free (codetext);
1755 if (i < nargs)
1757 voptgenerror (FLG_TYPE,
1758 message ("Format string for %q has %d arg%&, given %d",
1759 uentry_getName (fcn), i - argno, nargs - argno),
1760 f->loc);
1763 else
1765 /* no checking possible for compile-time unknown format strings */
1766 if (exprNode_isDefined (a))
1768 voptgenerror
1769 (FLG_FORMATCONST,
1770 message ("Format string parameter to %s is not a compile-time constant: %s",
1771 exprNode_unparse (f),
1772 exprNode_unparse (a)),
1773 f->loc);
1777 fileloc_free (formatloc);
1780 static void
1781 checkScanfArgs (/*@notnull@*/ /*@dependent@*/ exprNode f, uentry fcn,
1782 exprNodeList args, exprNode ret, int argno)
1784 int i = argno;
1785 fileloc formatloc;
1786 uentryList params = uentry_getParams (fcn);
1787 exprNode a;
1790 ** These should be ensured by checkSpecialFunction
1793 llassert (uentryList_size (params) == argno + 1);
1794 llassert (uentry_isElipsisMarker (uentryList_getN (params, argno)));
1796 a = exprNodeList_getN (args, argno - 1);
1797 formatloc = fileloc_copy (exprNode_loc (a));
1799 if (exprNode_isDefined (a) && exprNode_isStringLiteral (a)
1800 && exprNode_knownStringValue (a))
1802 char *format = cstring_toCharsSafe (multiVal_forceString (exprNode_getValue (a)));
1803 char *code = format;
1804 char *ocode = code;
1805 int nargs = exprNodeList_size (args);
1807 while ((code = strchr (code, '%')) != NULL)
1809 char *origcode = code;
1810 char key = *(++code);
1811 cstring codetext = cstring_newEmpty ();
1812 ctype modtype = ctype_int;
1813 char modifier = '\0';
1814 bool modified = TRUE;
1815 bool ignore = FALSE;
1817 codetext = cstring_appendChar (codetext, key);
1818 fileloc_addColumn (formatloc, code - ocode);
1821 ** this is based on ANSI standard library description of fscanf
1822 ** (from ANSI standard X3.159-1989, 4.9.6.1)
1825 /* '*' suppresses assignment (does not need match argument) */
1827 if (key == '*')
1829 key = *(++code);
1830 codetext = cstring_appendChar (codetext, key);
1831 modified = FALSE;
1832 ignore = TRUE;
1833 fileloc_incColumn (formatloc);
1836 /* ignore field width */
1837 while (isdigit ((int) key) != 0)
1839 key = *(++code);
1840 codetext = cstring_appendChar (codetext, key);
1841 fileloc_incColumn (formatloc);
1844 if (key == 'h')
1846 modtype = ctype_sint; /* short */
1847 key = *(++code);
1848 codetext = cstring_appendChar (codetext, key);
1849 fileloc_incColumn (formatloc);
1851 else if (key == 'l' || key == 'L')
1853 modtype = ctype_lint; /* long */
1854 modifier = key;
1856 key = *(++code);
1857 codetext = cstring_appendChar (codetext, key);
1859 fileloc_incColumn (formatloc);
1861 if (key == 'l' || key == 'L') {
1862 modtype = ctype_llint; /* long long */
1863 key = *(++code);
1864 codetext = cstring_appendChar (codetext, key);
1865 fileloc_incColumn (formatloc);
1868 else
1870 ; /* no modifier */
1873 /* now, key = type of conversion to apply */
1874 ++code;
1875 fileloc_incColumn (formatloc);
1877 if (key != '%')
1879 if (ignore)
1883 else
1885 if (i >= nargs)
1887 if (optgenerror
1888 (FLG_TYPE,
1889 message ("No argument corresponding to %q format "
1890 "code %d (%%%s): \"%s\"",
1891 uentry_getName (fcn),
1892 i, codetext,
1893 cstring_fromChars (format)),
1894 f->loc))
1896 if (fileloc_isDefined (formatloc)
1897 && context_getFlag (FLG_SHOWCOL))
1899 llgenindentmsg
1900 (cstring_makeLiteral ("Corresponding format code"),
1901 formatloc);
1904 i++;
1906 else
1908 a = exprNodeList_getN (args, i);
1909 i++;
1911 if (!exprNode_isError (a))
1913 ctype expecttype;
1915 switch (key)
1917 case '*': /* int argument for fieldwidth */
1918 expecttype = ctype_makePointer (ctype_int);
1919 *(--code) = '%'; /* convert it for next code */
1920 fileloc_subColumn (formatloc, 1);
1921 /*@switchbreak@*/ break;
1922 case 'u':
1923 case 'o':
1924 expecttype = ctype_makePointer (ctype_combine (ctype_uint, modtype));
1925 /*@switchbreak@*/ break;
1927 case 'i':
1928 case 'd':
1929 expecttype = ctype_makePointer (ctype_combine (ctype_int, modtype));
1930 /*@switchbreak@*/ break;
1932 case 'x':
1933 case 'X': /* unsigned int */
1934 expecttype = ctype_makePointer (ctype_combine (ctype_uint, modtype));
1935 /*@switchbreak@*/ break;
1937 case 'e':
1938 case 'E':
1939 case 'g':
1940 case 'G':
1941 case 'f':
1942 /* printf is double, scanf is float! */
1944 if (modifier == 'l')
1946 expecttype = ctype_makePointer (ctype_double);
1948 else if (modifier == 'L')
1950 expecttype = ctype_makePointer (ctype_ldouble);
1952 else
1954 llassert (modifier == '\0');
1955 expecttype = ctype_makePointer (ctype_float);
1957 /*@switchbreak@*/ break;
1959 case 'c': /* int converted to char (check its a char?) */
1960 expecttype = ctype_makePointer (ctype_makeConj (ctype_char, ctype_uchar));
1961 /*@switchbreak@*/ break;
1963 case 's': /* string */
1964 expecttype = ctype_string;
1965 /*@switchbreak@*/ break;
1967 case '[':
1968 /* skip to ']' */
1969 while (((key = *(++code)) != ']')
1970 && (key != '\0'))
1972 codetext = cstring_appendChar (codetext, key);
1973 fileloc_incColumn (formatloc);
1976 if (key == '\0')
1978 llfatalerrorLoc
1979 (message ("Bad character set format: %s",
1980 cstring_fromChars (origcode)));
1983 expecttype = ctype_string;
1984 /*@switchbreak@*/ break;
1987 case 'p': /* pointer */
1988 voptgenerror
1989 (FLG_FORMATCODE,
1990 message ("Format code should not be used in scanf: %s",
1991 cstring_fromChars (origcode)),
1992 fileloc_isDefined (formatloc)
1993 ? formatloc : g_currentloc);
1995 expecttype = ctype_unknown;
1996 /*@switchbreak@*/ break;
1998 case 'n': /* pointer to int, modified by call! */
1999 expecttype = ctype_makePointer (ctype_int);
2000 /*@switchbreak@*/ break;
2002 default:
2003 expecttype = ctype_unknown;
2005 voptgenerror
2006 (FLG_FORMATCODE,
2007 message ("Unrecognized format code: %s",
2008 cstring_fromChars (origcode)),
2009 fileloc_isDefined (formatloc)
2010 ? formatloc : g_currentloc);
2012 /*@switchbreak@*/ break;
2015 if (!(exprNode_matchArgType (expecttype, a)))
2017 if (ctype_isVoidPointer (expecttype)
2018 && ctype_isRealAbstract (a->typ)
2019 && (context_getFlag (FLG_ABSTVOIDP)))
2023 else
2025 if (llgenformattypeerror
2026 (expecttype, exprNode_undefined,
2027 a->typ, a,
2028 message ("Format argument %d to %q (%%%s) expects "
2029 "%t gets %t: %s",
2030 i - argno,
2031 uentry_getName (fcn),
2032 codetext, expecttype,
2033 a->typ, exprNode_unparse (a)),
2034 a->loc))
2036 if (fileloc_isDefined (formatloc)
2037 && context_getFlag (FLG_SHOWCOL))
2039 llgenindentmsg
2040 (cstring_makeLiteral
2041 ("Corresponding format code"),
2042 formatloc);
2048 uentry_setType (outArg, expecttype);
2049 checkOneArg (outArg, a, f, FALSE, i+1, nargs);
2050 uentry_setType (outArg, ctype_unknown);
2051 uentry_fixupSref (outArg);
2053 if (modified)
2055 exprNode_checkCallModifyVal (a->sref, args, f, ret);
2058 else
2060 /* a->sref = sRef_undefined; */
2066 ocode = code;
2067 cstring_free (codetext);
2070 if (i < nargs)
2072 voptgenerror (FLG_TYPE,
2073 message ("Format string for %q has %d arg%&, given %d",
2074 uentry_getName (fcn), i - argno, nargs - argno),
2075 f->loc);
2078 else
2080 /* no checking possible for compile-time unknown format strings */
2083 fileloc_free (formatloc);
2086 static void
2087 checkMessageArgs (/*@notnull@*/ /*@dependent@*/ exprNode f,
2088 uentry fcn,
2089 exprNodeList args,
2090 /*@unused@*/ int argno)
2093 ** the last argument before the elips is the format string
2096 int i = argno;
2097 fileloc formatloc;
2098 exprNode a;
2100 a = exprNodeList_getN (args, argno - 1);
2101 formatloc = fileloc_copy (exprNode_loc (a));
2103 if (ctype_isUnknown (cstringType)) {
2104 if (usymtab_existsType (cstring_makeLiteralTemp ("cstring")))
2106 cstringType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("cstring"));
2110 if (ctype_isUnknown (ctypeType)) {
2111 if (usymtab_existsType (cstring_makeLiteralTemp ("ctype")))
2113 ctypeType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("ctype"));
2117 if (ctype_isUnknown (filelocType)) {
2118 if (usymtab_existsType (cstring_makeLiteralTemp ("fileloc")))
2120 filelocType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("fileloc"));
2124 if (exprNode_isDefined (a) && exprNode_isStringLiteral (a)
2125 && exprNode_knownStringValue (a))
2127 cstring format = multiVal_forceString (exprNode_getValue (a));
2128 char *code = cstring_toCharsSafe (format);
2129 char *ocode = code;
2130 int nargs = exprNodeList_size (args);
2132 while ((code = strchr (code, '%')) != NULL)
2134 char *origcode = code;
2135 char key = *(++code);
2136 cstring codetext = cstring_newEmpty ();
2137 bool isOnly = FALSE;
2139 codetext = cstring_appendChar (codetext, key);
2141 fileloc_addColumn (formatloc, code - ocode);
2143 while (key >= '0' && key <= '9')
2145 key = *(++code);
2146 codetext = cstring_appendChar (codetext, key);
2147 fileloc_incColumn (formatloc);
2150 ++code;
2151 fileloc_incColumn (formatloc);
2153 if (key != '%')
2155 if (key == '&') /* plural marker */
2157 goto nextKey;
2160 if (i >= nargs)
2162 voptgenerror
2163 (FLG_TYPE,
2164 message ("Message missing format arg %d (%%%s): \"%s\"",
2165 i + 1, codetext, format),
2166 f->loc);
2167 i++;
2169 else
2171 a = exprNodeList_getN (args, i);
2172 i++;
2174 nextKey:
2175 if (!exprNode_isError (a))
2177 ctype expecttype;
2179 /*@-loopswitchbreak@*/
2181 switch (key)
2183 case 'c':
2184 case 'h':
2185 expecttype = ctype_char; break;
2186 case 's':
2187 expecttype = cstringType; break;
2188 case 'q':
2189 expecttype = cstringType; isOnly = TRUE; break;
2190 case 'x':
2191 expecttype = cstringType; isOnly = TRUE; break;
2192 case 'd': expecttype = ctype_int; break;
2193 case 'u': expecttype = ctype_uint; break;
2194 case 'w': expecttype = ctype_ulint; break;
2195 case 'f': expecttype = ctype_float; break;
2196 case 'b': expecttype = ctype_bool; break;
2197 case 't': expecttype = ctypeType; break;
2198 case 'p':
2199 expecttype = ctype_makePointer (ctype_void);
2200 /* need not be defined */
2201 uentry_setDefState (regArg, SS_RELDEF);
2202 sRef_setPosNull (uentry_getSref (regArg),
2203 fileloc_undefined);
2204 /* could be null */
2205 /*@switchbreak@*/ break;
2206 case 'l': expecttype = filelocType; break;
2207 case '&': /* a wee bit of a hack methinks */
2208 expecttype = ctype_int;
2209 break;
2210 case 'r': expecttype = ctype_bool; break;
2211 default:
2212 expecttype = ctype_unknown;
2213 voptgenerror
2214 (FLG_FORMATCODE,
2215 message ("Unrecognized format code: %s",
2216 cstring_fromChars (origcode)),
2217 fileloc_isDefined (formatloc)
2218 ? formatloc : g_currentloc);
2219 break;
2221 /*@=loopswitchbreak@*/
2223 if (!(exprNode_matchArgType (expecttype, a)))
2225 if (ctype_isVoidPointer (expecttype)
2226 && ctype_isRealAbstract (a->typ)
2227 && (context_getFlag (FLG_ABSTVOIDP)))
2231 else
2233 if (llgenformattypeerror
2234 (expecttype, exprNode_undefined,
2235 a->typ, a,
2236 message ("Format argument %d to %q (%%%s) expects "
2237 "%t gets %t: %s",
2238 i - argno,
2239 uentry_getName (fcn),
2240 codetext, expecttype,
2241 a->typ, exprNode_unparse (a)),
2242 a->loc))
2244 if (fileloc_isDefined (formatloc)
2245 && context_getFlag (FLG_SHOWCOL))
2247 llgenindentmsg
2248 (cstring_makeLiteral
2249 ("Corresponding format code"),
2250 formatloc);
2256 if (ctype_equal (expecttype, cstringType))
2258 if (isOnly)
2260 checkOneArg (csOnlyArg, a, f, FALSE, i+1, nargs);
2261 uentry_fixupSref (csOnlyArg);
2263 else
2265 checkOneArg (csArg, a, f, FALSE, i+1, nargs);
2266 uentry_fixupSref (csArg);
2269 else
2271 checkOneArg (regArg, a, f, FALSE, i+1, nargs);
2272 uentry_fixupSref (regArg);
2278 cstring_free (codetext);
2281 if (i < nargs)
2283 voptgenerror (FLG_TYPE,
2284 message ("Format string for %q has %d arg%&, given %d",
2285 uentry_getName (fcn), i - argno, nargs -argno),
2286 f->loc);
2289 else
2291 /* no checking possible for compile-time unknown format strings */
2294 fileloc_free (formatloc);
2297 static void
2298 checkExpressionDefinedAux (/*@notnull@*/ exprNode e1,
2299 /*@notnull@*/ exprNode e2,
2300 sRefSet sets1,
2301 sRefSet sets2,
2302 lltok op,
2303 flagcode flag)
2305 bool hadUncon = FALSE;
2307 if (sRef_isFileOrGlobalScope (sRef_getRootBase (e1->sref)) &&
2308 sRefSet_hasUnconstrained (sets2))
2310 voptgenerror
2311 (FLG_EVALORDERUNCON,
2312 message
2313 ("Expression may have undefined behavior (%q used in right operand "
2314 "may set global variable %q used in left operand): %s %s %s",
2315 sRefSet_unparseUnconstrained (sets2),
2316 sRef_unparse (sRef_getRootBase (e1->sref)),
2317 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
2318 e2->loc);
2321 if (sRef_isFileOrGlobalScope (sRef_getRootBase (e2->sref)) &&
2322 sRefSet_hasUnconstrained (sets1))
2324 voptgenerror
2325 (FLG_EVALORDERUNCON,
2326 message
2327 ("Expression has undefined behavior (%q used in left operand "
2328 "may set global variable %q used in right operand): %s %s %s",
2329 sRefSet_unparseUnconstrained (sets1),
2330 sRef_unparse (e2->sref),
2331 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
2332 e2->loc);
2335 sRefSet_realElements (e1->uses, sr)
2337 if (sRef_isMeaningful (sr) && sRefSet_member (sets2, sr))
2339 voptgenerror
2340 (FLG_EVALORDER,
2341 message
2342 ("Expression has undefined behavior (left operand uses %q, "
2343 "modified by right operand): %s %s %s",
2344 sRef_unparse (sr),
2345 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
2346 e2->loc);
2348 } end_sRefSet_realElements;
2350 sRefSet_realElements (sets1, sr)
2352 if (sRef_isMeaningful (sr))
2354 if (sRef_same (sr, e2->sref))
2356 voptgenerror
2357 (flag,
2358 message
2359 ("Expression has undefined behavior (value of right operand "
2360 "modified by left operand): %s %s %s",
2361 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
2362 e2->loc);
2364 else if (sRefSet_member (e2->uses, sr))
2366 voptgenerror
2367 (flag,
2368 message
2369 ("Expression has undefined behavior (left operand modifies %q, "
2370 "used by right operand): %s %s %s",
2371 sRef_unparse (sr),
2372 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
2373 e2->loc);
2375 else
2377 if (sRefSet_member (sets2, sr))
2379 if (sRef_isUnconstrained (sr))
2381 if (hadUncon)
2385 else
2387 hadUncon = optgenerror
2388 (FLG_EVALORDERUNCON,
2389 message
2390 ("Expression may have undefined behavior. Left operand "
2391 "calls %q; right operand calls %q. The unconstrained "
2392 "functions may modify global state used by "
2393 "the other operand): %s %s %s",
2394 sRefSet_unparseUnconstrained (sets1),
2395 sRefSet_unparseUnconstrained (sets2),
2396 exprNode_unparse (e1), lltok_unparse (op),
2397 exprNode_unparse (e2)),
2398 e2->loc);
2401 else
2403 voptgenerror
2404 (flag,
2405 message
2406 ("Expression has undefined behavior (both "
2407 "operands modify %q): %s %s %s",
2408 sRef_unparse (sr),
2409 exprNode_unparse (e1),
2410 lltok_unparse (op), exprNode_unparse (e2)),
2411 e2->loc);
2416 } end_sRefSet_realElements;
2419 static void checkExpressionDefined (exprNode e1, exprNode e2, lltok op)
2421 bool hasError = FALSE;
2423 if (exprNode_isError (e1) || exprNode_isError (e2))
2425 return;
2428 if (sRefSet_member (e2->sets, e1->sref))
2430 if (e2->kind == XPR_CALL)
2434 else
2436 hasError = optgenerror
2437 (FLG_EVALORDER,
2438 message ("Expression has undefined behavior "
2439 "(value of left operand %s is modified "
2440 "by right operand %s): %s %s %s",
2441 exprNode_unparse (e1),
2442 exprNode_unparse (e2),
2443 exprNode_unparse (e1), lltok_unparse (op),
2444 exprNode_unparse (e2)),
2445 e2->loc);
2449 if (context_getFlag (FLG_EVALORDERUNCON))
2451 if (sRefSet_member (e2->msets, e1->sref))
2453 if (e2->kind == XPR_CALL)
2457 else
2459 hasError = optgenerror
2460 (FLG_EVALORDER,
2461 message
2462 ("Expression has undefined behavior (value of left "
2463 "operand may be modified by right operand): %s %s %s",
2464 exprNode_unparse (e1), lltok_unparse (op),
2465 exprNode_unparse (e2)),
2466 e2->loc);
2471 if (!hasError)
2473 checkExpressionDefinedAux (e1, e2, e1->sets, e2->sets, op, FLG_EVALORDER);
2475 if (context_maybeSet (FLG_EVALORDERUNCON))
2477 checkExpressionDefinedAux (e1, e2, e1->msets,
2478 e2->msets, op, FLG_EVALORDERUNCON);
2483 static void checkSequencing (exprNode p_f, exprNodeList p_args);
2485 static int
2486 checkArgsReal (uentry fcn, /*@dependent@*/ exprNode f, uentryList cl,
2487 exprNodeList args, bool isIter, exprNode ret)
2489 int special = 0;
2491 if (!exprNode_isError (f))
2493 if (!uentryList_isMissingParams (cl))
2495 int nargs = exprNodeList_size (args);
2496 int expectargs = uentryList_size (cl);
2497 ctype last;
2498 int i = 0;
2500 if (expectargs == 0)
2502 if (nargs != 0)
2504 if (isIter)
2506 voptgenerror
2507 (FLG_TYPE,
2508 message ("Iter %q invoked with %d args, "
2509 "declared void",
2510 uentry_getName (fcn),
2511 nargs),
2512 f->loc);
2514 else
2516 voptgenerror
2517 (FLG_TYPE,
2518 message ("Function %s called with %d args, "
2519 "declared void",
2520 exprNode_unparse (f), nargs),
2521 f->loc);
2524 return special;
2527 last = uentry_getType (uentryList_getN (cl, expectargs - 1));
2529 exprNodeList_reset (args);
2531 uentryList_elements (cl, current)
2533 ctype ct = uentry_getType (current);
2534 exprNode a;
2536 if (ctype_isElips (ct))
2539 ** do special checking for printf/scanf library functions
2541 ** this is kludgey code, just for handling the special case
2545 if (uentry_isPrintfLike (fcn))
2547 checkPrintfArgs (f, fcn, args, ret, i);
2548 special = i;
2550 else if (uentry_isScanfLike (fcn))
2552 checkScanfArgs (f, fcn, args, ret, i);
2553 special = i;
2555 else if (uentry_isMessageLike (fcn))
2557 checkMessageArgs (f, fcn, args, i);
2558 special = i;
2560 else
2562 llassert (!uentry_isSpecialFunction (fcn));
2565 nargs = expectargs; /* avoid errors */
2566 break;
2568 else
2570 if (i >= nargs) break;
2572 a = exprNodeList_current (args);
2573 exprNodeList_advance (args);
2575 i++;
2577 if (exprNode_isError (a))
2581 else
2584 probably necessary? I'm not sure about this one
2585 checkMacroParen (a);
2588 f->guards = guardSet_union (f->guards, a->guards);
2590 DPRINTF (("match arg: %s / %s", ctype_unparse (ct), ctype_unparse (a->typ)));
2592 if (!(exprNode_matchArgType (ct, a)))
2594 DPRINTF (("Args mismatch!"));
2596 if (ctype_isVoidPointer (ct)
2597 && (ctype_isPointer (a->typ)
2598 && (ctype_isRealAbstract (ctype_baseArrayPtr (a->typ)))))
2600 vnoptgenerror
2601 (FLG_ABSTVOIDP,
2602 message
2603 ("Pointer to abstract type (%t) used "
2604 "as void pointer "
2605 "(arg %d to %q): %s",
2606 a->typ, i,
2607 uentry_getName (fcn),
2608 exprNode_unparse (a)),
2609 a->loc);
2611 else
2613 if (isIter)
2615 (void) gentypeerror
2616 (ct, exprNode_undefined,
2617 a->typ, a,
2618 message
2619 ("Iter %q expects arg %d to "
2620 "be %t gets %t: %s",
2621 uentry_getName (fcn),
2622 i, ct, a->typ, exprNode_unparse (a)),
2623 a->loc);
2625 else
2627 if (gentypeerror
2628 (ct,
2629 exprNode_undefined,
2630 a->typ,
2632 message
2633 ("Function %q expects arg %d to be %t gets %t: %s",
2634 uentry_getName (fcn),
2635 i, ct, a->typ, exprNode_unparse (a)),
2636 a->loc))
2638 DPRINTF (("Types: %s / %s",
2639 ctype_unparse (ct),
2640 ctype_unparse (a->typ)));
2644 ** Clear null marker for abstract types.
2645 ** (It is not revealed, so suppress future messages.)
2648 if (ctype_isAbstract (a->typ))
2650 sRef_setNullUnknown (exprNode_getSref (a), a->loc);
2657 } end_uentryList_elements ;
2660 if (expectargs != nargs) /* note: not != since we may have ... */
2662 if (ctype_isElips (last))
2664 voptgenerror
2665 (FLG_TYPE,
2666 message ("Function %s called with %d args, expects at least %d",
2667 exprNode_unparse (f),
2668 nargs, expectargs - 1),
2669 f->loc);
2671 else
2673 if (isIter)
2675 voptgenerror
2676 (FLG_TYPE,
2677 message ("Iter %q invoked with %d args, expects %d",
2678 uentry_getName (fcn), nargs, expectargs),
2679 f->loc);
2681 else
2683 voptgenerror
2684 (FLG_TYPE,
2685 message ("Function %s called with %d args, expects %d",
2686 exprNode_unparse (f),
2687 nargs, expectargs),
2688 f->loc);
2695 return special;
2699 ** Check for undefined code sequences in function arguments:
2701 ** one parameter sets something used by another parameter
2702 ** one parameter sets something set by another parameter
2705 static void
2706 checkSequencingOne (exprNode f, exprNodeList args,
2707 /*@notnull@*/ exprNode el, int argno)
2710 ** Do second loop, iff +undefunspec
2713 int checkloop;
2714 int numloops = context_maybeSet (FLG_EVALORDERUNCON) ? 2 : 1;
2716 for (checkloop = 0; checkloop < numloops; checkloop++)
2718 sRefSet thissets;
2720 if (checkloop == 0)
2722 thissets = el->sets;
2724 else
2726 llassert (checkloop == 1);
2727 thissets = el->msets;
2730 sRefSet_realElements (thissets, thisset)
2732 int j;
2734 /*@access exprNodeList@*/
2735 for (j = 0; j < args->nelements; j++)
2737 exprNode jl = args->elements[j];
2738 int thisargno = j + 1;
2740 if (thisargno != argno && exprNode_isDefined (jl))
2742 sRefSet otheruses = jl->uses;
2744 if (sRef_isFileOrGlobalScope (sRef_getRootBase (jl->sref)) &&
2745 sRefSet_hasUnconstrained (thissets))
2747 voptgenerror
2748 (FLG_EVALORDERUNCON,
2749 /*@-sefparams@*/
2750 message
2751 ("%q used in argument %d may set "
2752 "global variable %q used by argument %d: %s(%q)",
2753 cstring_capitalizeFree (sRefSet_unparseUnconstrained (thissets)),
2754 /*@=sefparams@*/
2755 argno,
2756 sRef_unparse (sRef_getRootBase (jl->sref)),
2757 thisargno,
2758 exprNode_unparse (f), exprNodeList_unparse (args)),
2759 el->loc);
2762 if (sRefSet_member (otheruses, thisset))
2764 if (sRef_isUnconstrained (thisset))
2766 voptgenerror
2767 (FLG_EVALORDERUNCON,
2768 message
2769 ("Unconstrained functions used in arguments %d (%q) "
2770 "and %d (%s) may modify "
2771 "or use global state in undefined way: %s(%q)",
2772 argno,
2773 sRefSet_unparseUnconstrainedPlain (otheruses),
2774 thisargno,
2775 sRef_unconstrainedName (thisset),
2776 exprNode_unparse (f),
2777 exprNodeList_unparse (args)),
2778 el->loc);
2780 else
2782 voptgenerror
2783 (FLG_EVALORDER,
2784 message
2785 ("Argument %d modifies %q, used by argument %d "
2786 "(order of evaluation of actual parameters is "
2787 "undefined): %s(%q)",
2788 argno, sRef_unparse (thisset), thisargno,
2789 exprNode_unparse (f), exprNodeList_unparse (args)),
2790 el->loc);
2793 else
2795 sRefSet othersets = jl->sets;
2797 if (sRefSet_member (othersets, thisset))
2799 if (sRef_isUnconstrained (thisset))
2801 voptgenerror
2802 (FLG_EVALORDERUNCON,
2803 message
2804 ("Unconstrained functions used in "
2805 "arguments %d (%q) and %d (%s) may modify "
2806 "or use global state in undefined way: %s(%q)",
2807 argno,
2808 sRefSet_unparseUnconstrainedPlain (othersets),
2809 thisargno,
2810 sRef_unconstrainedName (thisset),
2811 exprNode_unparse (f), exprNodeList_unparse (args)),
2812 el->loc);
2814 else
2816 voptgenerror
2817 (FLG_EVALORDER,
2818 message
2819 ("Argument %d modifies %q, set by argument %d (order of"
2820 " evaluation of actual parameters is undefined): %s(%q)",
2821 argno, sRef_unparse (thisset), thisargno,
2822 exprNode_unparse (f), exprNodeList_unparse (args)),
2823 el->loc);
2829 /*@noaccess exprNodeList@*/
2830 } end_sRefSet_realElements;
2834 static void
2835 checkSequencing (exprNode f, exprNodeList args)
2837 if (exprNodeList_size (args) > 1)
2839 int i;
2840 exprNode el;
2842 /*@access exprNodeList*/
2844 for (i = 0; i < args->nelements; i++)
2846 el = args->elements[i];
2848 if (!exprNode_isError (el))
2850 checkSequencingOne (f, args, el, i + 1);
2853 /*@noaccess exprNodeList*/
2858 ** requires le = exprNode_getUentry (f)
2861 static void
2862 checkGlobMods (/*@notnull@*/ /*@dependent@*/ exprNode f,
2863 uentry le, exprNodeList args,
2864 /*@notnull@*/ exprNode ret, int specialArgs)
2866 bool isSpec = FALSE;
2867 bool hasMods = FALSE;
2868 cstring fname;
2869 globSet usesGlobs = globSet_undefined;
2870 sRefSet mods = sRefSet_undefined;
2871 bool freshMods = FALSE;
2872 uentryList params = uentryList_undefined;
2874 DPRINTF (("Check glob mods: %s", exprNode_unparse (ret)));
2877 ** check globals and modifies
2880 setCodePoint ();
2882 if (!uentry_isValid (le))
2884 ctype fr = ctype_realType (f->typ);
2886 if (ctype_isFunction (fr))
2888 params = ctype_argsFunction (fr);
2890 else
2892 params = uentryList_missingParams;
2895 if (!context_getFlag (FLG_MODNOMODS)
2896 && !context_getFlag (FLG_GLOBUNSPEC))
2898 checkUnspecCall (f, params, args);
2901 return;
2904 fname = uentry_rawName (le);
2906 setCodePoint ();
2908 if (uentry_isFunction (le))
2910 params = uentry_getParams (le);
2911 mods = uentry_getMods (le);
2912 hasMods = uentry_hasMods (le);
2913 usesGlobs = uentry_getGlobs (le);
2914 isSpec = uentry_isSpecified (le);
2916 else /* not a function */
2918 ctype ct = ctype_realType (uentry_getType (le));
2920 llassertprint (uentry_isVar (le) && ctype_isFunction (ct),
2921 ("checkModGlobs: uentry not a function: %s",
2922 uentry_unparse (le)));
2924 params = ctype_argsFunction (ct);
2925 return; /* No checking for non-function */
2929 ** check globals
2932 setCodePoint ();
2934 globSet_allElements (usesGlobs, el)
2936 if (sRef_isValid (el))
2938 if (sRef_isInternalState (el) || sRef_isSystemState (el))
2940 context_usedGlobal (el);
2941 exprNode_checkUse (f, el, f->loc);
2943 if (context_checkInternalUse ())
2945 if (!context_globAccess (el))
2947 if (sRef_isSystemState (el)
2948 && !context_getFlag (FLG_MODFILESYSTEM))
2952 else
2954 voptgenerror
2955 (FLG_INTERNALGLOBS,
2956 message
2957 ("Called procedure %s may access %q, but "
2958 "globals list does not include globals %s",
2959 exprNode_unparse (f),
2960 sRef_unparse (el),
2961 cstring_makeLiteralTemp (sRef_isInternalState (el)
2962 ? "internalState"
2963 : "fileSystem")),
2964 f->loc);
2969 else if (sRef_isNothing (el) || sRef_isSpecState (el))
2973 else
2975 uentry gle = sRef_getUentry (el);
2976 sRef sr = sRef_updateSref (el);
2978 if (sRef_isUndefGlob (el))
2980 sRef_setDefined (sr, f->loc);
2981 exprNode_checkSet (f, sr);
2983 else
2986 ** check definition
2989 if (sRef_isAllocated (el))
2991 exprNode_checkSet (f, sr);
2993 else
2995 if (sRef_isStateUndefined (sr))
2997 voptgenerror
2998 (FLG_GLOBSTATE,
2999 message
3000 ("%s %q used by function undefined before call: %s",
3001 sRef_getScopeName (sr),
3002 sRef_unparse (sr),
3003 exprNode_unparse (f)),
3004 f->loc);
3005 sRef_setDefined (sr, f->loc);
3007 exprNode_checkUse (f, sr, f->loc);
3010 checkGlobUse (gle, TRUE, f);
3013 if (sRef_isKilledGlob (el))
3015 sRef_kill (sr, f->loc);
3016 context_usedGlobal (sr);
3020 } end_globSet_allElements;
3023 ** check modifies
3026 if (context_hasMods () || context_getFlag (FLG_MODNOMODS))
3028 sRefSet smods = sRefSet_undefined;
3031 ** NEED to check for modifies anything
3035 ** check each sRef that called function modifies (ml), is
3036 ** modifiable by tl
3039 setCodePoint ();
3041 sRefSet_allElements (mods, s) /* s is something which may be modified */
3043 DPRINTF (("Check modify: %s", sRef_unparse (s)));
3045 if (sRef_isKindSpecial (s))
3047 if (sRef_isSpecInternalState (s))
3049 if (context_getFlag (FLG_MODINTERNALSTRICT))
3051 exprNode_checkCallModifyVal (s, args, f, ret);
3053 else
3055 sRefSet mmods = context_modList ();
3057 sRefSet_allElements (mmods, el)
3059 if (sRef_isInternalState (el))
3061 sRef_setModified (el);
3063 } end_sRefSet_allElements ;
3066 else
3068 exprNode_checkCallModifyVal (s, args, f, ret);
3071 else
3073 sRef rb = sRef_getRootBase (s);
3075 if (sRef_isFileOrGlobalScope (rb))
3077 context_usedGlobal (rb);
3080 if (sRef_isFileStatic (s)
3081 && !fileId_equal (fileloc_fileId (f->loc),
3082 fileloc_fileId (uentry_whereDefined (le))))
3084 smods = sRefSet_insert (smods, s);
3086 else
3088 exprNode_checkCallModifyVal (s, args, f, ret);
3091 } end_sRefSet_allElements;
3093 setCodePoint ();
3096 ** Static elements in modifies set can have nasty consequences.
3097 ** (I think...have not been able to reproduce a possible bug.)
3100 if (!sRefSet_isDefined (smods))
3102 mods = sRefSet_newCopy (mods);
3103 freshMods = TRUE;
3105 sRefSet_allElements (smods, el)
3107 bool res = sRefSet_delete (mods, el);
3109 llassert (res);
3110 } end_sRefSet_allElements;
3112 sRefSet_free (smods);
3113 /*@-branchstate@*/
3115 /*@=branchstate@*/
3117 else if (sRefSet_isDefined (mods))
3118 { /* just check observers */
3119 setCodePoint ();
3121 sRefSet_allElements (mods, s) /* s is something which may be modified */
3123 sRef rb = sRef_getRootBase (s);
3125 setCodePoint ();
3127 if (sRef_isParam (rb))
3129 sRef b = sRef_fixBaseParam (s, args);
3131 if (sRef_isObserver (b))
3133 exprNode e = exprNodeList_nth (args, sRef_getParam (rb));
3135 if (optgenerror
3136 (FLG_MODOBSERVER,
3137 message ("Function call may modify observer%q: %s",
3138 sRef_unparsePreOpt (b), exprNode_unparse (e)),
3139 exprNode_loc (e)))
3141 sRef_showExpInfo (b);
3145 } end_sRefSet_allElements;
3147 else
3149 if (!hasMods) /* no specified modifications */
3151 if (context_getFlag (FLG_MODOBSERVERUNCON))
3153 exprNodeList_elements (args, e)
3155 if (exprNode_isDefined (e))
3157 sRef s = exprNode_getSref (e);
3159 if (sRef_isObserver (s)
3160 && ctype_isMutable (sRef_getType (s)))
3162 if (optgenerror
3163 (FLG_MODOBSERVERUNCON,
3164 message
3165 ("Call to unconstrained function %s may modify observer%q: %s",
3166 exprNode_unparse (f),
3167 sRef_unparsePreOpt (s), exprNode_unparse (e)),
3168 exprNode_loc (e)))
3170 sRef_showExpInfo (s);
3174 } end_exprNodeList_elements;
3179 checkAnyCall (f, fname, params, args, hasMods, mods, isSpec, specialArgs);
3181 ret->uses = sRefSet_union (ret->uses, f->uses);
3182 ret->sets = sRefSet_union (ret->sets, f->sets);
3183 ret->msets = sRefSet_union (ret->msets, f->msets);
3185 if (freshMods)
3188 ** Spurious errors reported, because splint can't tell
3189 ** mods must be fresh if freshMods is true.
3192 /*@i@*/ sRefSet_free (mods);
3195 setCodePoint ();
3198 void checkGlobUse (uentry glob, bool isCall, /*@notnull@*/ exprNode e)
3200 if (uentry_isVar (glob))
3202 if (context_inFunctionLike ())
3204 sRef sr = uentry_getSref (glob);
3206 context_usedGlobal (sr);
3208 if (context_checkGlobUse (glob))
3210 if (!context_globAccess (sr))
3212 if (isCall)
3214 voptgenerror
3215 (FLG_GLOBALS,
3216 message ("Called procedure %s may access %s %q",
3217 exprNode_unparse (e),
3218 sRef_unparseScope (sr),
3219 uentry_getName (glob)),
3220 e->loc);
3222 else
3224 voptgenerror
3225 (FLG_GLOBALS,
3226 message ("Undocumented use of %s %s",
3227 sRef_unparseScope (sr),
3228 exprNode_unparse (e)),
3229 e->loc);
3235 else
3237 llbug (message ("Global not variable: %q", uentry_unparse (glob)));
3241 static void
3242 reflectEnsuresClause (exprNode ret, uentry le, exprNode f, exprNodeList args)
3244 DPRINTF (("Reflect ensures clause: %s(%s) / %s / %s",
3245 exprNode_unparse (f), exprNodeList_unparse (args),
3246 uentry_unparseFull (le),
3247 stateClauseList_unparse (uentry_getStateClauseList (le))));
3249 if (uentry_isValid (le) && uentry_isFunction (le))
3251 stateClauseList sclauses = uentry_getStateClauseList (le);
3253 if (stateClauseList_isDefined (sclauses))
3255 DPRINTF (("Reflect ensures: %s / %s / %s",
3256 uentry_unparse (le),
3257 exprNode_unparse (f), exprNodeList_unparse (args)));
3259 stateClauseList_elements (sclauses, cl)
3261 if (stateClause_hasEnsures (cl))
3263 /* Same in usymtab.c:1904 */
3264 if (stateClause_setsMetaState (cl))
3266 qual q = stateClause_getMetaQual (cl);
3267 annotationInfo ainfo = qual_getAnnotationInfo (q);
3268 metaStateInfo minfo = annotationInfo_getState (ainfo);
3269 cstring key = metaStateInfo_getName (minfo);
3270 int mvalue = annotationInfo_getValue (ainfo);
3272 sRefSet osrs = sRefSet_undefined;
3273 sRefSet srs;
3275 if (stateClause_isGlobal (cl))
3277 srs = sRefSet_single (usymtab_lookupGlobalMarker ());
3278 osrs = srs;
3280 else
3282 srs = stateClause_getRefs (cl);
3285 DPRINTF (("Reflect ensures clause: %s", stateClause_unparse (cl)));
3288 DPRINTF (("Sets meta state! %s", stateClause_unparse (cl)));
3290 sRefSet_elements (srs, sel)
3292 sRef s;
3294 if (sRef_isResult (sRef_getRootBase (sel)))
3296 s = exprNode_getSref (ret);
3298 else
3300 s = sRef_fixBaseParam (sel, args);
3303 DPRINTF (("Reflecting state clause on: %s / %s",
3304 sRef_unparse (sel), sRef_unparse (s)));
3306 sRef_setMetaStateValueComplete (s, key, mvalue, exprNode_loc (f));
3307 } end_sRefSet_elements;
3309 sRefSet_free (osrs);
3311 else
3313 sRefSet srs = stateClause_getRefs (cl);
3314 sRefModVal modf = stateClause_getEnsuresFunction (cl);
3315 int eparam = stateClause_getStateParameter (cl);
3317 llassert (modf != NULL);
3319 DPRINTF (("Reflect after clause: %s / %s",
3320 stateClause_unparse (cl),
3321 sRefSet_unparse (srs)));
3323 sRefSet_elements (srs, sel)
3325 sRef s;
3327 DPRINTF (("elements: %s", sRef_unparse (sel)));
3328 DPRINTF (("elements: %s", sRef_unparseFull (sel)));
3330 if (sRef_isResult (sRef_getRootBase (sel)))
3332 DPRINTF (("Fix base: %s / %s",
3333 sRef_unparse (sel), sRef_unparse (exprNode_getSref (ret))));
3334 s = sRef_fixBase (sel, exprNode_getSref (ret));
3335 DPRINTF (("==> %s", sRef_unparseFull (s)));
3337 else
3339 s = sRef_fixBaseParam (sel, args);
3342 DPRINTF (("elements: %s", sRef_unparse (s)));
3343 DPRINTF (("elements: %s", sRef_unparseFull (s)));
3345 DPRINTF (("Reflecting state clause on: %s / %s",
3346 sRef_unparseFull (sel), sRef_unparseFull (s)));
3348 /* evans 2001-08-24 - added aliasSetCompleteParam */
3349 sRef_aliasSetCompleteParam (modf, s, eparam, exprNode_loc (f));
3351 DPRINTF (("After reflecting state clause on: %s / %s",
3352 sRef_unparseFull (sel), sRef_unparseFull (s)));
3353 } end_sRefSet_elements;
3356 } end_stateClauseList_elements ;
3359 DPRINTF (("Here: %s / %s",
3360 uentry_unparseFull (le),
3361 bool_unparse (uentry_hasMetaStateEnsures (le))));
3363 if (uentry_hasMetaStateEnsures (le))
3365 fileloc loc = exprNode_loc (f);
3367 metaStateConstraintList mscl = uentry_getMetaStateEnsures (le);
3369 metaStateConstraintList_elements (mscl, msc)
3371 metaStateSpecifier msspec = metaStateConstraint_getSpecifier (msc);
3372 metaStateInfo msinfo = metaStateSpecifier_getMetaStateInfo (msspec);
3373 metaStateExpression msexpr = metaStateConstraint_getExpression (msc);
3374 cstring key = metaStateInfo_getName (msinfo);
3375 sRef mlsr = metaStateSpecifier_getSref (msspec);
3376 sRef s;
3377 sRef lastref = sRef_undefined;
3378 stateValue sval = stateValue_undefined;
3380 DPRINTF (("Meta state constraint for %s: %s", uentry_unparse (le),
3381 metaStateConstraint_unparse (msc)));
3382 DPRINTF (("Matches left: %s", sRef_unparseDebug (mlsr)));
3384 if (sRef_isResult (sRef_getRootBase (mlsr)))
3386 s = exprNode_getSref (ret);
3388 else
3390 s = sRef_fixBaseParam (mlsr, args);
3393 DPRINTF (("Setting state: %s", sRef_unparseFull (s)));
3395 while (metaStateExpression_isDefined (msexpr))
3397 metaStateSpecifier ms = metaStateExpression_getSpecifier (msexpr);
3398 metaStateInfo msi = metaStateSpecifier_getMetaStateInfo (ms);
3399 sRef msr, fs;
3401 DPRINTF (("Check expression: %s", metaStateExpression_unparse (msexpr)));
3403 if (metaStateExpression_isMerge (msexpr))
3405 msexpr = metaStateExpression_getRest (msexpr);
3407 else
3409 msexpr = metaStateExpression_undefined;
3412 if (metaStateInfo_isDefined (msi))
3414 /* Must match lhs state */
3415 llassert (metaStateInfo_equal (msinfo, msi));
3418 if (metaStateSpecifier_isElipsis (ms))
3421 ** For elipsis, we need to merge all the relevant elipsis parameters
3425 uentryList params = uentry_getParams (le);
3426 int paramno = uentryList_size (params) - 1;
3428 if (!uentry_isElipsisMarker (uentryList_getN (params, paramno)))
3430 voptgenerror
3431 (FLG_TYPE,
3432 message ("Ensures clauses uses ... for function without ... in parameter list: %q",
3433 uentry_getName (le)),
3434 uentry_whereLast (le));
3435 /*@innerbreak@*/ break;
3438 while (paramno < exprNodeList_size (args))
3440 exprNode arg = exprNodeList_getN (args, paramno);
3441 fs = exprNode_getSref (arg);
3442 DPRINTF (("Merge arg: %s", exprNode_unparse (arg)));
3444 /* cut and pasted... gack*/
3445 if (stateValue_isDefined (sval))
3447 /* Use combination table to merge old state value with new one: */
3448 stateValue tval = sRef_getMetaStateValue (fs, key);
3450 if (stateValue_isDefined (tval))
3452 stateCombinationTable sctable = metaStateInfo_getMergeTable (msinfo);
3453 cstring msg = cstring_undefined;
3454 int nval = stateCombinationTable_lookup (sctable,
3455 stateValue_getValue (sval),
3456 stateValue_getValue (tval),
3457 &msg);
3458 DPRINTF (("Combining: %s + %s -> %d",
3459 stateValue_unparseValue (sval, msinfo),
3460 stateValue_unparseValue (tval, msinfo),
3461 nval));
3463 if (nval == stateValue_error)
3465 if (optgenerror
3466 (FLG_STATEMERGE,
3467 message
3468 ("Attributes merged in ensures clause in states that "
3469 "cannot be combined (%q is %q, %q is %q)%q",
3470 sRef_unparse (lastref),
3471 stateValue_unparseValue (sval, msinfo),
3472 sRef_unparse (fs),
3473 stateValue_unparseValue (tval, msinfo),
3474 cstring_isDefined (msg) ?
3475 message (": %s", msg) : cstring_undefined),
3476 exprNode_loc (f)))
3478 sRef_showMetaStateInfo (fs, key);
3482 stateValue_updateValueLoc (sval, nval, fileloc_undefined);
3483 loc = exprNode_loc (arg);
3485 else
3487 DPRINTF (("No value for: %s:%s", sRef_unparse (fs), key));
3490 else
3492 sval = sRef_getMetaStateValue (fs, key);
3495 lastref = fs;
3497 if (stateValue_isError (sval))
3499 /*@innerbreak@*/ break; /* Don't merge any more values if here was an error */
3503 paramno++;
3506 else
3508 msr = metaStateSpecifier_getSref (ms);
3511 llassert (sRef_isParam (sRef_getRootBase (msr)));
3512 fs = sRef_fixBaseParam (msr, args);
3514 if (stateValue_isDefined (sval))
3516 /* Use combination table to merge old state value with new one: */
3517 stateValue tval = sRef_getMetaStateValue (fs, key);
3519 if (stateValue_isDefined (tval))
3521 stateCombinationTable sctable = metaStateInfo_getMergeTable (msinfo);
3522 cstring msg = cstring_undefined;
3523 int nval = stateCombinationTable_lookup (sctable,
3524 stateValue_getValue (sval),
3525 stateValue_getValue (tval),
3526 &msg);
3527 DPRINTF (("Combining: %s + %s -> %d",
3528 stateValue_unparseValue (sval, msinfo),
3529 stateValue_unparseValue (tval, msinfo),
3530 nval));
3532 if (nval == stateValue_error)
3534 if (optgenerror
3535 (FLG_STATEMERGE,
3536 message
3537 ("Attributes merged in ensures clause in states that "
3538 "cannot be combined (%q is %q, %q is %q)%q",
3539 sRef_unparse (lastref),
3540 stateValue_unparseValue (sval, msinfo),
3541 sRef_unparse (fs),
3542 stateValue_unparseValue (tval, msinfo),
3543 cstring_isDefined (msg)
3544 ? message (": %s", msg) : cstring_undefined),
3545 exprNode_loc (f)))
3547 sRef_showMetaStateInfo (fs, key);
3551 stateValue_updateValueLoc (sval, nval, fileloc_undefined);
3553 else
3555 DPRINTF (("No value for: %s:%s", sRef_unparse (fs), key));
3558 else
3560 sval = sRef_getMetaStateValue (fs, key);
3563 lastref = fs;
3565 if (stateValue_isError (sval))
3567 /*@innerbreak@*/ break; /* Don't merge any more values if here was an error */
3572 DPRINTF (("Setting: %s:%s <- %s", sRef_unparse (s), key, stateValue_unparse (sval)));
3574 if (stateValue_isDefined (sval))
3576 sRef_setMetaStateValueComplete (s, key, stateValue_getValue (sval), loc);
3578 else
3580 DPRINTF (("Undefined state: %s", cstring_toCharsSafe (sRef_unparse (s))));
3582 } end_metaStateConstraintList_elements ;
3584 metaStateConstraintList_free (mscl);
3589 static void
3590 checkRequiresClause (uentry le, exprNode f, exprNodeList args)
3592 DPRINTF (("Check requires clause: %s(%s) / %s / %s",
3593 exprNode_unparse (f), exprNodeList_unparse (args),
3594 uentry_unparseFull (le),
3595 stateClauseList_unparse (uentry_getStateClauseList (le))));
3597 if (uentry_isValid (le) && uentry_isFunction (le))
3599 stateClauseList sclauses = uentry_getStateClauseList (le);
3601 if (stateClauseList_isDefined (sclauses))
3603 DPRINTF (("Check requires: %s / %s / %s",
3604 uentry_unparse (le),
3605 exprNode_unparse (f), exprNodeList_unparse (args)));
3607 stateClauseList_elements (sclauses, cl)
3609 DPRINTF (("Check clause: %s / %s",
3610 stateClause_unparse (cl),
3611 bool_unparse (stateClause_hasRequires (cl))));
3613 if (stateClause_hasRequires (cl))
3615 sRefSet osrs = sRefSet_undefined;
3616 sRefSet srs;
3618 if (stateClause_isGlobal (cl))
3620 srs = sRefSet_single (usymtab_lookupGlobalMarker ());
3621 osrs = srs;
3623 else
3625 srs = stateClause_getRefs (cl);
3628 DPRINTF (("Refs: %s", sRefSet_unparse (srs)));
3630 if (stateClause_setsMetaState (cl))
3632 qual q = stateClause_getMetaQual (cl);
3633 annotationInfo ainfo = qual_getAnnotationInfo (q);
3634 metaStateInfo minfo = annotationInfo_getState (ainfo);
3635 cstring key = metaStateInfo_getName (minfo);
3636 int mvalue = annotationInfo_getValue (ainfo);
3638 DPRINTF (("Requires meta state! %s = %d", key, mvalue));
3640 sRefSet_elements (srs, sel)
3642 sRef s = sRef_fixBaseParam (sel, args);
3644 if (sRef_isResult (sRef_getRootBase (sel)))
3646 BADBRANCH;
3648 else
3650 DPRINTF (("Checking state clause on: %s / %s / %s = %d",
3651 sRef_unparseFull (sel), sRef_unparseFull (s),
3652 key, mvalue));
3654 if (!sRef_checkMetaStateValue (s, key, mvalue))
3656 DPRINTF (("HERE: %s", sRef_unparse (s)));
3657 if (optgenerror
3658 (FLG_STATETRANSFER,
3659 message
3660 ("Requires clause of called function %q not satisfied%q (state is %q): %q",
3661 uentry_getName (le),
3662 sRef_isGlobalMarker (s)
3663 ? message ("")
3664 : message (" by %q", sRef_unparse (s)),
3665 stateValue_unparseValue (sRef_getMetaStateValue (s, key),
3666 minfo),
3667 stateClause_unparse (cl)),
3668 exprNode_loc (f)))
3670 sRef_showAliasInfo (s);
3672 else
3674 DPRINTF (("Error supressed!"));
3675 DPRINTF (("Loc: %s", fileloc_unparse (exprNode_loc (f))));
3676 DPRINTF (("Context supress: %s",
3677 bool_unparse (context_suppressFlagMsg (FLG_STATETRANSFER, exprNode_loc (f)))));
3681 } end_sRefSet_elements;
3683 else
3685 sRefModVal modf = stateClause_getRequiresBodyFunction (cl);
3686 int eparam = stateClause_getStateParameter (cl);
3688 DPRINTF (("Reflect after clause: %s / %s",
3689 stateClause_unparse (cl),
3690 sRefSet_unparse (srs)));
3692 llassert (modf != NULL);
3694 sRefSet_elements (srs, sel)
3696 sRef s;
3698 DPRINTF (("elements: %s", sRef_unparse (sel)));
3699 DPRINTF (("elements: %s", sRef_unparseFull (sel)));
3701 s = sRef_fixBaseParam (sel, args);
3703 DPRINTF (("elements: %s", sRef_unparse (s)));
3704 DPRINTF (("elements: %s", sRef_unparseFull (s)));
3706 if (sRef_isResult (sRef_getRootBase (sel)))
3708 ; /* what do we do about results? */
3710 else
3712 DPRINTF (("Reflecting state clause on: %s / %s",
3713 sRef_unparse (sel), sRef_unparse (s)));
3715 modf (s, eparam, exprNode_loc (f));
3717 } end_sRefSet_elements;
3720 sRefSet_free (osrs);
3722 } end_stateClauseList_elements ;
3727 static /*@only@*/ exprNode
3728 functionCallSafe (/*@only@*/ /*@notnull@*/ exprNode f,
3729 ctype t, /*@keep@*/ exprNodeList args)
3731 /* requires f is a non-error exprNode, with type function */
3732 cstring fname = exprNode_unparse (f);
3733 uentry le = exprNode_getUentry (f);
3734 exprNode ret = exprNode_createPartialCopy (f);
3735 int special;
3737 setCodePoint ();
3739 DPRINTF (("Call: %s %s",exprNode_unparse (f), exprNodeList_unparse (args)));
3741 ret->typ = ctype_getReturnType (t);
3742 ret->kind = XPR_CALL;
3744 ret->edata = exprData_makeCall (f, args);
3747 ** Order of these steps is very important!
3749 ** Must check for argument dependencies before messing up uses and sets.
3752 if (context_getFlag (FLG_EVALORDER))
3754 exprNodeList_elements (args, current)
3756 if (exprNode_isDefined (current))
3758 exprNode_addUse (current, current->sref);
3760 } end_exprNodeList_elements;
3762 if (context_maybeSet (FLG_EVALORDER) || context_maybeSet (FLG_EVALORDERUNCON))
3764 checkSequencing (f, args);
3767 exprNodeList_elements (args, current)
3769 if (exprNode_isDefined (current) && sRef_isMeaningful (current->sref))
3771 exprNode_addUse (ret, sRef_makeDerived (current->sref));
3773 } end_exprNodeList_elements ;
3776 special = checkArgs (le, f, t, args, ret);
3777 checkGlobMods (f, le, args, ret, special);
3778 checkRequiresClause (le, f, args);
3779 setCodePoint ();
3781 if (uentry_isValid (le)
3782 && (uentry_isFunction (le)
3783 || (uentry_isVariable (le)
3784 && ctype_isFunction (uentry_getType (le)))))
3786 exitkind exk = uentry_getExitCode (le);
3788 /* f->typ is already set to the return type */
3790 DPRINTF (("Function: %s", uentry_unparseFull (le)));
3791 ret->sref = uentry_returnedRef (le, args, exprNode_loc (f));
3792 DPRINTF (("Returned: %s / %s",
3793 uentry_unparseFull (le),
3794 sRef_unparseFull (ret->sref)));
3796 if (uentry_isFunction (le) && exprNodeList_size (args) >= 1)
3798 qual nullPred = uentry_nullPred (le);
3800 if (qual_isTrueNull (nullPred))
3802 exprNode arg = exprNodeList_head (args);
3804 if (exprNode_isDefined (arg))
3806 ret->guards = guardSet_addFalseGuard (ret->guards, arg->sref);
3809 else if (qual_isFalseNull (nullPred))
3811 exprNode arg = exprNodeList_head (args);
3813 if (exprNode_isDefined (arg))
3815 ret->guards = guardSet_addTrueGuard (ret->guards, arg->sref);
3818 else
3820 llassert (qual_isUnknown (nullPred));
3824 if (exitkind_isConditionalExit (exk))
3827 ** True exit is:
3828 ** if (arg0) then { exit! } else { ; }
3829 ** False exit is:
3830 ** if (arg0) then { ; } else { exit! }
3833 exprNode firstArg;
3835 llassert (!exprNodeList_isEmpty (args));
3836 firstArg = exprNodeList_head (args);
3838 if (exprNode_isDefined (firstArg)
3839 && !guardSet_isEmpty (firstArg->guards))
3841 usymtab_trueBranch (guardSet_undefined);
3842 usymtab_altBranch (guardSet_undefined);
3844 if (exitkind_isTrueExit (exk))
3846 usymtab_popBranches (firstArg,
3847 exprNode_makeMustExit (),
3848 exprNode_undefined,
3849 TRUE, TRUEEXITCLAUSE);
3851 else
3853 usymtab_popBranches (firstArg,
3854 exprNode_undefined,
3855 exprNode_makeMustExit (),
3856 TRUE, FALSEEXITCLAUSE);
3860 ret->exitCode = XK_MAYEXIT;
3862 else if (exitkind_mustExit (exk))
3864 ret->exitCode = XK_MUSTEXIT;
3866 else if (exitkind_couldExit (exk))
3868 ret->exitCode = XK_MAYEXIT;
3870 else
3875 if (cstring_equalLit (fname, "exit"))
3877 if (exprNodeList_size (args) == 1)
3879 exprNode arg = exprNodeList_head (args);
3881 if (exprNode_isDefined (arg) && exprNode_knownIntValue (arg))
3883 long int val = multiVal_forceInt (exprNode_getValue (arg));
3885 if (val != 0)
3887 voptgenerror
3888 (FLG_EXITARG,
3889 message
3890 ("Argument to exit has implementation defined behavior: %s",
3891 exprNode_unparse (arg)),
3892 exprNode_loc (arg));
3898 else
3900 ret->sref = sRef_undefined;
3901 exprNode_checkSetAny (ret, uentry_rawName (le));
3904 DPRINTF (("Before reflect: %s", sRef_unparseFull (ret->sref)));
3905 DPRINTF (("Reflect: %s", uentry_unparseFull (le)));
3906 reflectEnsuresClause (ret, le, f, args);
3907 setCodePoint ();
3909 DPRINTF (("Here: %s", sRef_unparseFull (ret->sref)));
3910 return (ret);
3914 ** this is yucky! should keep the uentry as part of exprNode!
3917 uentry exprNode_getUentry (exprNode e)
3919 if (exprNode_isError (e))
3921 return uentry_undefined;
3923 else
3925 cstring s = exprNode_rootVarName (e);
3926 uentry ue = usymtab_lookupSafe (s);
3928 return ue;
3933 ** Returns true iff e1 and e2 are both exactly the same storage
3934 ** (conservative).
3937 static bool exprNode_sameStorage (exprNode e1, exprNode e2)
3939 sRef s1 = exprNode_getSref (e1);
3940 sRef s2 = exprNode_getSref (e2);
3942 return (sRef_realSame (s1, s2));
3945 exprNode
3946 exprNode_makeInitBlock (lltok brace, /*@only@*/ exprNodeList inits)
3948 exprNode ret = exprNode_createPlain (ctype_unknown);
3950 ret->kind = XPR_INITBLOCK;
3951 ret->edata = exprData_makeCall (exprNode_undefined, inits);
3952 ret->loc = fileloc_update (ret->loc, lltok_getLoc (brace));
3954 return (ret);
3957 exprNode
3958 exprNode_functionCall (/*@only@*/ exprNode f, /*@only@*/ exprNodeList args)
3960 ctype t;
3962 # ifdef DEBUGSPLINT
3963 usymtab_checkAllValid ();
3964 # endif
3966 if (exprNode_isUndefined (f))
3968 exprNode_free (f);
3969 exprNodeList_free (args);
3970 return exprNode_undefined;
3973 t = exprNode_getType (f);
3975 if (sRef_isLocalVar (f->sref))
3977 exprNode_checkUse (f, f->sref, f->loc);
3979 if (sRef_possiblyNull (f->sref))
3981 if (!usymtab_isGuarded (f->sref))
3983 if (optgenerror (FLG_NULLDEREF,
3984 message ("Function call using %s pointer %q",
3985 sRef_nullMessage (f->sref),
3986 sRef_unparse (f->sref)),
3987 f->loc))
3989 sRef_showNullInfo (f->sref);
3990 sRef_setNullError (f->sref);
3996 setCodePoint ();
3998 if (ctype_isRealFunction (t))
4000 exprNode ret = functionCallSafe (f, t, args);
4001 setCodePoint ();
4002 return ret;
4004 else if (ctype_isUnknown (t))
4006 exprNode ret = exprNode_createPartialCopy (f);
4007 cstring tstring;
4009 setCodePoint ();
4011 ret->typ = t;
4012 exprNodeList_elements (args, current)
4014 if (exprNode_isDefined (current))
4016 exprNode_checkUse (ret, current->sref, ret->loc);
4019 ** also, anything derivable from current->sref may be used
4022 exprNode_addUse (ret, sRef_makeDerived (current->sref));
4023 exprNode_mergeUSs (ret, current);
4025 } end_exprNodeList_elements;
4027 ret->edata = exprData_makeCall (f, args);
4028 ret->kind = XPR_CALL;
4030 tstring = cstring_copy (exprNode_unparse (f));
4032 cstring_markOwned (tstring);
4033 exprNode_checkSetAny (ret, tstring);
4035 return (ret);
4037 else
4039 voptgenerror (FLG_TYPE,
4040 message ("Call to non-function (type %t): %s", t,
4041 exprNode_unparse (f)),
4042 f->loc);
4043 exprNode_free (f);
4044 exprNodeList_free (args);
4046 return (exprNode_makeError ());
4050 static exprNode
4051 exprNode_fieldAccessAux (/*@only@*/ exprNode s, /*@observer@*/ fileloc loc,
4052 /*@only@*/ cstring f)
4054 exprNode ret = exprNode_createPartialCopy (s);
4056 ret->kind = XPR_FACCESS;
4058 if (exprNode_isError (s))
4060 ret->edata = exprData_makeField (s, f);
4061 return ret;
4063 else
4065 ctype t = exprNode_getType (s);
4066 ctype tr = ctype_realType (t);
4068 checkMacroParen (s);
4070 ret->edata = exprData_makeField (s, f);
4072 if (ctype_isStructorUnion (tr))
4074 uentry tf = uentryList_lookupField (ctype_getFields (tr), f);
4076 if (uentry_isUndefined (tf))
4078 voptgenerror (FLG_TYPE,
4079 message ("Access non-existent field %s of %t: %s", f, t,
4080 exprNode_unparse (ret)),
4081 loc);
4082 /*! cstring_free (f); */ /* evans 2001-03-25 self-detect */
4083 return (ret);
4085 else
4087 uentry_setUsed (tf, exprNode_loc (ret));
4089 ret->typ = uentry_getType (tf);
4090 checkSafeUse (ret, s->sref);
4092 ret->sref = sRef_makeField (s->sref, uentry_rawName (tf));
4093 /*!? exprNode_free (s); */ /* evans 2001-03-25 self-detect */
4094 return (ret);
4097 else /* isStructorUnion */
4099 if (ctype_isRealAbstract (tr))
4101 voptgenerror
4102 (FLG_ABSTRACT,
4103 message ("Access field of abstract type (%t): %s.%s",
4104 t, exprNode_unparse (s), f),
4105 loc);
4106 ret->typ = ctype_unknown;
4108 else
4110 if (ctype_isKnown (tr))
4112 voptgenerror
4113 (FLG_TYPE,
4114 message
4115 ("Access field of non-struct or union (%t): %s.%s",
4116 t, exprNode_unparse (s), f),
4117 loc);
4119 ret->typ = ctype_unknown;
4121 else
4123 cstring sn = cstring_copy (f);
4125 checkSafeUse (ret, s->sref);
4126 cstring_markOwned (sn);
4127 ret->sref = sRef_makeField (s->sref, sn);
4128 return (ret);
4132 return (ret);
4135 BADEXIT;
4138 exprNode
4139 exprNode_fieldAccess (/*@only@*/ exprNode s, /*@only@*/ lltok dot,
4140 /*@only@*/ cstring f)
4142 exprNode res = exprNode_fieldAccessAux (s, lltok_getLoc (dot), f);
4143 lltok_free (dot);
4144 return res;
4147 exprNode
4148 exprNode_addParens (/*@only@*/ lltok lpar, /*@only@*/ exprNode e)
4150 exprNode ret = exprNode_createPartialCopy (e);
4152 ret->loc = fileloc_update (ret->loc, lltok_getLoc (lpar));
4153 ret->kind = XPR_PARENS;
4154 ret->edata = exprData_makeUop (e, lpar);
4156 if (!exprNode_isError (e))
4158 ret->exitCode = e->exitCode;
4159 ret->canBreak = e->canBreak;
4160 ret->mustBreak = e->mustBreak;
4161 ret->isJumpPoint = e->isJumpPoint;
4162 ret->sref = e->sref;
4165 return ret;
4168 static exprNode
4169 exprNode_arrowAccessAux (/*@only@*/ exprNode s, /*@observer@*/ fileloc loc,
4170 /*@only@*/ cstring f)
4172 exprNode ret = exprNode_createPartialCopy (s);
4174 ret->edata = exprData_makeField (s, f);
4175 ret->kind = XPR_ARROW;
4177 if (exprNode_isError (s))
4179 return (ret);
4181 else
4183 ctype t = exprNode_getType (s);
4184 ctype tr = ctype_realType (t);
4186 checkMacroParen (s);
4188 (void) ctype_fixArrayPtr (tr); /* REWRITE THIS */
4190 if (ctype_isRealPointer (tr))
4192 ctype b = ctype_realType (ctype_baseArrayPtr (tr));
4194 if (ctype_isStructorUnion (b))
4196 uentry fentry = uentryList_lookupField (ctype_getFields (b), f);
4198 if (sRef_isKnown (s->sref) && sRef_possiblyNull (s->sref))
4200 if (!usymtab_isGuarded (s->sref) && !context_inProtectVars ())
4202 if (optgenerror
4203 (FLG_NULLDEREF,
4204 message ("Arrow access from %s pointer%q: %s",
4205 sRef_nullMessage (s->sref),
4206 sRef_unparsePreOpt (s->sref),
4207 exprNode_unparse (ret)),
4208 loc))
4210 sRef_showNullInfo (s->sref);
4211 sRef_setNullError (s->sref);
4216 if (uentry_isUndefined (fentry))
4218 voptgenerror
4219 (FLG_TYPE,
4220 message ("Access non-existent field %s of %t: %s",
4221 f, t, exprNode_unparse (ret)),
4222 loc);
4223 ret->typ = ctype_unknown;
4224 return (ret);
4226 else
4229 ** was safeUse: shouldn't be safe!
4231 ** to do rec->field
4232 ** rec must be defined,
4233 ** *rec must be allocated
4234 ** rec->field need only be defined it if is an rvalue
4237 uentry_setUsed (fentry, exprNode_loc (ret));
4238 ret->typ = uentry_getType (fentry);
4240 exprNode_checkUse (ret, s->sref, s->loc);
4242 /* exprNode_checkUse (ret, sRef_makePointer (s->sref), s->loc); */
4243 ret->sref = sRef_makeArrow (s->sref, uentry_rawName (fentry));
4244 return (ret);
4247 else /* Pointer to something that is not a struct or union*/
4249 if (ctype_isRealAbstract (tr))
4251 ctype xrt = ctype_forceRealType (tr);
4253 voptgenerror
4254 (FLG_ABSTRACT,
4255 message ("Arrow access field of abstract type (%t): %s->%s",
4256 t, exprNode_unparse (s), f),
4257 loc);
4260 ** Set the state correctly, as if the abstraction is broken.
4263 if (ctype_isRealPointer (xrt) &&
4264 (b = ctype_realType (ctype_baseArrayPtr (xrt)),
4265 ctype_isStructorUnion (b)))
4267 uentry fentry = uentryList_lookupField (ctype_getFields (b), f);
4268 ret->typ = uentry_getType (fentry);
4269 ret->sref = sRef_makeArrow (s->sref, uentry_rawName (fentry));
4271 else
4273 ret->typ = ctype_unknown;
4274 ret->sref = sRef_undefined;
4277 else /* not a struct, union or abstract */
4279 if (ctype_isUnknown (tr)) {
4280 cstring sn = cstring_copy (f);
4282 DPRINTF (("Here: %s", exprNode_unparse (s)));
4284 exprNode_checkUse (ret, s->sref, s->loc);
4285 exprNode_checkUse (ret, sRef_makePointer (s->sref), s->loc);
4287 cstring_markOwned (sn);
4288 ret->sref = sRef_makeArrow (s->sref, sn);
4290 ret->kind = XPR_ARROW;
4291 return (ret);
4292 } else {
4293 voptgenerror
4294 (FLG_TYPE,
4295 message ("Arrow access field of non-struct or union "
4296 "pointer (%t): %s->%s",
4297 t, exprNode_unparse (s), f),
4298 loc);
4300 ret->typ = ctype_unknown;
4301 ret->sref = sRef_undefined;
4306 else /* its not a pointer */
4308 if (!ctype_isUnknown (tr))
4310 voptgenerror
4311 (FLG_TYPE,
4312 message ("Arrow access of non-pointer (%t): %s->%s",
4313 t, exprNode_unparse (s), f),
4314 loc);
4316 ret->typ = ctype_unknown;
4317 ret->sref = sRef_undefined;
4319 else
4321 cstring sn = cstring_copy (f);
4323 DPRINTF (("Here: %s", exprNode_unparse (s)));
4325 exprNode_checkUse (ret, s->sref, s->loc);
4326 exprNode_checkUse (ret, sRef_makePointer (s->sref), s->loc);
4328 cstring_markOwned (sn);
4329 ret->sref = sRef_makeArrow (s->sref, sn);
4331 ret->kind = XPR_ARROW;
4332 return (ret);
4336 return (ret);
4338 BADEXIT;
4341 exprNode
4342 exprNode_arrowAccess (/*@only@*/ exprNode s,
4343 /*@only@*/ lltok arrow,
4344 /*@only@*/ cstring f)
4346 exprNode res = exprNode_arrowAccessAux (s, lltok_getLoc (arrow), f);
4347 lltok_free (arrow);
4348 return res;
4352 ** only postOp's in C: i++ and i--
4355 exprNode
4356 exprNode_postOp (/*@only@*/ exprNode e, /*@only@*/ lltok op)
4358 /* check modification also */
4359 /* cstring opname = lltok_unparse (op);*/
4360 ctype t;
4361 exprNode ret = exprNode_createPartialCopy (e);
4363 ret->loc = fileloc_update (ret->loc, lltok_getLoc (op));
4364 ret->kind = XPR_POSTOP;
4365 ret->edata = exprData_makeUop (e, op);
4367 if (!exprNode_isDefined (e))
4369 return ret;
4372 checkMacroParen (e);
4374 exprNode_checkUse (ret, e->sref, e->loc);
4375 exprNode_checkSet (ret, e->sref);
4377 t = exprNode_getType (e);
4379 if (sRef_isUnsafe (e->sref))
4381 voptgenerror (FLG_MACROPARAMS,
4382 message ("Operand of %s is macro parameter (non-functional): %s%s",
4383 lltok_unparse (op), exprNode_unparse (e), lltok_unparse (op)),
4384 e->loc);
4385 sRef_makeSafe (e->sref);
4386 sRef_makeSafe (ret->sref);
4389 if (ctype_isForceRealNumeric (&t) || ctype_isRealAP (t))
4391 ret->typ = e->typ;
4393 else
4395 if (ctype_isRealAbstract (t))
4397 if (ctype_isRealNumAbstract (t)) {
4398 ; /* Allow operations on numabstract types */
4399 } else {
4400 voptgenerror
4401 (FLG_ABSTRACT,
4402 message ("Operand of %s is abstract type (%t): %s",
4403 lltok_unparse (op), t, exprNode_unparse (e)),
4404 e->loc);
4407 else
4409 voptgenerror
4410 (FLG_TYPE,
4411 message ("Operand of %s is non-numeric (%t): %s",
4412 lltok_unparse (op), t, exprNode_unparse (e)),
4413 e->loc);
4415 ret->typ = ctype_unknown;
4418 /* if (ctype_isZero (t)) e->typ = ctype_int; */
4420 exprNode_checkModify (e, ret);
4422 /* added 7/11/2000 D.L */
4424 /* updateEnvironmentForPostOp (e); */
4426 /* start modifications */
4427 /* added by Seejo on 4/16/2000 */
4429 /* Arithmetic operations on pointers wil modify the size/len/null terminated
4430 status */
4431 if ((sRef_isPossiblyNullTerminated (e->sref)) || (sRef_isNullTerminated(e->sref))) {
4433 ret->sref = sRef_copy (e->sref);
4435 /* Operator : ++ */
4436 if (lltok_getTok (op) == INC_OP) {
4437 if (sRef_getSize(e->sref) > 0) {
4439 sRef_setSize (ret->sref, sRef_getSize(e->sref) - 1);
4441 if (sRef_getLen(e->sref) == 1) { /* i.e. the first character is \0 */
4442 /* Assumption: there is only 1 \0 in the buffer */
4443 /* This will not be correct if there are 2 \0's in the buffer */
4444 sRef_setNotNullTerminatedState(ret->sref);
4445 sRef_resetLen(ret->sref);
4446 } else {
4447 sRef_setNullTerminatedState(ret->sref);
4448 sRef_setLen (ret->sref, sRef_getLen(e->sref) - 1);
4450 if (sRef_isNullTerminated (ret->sref))
4451 printf ("ret->sref is Null Terminated\n");
4452 else if (sRef_isPossiblyNullTerminated (ret->sref))
4453 printf ("ret->sref is Possibly Null Terminated\n");
4454 else if (sRef_isNotNullTerminated (ret->sref))
4455 printf ("ret->sref is Not Null Terminated\n");
4456 else
4461 /* Operator : -- */
4462 if (lltok_getTok (op) == DEC_OP) {
4463 if (sRef_getSize(e->sref) >= 0) {
4464 sRef_setSize (ret->sref, sRef_getSize(e->sref) + 1);
4465 sRef_setLen (ret->sref, sRef_getLen(e->sref) + 1);
4469 /* end modifications */
4471 return ret;
4474 exprNode
4475 exprNode_preOp (/*@only@*/ exprNode e, /*@only@*/ lltok op)
4477 bool checkMod = FALSE;
4478 ctype te, tr;
4479 int opid = lltok_getTok (op);
4480 exprNode ret = exprNode_createSemiCopy (e);
4482 exprNode_copySets (ret, e);
4484 multiVal_free (ret->val);
4485 ret->val = multiVal_undefined;
4486 ret->loc = fileloc_update (ret->loc, lltok_getLoc (op));
4487 ret->kind = XPR_PREOP;
4488 ret->edata = exprData_makeUop (e, op);
4490 if (exprNode_isError (e))
4492 return ret;
4495 checkMacroParen (e);
4497 te = exprNode_getType (e);
4498 tr = ctype_realType (te);
4500 if (opid != TAMPERSAND)
4502 exprNode_checkUse (ret, e->sref, e->loc);
4504 if (ctype_isRealAbstract (tr)
4505 && (!(ctype_isRealBool (te) && (opid == TEXCL))))
4507 if (ctype_isRealNumAbstract (tr))
4509 ; /* no warning for numabstract types */
4511 else
4513 if (optgenerror (FLG_ABSTRACT,
4514 message ("Operand of %s is abstract type (%t): %s",
4515 lltok_unparse (op), tr,
4516 exprNode_unparse (ret)),
4517 e->loc))
4519 tr = te = ctype_unknown;
4520 ret->typ = ctype_unknown;
4521 sRef_setNullError (e->sref);
4527 switch (opid)
4529 case INC_OP:
4530 case DEC_OP: /* should also check modification! */
4531 if (sRef_isMacroParamRef (e->sref))
4533 voptgenerror
4534 (FLG_MACROPARAMS,
4535 message ("Operand of %s is macro parameter (non-functional): %s",
4536 lltok_unparse (op), exprNode_unparse (ret)),
4537 e->loc);
4539 else
4541 exprNode_checkSet (ret, e->sref);
4544 if (ctype_isForceRealNumeric (&tr) || ctype_isRealAP (tr))
4547 else
4549 if (context_msgStrictOps ())
4551 voptgenerror
4552 (FLG_STRICTOPS,
4553 message ("Operand of %s is non-numeric (%t): %s",
4554 lltok_unparse (op), te, exprNode_unparse (ret)),
4555 e->loc);
4557 ret->typ = ctype_int;
4560 /* start modifications */
4561 /* added by Seejo on 4/16/2000 */
4563 /* Arithmetic operations on pointers wil modify the size/len/null terminated
4564 status */
4565 if ((sRef_isPossiblyNullTerminated (e->sref))
4566 || (sRef_isNullTerminated(e->sref))) {
4567 ret->sref = sRef_copy (e->sref);
4569 /* Operator : ++ */
4570 if (lltok_getTok (op) == INC_OP) {
4571 if (sRef_getSize(e->sref) > 0) {
4573 sRef_setSize (ret->sref, sRef_getSize(e->sref) - 1);
4575 if (sRef_getLen(e->sref) == 1) { /* i.e. the first character is \0 */
4576 /* Assumption: there is only 1 \0 in the buffer */
4577 /* This will not be correct if there are 2 \0's in the buffer */
4578 sRef_setNotNullTerminatedState(ret->sref);
4579 sRef_resetLen (ret->sref);
4580 } else {
4581 sRef_setNullTerminatedState(ret->sref);
4582 sRef_setLen (ret->sref, sRef_getLen(e->sref) - 1);
4587 /* Operator : -- */
4588 if (lltok_getTok (op) == DEC_OP) {
4589 if (sRef_getSize(e->sref) >= 0) {
4590 sRef_setSize (ret->sref, sRef_getSize(e->sref) + 1);
4591 sRef_setLen (ret->sref, sRef_getLen(e->sref) + 1);
4596 /* end modifications */
4598 checkMod = TRUE;
4599 break;
4601 case TMINUS:
4602 case TPLUS:
4603 if (ctype_isForceRealNumeric (&tr))
4605 if (opid == TMINUS)
4607 ret->val = multiVal_invert (exprNode_getValue (e));
4609 else
4611 ret->val = multiVal_copy (exprNode_getValue (e));
4614 else
4616 if (context_msgStrictOps ())
4618 voptgenerror
4619 (FLG_STRICTOPS,
4620 message ("Operand of %s is non-numeric (%t): %s",
4621 lltok_unparse (op), te, exprNode_unparse (ret)),
4622 e->loc);
4625 ret->typ = ctype_int;
4627 break;
4629 case TEXCL: /* maybe this should be restricted */
4630 guardSet_flip (ret->guards);
4632 if (ctype_isRealBool (te) || ctype_isUnknown (te))
4636 else
4638 if (ctype_isRealPointer (tr))
4640 if (sRef_isKnown (e->sref))
4642 ret->guards = guardSet_addFalseGuard (ret->guards, e->sref);
4645 voptgenerror2n
4646 (FLG_BOOLOPS, FLG_PTRNEGATE,
4647 message ("Operand of %s is non-boolean (%t): %s",
4648 lltok_unparse (op), te, exprNode_unparse (ret)),
4649 e->loc);
4651 else
4653 voptgenerror
4654 (FLG_BOOLOPS,
4655 message ("Operand of %s is non-boolean (%t): %s",
4656 lltok_unparse (op), te, exprNode_unparse (ret)),
4657 e->loc);
4660 ret->typ = ctype_bool;
4662 break;
4664 case TTILDE:
4665 if (ctype_isForceRealInt (&tr))
4668 else
4670 if (context_msgStrictOps ())
4672 voptgenerror
4673 (FLG_STRICTOPS,
4674 message ("Operand of %s is non-integer (%t): %s",
4675 lltok_unparse (op), te, exprNode_unparse (ret)),
4676 e->loc);
4679 if (ctype_isInt (e->typ))
4681 ret->typ = e->typ;
4683 else
4685 ret->typ = ctype_int;
4688 break;
4690 case TAMPERSAND:
4691 ret->typ = ctype_makePointer (e->typ);
4693 if (sRef_isKnown (e->sref))
4695 ret->sref = sRef_makeAddress (e->sref);
4698 break;
4700 case TMULT:
4702 if (ctype_isAP (tr))
4704 ret->typ = ctype_baseArrayPtr (e->typ);
4706 else
4708 if (ctype_isKnown (te))
4710 if (ctype_isFunction (te))
4712 ret->typ = e->typ;
4714 voptgenerror
4715 (FLG_FCNDEREF,
4716 message ("Dereference of function type (%t): %s",
4717 te, exprNode_unparse (ret)),
4718 e->loc);
4720 else
4722 voptgenerror (FLG_TYPE,
4723 message ("Dereference of non-pointer (%t): %s",
4724 te, exprNode_unparse (ret)),
4725 e->loc);
4726 ret->typ = ctype_unknown;
4729 else
4731 ret->typ = ctype_unknown;
4736 if (sRef_isKnown (e->sref))
4738 DPRINTF (("Checking possibly null: %s", sRef_unparseFull (e->sref)));
4740 if (sRef_possiblyNull (e->sref))
4742 DPRINTF (("Checking possibly null: %s", sRef_unparse (e->sref)));
4743 if (!usymtab_isGuarded (e->sref) && !context_inProtectVars ())
4745 if (optgenerror
4746 (FLG_NULLDEREF,
4747 message ("Dereference of %s pointer %q: %s",
4748 sRef_nullMessage (e->sref),
4749 sRef_unparse (e->sref),
4750 exprNode_unparse (ret)),
4751 e->loc))
4753 sRef_showNullInfo (e->sref);
4754 sRef_setNotNull (e->sref, e->loc); /* suppress future messages */
4759 ret->sref = sRef_makePointer (e->sref);
4761 break;
4763 default:
4764 llbug (message ("exprNode_preOp: unhandled op: %s", lltok_unparse (op)));
4767 if (checkMod)
4769 exprNode_checkModify (e, ret);
4772 return ret;
4776 ** any reason to disallow sizeof (abstract type) ?
4780 ** used by both sizeof
4783 static
4784 ctype sizeof_resultType (void)
4786 static ctype sizet = ctype_unknown;
4788 if (ctype_isUnknown (sizet))
4790 if (usymtab_existsType (cstring_makeLiteralTemp ("size_t")))
4792 sizet = uentry_getAbstractType (usymtab_lookup (cstring_makeLiteralTemp ("size_t")));
4794 else
4796 sizet = ctype_ulint;
4799 return sizet;
4802 exprNode
4803 exprNode_sizeofType (/*@only@*/ qtype qt)
4805 exprNode ret = exprNode_create (sizeof_resultType ());
4806 ctype ct = qtype_getType (qt);
4808 ret->kind = XPR_SIZEOFT;
4809 ret->edata = exprData_makeSizeofType (qt);
4811 voptgenerror (FLG_SIZEOFTYPE,
4812 message ("Parameter to sizeof is type %s: %s",
4813 ctype_unparse (ct),
4814 exprNode_unparse (ret)),
4815 ret->loc);
4817 return (ret);
4820 exprNode
4821 exprNode_alignofType (/*@only@*/ qtype qt)
4823 exprNode ret = exprNode_create (sizeof_resultType ());
4824 ctype ct = qtype_getType (qt);
4826 ret->kind = XPR_ALIGNOFT;
4827 ret->edata = exprData_makeSizeofType (qt);
4829 voptgenerror (FLG_SIZEOFTYPE,
4830 message ("Parameter to alignof is type %s: %s",
4831 ctype_unparse (ct),
4832 exprNode_unparse (ret)),
4833 ret->loc);
4835 return (ret);
4838 exprNode exprNode_offsetof (qtype qt, cstringList s)
4840 exprNode ret = exprNode_create (sizeof_resultType ());
4841 ctype ct = qtype_getType (qt);
4843 ret->kind = XPR_OFFSETOF;
4844 ret->edata = exprData_makeOffsetof (qt, s);
4846 if (!ctype_isRealSU (ct))
4848 voptgenerror (FLG_TYPE,
4849 message ("First parameter to offsetof is not a "
4850 "struct or union type (type %s): %s",
4851 ctype_unparse (ct),
4852 exprNode_unparse (ret)),
4853 ret->loc);
4855 else
4857 ctype lt = ct;
4859 cstringList_elements (s, el) {
4860 uentryList fields;
4861 uentry fld;
4863 if (ctype_isUndefined (lt))
4865 break;
4867 else if (!ctype_isRealSU (lt))
4869 voptgenerror (FLG_TYPE,
4870 message ("Inner offsetof type is not a "
4871 "struct or union type (type %s before field %s): %s",
4872 ctype_unparse (lt), el,
4873 exprNode_unparse (ret)),
4874 ret->loc);
4875 break;
4877 else
4879 fields = ctype_getFields (ctype_realType (lt));
4880 fld = uentryList_lookupField (fields, el);
4881 DPRINTF (("Try: %s / %s", ctype_unparse (lt), el));
4883 if (uentry_isUndefined (fld))
4885 if (ctype_equal (lt, ct)) {
4886 voptgenerror (FLG_TYPE,
4887 message ("Field %s in offsetof is not the "
4888 "name of a field of %s: %s",
4890 ctype_unparse (ct),
4891 exprNode_unparse (ret)),
4892 ret->loc);
4893 } else {
4894 voptgenerror (FLG_TYPE,
4895 message ("Deep field %s in offsetof is not the "
4896 "name of a field of %s: %s",
4898 ctype_unparse (lt),
4899 exprNode_unparse (ret)),
4900 ret->loc);
4903 else
4905 lt = uentry_getType (fld);
4908 } end_cstringList_elements;
4910 /* Should report error if its a bit field - behavior is undefined! */
4913 return (ret);
4916 /*@only@*/ exprNode
4917 exprNode_sizeofExpr (/*@only@*/ exprNode e)
4919 exprNode ret;
4921 if (exprNode_isUndefined (e))
4923 ret = exprNode_createLoc (ctype_unknown, fileloc_copy (g_currentloc));
4924 ret->edata = exprData_makeSingle (e);
4925 ret->typ = sizeof_resultType ();
4926 ret->kind = XPR_SIZEOF;
4928 else
4930 uentry u = exprNode_getUentry (e);
4932 ret = exprNode_createPartialCopy (e);
4933 ret->edata = exprData_makeSingle (e);
4935 ret->typ = sizeof_resultType ();
4936 ret->kind = XPR_SIZEOF;
4938 if (uentry_isValid (u)
4939 && uentry_isRefParam (u)
4940 && ctype_isRealArray (uentry_getType (u)))
4942 voptgenerror
4943 (FLG_SIZEOFFORMALARRAY,
4944 message ("Parameter to sizeof is an array-type function parameter: %s",
4945 exprNode_unparse (ret)),
4946 ret->loc);
4951 ** sizeof (x) doesn't "really" use x
4954 return (ret);
4957 /*@only@*/ exprNode
4958 exprNode_alignofExpr (/*@only@*/ exprNode e)
4960 exprNode ret;
4962 if (exprNode_isUndefined (e))
4964 ret = exprNode_createLoc (ctype_unknown, fileloc_copy (g_currentloc));
4966 else
4968 ret = exprNode_createPartialCopy (e);
4971 ret->edata = exprData_makeSingle (e);
4972 ret->typ = sizeof_resultType ();
4973 ret->kind = XPR_ALIGNOF;
4976 ** sizeof (x) doesn't "really" use x
4979 return (ret);
4982 /*@only@*/ exprNode
4983 exprNode_cast (/*@only@*/ lltok tok, /*@only@*/ exprNode e, /*@only@*/ qtype q)
4985 ctype c;
4986 ctype t;
4987 exprNode ret;
4989 if (exprNode_isError (e))
4991 qtype_free (q);
4992 lltok_free (tok);
4993 return exprNode_undefined;
4996 checkMacroParen (e);
4998 c = qtype_getType (q);
4999 t = exprNode_getType (e);
5001 ret = exprNode_createPartialCopy (e);
5003 ret->loc = fileloc_update (ret->loc, lltok_getLoc (tok));
5004 ret->typ = c;
5005 ret->kind = XPR_CAST;
5006 ret->edata = exprData_makeCast (tok, e, q);
5008 ret->sref = sRef_copy (e->sref);
5010 DPRINTF (("Cast: -> %s", sRef_unparseFull (ret->sref)));
5012 if (!sRef_isConst (e->sref))
5014 usymtab_addForceMustAlias (ret->sref, e->sref);
5017 DPRINTF (("Cast 2: -> %s", sRef_unparseFull (ret->sref)));
5018 sRef_setTypeFull (ret->sref, c);
5019 DPRINTF (("Cast 2: -> %s", sRef_unparseFull (ret->sref)));
5022 ** we allow
5023 ** abstract -> void
5024 ** 0 <-> abstract *
5025 ** void * <-> abstract * (if FLG_ABSTVOIDP)
5026 ** abstract * <-> void * (if FLG_ABSTVOIDP)
5029 if (ctype_isVoid (c)) /* cast to void is always okay --- discard value */
5031 /* evans 2002-07-19: added this warning */
5032 DPRINTF (("Checking: %s / %s", exprNode_unparse (ret), sRef_unparseFull (ret->sref)));
5033 if (sRef_isFresh (ret->sref))
5035 voptgenerror
5036 (FLG_MUSTFREEFRESH,
5037 message ("New fresh storage %q(type %s) cast to void (not released): %s",
5038 sRef_unparseOpt (ret->sref),
5039 ctype_unparse (exprNode_getType (ret)),
5040 exprNode_unparse (ret)),
5041 exprNode_loc (ret));
5044 else if (ctype_isRealAP (c)) /* casting to array or pointer */
5046 ctype bc = ctype_getBaseType (c);
5047 ctype bt = ctype_getBaseType (t);
5048 ctype rt = ctype_realType (t);
5050 if (ctype_isFunction (ctype_baseArrayPtr (ctype_realType (c)))
5051 && (ctype_isArrayPtr (rt)
5052 && !ctype_isFunction (ctype_realType (ctype_baseArrayPtr (rt)))))
5054 voptgenerror
5055 (FLG_CASTFCNPTR,
5056 message ("Cast from function pointer type (%t) to "
5057 "non-function pointer (%t): %s",
5058 c, t, exprNode_unparse (ret)),
5059 e->loc);
5062 if (!ctype_isFunction (ctype_baseArrayPtr (c))
5063 && (ctype_isArrayPtr (rt)
5064 && ctype_isFunction (ctype_realType (ctype_baseArrayPtr (rt)))))
5066 voptgenerror
5067 (FLG_CASTFCNPTR,
5068 message ("Cast from non-function pointer type (%t) to "
5069 "function pointer (%t): %s",
5070 c, t, exprNode_unparse (ret)),
5071 e->loc);
5074 if (exprNode_isZero (e) && context_getFlag (FLG_ZEROPTR) &&
5075 !(ctype_isRealAbstract (bc)
5076 && context_hasAccess (ctype_typeId (bc))))
5078 ; /* okay to cast zero */
5080 else
5082 if (ctype_isRealAbstract (bc)
5083 && !context_hasAccess (ctype_typeId (bc)))
5085 if (ctype_isVoidPointer (t) || ctype_isUnknown (t))
5087 vnoptgenerror
5088 (FLG_ABSTVOIDP,
5089 message ("Cast to underlying abstract type %t: %s",
5090 c, exprNode_unparse (ret)),
5091 e->loc);
5093 else
5095 voptgenerror
5096 (FLG_ABSTRACT,
5097 message ("Cast to underlying abstract type %t: %s",
5098 c, exprNode_unparse (ret)),
5099 e->loc);
5103 if (ctype_isRealAbstract (bt)
5104 && !context_hasAccess (ctype_typeId (bt)))
5106 if (ctype_isUnknown (c) || ctype_isVoidPointer (c))
5108 vnoptgenerror
5109 (FLG_ABSTVOIDP,
5110 message ("Cast from underlying abstract type %t: %s",
5111 t, exprNode_unparse (ret)),
5112 e->loc);
5114 else
5116 voptgenerror
5117 (FLG_ABSTRACT,
5118 message ("Cast from underlying abstract type %t: %s",
5119 t, exprNode_unparse (ret)),
5120 e->loc);
5125 else
5127 ctype bt = ctype_realType (ctype_getBaseType (t));
5128 ctype bc = ctype_realType (ctype_getBaseType (c));
5130 if (ctype_isAbstract (bt) && !context_hasAccess (ctype_typeId (bt)))
5132 if (ctype_match (c, t))
5134 if (ctype_equal (c, t))
5136 voptgenerror
5137 (FLG_TYPE,
5138 message ("Redundant cast involving abstract type %t: %s",
5139 bt, exprNode_unparse (ret)),
5140 e->loc);
5143 else
5145 voptgenerror
5146 (FLG_ABSTRACT,
5147 message ("Cast from abstract type %t: %s",
5148 bt, exprNode_unparse (ret)),
5149 e->loc);
5153 if (ctype_isAbstract (bc)
5154 && !context_hasAccess (ctype_typeId (bc)))
5156 if (ctype_match (c, t))
5160 else
5162 if (ctype_isNumAbstract (bc))
5164 if (exprNode_isNumLiteral (e))
5166 voptgenerror
5167 (FLG_NUMABSTRACTCAST,
5168 message ("Cast from literal to numabstract type %t: %s", bc,
5169 exprNode_unparse (ret)),
5170 e->loc);
5172 else
5174 voptgenerror
5175 (FLG_NUMABSTRACT,
5176 message ("Cast to numabstract type %t: %s", bc,
5177 exprNode_unparse (ret)),
5178 e->loc);
5181 else
5183 DPRINTF (("No access to: %s / %d",
5184 ctype_unparse (bc), ctype_typeId (bc)));
5185 DPRINTF (("Context %s %s",
5186 bool_unparse (context_inFunctionLike ()),
5187 context_unparse ()));
5188 voptgenerror
5189 (FLG_ABSTRACT,
5190 message ("Cast to abstract type %t: %s", bc,
5191 exprNode_unparse (ret)),
5192 e->loc);
5198 if (ctype_isAbstract (c))
5200 if (sRef_isExposed (e->sref) || sRef_isOnly (e->sref))
5202 /* okay, cast exposed to abstract */
5203 sRef_clearExKindComplete (ret->sref, fileloc_undefined);
5205 else
5207 if (ctype_isVisiblySharable (t)
5208 && sRef_isExternallyVisible (e->sref)
5209 && !(ctype_isAbstract (t)
5210 && context_hasAccess (ctype_typeId (t))))
5212 voptgenerror
5213 (FLG_CASTEXPOSE,
5214 message ("Cast to abstract type from externally visible "
5215 "mutable storage exposes rep of %s: %s",
5216 ctype_unparse (c),
5217 exprNode_unparse (e)),
5218 e->loc);
5223 return (ret);
5226 static bool
5227 evaluationOrderUndefined (lltok op)
5229 int opid = lltok_getTok (op);
5231 return (opid != AND_OP && opid != OR_OP);
5234 static bool checkIntegral (/*@notnull@*/ exprNode e1,
5235 /*@notnull@*/ exprNode e2,
5236 /*@notnull@*/ exprNode ret,
5237 lltok op)
5239 bool error = FALSE;
5241 ctype te1 = exprNode_getType (e1);
5242 ctype te2 = exprNode_getType (e2);
5244 ctype tr1 = ctype_realishType (te1);
5245 ctype tr2 = ctype_realishType (te2);
5247 if (ctype_isForceRealInt (&tr1) && ctype_isForceRealInt (&tr2))
5251 else
5253 if (context_msgStrictOps ())
5255 if (!ctype_isInt (tr1) && !ctype_isInt (tr2))
5257 if (ctype_sameName (te1, te2))
5259 error = optgenerror
5260 (FLG_STRICTOPS,
5261 message ("Operands of %s are non-integer (%t): %s",
5262 lltok_unparse (op), te1,
5263 exprNode_unparse (ret)),
5264 e1->loc);
5266 else
5268 error = optgenerror
5269 (FLG_STRICTOPS,
5270 message ("Operands of %s are non-integers (%t, %t): %s",
5271 lltok_unparse (op), te1, te2,
5272 exprNode_unparse (ret)),
5273 e1->loc);
5276 else if (!ctype_isInt (tr1))
5278 error = optgenerror
5279 (FLG_STRICTOPS,
5280 message ("Left operand of %s is non-integer (%t): %s",
5281 lltok_unparse (op), te1, exprNode_unparse (ret)),
5282 e1->loc);
5284 else
5285 /* !ctype_isInt (te2) */
5287 error = optgenerror
5288 (FLG_STRICTOPS,
5289 message ("Right operand of %s is non-integer (%t): %s",
5290 lltok_unparse (op), te2, exprNode_unparse (ret)),
5291 e2->loc);
5296 return !error;
5300 ** returns exprNode representing e1 op e2
5302 ** uses msg if there are errors
5303 ** can be used for both assignment ops and regular ops
5305 ** modifies e1
5308 static /*@only@*/ /*@notnull@*/ exprNode
5309 exprNode_makeOp (/*@keep@*/ exprNode e1, /*@keep@*/ exprNode e2,
5310 /*@keep@*/ lltok op)
5312 ctype te1, te2, tr1, tr2, tret;
5313 int opid = lltok_getTok (op);
5314 bool hasError = FALSE;
5315 exprNode ret;
5317 if (exprNode_isError (e1))
5319 ret = exprNode_createPartialNVCopy (e2);
5321 else
5323 ret = exprNode_createPartialNVCopy (e1);
5326 ret->val = multiVal_undefined;
5328 ret->kind = XPR_OP;
5329 ret->edata = exprData_makeOp (e1, e2, op);
5331 if (exprNode_isError (e1) || exprNode_isError (e2))
5333 if (opid == TLT || opid == TGT || opid == LE_OP || opid == GE_OP
5334 || opid == EQ_OP || opid == NE_OP
5335 || opid == AND_OP || opid == OR_OP)
5337 ret->typ = ctype_bool;
5340 if (exprNode_isDefined (e1))
5342 exprNode_checkUse (ret, e1->sref, e1->loc);
5345 if (exprNode_isDefined (e2))
5347 exprNode_mergeUSs (ret, e2);
5348 exprNode_checkUse (ret, e2->sref, e2->loc);
5351 return ret;
5354 tret = ctype_unknown;
5355 te1 = exprNode_getType (e1);
5357 DPRINTF (("te1 = %s / %s", exprNode_unparse (e1), ctype_unparse (te1)));
5359 te2 = exprNode_getType (e2);
5361 tr1 = ctype_realishType (te1);
5362 tr2 = ctype_realishType (te2);
5364 if (opid == OR_OP)
5366 exprNode_produceGuards (e2);
5367 ret->guards = guardSet_or (ret->guards, e2->guards);
5369 else if (opid == AND_OP)
5371 exprNode_produceGuards (e2); /* evans 2003-08-13: need to produce guards for expression */
5372 /* Shouldn't this have already happened? */
5373 DPRINTF (("Anding guards: %s / %s", guardSet_unparse (ret->guards), guardSet_unparse (e2->guards)));
5374 ret->guards = guardSet_and (ret->guards, e2->guards);
5376 else
5378 /* no guards */
5381 if (opid == EQ_OP || opid == NE_OP)
5383 exprNode temp1 = e1, temp2 = e2;
5385 /* could do NULL == x */
5387 if (exprNode_isNullValue (e1) || exprNode_isUnknownConstant (e1))
5389 temp1 = e2; temp2 = e1;
5392 if (exprNode_isNullValue (temp2) || exprNode_isUnknownConstant (temp2))
5394 reflectNullTest (temp1, (opid == NE_OP));
5395 guardSet_free (ret->guards);
5396 ret->guards = guardSet_copy (temp1->guards);
5400 if (opid == TLT || opid == TGT || opid == LE_OP || opid == GE_OP
5401 || opid == EQ_OP || opid == NE_OP || opid == AND_OP || opid == OR_OP)
5403 tret = ctype_bool;
5406 if (anyAbstract (tr1, tr2) &&
5407 (!((ctype_isRealBool (te1) || ctype_isRealBool (te2)) &&
5408 (opid == AND_OP || opid == OR_OP
5409 || opid == EQ_OP || opid == NE_OP))))
5411 if (abstractOpError (tr1, tr2, op, e1, e2, e1->loc, e2->loc))
5413 tret = ctype_unknown;
5414 goto skiprest;
5418 if (ctype_isUnknown (te1) || ctype_isUnknown (te2))
5420 /* unknown types, no comparisons possible */
5421 goto skiprest;
5424 switch (opid)
5426 case TMULT: /* multiplication and division: */
5427 case TDIV: /* */
5428 case MUL_ASSIGN: /* numeric, numeric -> numeric */
5429 case DIV_ASSIGN: /* */
5430 if (opid == TMULT || opid == MUL_ASSIGN)
5432 ret->val = multiVal_multiply (exprNode_getValue (e1),
5433 exprNode_getValue (e2));
5435 else
5437 ret->val = multiVal_divide (exprNode_getValue (e1),
5438 exprNode_getValue (e2));
5441 tret = checkNumerics (tr1, tr2, te1, te2, e1, e2, op);
5442 break;
5444 case TPLUS: /* addition and subtraction: */
5445 case TMINUS: /* pointer, int -> pointer */
5446 case SUB_ASSIGN: /* int, pointer -> pointer */
5447 case ADD_ASSIGN: /* numeric, numeric -> numeric */
5448 if (opid == TPLUS || opid == ADD_ASSIGN)
5450 ret->val = multiVal_add (exprNode_getValue (e1),
5451 exprNode_getValue (e2));
5453 else
5455 ret->val = multiVal_subtract (exprNode_getValue (e1),
5456 exprNode_getValue (e2));
5459 tr1 = ctype_fixArrayPtr (tr1);
5461 if ((ctype_isRealPointer (tr1) && !exprNode_isNullValue (e1))
5462 && (!ctype_isRealPointer (tr2) && ctype_isRealInt (tr2)))
5464 /* pointer + int */
5466 if (context_msgPointerArith ())
5468 voptgenerror
5469 (FLG_POINTERARITH,
5470 message ("Pointer arithmetic (%t, %t): %s",
5471 te1, te2, exprNode_unparse (ret)),
5472 e1->loc);
5476 ** Swap terms so e1 is always the pointer
5479 if (ctype_isRealPointer (tr1))
5483 else
5485 exprNode_swap (e1, e2);
5488 if (sRef_possiblyNull (e1->sref)
5489 && !usymtab_isGuarded (e1->sref))
5491 voptgenerror
5492 (FLG_NULLPOINTERARITH,
5493 message ("Pointer arithmetic involving possibly "
5494 "null pointer %s: %s",
5495 exprNode_unparse (e1),
5496 exprNode_unparse (ret)),
5497 e1->loc);
5500 ret->sref = sRef_copy (e1->sref);
5502 /* start modifications */
5503 /* added by Seejo on 4/16/2000 */
5505 /* Arithmetic operations on pointers wil modify the size/len/null terminated
5506 status */
5507 if ((sRef_isPossiblyNullTerminated (e1->sref)) || (sRef_isNullTerminated(e1->sref))) {
5508 int val;
5509 /*drl 1-4-2002
5510 added ugly fixed to stop
5511 program from crashing on point + int +int
5512 one day I'll fix this or ask Seejo wtf the codes supposed to do. */
5514 if (!multiVal_isInt (e2->val) )
5515 break;
5516 /*end drl*/
5518 val = (int) multiVal_forceInt (e2->val);
5520 /* Operator : + or += */
5521 if ((lltok_getTok (op) == TPLUS) || (lltok_getTok(op) == ADD_ASSIGN)) {
5522 if (sRef_getSize(e1->sref) >= val) {/* Incrementing the pointer by
5523 val should not result in a
5524 size < 0 (size = 0 is ok !) */
5526 sRef_setSize (ret->sref, sRef_getSize(e1->sref) - val);
5528 if (sRef_getLen(e1->sref) == val) { /* i.e. the character at posn val is \0 */
5529 sRef_setNotNullTerminatedState(ret->sref);
5530 sRef_resetLen (ret->sref);
5531 } else {
5532 sRef_setNullTerminatedState(ret->sref);
5533 sRef_setLen (ret->sref, sRef_getLen(e1->sref) - val);
5538 /* Operator : - or -= */
5539 if ((lltok_getTok (op) == TMINUS) || (lltok_getTok (op) == SUB_ASSIGN)) {
5540 if (sRef_getSize(e1->sref) >= 0) {
5541 sRef_setSize (ret->sref, sRef_getSize(e1->sref) + val);
5542 sRef_setLen (ret->sref, sRef_getLen(e1->sref) + val);
5547 /* end modifications */
5549 sRef_setNullError (ret->sref);
5552 ** Fixed for 2.2c: the alias state of ptr + int is dependent,
5553 ** since is points to storage that should not be deallocated
5554 ** through this pointer.
5557 if (sRef_isOnly (ret->sref)
5558 || sRef_isFresh (ret->sref))
5560 sRef_setAliasKind (ret->sref, AK_DEPENDENT, exprNode_loc (ret));
5563 tret = e1->typ;
5565 else if ((!ctype_isRealPointer(tr1) && ctype_isRealInt (tr1))
5566 && (ctype_isRealPointer (tr2) && !exprNode_isNullValue (e2)))
5568 if (context_msgPointerArith ())
5570 voptgenerror
5571 (FLG_POINTERARITH,
5572 message ("Pointer arithmetic (%t, %t): %s",
5573 te1, te2, exprNode_unparse (ret)),
5574 e1->loc);
5577 if (sRef_possiblyNull (e1->sref)
5578 && !usymtab_isGuarded (e1->sref))
5580 voptgenerror
5581 (FLG_NULLPOINTERARITH,
5582 message ("Pointer arithmetic involving possibly "
5583 "null pointer %s: %s",
5584 exprNode_unparse (e2),
5585 exprNode_unparse (ret)),
5586 e2->loc);
5589 ret->sref = sRef_copy (e2->sref);
5591 /* start modifications */
5592 /* added by Seejo on 4/16/2000 */
5594 /* Arithmetic operations on pointers wil modify the size/len/null terminated
5595 status */
5597 if ((sRef_isPossiblyNullTerminated (e2->sref)) || (sRef_isNullTerminated(e2->sref))) {
5598 if (multiVal_isDefined (e1->val))
5600 int val = (int) multiVal_forceInt (e1->val);
5602 /* Operator : + or += */
5603 if ((lltok_getTok (op) == TPLUS) || (lltok_getTok(op) == ADD_ASSIGN)) {
5604 if (sRef_getSize(e2->sref) >= val) {/* Incrementing the pointer by
5605 val should not result in a
5606 size < 0 (size = 0 is ok !) */
5608 sRef_setSize (ret->sref, sRef_getSize(e2->sref) - val);
5610 if (sRef_getLen(e2->sref) == val) { /* i.e. the character at posn val is \0 */
5611 sRef_setNotNullTerminatedState(ret->sref);
5612 sRef_resetLen (ret->sref);
5613 } else {
5614 sRef_setNullTerminatedState(ret->sref);
5615 sRef_setLen (ret->sref, sRef_getLen(e2->sref) - val);
5620 /* Operator : - or -= */
5621 if ((lltok_getTok (op) == TMINUS) || (lltok_getTok (op) == SUB_ASSIGN)) {
5622 if (sRef_getSize(e2->sref) >= 0) {
5623 sRef_setSize (ret->sref, sRef_getSize(e2->sref) + val);
5624 sRef_setLen (ret->sref, sRef_getLen(e2->sref) + val);
5630 /* end modifications */
5632 sRef_setNullError (ret->sref);
5635 ** Fixed for 2.2c: the alias state of ptr + int is dependent,
5636 ** since is points to storage that should not be deallocated
5637 ** through this pointer.
5640 if (sRef_isOnly (ret->sref)
5641 || sRef_isFresh (ret->sref)) {
5642 sRef_setAliasKind (ret->sref, AK_DEPENDENT, exprNode_loc (ret));
5645 tret = e2->typ;
5646 ret->sref = e2->sref;
5648 else
5650 tret = checkNumerics (tr1, tr2, te1, te2, e1, e2, op);
5653 break;
5655 case LEFT_ASSIGN:
5656 case RIGHT_ASSIGN:
5657 case LEFT_OP:
5658 case RIGHT_OP:
5659 case TAMPERSAND: /* bitwise & */
5660 case AND_ASSIGN:
5661 case TCIRC: /* ^ (XOR) */
5662 case TBAR:
5663 case XOR_ASSIGN:
5664 case OR_ASSIGN:
5666 bool reported = FALSE;
5669 ** Shift Operator
5672 if (opid == LEFT_OP || opid == LEFT_ASSIGN
5673 || opid == RIGHT_OP || opid == RIGHT_ASSIGN)
5676 ** evans 2002-01-01: fixed this to follow ISO 6.5.7.
5679 if (!ctype_isUnsigned (tr2)
5680 && !exprNode_isNonNegative (e2))
5682 reported = optgenerror
5683 (FLG_SHIFTNEGATIVE,
5684 message ("Right operand of %s may be negative (%t): %s",
5685 lltok_unparse (op), te2,
5686 exprNode_unparse (ret)),
5687 e2->loc);
5690 if (!ctype_isUnsigned (tr1)
5691 && !exprNode_isNonNegative (e1))
5693 reported = optgenerror
5694 (FLG_SHIFTIMPLEMENTATION,
5695 message ("Left operand of %s may be negative (%t): %s",
5696 lltok_unparse (op), te1,
5697 exprNode_unparse (ret)),
5698 e1->loc);
5702 ** Should check size of right operand also...
5706 else
5708 if (!ctype_isUnsigned (tr1))
5710 if (exprNode_isNonNegative (e1)) {
5712 } else {
5713 reported = optgenerror
5714 (FLG_BITWISEOPS,
5715 message ("Left operand of %s is not unsigned value (%t): %s",
5716 lltok_unparse (op), te1,
5717 exprNode_unparse (ret)),
5718 e1->loc);
5720 if (reported) {
5721 te1 = ctype_uint;
5725 else
5727 if (!ctype_isUnsigned (tr2))
5729 if (!exprNode_isNonNegative (e2)) {
5730 reported = optgenerror
5731 (FLG_BITWISEOPS,
5732 message ("Right operand of %s is not unsigned value (%t): %s",
5733 lltok_unparse (op), te2,
5734 exprNode_unparse (ret)),
5735 e2->loc);
5741 if (!reported)
5743 if (!checkIntegral (e1, e2, ret, op)) {
5744 te1 = ctype_unknown;
5748 DPRINTF (("Set: %s", ctype_unparse (te1)));
5751 ** tret is the widest type of te1 and te2
5754 tret = ctype_widest (te1, te2);
5755 break;
5757 case MOD_ASSIGN:
5758 case TPERCENT:
5759 if (checkIntegral (e1, e2, ret, op)) {
5760 tret = te1;
5761 } else {
5762 tret = ctype_unknown;
5764 break;
5765 case EQ_OP:
5766 case NE_OP:
5767 case TLT: /* comparisons */
5768 case TGT: /* numeric, numeric -> bool */
5770 DPRINTF (("Here we go: %s / %s",
5771 ctype_unparse (tr1), ctype_unparse (tr2)));
5773 if ((ctype_isReal (tr1) && !ctype_isInt (tr1))
5774 || (ctype_isReal (tr2) && !ctype_isInt (tr2)))
5776 ctype rtype = tr1;
5777 bool fepsilon = FALSE;
5779 if (!ctype_isReal (rtype) || ctype_isInt (rtype))
5781 rtype = tr2;
5784 if (opid == TLT || opid == TGT)
5786 uentry ue1 = exprNode_getUentry (e1);
5787 uentry ue2 = exprNode_getUentry (e2);
5790 ** FLT_EPSILON, etc. really is a variable, not
5791 ** a constant.
5794 if (uentry_isVariable (ue1))
5796 cstring uname = uentry_rawName (ue1);
5798 if (cstring_equalLit (uname, "FLT_EPSILON")
5799 || cstring_equalLit (uname, "DBL_EPSILON")
5800 || cstring_equalLit (uname, "LDBL_EPSILON"))
5802 fepsilon = TRUE;
5806 if (uentry_isVariable (ue2))
5808 cstring uname = uentry_rawName (ue2);
5810 if (cstring_equalLit (uname, "FLT_EPSILON")
5811 || cstring_equalLit (uname, "DBL_EPSILON")
5812 || cstring_equalLit (uname, "LDBL_EPSILON"))
5814 fepsilon = TRUE;
5819 if (fepsilon)
5821 ; /* Don't complain. */
5823 else
5825 if (opid == EQ_OP || opid == NE_OP)
5827 voptgenerror
5828 (FLG_REALCOMPARE,
5829 message ("Dangerous equality comparison involving %s types: %s",
5830 ctype_unparse (rtype),
5831 exprNode_unparse (ret)),
5832 ret->loc);
5834 else
5836 voptgenerror
5837 (FLG_REALRELATECOMPARE,
5838 message ("Possibly dangerous relational comparison involving %s types: %s",
5839 ctype_unparse (rtype),
5840 exprNode_unparse (ret)),
5841 ret->loc);
5845 /*@fallthrough@*/
5846 case LE_OP:
5847 case GE_OP:
5850 ** Types should match.
5853 DPRINTF (("Match types: %s / %s", exprNode_unparse (e1),
5854 exprNode_unparse (e2)));
5856 if (!exprNode_matchTypes (e1, e2))
5858 hasError = gentypeerror
5859 (te1, e1, te2, e2,
5860 message ("Operands of %s have incompatible types (%t, %t): %s",
5861 lltok_unparse (op), te1, te2, exprNode_unparse (ret)),
5862 e1->loc);
5866 if (hasError
5867 || (ctype_isForceRealNumeric (&tr1)
5868 && ctype_isForceRealNumeric (&tr2)) ||
5869 (ctype_isRealPointer (tr1) && ctype_isRealPointer (tr2)))
5871 ; /* okay */
5873 else
5875 if ((ctype_isRealNumeric (tr1) && ctype_isRealPointer (tr2)) ||
5876 (ctype_isRealPointer (tr1) && ctype_isRealNumeric (tr2)))
5878 voptgenerror
5879 (FLG_PTRNUMCOMPARE,
5880 message ("Comparison of pointer and numeric (%t, %t): %s",
5881 te1, te2, exprNode_unparse (ret)),
5882 e1->loc);
5884 else
5886 (void) checkNumerics (tr1, tr2, te1, te2, e1, e2, op);
5888 tret = ctype_bool;
5891 /* certain comparisons on unsigned's and zero look suspicious */
5893 if (opid == TLT || opid == LE_OP || opid == GE_OP)
5895 if ((ctype_isUnsigned (tr1) && exprNode_isZero (e2))
5896 || (ctype_isUnsigned (tr2) && exprNode_isZero (e1)))
5898 voptgenerror
5899 (FLG_UNSIGNEDCOMPARE,
5900 message ("Comparison of unsigned value involving zero: %s",
5901 exprNode_unparse (ret)),
5902 e1->loc);
5906 /* EQ_OP should NOT be used with booleans (unless one is FALSE) */
5908 if ((opid == EQ_OP || opid == NE_OP) &&
5909 ctype_isDirectBool (tr1) && ctype_isDirectBool (tr2))
5912 ** is one a variable?
5915 if (uentry_isVariable (exprNode_getUentry (e1))
5916 || uentry_isVariable (exprNode_getUentry (e2)))
5919 ** comparisons with FALSE are okay
5922 if (exprNode_isFalseConstant (e1)
5923 || exprNode_isFalseConstant (e2))
5927 else
5929 voptgenerror
5930 (FLG_BOOLCOMPARE,
5931 message
5932 ("Use of %q with %s variables (risks inconsistency because "
5933 "of multiple true values): %s",
5934 cstring_makeLiteral ((opid == EQ_OP) ? "==" : "!="),
5935 context_printBoolName (), exprNode_unparse (ret)),
5936 e1->loc);
5940 break;
5942 case AND_OP: /* bool, bool -> bool */
5943 case OR_OP:
5944 if (ctype_isForceRealBool (&tr1) && ctype_isForceRealBool (&tr2))
5948 else
5950 if (context_maybeSet (FLG_BOOLOPS))
5952 if (!ctype_isRealBool (te1) && !ctype_isRealBool (te2))
5954 if (ctype_sameName (te1, te2))
5956 voptgenerror
5957 (FLG_BOOLOPS,
5958 message ("Operands of %s are non-boolean (%t): %s",
5959 lltok_unparse (op), te1,
5960 exprNode_unparse (ret)),
5961 e1->loc);
5963 else
5965 voptgenerror
5966 (FLG_BOOLOPS,
5967 message
5968 ("Operands of %s are non-booleans (%t, %t): %s",
5969 lltok_unparse (op), te1, te2, exprNode_unparse (ret)),
5970 e1->loc);
5973 else if (!ctype_isRealBool (te1))
5975 voptgenerror
5976 (FLG_BOOLOPS,
5977 message ("Left operand of %s is non-boolean (%t): %s",
5978 lltok_unparse (op), te1, exprNode_unparse (ret)),
5979 e1->loc);
5981 else if (!ctype_isRealBool (te2))
5983 voptgenerror
5984 (FLG_BOOLOPS,
5985 message ("Right operand of %s is non-boolean (%t): %s",
5986 lltok_unparse (op), te2, exprNode_unparse (ret)),
5987 e2->loc);
5989 else
5994 tret = ctype_bool;
5996 break;
5997 default:
5998 llfatalbug
5999 (cstring_makeLiteral
6000 ("There has been a problem in the parser. This is believed to result "
6001 "from a problem with bison v. 1.25. Please try rebuidling Splint "
6002 "using the pre-compiled grammar files by commenting out the "
6003 "BISON= line in the top-level Makefile."));
6006 skiprest:
6007 ret->typ = tret;
6008 DPRINTF (("Return type %s: %s", exprNode_unparse (ret), ctype_unparse (tret)));
6010 exprNode_checkUse (ret, e1->sref, e1->loc);
6011 exprNode_mergeUSs (ret, e2);
6012 exprNode_checkUse (ret, e2->sref, e2->loc);
6014 return ret;
6017 /*@only@*/ exprNode
6018 exprNode_op (/*@only@*/ exprNode e1, /*@keep@*/ exprNode e2,
6019 /*@only@*/ lltok op)
6021 exprNode ret;
6023 checkMacroParen (e1);
6024 checkMacroParen (e2);
6026 if (evaluationOrderUndefined (op) && context_maybeSet (FLG_EVALORDER))
6028 checkExpressionDefined (e1, e2, op);
6031 ret = exprNode_makeOp (e1, e2, op);
6032 return (ret);
6035 static
6036 void exprNode_checkAssignMod (exprNode e1, exprNode ret)
6039 ** This is somewhat bogus!
6041 ** Assigning to a nested observer in a non-observer datatype
6042 ** should not produce an error.
6045 sRef ref = exprNode_getSref (e1);
6047 DPRINTF (("Check assign mod: %s",
6048 sRef_unparseFull (ref)));
6050 if (sRef_isObserver (ref)
6051 || ((sRef_isFileStatic (ref) || sRef_isFileOrGlobalScope (ref))
6052 && ctype_isArray (ctype_realType (sRef_getType (ref)))))
6054 sRef base = sRef_getBase (ref);
6056 if (sRef_isValid (base) && sRef_isObserver (base))
6058 exprNode_checkModify (e1, ret);
6060 else
6062 exprNode_checkModifyVal (e1, ret);
6065 else
6067 exprNode_checkModify (e1, ret);
6071 exprNode
6072 exprNode_assign (/*@only@*/ exprNode e1, /*@only@*/ exprNode e2, /*@only@*/ lltok op)
6074 bool isalloc = FALSE;
6075 bool isjustalloc = FALSE;
6076 bool noalias = FALSE;
6077 exprNode ret;
6079 DPRINTF (("%s [%s] <- %s [%s]",
6080 exprNode_unparse (e1),
6081 ctype_unparse (e1->typ),
6082 exprNode_unparse (e2),
6083 ctype_unparse (e2->typ)));
6085 if (lltok_getTok (op) != TASSIGN)
6087 ret = exprNode_makeOp (e1, e2, op);
6089 DPRINTF (("Here goes: %s %s",
6090 ctype_unparse (e1->typ),
6091 ctype_unparse (e2->typ)));
6093 if (exprNode_isDefined (e1)
6094 && exprNode_isDefined (e2))
6096 if (ctype_isNumeric (e2->typ)
6097 || ctype_isNumeric (e1->typ))
6099 /* Its a pointer arithmetic expression like ptr += i */
6100 noalias = TRUE;
6104 else
6106 ret = exprNode_createPartialCopy (e1);
6107 ret->kind = XPR_ASSIGN;
6108 ret->edata = exprData_makeOp (e1, e2, op);
6110 if (!exprNode_isError (e2))
6112 ret->sets = sRefSet_union (ret->sets, e2->sets);
6113 ret->msets = sRefSet_union (ret->msets, e2->msets);
6114 ret->uses = sRefSet_union (ret->uses, e2->uses);
6118 checkExpressionDefined (e1, e2, op);
6120 if (exprNode_isError (e1))
6122 if (!exprNode_isError (e2))
6124 ret->loc = fileloc_update (ret->loc, e2->loc);
6126 else
6128 ret->loc = fileloc_update (ret->loc, g_currentloc);
6132 if (!exprNode_isError (e2))
6134 checkMacroParen (e2);
6137 if (exprNode_isDefined (e1))
6139 if (sRef_isMacroParamRef (e1->sref))
6141 if (context_inIterDef ())
6143 uentry ue = sRef_getUentry (e1->sref);
6145 if (uentry_isYield (ue))
6149 else
6151 if (fileloc_isDefined (e1->loc))
6153 voptgenerror
6154 (FLG_MACROPARAMS,
6155 message ("Assignment to non-yield iter parameter: %q",
6156 sRef_unparse (e1->sref)),
6157 e1->loc);
6159 else
6161 voptgenerror
6162 (FLG_MACROPARAMS,
6163 message ("Assignment to non-yield iter parameter: %q",
6164 sRef_unparse (e1->sref)),
6165 g_currentloc);
6169 else
6171 if (fileloc_isDefined (e1->loc))
6173 voptgenerror
6174 (FLG_MACROASSIGN,
6175 message ("Assignment to macro parameter: %q",
6176 sRef_unparse (e1->sref)),
6177 e1->loc);
6179 else
6181 voptgenerror
6182 (FLG_MACROASSIGN,
6183 message ("Assignment to macro parameter: %q",
6184 sRef_unparse (e1->sref)),
6185 g_currentloc);
6188 exprNode_checkAssignMod (e1, ret); /* evans 2001-07-22 */
6191 else
6193 exprNode_checkAssignMod (e1, ret);
6196 if (exprNode_isDefined (e2))
6198 if (lltok_getTok (op) == TASSIGN)
6200 ctype te1 = exprNode_getType (e1);
6201 ctype te2 = exprNode_getType (e2);
6203 if (ctype_isVoid (te2))
6205 (void) gentypeerror
6206 (te2, e2, te1, e1,
6207 message ("Assignment of void value to %t: %s %s %s",
6208 te1, exprNode_unparse (e1),
6209 lltok_unparse (op),
6210 exprNode_unparse (e2)),
6211 e1->loc);
6213 else if (!ctype_forceMatch (te1, te2))
6215 if (exprNode_matchLiteral (te1, e2))
6217 DPRINTF (("Literals match: %s / %s",
6218 ctype_unparse (te1), exprNode_unparse (e2)));
6219 if (ctype_isNumAbstract (te1)) {
6220 if (!context_flagOn (FLG_NUMABSTRACTLIT, e1->loc)) {
6221 (void) llgenhinterror
6222 (FLG_NUMABSTRACT,
6223 message
6224 ("Assignment of %t literal to numabstract type %t: %s %s %s",
6225 te2, te1,
6226 exprNode_unparse (e1),
6227 lltok_unparse (op),
6228 exprNode_unparse (e2)),
6229 cstring_makeLiteral
6230 ("Use +numabstractlit to allow numeric literals to be used as numabstract values"),
6231 e1->loc);
6235 else
6237 (void) gentypeerror
6238 (te2, e2, te1, e1,
6239 message ("Assignment of %t to %t: %s %s %s",
6240 te2, te1, exprNode_unparse (e1),
6241 lltok_unparse (op),
6242 exprNode_unparse (e2)),
6243 e1->loc);
6246 else
6248 /* Type checks okay */
6252 exprNode_mergeUSs (ret, e2);
6253 exprNode_checkUse (ret, e2->sref, e2->loc);
6255 DPRINTF (("Do assign! %s %s", exprNode_unparse (e1), exprNode_unparse (e2)));
6256 if (noalias)
6260 else
6262 doAssign (e1, e2, FALSE);
6265 ret->sref = e1->sref;
6267 else
6269 if (exprNode_isDefined (e2))
6271 exprNode_mergeUSs (ret, e2);
6272 exprNode_checkUse (ret, e2->sref, e2->loc);
6276 if (sRef_isPointer (e1->sref) && !sRef_isMacroParamRef (e1->sref))
6278 exprNode_checkUse (ret, sRef_getBase (e1->sref), e1->loc);
6281 isjustalloc = sRef_isJustAllocated (e1->sref);
6282 isalloc = sRef_isAllocated (e1->sref);
6284 if (sRef_isField (e1->sref))
6286 sRef root = sRef_getRootBase (sRef_getBase (e1->sref));
6288 if (!sRef_isAllocated (root) && !sRef_isMacroParamRef (root))
6290 exprNode_checkUse (ret, root, e1->loc);
6296 ** be careful! this defines e1->sref.
6299 /* evans 2001-07-22: removed if (!sRef_isMacroParamRef (e1->sref)) */
6301 DPRINTF (("Setting: %s -> %s", exprNode_unparse (ret), sRef_unparse (e1->sref)));
6302 exprNode_checkSet (ret, e1->sref);
6304 if (isjustalloc)
6306 sRef_setAllocatedComplete (e1->sref, exprNode_isDefined (e2)
6307 ? e2->loc : e1->loc);
6309 else
6311 if (isalloc)
6313 sRef_setAllocatedShallowComplete (e1->sref, exprNode_loc (e2));
6318 return ret;
6321 exprNode
6322 exprNode_cond (/*@keep@*/ exprNode pred, /*@keep@*/ exprNode ifclause,
6323 /*@keep@*/ exprNode elseclause)
6325 exprNode ret;
6327 if (!exprNode_isError (pred))
6329 ret = exprNode_createPartialCopy (pred);
6330 checkMacroParen (pred);
6331 exprNode_checkPred (cstring_makeLiteralTemp ("conditional"), pred);
6333 if (!exprNode_isError (ifclause))
6335 checkMacroParen (ifclause); /* update macro counts! */
6337 if (!exprNode_isError (elseclause))
6339 checkMacroParen (elseclause);
6341 if (!exprNode_matchTypes (ifclause, elseclause))
6343 if (gentypeerror
6344 (exprNode_getType (ifclause),
6345 ifclause,
6346 exprNode_getType (elseclause),
6347 elseclause,
6348 message ("Conditional clauses are not of same type: "
6349 "%s (%t), %s (%t)",
6350 exprNode_unparse (ifclause),
6351 exprNode_getType (ifclause),
6352 exprNode_unparse (elseclause),
6353 exprNode_getType (elseclause)),
6354 ifclause->loc))
6356 ret->sref = sRef_undefined;
6357 ret->typ = ctype_unknown;
6360 else
6362 /* for now...should merge the states */
6363 ret->sref = ifclause->sref;
6364 ret->typ = ifclause->typ;
6366 if (exprNode_isNullValue (ifclause))
6368 ret->typ = elseclause->typ;
6372 exprNode_checkUse (ret, pred->sref, pred->loc);
6373 exprNode_checkUse (ifclause, ifclause->sref, ifclause->loc);
6374 exprNode_checkUse (elseclause, elseclause->sref, elseclause->loc);
6376 exprNode_mergeCondUSs (ret, ifclause, elseclause);
6379 else
6381 ret->typ = ifclause->typ;
6383 exprNode_checkUse (pred, pred->sref, pred->loc);
6384 exprNode_checkUse (ifclause, ifclause->sref, ifclause->loc);
6386 exprNode_mergeCondUSs (ret, ifclause, exprNode_undefined);
6389 else
6391 if (!exprNode_isError (elseclause))
6393 ret->typ = elseclause->typ;
6395 exprNode_checkUse (pred, pred->sref, pred->loc);
6396 exprNode_checkUse (elseclause, elseclause->sref, elseclause->loc);
6398 exprNode_mergeCondUSs (ret, exprNode_undefined, elseclause);
6402 else /* pred is error */
6404 if (!exprNode_isError (ifclause))
6406 ret = exprNode_createSemiCopy (ifclause);
6408 checkMacroParen (ifclause); /* update macro counts! */
6410 if (!exprNode_isError (elseclause))
6412 checkMacroParen (elseclause);
6414 ret->typ = ifclause->typ;
6416 if (!ctype_forceMatch (ifclause->typ, elseclause->typ))
6418 if (gentypeerror
6419 (exprNode_getType (ifclause),
6420 ifclause,
6421 exprNode_getType (elseclause),
6422 elseclause,
6423 message ("Conditional clauses are not of same type: "
6424 "%s (%t), %s (%t)",
6425 exprNode_unparse (ifclause),
6426 exprNode_getType (ifclause),
6427 exprNode_unparse (elseclause),
6428 exprNode_getType (elseclause)),
6429 ifclause->loc))
6431 ret->typ = ctype_unknown;
6435 exprNode_checkUse (ifclause, ifclause->sref, ifclause->loc);
6436 exprNode_checkUse (elseclause, elseclause->sref, elseclause->loc);
6438 exprNode_mergeCondUSs (ret, ifclause, elseclause);
6441 else if (!exprNode_isError (elseclause)) /* pred, if errors */
6443 ret = exprNode_createSemiCopy (ifclause);
6445 ret->typ = elseclause->typ;
6446 checkMacroParen (elseclause);
6448 exprNode_checkUse (elseclause, elseclause->sref, elseclause->loc);
6449 exprNode_mergeCondUSs (ret, exprNode_undefined, elseclause);
6451 else /* all errors! */
6453 ret = exprNode_createLoc (ctype_unknown, fileloc_copy (g_currentloc));
6457 ret->kind = XPR_COND;
6458 ret->edata = exprData_makeCond (pred, ifclause, elseclause);
6460 if (exprNode_isDefined (ifclause) && exprNode_isDefined (elseclause))
6462 exprNode_combineControl (ret, ifclause, elseclause);
6465 return (ret);
6468 exprNode
6469 exprNode_condIfOmit (/*@keep@*/ exprNode pred,
6470 /*@keep@*/ exprNode elseclause)
6472 exprNode ifclause = exprNode_createPartialCopy (pred);
6474 if (!context_flagOn (FLG_GNUEXTENSIONS, exprNode_loc (pred)))
6476 (void) llgenhinterror
6477 (FLG_SYNTAX,
6478 message ("Conditionals with Omitted Operands is not supported by ISO C99"),
6479 message ("Use +gnuextensions to allow compound statement "
6480 "expressions (and other GNU language extensions) "
6481 "without this warning"),
6482 exprNode_loc (pred));
6485 return exprNode_cond(pred, ifclause, elseclause);
6488 exprNode
6489 exprNode_vaArg (/*@only@*/ lltok tok, /*@only@*/ exprNode arg, /*@only@*/ qtype qt)
6491 ctype totype = qtype_getType (qt);
6492 exprNode ret =
6493 exprNode_createPartialLocCopy (arg, fileloc_copy (lltok_getLoc (tok)));
6494 ctype targ;
6497 ** check use of va_arg : <valist>, type -> type
6500 if (exprNode_isError (arg))
6503 else
6505 targ = exprNode_getType (arg);
6508 ** arg should have be a pointer
6511 if (!ctype_isUA (targ) ||
6512 (!typeId_equal (ctype_typeId (targ),
6513 usymtab_getTypeId (cstring_makeLiteralTemp ("va_list")))))
6515 voptgenerror
6516 (FLG_TYPE,
6517 message ("First argument to va_arg is not a va_list (type %t): %s",
6518 targ, exprNode_unparse (arg)),
6519 arg->loc);
6522 exprNode_checkSet (ret, arg->sref);
6526 ** return type is totype
6529 ret->typ = totype;
6530 ret->kind = XPR_VAARG;
6531 ret->edata = exprData_makeCast (tok, arg, qt);
6533 return (ret);
6536 exprNode exprNode_labelMarker (/*@only@*/ cstring label)
6538 exprNode ret = exprNode_createPlain (ctype_undefined);
6539 ret->kind = XPR_LABEL;
6540 ret->edata = exprData_makeLiteral (label);
6541 ret->isJumpPoint = TRUE;
6543 return (ret); /* for now, ignore label */
6546 exprNode exprNode_notReached (/*@returned@*/ exprNode stmt)
6548 if (exprNode_isDefined (stmt))
6550 stmt->isJumpPoint = TRUE;
6552 /* This prevent stray no return path errors, etc. */
6553 stmt->exitCode = XK_MUSTEXIT;
6556 return (stmt);
6559 static bool exprNode_isDefaultMarker (exprNode e)
6561 if (exprNode_isDefined (e))
6563 return (e->kind == XPR_DEFAULT || e->kind == XPR_FTDEFAULT);
6566 return FALSE;
6569 bool exprNode_isCaseMarker (exprNode e)
6571 if (exprNode_isDefined (e))
6573 return (e->kind == XPR_FTCASE || e->kind == XPR_CASE);
6576 return FALSE;
6579 static bool exprNode_isLabelMarker (exprNode e)
6581 if (exprNode_isDefined (e))
6583 return (e->kind == XPR_LABEL);
6586 return FALSE;
6589 exprNode exprNode_caseMarker (/*@only@*/ exprNode test, bool fallThrough)
6591 exprNode ret = exprNode_createPartialCopy (test);
6593 ret->kind = fallThrough ? XPR_FTCASE : XPR_CASE;
6595 if (exprNode_isError (test)) {
6596 return ret;
6599 exprNode_checkUse (ret, test->sref, test->loc);
6601 usymtab_setExitCode (ret->exitCode);
6603 if (ret->mustBreak)
6605 usymtab_setMustBreak ();
6608 ret->edata = exprData_makeSingle (test);
6609 ret->isJumpPoint = TRUE;
6611 return ret;
6614 # if 0
6615 exprNode exprNode_caseStatement (/*@only@*/ exprNode test, /*@only@*/ exprNode stmt, bool fallThrough)
6617 exprNode ret = exprNode_createPartialCopy (test);
6619 ret->kind = fallThrough ? XPR_FTCASE : XPR_CASE;
6620 ret->edata = exprData_makePair (test, stmt);
6621 ret->isJumpPoint = TRUE;
6623 if (exprNode_isError (test))
6625 return ret;
6628 exprNode_checkUse (ret, test->sref, test->loc);
6630 if (exprNode_isError (stmt))
6632 return ret;
6635 exprNode_mergeUSs (ret, stmt);
6637 ret->exitCode = stmt->exitCode;
6638 ret->mustBreak = stmt->mustBreak;
6639 ret->canBreak = stmt->canBreak;
6641 usymtab_setExitCode (ret->exitCode);
6643 if (ret->mustBreak)
6645 usymtab_setMustBreak ();
6648 return ret;
6650 # endif
6652 /*@notnull@*/ /*@only@*/ exprNode
6653 exprNode_defaultMarker (/*@only@*/ lltok def, bool fallThrough)
6655 exprNode ret = exprNode_createTok (def);
6657 ret->isJumpPoint = TRUE;
6658 ret->kind = fallThrough ? XPR_FTDEFAULT : XPR_DEFAULT;
6659 return (ret);
6662 bool
6663 exprNode_mayEscape (exprNode e)
6665 if (exprNode_isDefined (e))
6667 return exitkind_couldEscape (e->exitCode);
6669 return FALSE;
6672 static bool
6673 exprNode_mustBreak (exprNode e)
6675 if (exprNode_isDefined (e))
6677 return e->mustBreak;
6680 return FALSE;
6683 bool
6684 exprNode_mustEscape (exprNode e)
6686 if (exprNode_isDefined (e))
6688 return exitkind_mustEscape (e->exitCode) || exprNode_mustBreak (e);
6691 return FALSE;
6694 bool
6695 exprNode_errorEscape (exprNode e)
6697 if (exprNode_isDefined (e))
6699 return exitkind_isError (e->exitCode);
6702 return FALSE;
6705 exprNode exprNode_concat (/*@only@*/ exprNode e1, /*@only@*/ exprNode e2)
6707 exprNode ret = exprNode_createPartialCopy (e1);
6709 DPRINTF (("Concat: %s / %s", exprNode_unparse (e1), exprNode_unparse (e2)));
6711 ret->edata = exprData_makePair (e1, e2);
6712 ret->kind = XPR_STMTLIST;
6714 if (exprNode_isDefined (e1))
6716 ret->isJumpPoint = e1->isJumpPoint;
6717 ret->canBreak = e1->canBreak;
6719 else
6721 if (exprNode_isDefined (e2))
6723 ret->loc = fileloc_update (ret->loc, e2->loc);
6727 if (exprNode_isDefined (e2))
6729 ret->exitCode = e2->exitCode;
6730 ret->mustBreak = e2->mustBreak;
6731 if (e2->canBreak) ret->canBreak = TRUE;
6735 ** if e1 must return, then e2 is unreachable!
6738 if (exprNode_isDefined (e1) && exprNode_isDefined (e2))
6740 if ((exprNode_mustEscape (e1) || exprNode_mustBreak (e1))
6741 && !(e2->isJumpPoint))
6743 if (context_getFlag (FLG_UNREACHABLE))
6745 exprNode nr = e2;
6747 if (e2->kind == XPR_STMT)
6749 nr = exprData_getUopNode (e2->edata);
6752 if ((nr->kind == XPR_TOK
6753 && lltok_isSemi (exprData_getTok (nr->edata))))
6755 /* okay to have unreachable ";" */
6756 ret->exitCode = XK_MUSTEXIT;
6757 ret->canBreak = TRUE;
6759 else
6761 if (optgenerror (FLG_UNREACHABLE,
6762 message ("Unreachable code: %s",
6763 exprNode_unparseFirst (nr)),
6764 exprNode_loc (nr)))
6766 ret->isJumpPoint = TRUE;
6767 ret->mustBreak = FALSE;
6768 ret->exitCode = XK_ERROR;
6769 DPRINTF (("Jump point: %s", exprNode_unparse (ret)));
6771 else
6773 ret->exitCode = XK_MUSTEXIT;
6774 ret->canBreak = TRUE;
6780 else
6782 if ((e2->kind == XPR_CASE || e2->kind == XPR_DEFAULT))
6785 ** We want a warning anytime we have:
6786 ** case xxx: ...
6787 ** yyy; <<<- no break or return
6788 ** case zzz: ...
6791 exprNode lastStmt = exprNode_lastStatement (e1);
6793 if (exprNode_isDefined (lastStmt)
6794 && !exprNode_mustEscape (lastStmt)
6795 && !exprNode_mustBreak (lastStmt)
6796 && !exprNode_isCaseMarker (lastStmt)
6797 && !exprNode_isDefaultMarker (lastStmt)
6798 && !exprNode_isLabelMarker (lastStmt))
6800 voptgenerror (FLG_CASEBREAK,
6801 cstring_makeLiteral
6802 ("Fall through case (no preceding break)"),
6803 e2->loc);
6809 exprNode_mergeUSs (ret, e2);
6811 usymtab_setExitCode (ret->exitCode);
6813 if (ret->mustBreak)
6815 usymtab_setMustBreak ();
6818 DPRINTF (("==> %s", exprNode_unparse (ret)));
6819 return ret;
6822 exprNode exprNode_createTok (/*@only@*/ lltok t)
6824 exprNode ret = exprNode_create (ctype_unknown);
6825 ret->kind = XPR_TOK;
6826 ret->edata = exprData_makeTok (t);
6827 return ret;
6830 exprNode exprNode_statement (/*@only@*/ exprNode e, /*@only@*/ lltok t)
6832 if (!exprNode_isError (e))
6834 exprChecks_checkStatementEffect(e);
6837 return (exprNode_statementError (e, t));
6840 static exprNode exprNode_statementError (/*@only@*/ exprNode e, /*@only@*/ lltok t)
6842 exprNode ret = exprNode_createPartialCopy (e);
6844 if (!exprNode_isError (e))
6846 if (e->kind != XPR_ASSIGN)
6848 exprNode_checkUse (ret, e->sref, e->loc);
6851 ret->exitCode = e->exitCode;
6852 ret->canBreak = e->canBreak;
6853 ret->mustBreak = e->mustBreak;
6856 ret->edata = exprData_makeUop (e, t);
6857 ret->kind = XPR_STMT;
6859 return ret;
6862 exprNode exprNode_checkExpr (/*@returned@*/ exprNode e)
6864 if (!exprNode_isError (e))
6866 if (e->kind != XPR_ASSIGN)
6868 exprNode_checkUse (e, e->sref, e->loc);
6872 return e;
6875 void exprNode_produceGuards (exprNode pred)
6877 if (!exprNode_isError (pred))
6879 if (ctype_isRealPointer (pred->typ))
6881 pred->guards = guardSet_addTrueGuard (pred->guards, pred->sref);
6884 exprNode_checkUse (pred, pred->sref, pred->loc);
6885 exprNode_resetSref (pred);
6889 exprNode exprNode_compoundStatementExpression (/*@only@*/ lltok tlparen, /*@only@*/ exprNode e)
6891 exprNode laststmt;
6893 DPRINTF (("Compound: %s", exprNode_unparse (e)));
6895 if (!context_flagOn (FLG_GNUEXTENSIONS, exprNode_loc (e)))
6897 (void) llgenhinterror
6898 (FLG_SYNTAX,
6899 message ("Compound statement expressions is not supported by ISO C99"),
6900 message ("Use +gnuextensions to allow compound statement expressions (and other GNU language extensions) "
6901 "without this warning"),
6902 exprNode_loc (e));
6906 ** The type of a compoundStatementExpression is the type of the last statement
6909 llassert (exprNode_isBlock (e));
6910 laststmt = exprNode_lastStatement (e);
6912 DPRINTF (("Last statement: %s / %s", exprNode_unparse (laststmt), ctype_unparse (exprNode_getType (laststmt))));
6913 DPRINTF (("e: %s", exprNode_unparse (e)));
6914 e->typ = exprNode_getType (laststmt);
6915 return exprNode_addParens (tlparen, e);
6919 exprNode exprNode_makeBlock (/*@only@*/ exprNode e)
6921 exprNode ret = exprNode_createPartialCopy (e);
6923 if (!exprNode_isError (e))
6925 ret->exitCode = e->exitCode;
6926 ret->canBreak = e->canBreak;
6927 ret->mustBreak = e->mustBreak;
6930 DPRINTF (("Block e: %s", exprNode_unparse (e)));
6931 ret->edata = exprData_makeSingle (e);
6932 ret->kind = XPR_BLOCK;
6933 DPRINTF (("Block: %s", exprNode_unparse (ret)));
6934 return ret;
6937 static bool exprNode_isBlock (exprNode e)
6939 return (exprNode_isDefined (e)
6940 && ((e)->kind == XPR_BLOCK));
6943 bool exprNode_isStatement (exprNode e)
6945 return (exprNode_isDefined (e)
6946 && ((e)->kind == XPR_STMT));
6949 bool exprNode_isAssign (exprNode e)
6951 if (exprNode_isDefined (e))
6953 return (e->kind == XPR_ASSIGN);
6956 return FALSE;
6959 bool exprNode_isEmptyStatement (exprNode e)
6961 return (exprNode_isDefined (e)
6962 && (e->kind == XPR_TOK)
6963 && (lltok_isSemi (exprData_getTok (e->edata))));
6966 bool exprNode_isMultiStatement (exprNode e)
6968 return (exprNode_isDefined (e)
6969 && ((e->kind == XPR_FOR)
6970 || (e->kind == XPR_FORPRED)
6971 || (e->kind == XPR_IF)
6972 || (e->kind == XPR_IFELSE)
6973 || (e->kind == XPR_WHILE)
6974 || (e->kind == XPR_WHILEPRED)
6975 || (e->kind == XPR_DOWHILE)
6976 || (e->kind == XPR_BLOCK)
6977 || (e->kind == XPR_STMT)
6978 || (e->kind == XPR_STMTLIST)
6979 || (e->kind == XPR_SWITCH)));
6982 void exprNode_checkIfPred (exprNode pred)
6984 exprNode_checkPred (cstring_makeLiteralTemp ("if"), pred);
6987 exprNode exprNode_if (/*@only@*/ exprNode pred, /*@only@*/ exprNode tclause)
6989 exprNode ret;
6990 bool emptyErr = FALSE;
6992 if (context_maybeSet (FLG_IFEMPTY))
6994 if (exprNode_isEmptyStatement (tclause))
6996 emptyErr = optgenerror (FLG_IFEMPTY,
6997 cstring_makeLiteral
6998 ("Body of if statement is empty"),
6999 exprNode_loc (tclause));
7003 if (!emptyErr && context_maybeSet (FLG_IFBLOCK))
7005 if (exprNode_isDefined (tclause)
7006 && !exprNode_isBlock (tclause))
7008 voptgenerror (FLG_IFBLOCK,
7009 message
7010 ("Body of if statement is not a block: %s",
7011 exprNode_unparse (tclause)),
7012 exprNode_loc (tclause));
7016 if (exprNode_isError (pred))
7018 if (exprNode_isError (tclause))
7020 ret = exprNode_createLoc (ctype_unknown, fileloc_copy (g_currentloc));
7022 else
7024 ret = exprNode_createPartialCopy (tclause);
7027 else
7029 if (exprNode_mustEscape (pred))
7031 voptgenerror
7032 (FLG_UNREACHABLE,
7033 message ("Predicate always exits: %s", exprNode_unparse (pred)),
7034 exprNode_loc (pred));
7037 exprNode_checkUse (pred, pred->sref, pred->loc);
7039 if (!exprNode_isError (tclause))
7041 exprNode_mergeCondUSs (pred, tclause, exprNode_undefined);
7044 ret = exprNode_createPartialCopy (pred);
7047 ret->kind = XPR_IF;
7048 ret->edata = exprData_makePair (pred, tclause);
7050 ret->exitCode = XK_UNKNOWN;
7052 if (exprNode_isDefined (tclause))
7054 ret->exitCode = exitkind_makeConditional (tclause->exitCode);
7055 ret->canBreak = tclause->canBreak;
7056 ret->sets = sRefSet_union (ret->sets, tclause->sets);
7057 ret->msets = sRefSet_union (ret->msets, tclause->msets);
7058 ret->uses = sRefSet_union (ret->uses, tclause->uses);
7061 ret->mustBreak = FALSE;
7063 return ret;
7066 exprNode exprNode_ifelse (/*@only@*/ exprNode pred,
7067 /*@only@*/ exprNode tclause,
7068 /*@only@*/ exprNode eclause)
7070 exprNode ret;
7071 bool tEmptyErr = FALSE;
7072 bool eEmptyErr = FALSE;
7074 if (context_maybeSet (FLG_IFEMPTY))
7076 if (exprNode_isEmptyStatement (tclause))
7078 tEmptyErr = optgenerror
7079 (FLG_IFEMPTY,
7080 cstring_makeLiteral
7081 ("Body of if clause of if statement is empty"),
7082 exprNode_loc (tclause));
7085 if (exprNode_isEmptyStatement (eclause))
7087 eEmptyErr = optgenerror
7088 (FLG_IFEMPTY,
7089 cstring_makeLiteral
7090 ("Body of else clause of if statement is empty"),
7091 exprNode_loc (eclause));
7095 if (context_maybeSet (FLG_IFBLOCK))
7097 if (!tEmptyErr
7098 && exprNode_isDefined (tclause)
7099 && !exprNode_isBlock (tclause))
7101 voptgenerror (FLG_IFBLOCK,
7102 message
7103 ("Body of if clause of if statement is not a block: %s",
7104 exprNode_unparse (tclause)),
7105 exprNode_loc (tclause));
7108 if (!eEmptyErr
7109 && exprNode_isDefined (eclause)
7110 && !exprNode_isBlock (eclause)
7111 && !(eclause->kind == XPR_IF)
7112 && !(eclause->kind == XPR_IFELSE))
7114 voptgenerror
7115 (FLG_IFBLOCK,
7116 message
7117 ("Body of else clause of if statement is not a block: %s",
7118 exprNode_unparse (eclause)),
7119 exprNode_loc (eclause));
7123 if (context_maybeSet (FLG_ELSEIFCOMPLETE))
7125 if (exprNode_isDefined (eclause)
7126 && (eclause->kind == XPR_IF))
7128 voptgenerror (FLG_ELSEIFCOMPLETE,
7129 message ("Incomplete else if logic (no final else): %s",
7130 exprNode_unparse (eclause)),
7131 exprNode_loc (eclause));
7135 if (exprNode_isError (pred))
7137 if (exprNode_isError (tclause))
7139 if (exprNode_isError (eclause))
7141 ret = exprNode_createLoc (ctype_unknown, fileloc_copy (g_currentloc));
7143 else
7145 ret = exprNode_createPartialCopy (eclause);
7148 else
7150 ret = exprNode_createPartialCopy (tclause);
7153 else /* pred is okay */
7155 ret = exprNode_createPartialCopy (pred);
7157 if (exprNode_mustEscape (pred))
7159 voptgenerror
7160 (FLG_UNREACHABLE,
7161 message ("Predicate always exits: %s", exprNode_unparse (pred)),
7162 exprNode_loc (pred));
7165 exprNode_checkUse (ret, pred->sref, pred->loc);
7166 exprNode_mergeCondUSs (ret, tclause, eclause);
7169 ret->kind = XPR_IFELSE;
7170 ret->edata = exprData_makeCond (pred, tclause, eclause);
7172 if (exprNode_isDefined (tclause) && exprNode_isDefined (eclause))
7174 exprNode_combineControl (ret, tclause, eclause);
7175 ret->loc = fileloc_update (ret->loc, eclause->loc);
7178 return ret;
7182 ** *allpaths <- TRUE iff all executions paths must go through the switch
7185 static bool
7186 checkSwitchExpr (exprNode test, /*@dependent@*/ exprNode e, /*@out@*/ bool *allpaths)
7188 exprNodeSList el = exprNode_flatten (e);
7189 bool mustReturn = TRUE; /* find a branch that doesn't */
7190 bool thisReturn = FALSE;
7191 bool hasDefault = FALSE;
7192 bool hasAllMembers = FALSE;
7193 bool inSwitch = FALSE;
7194 bool isEnumSwitch = FALSE;
7195 bool canBreak = FALSE;
7196 bool fallThrough = FALSE;
7197 ctype ct = ctype_unknown;
7198 enumNameSList usedEnums;
7199 enumNameList enums;
7201 if (exprNode_isDefined (test))
7203 ctype ttype;
7205 ct = test->typ;
7206 ttype = ctype_realType (ct);
7208 if (ctype_isEnum (ttype))
7210 isEnumSwitch = TRUE;
7211 enums = ctype_elist (ttype);
7212 usedEnums = enumNameSList_new ();
7216 exprNodeSList_elements (el, current)
7219 DPRINTF ((message("checkSwitchExpr current = %s ", exprNode_unparse(current) ) ));
7221 if (exprNode_isDefined (current))
7223 switch (current->kind)
7225 case XPR_FTDEFAULT:
7226 case XPR_DEFAULT:
7227 if (hasDefault)
7229 voptgenerror
7230 (FLG_DUPLICATECASES,
7231 message ("Duplicate default cases in switch"),
7232 exprNode_loc (current));
7234 /*@fallthrough@*/
7235 case XPR_FTCASE:
7236 case XPR_CASE:
7237 if (current->kind == XPR_DEFAULT || current->kind == XPR_FTDEFAULT)
7239 hasDefault = TRUE;
7241 else
7243 if (isEnumSwitch)
7245 exprNode st = exprData_getSingle (current->edata);
7246 uentry ue = exprNode_getUentry (st);
7248 if (uentry_isValid (ue))
7250 cstring cname = uentry_rawName (ue);
7252 if (enumNameList_member (/*@-usedef@*/enums/*@=usedef@*/, cname))
7254 if (enumNameSList_member
7255 (/*@-usedef@*/usedEnums/*@=usedef@*/, cname))
7257 voptgenerror
7258 (FLG_DUPLICATECASES,
7259 message ("Duplicate case in switch: %s",
7260 cname),
7261 current->loc);
7263 else
7265 enumNameSList_addh (usedEnums, cname);
7268 else
7270 voptgenerror
7271 (FLG_TYPE,
7272 message ("Case in switch not %s member: %s",
7273 ctype_unparse (ct), cname),
7274 current->loc);
7280 if (inSwitch && !fallThrough)
7282 if (!thisReturn || canBreak)
7284 mustReturn = FALSE;
7288 fallThrough = TRUE;
7289 inSwitch = TRUE;
7290 thisReturn = FALSE;
7291 canBreak = FALSE;
7292 /*@switchbreak@*/ break;
7293 default:
7294 thisReturn = thisReturn || exprNode_mustEscape (current);
7295 canBreak = canBreak || current->canBreak;
7296 if (canBreak) fallThrough = FALSE;
7299 } end_exprNodeSList_elements;
7301 if (inSwitch) /* check the last one! */
7303 if (!thisReturn || canBreak)
7305 mustReturn = FALSE;
7309 if (isEnumSwitch)
7311 if (!hasDefault
7312 && (enumNameSList_size (/*@-usedef@*/usedEnums/*@=usedef@*/) !=
7313 enumNameList_size (/*@-usedef@*/enums/*@=usedef@*/)))
7315 enumNameSList unused = enumNameSList_subtract (enums, usedEnums);
7317 voptgenerror (FLG_MISSCASE,
7318 message ("Missing case%s in switch: %q",
7319 cstring_makeLiteralTemp
7320 ((enumNameSList_size (unused) > 1) ? "s" : ""),
7321 enumNameSList_unparse (unused)),
7322 g_currentloc);
7324 enumNameSList_free (unused);
7325 *allpaths = FALSE; /* evans 2002-01-01 */
7327 else
7329 hasAllMembers = TRUE;
7330 *allpaths = TRUE;
7333 enumNameSList_free (usedEnums);
7335 else
7337 *allpaths = hasDefault;
7340 exprNodeSList_free (el);
7341 return ((hasDefault || hasAllMembers) && mustReturn);
7344 exprNode exprNode_switch (/*@only@*/ exprNode e, /*@only@*/ exprNode s)
7346 exprNode ret = exprNode_createPartialCopy (e);
7347 bool allpaths;
7349 DPRINTF (("Switch: %s", exprNode_unparse (s)));
7351 ret->kind = XPR_SWITCH;
7352 ret->edata = exprData_makePair (e, s);
7354 if (!exprNode_isError (s))
7356 exprNode fs = exprNode_firstStatement (s);
7357 ret->loc = fileloc_update (ret->loc, s->loc);
7359 if (exprNode_isUndefined (fs)
7360 || exprNode_isCaseMarker (fs) || exprNode_isLabelMarker (fs)
7361 || exprNode_isDefaultMarker (fs)) {
7363 } else {
7364 voptgenerror (FLG_FIRSTCASE,
7365 message
7366 ("Statement after switch is not a case: %s", exprNode_unparse (fs)),
7367 fs->loc);
7371 if (!exprNode_isError (e))
7373 if (checkSwitchExpr (e, s, &allpaths))
7375 ret->exitCode = XK_MUSTRETURN;
7377 else
7379 ret->exitCode = e->exitCode;
7382 ret->canBreak = e->canBreak;
7383 ret->mustBreak = e->mustBreak;
7386 ** forgot this!
7387 ** exprNode.c:3883,32: Variable allpaths used before definition
7389 else
7391 allpaths = FALSE;
7394 DPRINTF (("Context exit switch!"));
7395 context_exitSwitch (ret, allpaths);
7396 DPRINTF (("Context exit switch done!"));
7398 return ret;
7401 static void checkInfiniteLoop (/*@notnull@*/ exprNode test,
7402 /*@notnull@*/ exprNode body)
7404 sRefSet tuses = test->uses;
7406 if (!sRefSet_isEmpty (test->uses))
7408 sRefSet sets = sRefSet_newCopy (body->sets);
7409 bool hasError = TRUE;
7410 bool innerState = FALSE;
7411 sRefSet tuncon = sRefSet_undefined;
7413 sets = sRefSet_union (sets, test->sets);
7414 sets = sRefSet_union (sets, body->msets);
7415 sets = sRefSet_union (sets, test->msets);
7417 sRefSet_allElements (tuses, el)
7419 if (sRef_isUnconstrained (el))
7421 tuncon = sRefSet_insert (tuncon, el);
7423 else
7425 if (sRefSet_member (sets, el))
7427 hasError = FALSE;
7428 break;
7432 if (sRef_isInternalState (el)
7433 || sRef_isFileStatic (sRef_getRootBase (el)))
7435 innerState = TRUE;
7437 } end_sRefSet_allElements ;
7439 if (hasError)
7441 sRefSet suncon = sRefSet_undefined;
7442 bool sinner = FALSE;
7444 sRefSet_allElements (sets, el)
7446 if (sRef_isUnconstrained (el))
7448 suncon = sRefSet_insert (suncon, el);
7450 else if (sRef_isInternalState (el))
7452 sinner = TRUE;
7454 else
7458 } end_sRefSet_allElements ;
7460 if (sinner && innerState)
7464 else if (sRefSet_isEmpty (tuncon)
7465 && sRefSet_isEmpty (suncon))
7467 voptgenerror
7468 (FLG_INFLOOPS,
7469 message
7470 ("Suspected infinite loop. No value used in loop test (%q) "
7471 "is modified by test or loop body.",
7472 sRefSet_unparsePlain (tuses)),
7473 test->loc);
7475 else
7477 if (sRefSet_isEmpty (tuncon))
7479 voptgenerror
7480 (FLG_INFLOOPSUNCON,
7481 message ("Suspected infinite loop. No condition values "
7482 "modified. Modification possible through "
7483 "unconstrained calls: %q",
7484 sRefSet_unparsePlain (suncon)),
7485 test->loc);
7487 else
7489 voptgenerror
7490 (FLG_INFLOOPSUNCON,
7491 message ("Suspected infinite loop. No condition values "
7492 "modified. Possible undetected dependency through "
7493 "unconstrained calls in loop test: %q",
7494 sRefSet_unparsePlain (tuncon)),
7495 test->loc);
7500 sRefSet_free (sets);
7504 exprNode exprNode_while (/*@keep@*/ exprNode t, /*@keep@*/ exprNode b)
7506 exprNode ret;
7507 bool emptyErr = FALSE;
7509 if (context_maybeSet (FLG_WHILEEMPTY))
7511 if (exprNode_isEmptyStatement (b))
7513 emptyErr = optgenerror
7514 (FLG_WHILEEMPTY,
7515 cstring_makeLiteral
7516 ("Body of while statement is empty"),
7517 exprNode_loc (b));
7521 if (!emptyErr && context_maybeSet (FLG_WHILEBLOCK))
7523 if (exprNode_isDefined (b)
7524 && !exprNode_isBlock (b))
7526 if (context_inIterDef ()
7527 && (b->kind == XPR_STMTLIST
7528 || b->kind == XPR_TOK))
7530 ; /* no error */
7532 else
7534 voptgenerror (FLG_WHILEBLOCK,
7535 message
7536 ("Body of while statement is not a block: %s",
7537 exprNode_unparse (b)),
7538 exprNode_loc (b));
7543 if (exprNode_isError (t))
7545 if (exprNode_isError (b))
7547 ret = exprNode_createLoc (ctype_unknown, fileloc_copy (g_currentloc));
7549 else
7551 ret = exprNode_createPartialCopy (b);
7554 else
7556 exprNode test;
7558 ret = exprNode_createPartialCopy (t);
7560 llassert (t->kind == XPR_WHILEPRED);
7562 test = exprData_getSingle (t->edata);
7564 if (!exprNode_isError (b) && exprNode_isDefined (test))
7566 if (context_maybeSet (FLG_INFLOOPS)
7567 || context_maybeSet (FLG_INFLOOPSUNCON))
7570 ** check that some variable in the predicate is set by the body
7571 ** if the predicate uses any variables
7574 checkInfiniteLoop (test, b);
7577 exprNode_mergeUSs (ret, b);
7579 if (exprNode_isDefined (b))
7581 ret->exitCode = exitkind_makeConditional (b->exitCode);
7586 ret->edata = exprData_makePair (t, b);
7587 ret->kind = XPR_WHILE;
7589 if (exprNode_isDefined (t) && exprNode_mustEscape (t))
7591 voptgenerror
7592 (FLG_ALWAYSEXITS,
7593 message ("Predicate always exits: %s", exprNode_unparse (t)),
7594 exprNode_loc (t));
7597 ret->exitCode = XK_NEVERESCAPE;
7600 ** If loop is infinite, and there is no break inside,
7601 ** exit code is never reach.
7604 if (exprNode_knownIntValue (t))
7606 if (!exprNode_isZero (t))
7608 if (exprNode_isDefined (b))
7610 if (!b->canBreak)
7612 /* Really, it means never reached. */
7613 ret->exitCode = XK_MUSTEXIT;
7618 else
7623 ret->canBreak = FALSE;
7624 ret->mustBreak = FALSE;
7626 return ret;
7630 ** do { b } while (t);
7632 ** note: body passed as first argument
7635 exprNode exprNode_doWhile (/*@only@*/ exprNode b, /*@only@*/ exprNode t)
7637 exprNode ret;
7639 DPRINTF (("Do while: %s / %s",
7640 exprNode_unparse (b), exprNode_unparse (t)));
7642 if (exprNode_isError (t))
7644 if (exprNode_isError (b))
7646 ret = exprNode_createLoc (ctype_unknown, fileloc_copy (g_currentloc));
7648 else
7650 ret = exprNode_createPartialCopy (b);
7652 ret->exitCode = exitkind_makeConditional (b->exitCode);
7653 exprNode_checkUse (ret, b->sref, b->loc);
7654 ret->exitCode = b->exitCode;
7655 ret->canBreak = b->canBreak;
7656 ret->mustBreak = FALSE;
7659 else
7661 DPRINTF (("Do while: %s / %s",
7662 exitkind_unparse (t->exitCode),
7663 exitkind_unparse (b->exitCode)));
7665 ret = exprNode_createPartialCopy (t);
7666 exprNode_checkPred (cstring_makeLiteralTemp ("while"), t);
7668 if (!exprNode_isError (b))
7671 ** forgot the copy's --- why wasn't this detected??
7674 ret->sets = sRefSet_copyInto (ret->sets, b->sets);
7675 ret->msets = sRefSet_copyInto (ret->msets, b->msets);
7676 ret->uses = sRefSet_copyInto (ret->uses, b->uses);
7678 /* left this out --- causes and aliasing bug (infinite loop)
7679 should be detected?? */
7681 exprNode_checkUse (ret, b->sref, b->loc);
7682 exprNode_mergeUSs (ret, t);
7683 exprNode_checkUse (ret, t->sref, t->loc);
7685 /* evans 2001-10-05: while loop can break */
7686 ret->exitCode = exitkind_makeConditional (b->exitCode);
7688 DPRINTF (("Do while: %s",
7689 exitkind_unparse (ret->exitCode)));
7691 ret->canBreak = b->canBreak;
7693 /* Always FALSE for doWhile loops - break's when test is false */
7694 ret->mustBreak = FALSE; /* b->mustBreak; */
7698 context_exitDoWhileClause (t);
7700 ret->kind = XPR_DOWHILE;
7701 ret->edata = exprData_makePair (t, b);
7702 return ret;
7705 bool exprNode_loopMustExec (exprNode forPred)
7708 ** Returns true if it is obvious that the loop always executes at least once
7710 ** For now, we only identify the most obvious cases. Should be true anytime
7711 ** we can prove init => !test.
7714 if (exprNode_isDefined (forPred))
7716 exprNode init, test;
7717 exprData edata;
7719 llassert (forPred->kind == XPR_FORPRED);
7721 edata = forPred->edata;
7722 init = exprData_getTripleInit (edata);
7723 test = exprData_getTripleTest (edata);
7725 if (exprNode_isAssign (init))
7727 exprNode loopVar = exprData_getOpA (init->edata);
7728 exprNode loopInit = exprData_getOpB (init->edata);
7730 if (exprNode_isDefined (test) && test->kind == XPR_OP)
7732 exprNode testVar = exprData_getOpA (test->edata);
7733 exprNode testVal = exprData_getOpB (test->edata);
7734 lltok comp = exprData_getOpTok (test->edata);
7735 int opid = lltok_getTok (comp);
7737 DPRINTF (("Same storage: %s / %s", exprNode_unparse (loopVar),
7738 exprNode_unparse (testVar)));
7740 if (exprNode_sameStorage (loopVar, testVar))
7742 multiVal valinit = exprNode_getValue (loopInit);
7743 multiVal valtest = exprNode_getValue (testVal);
7745 DPRINTF (("Values: %s / %s", multiVal_unparse (valinit),
7746 multiVal_unparse (valtest)));
7748 if (multiVal_isInt (valinit) && multiVal_isInt (valtest))
7750 long v1 = multiVal_forceInt (valinit);
7751 long v2 = multiVal_forceInt (valtest);
7753 DPRINTF (("Here: %ld %ld", v1, v2));
7755 if ((opid == EQ_OP && v1 < v2)
7756 || (opid == NE_OP && v1 != v2)
7757 || (opid == TLT && v1 <= v2)
7758 || (opid == TGT && v1 >= v2)
7759 || (opid == LE_OP && v1 < v2)
7760 || (opid == GE_OP && v1 > v2))
7762 DPRINTF (("mustexec if inc"));
7763 return TRUE;
7771 DPRINTF (("loop must exec: FALSE"));
7772 return FALSE;
7775 exprNode exprNode_for (/*@keep@*/ exprNode inc, /*@keep@*/ exprNode body)
7777 exprNode ret;
7778 bool emptyErr = FALSE;
7780 if (context_maybeSet (FLG_FOREMPTY))
7782 if (exprNode_isEmptyStatement (body))
7784 emptyErr = optgenerror
7785 (FLG_FOREMPTY,
7786 cstring_makeLiteral
7787 ("Body of for statement is empty"),
7788 exprNode_loc (body));
7792 if (!emptyErr && context_maybeSet (FLG_FORBLOCK))
7794 if (exprNode_isDefined (body)
7795 && !exprNode_isBlock (body))
7797 if (context_inIterDef ()
7798 && (body->kind == XPR_STMTLIST
7799 || body->kind == XPR_TOK))
7801 ; /* no error */
7803 else
7805 voptgenerror (FLG_FORBLOCK,
7806 message
7807 ("Body of for statement is not a block: %s",
7808 exprNode_unparse (body)),
7809 exprNode_loc (body));
7815 ** for ud purposes: (alreadly) init -> test -> (now) LOOP: body + inc + test
7818 if (exprNode_isError (body))
7820 ret = exprNode_createPartialCopy (inc);
7822 else
7824 ret = exprNode_createPartialCopy (body);
7826 ret->exitCode = exitkind_makeConditional (body->exitCode);
7828 exprNode_mergeUSs (inc, body);
7830 if (exprNode_isDefined (inc))
7832 exprNode tmp;
7834 context_setMessageAnnote (cstring_makeLiteral ("in post loop increment"));
7836 tmp = exprNode_effect (exprData_getTripleInc (inc->edata));
7837 exprNode_freeShallow (tmp);
7839 context_clearMessageAnnote ();
7840 context_setMessageAnnote (cstring_makeLiteral ("in post loop test"));
7842 tmp = exprNode_effect (exprData_getTripleTest (inc->edata));
7843 exprNode_freeShallow (tmp);
7845 context_clearMessageAnnote ();
7847 ret->uses = sRefSet_copyInto (ret->uses, inc->uses);
7848 ret->sets = sRefSet_copyInto (ret->sets, inc->sets);
7849 ret->msets = sRefSet_copyInto (ret->msets, inc->msets);
7853 ret->kind = XPR_FOR;
7854 ret->edata = exprData_makePair (inc, body);
7856 if (exprNode_isDefined (inc)) {
7857 exprNode test = exprData_getTripleTest (inc->edata);
7859 if (exprNode_isUndefined (test)) {
7860 if (exprNode_isDefined (body)) {
7861 if (!body->canBreak) {
7862 /* Really, it means never reached. */
7863 ret->exitCode = XK_MUSTEXIT;
7869 return (ret);
7873 ** for (init; test; inc)
7874 ** ==>
7875 ** init;
7876 ** while (test) { body; inc; }
7878 ** Now: check use of init (may set vars for test)
7879 ** check use of test
7880 ** no checks on inc
7883 /*@observer@*/ guardSet exprNode_getForGuards (exprNode pred)
7885 exprNode test;
7887 if (exprNode_isError (pred)) return guardSet_undefined;
7889 llassert (pred->kind == XPR_FORPRED);
7891 test = exprData_getTripleTest (pred->edata);
7893 if (!exprNode_isError (test))
7895 return (test->guards);
7898 return guardSet_undefined;
7901 exprNode exprNode_whilePred (/*@only@*/ exprNode test)
7903 exprNode ret = exprNode_createSemiCopy (test);
7905 if (exprNode_isDefined (test))
7907 exprNode_copySets (ret, test);
7908 exprNode_checkPred (cstring_makeLiteralTemp ("while"), test);
7909 exprNode_checkUse (ret, test->sref, test->loc);
7911 exprNode_produceGuards (test);
7913 ret->guards = guardSet_copy (test->guards);
7916 ret->edata = exprData_makeSingle (test);
7917 ret->kind = XPR_WHILEPRED;
7918 return ret;
7921 exprNode exprNode_forPred (/*@only@*/ exprNode init, /*@only@*/ exprNode test,
7922 /*@only@*/ exprNode inc)
7924 exprNode ret;
7927 ** for ud purposes: init -> test -> LOOP: [ body, inc ]
7930 exprNode_checkPred (cstring_makeLiteralTemp ("for"), test);
7932 if (!exprNode_isError (inc))
7934 ret = exprNode_createPartialCopy (inc);
7936 else
7938 if (!exprNode_isError (init))
7940 ret = exprNode_createPartialCopy (init);
7942 else if (!exprNode_isError (test))
7944 ret = exprNode_createPartialCopy (test);
7946 else
7948 ret = exprNode_createUnknown ();
7952 exprNode_mergeUSs (ret, init);
7954 if (exprNode_isDefined (init))
7956 exprNode_checkUse (ret, init->sref, init->loc);
7959 exprNode_mergeUSs (ret, test);
7961 if (exprNode_isDefined (test))
7963 exprNode_checkUse (ret, test->sref, test->loc);
7966 ret->kind = XPR_FORPRED;
7967 ret->edata = exprData_makeFor (init, test, inc);
7968 return (ret);
7971 /*@notnull@*/ /*@only@*/ exprNode exprNode_goto (/*@only@*/ cstring label)
7973 exprNode ret = exprNode_createUnknown ();
7975 if (context_inMacro ())
7977 voptgenerror (FLG_MACROSTMT,
7978 message ("Macro %s uses goto (not functional)",
7979 context_inFunctionName ()),
7980 g_currentloc);
7983 ret->kind = XPR_GOTO;
7984 ret->edata = exprData_makeLiteral (label);
7985 ret->mustBreak = TRUE;
7986 ret->exitCode = XK_GOTO;
7987 ret->canBreak = TRUE;
7988 return ret;
7991 exprNode exprNode_continue (/*@only@*/ lltok l, int qcontinue)
7993 exprNode ret = exprNode_createLoc (ctype_unknown, fileloc_copy (lltok_getLoc (l)));
7995 ret->kind = XPR_CONTINUE;
7996 ret->edata = exprData_makeTok (l);
7997 ret->canBreak = TRUE;
7998 ret->mustBreak = TRUE;
8000 if (qcontinue == QSAFEBREAK)
8002 ; /* no checking */
8004 else if (qcontinue == QINNERCONTINUE)
8006 if (!context_inDeepLoop ())
8008 voptgenerror
8009 (FLG_LOOPLOOPCONTINUE,
8010 cstring_makeLiteral ("Continue statement marked with innercontinue "
8011 "is not inside a nested loop"),
8012 exprNode_loc (ret));
8015 else if (qcontinue == BADTOK)
8017 if (context_inDeepLoop ())
8019 voptgenerror
8020 (FLG_LOOPLOOPCONTINUE,
8021 cstring_makeLiteral ("Continue statement in nested loop"),
8022 exprNode_loc (ret));
8025 else
8027 llbuglit ("exprNode_continue: bad qcontinue");
8030 return ret;
8033 exprNode exprNode_break (/*@only@*/ lltok l, int bqual)
8035 exprNode ret = exprNode_createLoc (ctype_unknown, fileloc_copy (lltok_getLoc (l)));
8036 clause breakClause = context_breakClause ();
8038 ret->kind = XPR_BREAK;
8039 ret->edata = exprData_makeTok (l);
8040 ret->canBreak = TRUE;
8041 ret->mustBreak = TRUE;
8043 if (breakClause == NOCLAUSE)
8045 voptgenerror
8046 (FLG_SYNTAX,
8047 cstring_makeLiteral ("Break not inside while, for or switch statement"),
8048 exprNode_loc (ret));
8050 else
8052 if (bqual != BADTOK)
8054 switch (bqual)
8056 case QSAFEBREAK:
8057 break;
8058 case QINNERBREAK:
8059 if (breakClause == SWITCHCLAUSE)
8061 if (!context_inDeepSwitch ())
8063 voptgenerror (FLG_SYNTAX,
8064 cstring_makeLiteral
8065 ("Break preceded by innerbreak is not in a deep switch"),
8066 exprNode_loc (ret));
8069 else
8071 if (!context_inDeepLoop ())
8073 voptgenerror (FLG_SYNTAX,
8074 cstring_makeLiteral
8075 ("Break preceded by innerbreak is not in a deep loop"),
8076 exprNode_loc (ret));
8079 break;
8080 case QLOOPBREAK:
8081 if (breakClause == SWITCHCLAUSE)
8083 voptgenerror (FLG_SYNTAX,
8084 cstring_makeLiteral
8085 ("Break preceded by loopbreak is breaking a switch"),
8086 exprNode_loc (ret));
8088 break;
8089 case QSWITCHBREAK:
8090 if (breakClause != SWITCHCLAUSE)
8092 voptgenerror
8093 (FLG_SYNTAX,
8094 message ("Break preceded by switchbreak is breaking %s",
8095 cstring_makeLiteralTemp
8096 ((breakClause == WHILECLAUSE
8097 || breakClause == DOWHILECLAUSE) ? "a while loop"
8098 : (breakClause == FORCLAUSE) ? "a for loop"
8099 : (breakClause == ITERCLAUSE) ? "an iterator"
8100 : "<error loop>")),
8101 exprNode_loc (ret));
8103 break;
8104 BADDEFAULT;
8107 else
8109 if (breakClause == SWITCHCLAUSE)
8111 clause nextBreakClause = context_nextBreakClause ();
8113 switch (nextBreakClause)
8115 case NOCLAUSE: break;
8116 case WHILECLAUSE:
8117 case DOWHILECLAUSE:
8118 case FORCLAUSE:
8119 case ITERCLAUSE:
8120 voptgenerror
8121 (FLG_LOOPSWITCHBREAK,
8122 cstring_makeLiteral ("Break statement in switch inside loop"),
8123 exprNode_loc (ret));
8124 break;
8125 case SWITCHCLAUSE:
8126 voptgenerror
8127 (FLG_SWITCHSWITCHBREAK,
8128 cstring_makeLiteral ("Break statement in switch inside switch"),
8129 exprNode_loc (ret));
8130 break;
8131 BADDEFAULT;
8134 else
8136 if (context_inDeepLoop ())
8138 voptgenerror
8139 (FLG_LOOPLOOPBREAK,
8140 cstring_makeLiteral ("Break statement in nested loop"),
8141 exprNode_loc (ret));
8143 else
8145 if (context_inDeepLoopSwitch ())
8147 voptgenerror
8148 (FLG_SWITCHLOOPBREAK,
8149 cstring_makeLiteral ("Break statement in loop inside switch"),
8150 exprNode_loc (ret));
8157 return ret;
8160 exprNode exprNode_nullReturn (/*@only@*/ lltok t)
8162 fileloc loc = lltok_getLoc (t);
8163 exprNode ret = exprNode_createLoc (ctype_unknown, fileloc_copy (loc));
8165 context_returnFunction ();
8166 exprChecks_checkNullReturn (loc);
8168 ret->kind = XPR_NULLRETURN;
8169 ret->edata = exprData_makeTok (t);
8170 ret->exitCode = XK_MUSTRETURN;
8171 return ret;
8174 exprNode exprNode_return (/*@only@*/ exprNode e)
8176 exprNode ret;
8178 if (exprNode_isError (e))
8180 ret = exprNode_createUnknown ();
8182 else
8184 ret = exprNode_createLoc (ctype_unknown, fileloc_copy (e->loc));
8186 exprNode_checkUse (ret, e->sref, e->loc);
8187 exprNode_checkReturn (e);
8190 context_returnFunction ();
8191 ret->kind = XPR_RETURN;
8192 ret->edata = exprData_makeSingle (e);
8193 ret->exitCode = XK_MUSTRETURN;
8195 return (ret);
8198 exprNode exprNode_comma (/*@only@*/ exprNode e1, /*@only@*/ exprNode e2)
8200 exprNode ret;
8202 if (exprNode_isError (e1))
8204 if (exprNode_isError (e2))
8206 ret = exprNode_createLoc (ctype_unknown, fileloc_copy (g_currentloc));
8208 else
8210 ret = exprNode_createPartialCopy (e2);
8211 exprNode_checkUse (ret, e2->sref, e2->loc);
8212 ret->sref = e2->sref;
8215 else
8217 ret = exprNode_createPartialCopy (e1);
8219 exprNode_checkUse (ret, e1->sref, e1->loc);
8221 if (!exprNode_isError (e2))
8223 exprNode_mergeUSs (ret, e2);
8224 exprNode_checkUse (ret, e2->sref, e2->loc);
8225 ret->sref = e2->sref;
8229 ret->kind = XPR_COMMA;
8230 ret->edata = exprData_makePair (e1, e2);
8232 if (exprNode_isDefined (e1))
8234 if (exprNode_isDefined (e2))
8236 ret->typ = e2->typ;
8238 if (exprNode_mustEscape (e1) || e1->mustBreak)
8240 voptgenerror
8241 (FLG_UNREACHABLE,
8242 message ("Second clause of comma expression is unreachable: %s",
8243 exprNode_unparse (e2)),
8244 exprNode_loc (e2));
8247 ret->exitCode = exitkind_combine (e1->exitCode, e2->exitCode);
8248 ret->mustBreak = e1->mustBreak || e2->mustBreak;
8249 ret->canBreak = e1->canBreak || e2->canBreak;
8251 else
8253 if (exprNode_mustEscape (e1) || e1->mustBreak)
8255 voptgenerror
8256 (FLG_UNREACHABLE,
8257 message ("Second clause of comma expression is unreachable: %s",
8258 exprNode_unparse (e2)),
8259 exprNode_loc (e2));
8262 ret->exitCode = e1->exitCode;
8263 ret->canBreak = e1->canBreak;
8266 else
8268 if (exprNode_isDefined (e2))
8270 ret->exitCode = e2->exitCode;
8271 ret->mustBreak = e2->mustBreak;
8272 ret->canBreak = e2->canBreak;
8276 return (ret);
8279 static bool exprNode_checkOneInit (/*@notnull@*/ exprNode el, exprNode val)
8281 ctype t1 = exprNode_getType (el);
8282 ctype t2 = exprNode_getType (val);
8283 bool hasError = FALSE;
8285 DPRINTF (("Check one init: %s / %s",
8286 exprNode_unparse (el),
8287 exprNode_unparse (val)));
8289 if (ctype_isUnknown (t1))
8291 voptgenerror (FLG_IMPTYPE,
8292 message ("Variable has unknown (implicitly int) type: %s",
8293 exprNode_unparse (el)),
8294 el->loc);
8296 t1 = ctype_int;
8297 el->typ = ctype_int;
8300 if (exprNode_isDefined (val) && val->kind == XPR_INITBLOCK)
8302 exprNodeList vals = exprData_getArgs (val->edata);
8304 DPRINTF (("Check one init: %s", exprNodeList_unparse (vals)));
8305 DPRINTF (("Type: %s", ctype_unparse (t1)));
8307 if (ctype_isRealAP (t1))
8309 int i = 0;
8310 int nerrors = 0;
8312 if (ctype_isFixedArray (t1))
8314 size_t nelements = ctype_getArraySize (t1);
8316 DPRINTF (("Checked array: %s / %d",
8317 ctype_unparse (t1), nelements));
8319 if (exprNode_isStringLiteral (val))
8321 exprNode_checkStringLiteralLength (t1, val);
8323 else
8325 if (exprNodeList_size (vals) != size_toInt (nelements))
8327 hasError = optgenerror
8328 (exprNodeList_size (vals) > size_toInt (nelements)
8329 ? FLG_INITSIZE : FLG_INITALLELEMENTS,
8330 message ("Initializer block for "
8331 "%s has %d element%&, but declared as %s: %q",
8332 exprNode_unparse (el),
8333 exprNodeList_size (vals),
8334 ctype_unparse (t1),
8335 exprNodeList_unparse (vals)),
8336 val->loc);
8341 exprNodeList_elements (vals, oneval)
8343 cstring istring = message ("%d", i);
8344 exprNode newel =
8345 exprNode_arrayFetch
8346 (exprNode_fakeCopy (el),
8347 exprNode_numLiteral (ctype_int, istring,
8348 fileloc_copy (el->loc), i));
8350 if (exprNode_isDefined (newel))
8352 if (exprNodeList_size (vals) == 1
8353 && ctype_isString (exprNode_getType (oneval))
8354 && ctype_isChar (exprNode_getType (newel)))
8356 exprNode_freeIniter (newel);
8358 else
8360 if (exprNode_checkOneInit (newel, oneval))
8362 hasError = TRUE;
8363 nerrors++;
8365 if (nerrors > 3 && exprNodeList_size (vals) > 6)
8367 llgenmsg
8368 (message ("Additional initialization errors "
8369 "for %s not reported",
8370 exprNode_unparse (el)),
8371 exprNode_loc (el));
8372 exprNode_freeIniter (newel);
8373 break;
8375 else
8377 exprNode_freeIniter (newel);
8380 else
8382 exprNode_freeIniter (newel);
8387 cstring_free (istring);
8388 i++;
8389 /*@-branchstate@*/
8390 } end_exprNodeList_elements;
8391 /*@=branchstate@*/
8393 else if (ctype_isStruct (ctype_realType (t1)))
8395 uentryList fields = ctype_getFields (t1);
8396 int i = 0;
8398 if (uentryList_size (fields) != exprNodeList_size (vals))
8400 if (uentryList_size (fields) > exprNodeList_size (vals))
8402 hasError = optgenerror
8403 (FLG_FULLINITBLOCK,
8404 message ("Initializer block for "
8405 "%s has %d field%&, but %s has %d field%&: %q",
8406 exprNode_unparse (el),
8407 exprNodeList_size (vals),
8408 ctype_unparse (t1),
8409 uentryList_size (fields),
8410 exprNodeList_unparse (vals)),
8411 val->loc);
8413 else
8415 hasError = optgenerror
8416 (FLG_TYPE,
8417 message ("Initializer block for "
8418 "%s has %d field%&, but %s has %d field%&: %q",
8419 exprNode_unparse (el),
8420 exprNodeList_size (vals),
8421 ctype_unparse (t1),
8422 uentryList_size (fields),
8423 exprNodeList_unparse (vals)),
8424 val->loc);
8427 else
8429 exprNodeList_elements (vals, oneval)
8431 uentry thisfield = uentryList_getN (fields, i);
8432 exprNode newel =
8433 exprNode_fieldAccessAux (exprNode_fakeCopy (el),
8434 exprNode_loc (el),
8435 uentry_getName (thisfield));
8437 if (exprNode_isDefined (newel))
8439 if (exprNode_checkOneInit (newel, oneval))
8441 hasError = TRUE;
8444 exprNode_freeIniter (newel);
8447 i++;
8448 } end_exprNodeList_elements;
8451 /* evans 2001-12-30: added to fix bug reported by Jim Zelenka */
8452 else if (ctype_isUnion (ctype_realType (t1)))
8454 uentryList fields = ctype_getFields (t1);
8455 int i = 0;
8458 ** Union initializers set the first member always.
8461 DPRINTF (("Union initializer: %s / %s",
8462 exprNode_unparse (el), ctype_unparse (ctype_realType (t1))));
8464 if (exprNodeList_size (vals) != 1)
8466 hasError = optgenerror
8467 (FLG_TYPE,
8468 message ("Initializer block for union "
8469 "%s has %d elements, union initializers should have one element: %q",
8470 exprNode_unparse (el),
8471 exprNodeList_size (vals),
8472 exprNodeList_unparse (vals)),
8473 val->loc);
8475 else
8477 exprNode oneval = exprNodeList_head (vals);
8478 uentry thisfield = uentryList_getN (fields, i);
8479 exprNode newel =
8480 exprNode_fieldAccessAux (exprNode_fakeCopy (el),
8481 exprNode_loc (el),
8482 uentry_getName (thisfield));
8484 if (exprNode_isDefined (newel))
8486 if (exprNode_checkOneInit (newel, oneval))
8488 hasError = TRUE;
8491 exprNode_freeIniter (newel);
8495 else
8497 hasError = optgenerror
8498 (FLG_TYPE,
8499 message ("Initializer block used for "
8500 "%s where %t is expected: %s",
8501 exprNode_unparse (el), t1, exprNode_unparse (val)),
8502 val->loc);
8505 else
8507 if (exprNode_isDefined (val))
8509 doAssign (el, val, TRUE);
8511 if (!exprNode_matchType (t1, val))
8513 hasError = gentypeerror
8514 (t1, val, t2, el,
8515 message ("Initial value of %s is type %t, "
8516 "expects %t: %s",
8517 exprNode_unparse (el),
8518 t2, t1, exprNode_unparse (val)),
8519 val->loc);
8524 return hasError;
8527 static /*@notnull@*/ exprNode
8528 exprNode_makeInitializationAux (/*@temp@*/ idDecl t)
8530 exprNode ret;
8532 DPRINTF (("Initialization: %s", idDecl_unparse (t)));
8534 if (usymtab_exists (idDecl_observeId (t)))
8536 uentry ue = usymtab_lookup (idDecl_observeId (t));
8537 ret = exprNode_createId (ue);
8539 else
8541 uentry ue;
8543 DPRINTF (("Unrecognized: %s", idDecl_unparse (t)));
8545 ue = uentry_makeUnrecognized (idDecl_observeId (t), fileloc_copy (g_currentloc));
8546 ret = exprNode_fromIdentifierAux (ue);
8549 ** No error - this happens in old style declarations:
8551 voptgenerror
8552 (FLG_UNRECOG,
8553 message ("Unrecognized identifier in intializer: %s", idDecl_observeId (t)),
8554 g_currentloc);
8560 exprData_free (ret->edata, ret->kind);
8561 ret->edata = exprData_undefined;
8562 ret->exitCode = XK_NEVERESCAPE;
8563 ret->mustBreak = FALSE;
8564 ret->kind = XPR_INIT;
8565 return ret;
8568 exprNode exprNode_makeEmptyInitialization (/*@only@*/ idDecl t)
8570 exprNode ret = exprNode_makeInitializationAux (t);
8571 llassert (ret->edata == exprData_undefined);
8572 ret->edata = exprData_makeInit (t, exprNode_undefined);
8573 return ret;
8576 exprNode exprNode_makeInitialization (/*@only@*/ idDecl t,
8577 /*@only@*/ exprNode e)
8579 uentry ue = usymtab_lookup (idDecl_observeId (t));
8580 exprNode ret = exprNode_makeInitializationAux (t);
8581 fileloc loc = exprNode_loc (e);
8583 DPRINTF (("initialization: %s = %s", idDecl_unparse (t), exprNode_unparse (e)));
8585 if (exprNode_isError (e))
8587 e = exprNode_createUnknown ();
8588 /* error: assume initializer is defined */
8589 sRef_setDefined (ret->sref, g_currentloc);
8590 ret->edata = exprData_makeInit (t, e);
8592 else
8594 ctype ct = ctype_realishType (ret->typ);
8597 ** evs - 9 Apr 1995
8599 ** was addSafeUse --- what's the problem?
8601 ** int x = 3, y = x ?
8604 exprData_free (ret->edata, ret->kind);
8605 ret->edata = exprData_makeInit (t, e);
8606 DPRINTF (("ret: %s", exprNode_unparse (ret)));
8608 exprNode_checkUse (ret, e->sref, e->loc);
8610 if (ctype_isUnknown (e->typ) && uentry_isValid (ue))
8612 exprNode lhs = exprNode_createId (ue);
8615 ** static storage should be undefined before initializing
8618 if (uentry_isStatic (ue))
8620 sRef_setDefState (lhs->sref, SS_PARTIAL, fileloc_undefined);
8623 (void) exprNode_checkOneInit (lhs, e);
8625 if (uentry_isStatic (ue))
8627 sRef_setDefState (lhs->sref, SS_DEFINED, fileloc_undefined);
8630 exprNode_free (lhs);
8632 else
8634 if (!exprNode_matchType (ct, e))
8636 if (exprNode_isZero (e) && ctype_isArrayPtr (ct))
8640 else
8642 (void) gentypeerror
8643 (exprNode_getType (e), e, exprNode_getType (ret), ret,
8644 message
8645 ("Variable %q initialized to type %t, expects %t: %s",
8646 uentry_getName (ue), exprNode_getType (e),
8647 exprNode_getType (ret),
8648 exprNode_unparse (e)),
8649 e->loc);
8654 if (uentry_isStatic (ue))
8656 sRef_setDefState (ret->sref, SS_PARTIAL, fileloc_undefined);
8659 if (exprNode_isStringLiteral (e)
8660 && (ctype_isArray (ct))
8661 && (ctype_isChar (ctype_realType (ctype_baseArrayPtr (ct)))))
8664 ** If t is a char [], the literal is copied.
8667 exprNode_checkStringLiteralLength (ct, e);
8668 sRef_setDefState (ret->sref, SS_DEFINED, e->loc);
8669 ret->val = multiVal_copy (e->val);
8671 sRef_setNullTerminatedState (ret->sref);
8673 if (multiVal_isDefined (e->val))
8675 cstring slit = multiVal_forceString (e->val);
8676 sRef_setLen (ret->sref, size_toInt (cstring_length (slit) + 1));
8679 if (ctype_isFixedArray (ct))
8681 sRef_setSize (ret->sref, size_toInt (ctype_getArraySize (ct)));
8684 else
8686 doAssign (ret, e, TRUE);
8689 if (uentry_isStatic (ue))
8691 sRef_setDefState (ret->sref, SS_DEFINED, fileloc_undefined);
8695 if (context_inIterDef ())
8697 /* should check if it is yield */
8698 uentry_setUsed (ue, loc);
8700 else
8705 exprNode_mergeUSs (ret, e);
8706 DPRINTF (("Ret: %s %p %p",
8707 exprNode_unparse (ret),
8708 ret->requiresConstraints,
8709 ret->ensuresConstraints));
8711 DPRINTF (("Ret: %s %s %s",
8712 exprNode_unparse (ret),
8713 constraintList_unparse (ret->requiresConstraints),
8714 constraintList_unparse (ret->ensuresConstraints)));
8715 return ret;
8718 exprNode exprNode_iter (/*@observer@*/ uentry name,
8719 /*@only@*/ exprNodeList alist,
8720 /*@only@*/ exprNode body,
8721 /*@observer@*/ uentry end)
8723 exprNode ret;
8724 cstring iname;
8726 llassert (uentry_isValid (name));
8728 uentry_setUsed (name, exprNode_loc (body));
8730 ret = exprNode_createPartialCopy (body);
8731 iname = uentry_getName (name);
8733 if (uentry_isInvalid (end))
8735 llerror (FLG_ITERBALANCE,
8736 message ("Iter %s not balanced with end_%s", iname, iname));
8738 else
8740 cstring ename = uentry_getName (end);
8742 if (!cstring_equalPrefixLit (ename, "end_"))
8744 llerror (FLG_ITERBALANCE, message ("Iter %s not balanced with end_%s: %s",
8745 iname, iname, ename));
8747 else
8749 if (!cstring_equal (iname, cstring_suffix (ename, 4)))
8751 llerror (FLG_ITERBALANCE,
8752 message ("Iter %s not balanced with end_%s: %s",
8753 iname, iname, ename));
8757 cstring_free (ename);
8760 context_exitIterClause (body);
8762 ret->kind = XPR_ITER;
8763 ret->edata = exprData_makeIter (name, alist, body, end);
8765 if (uentry_isIter (name))
8767 (void) checkArgsReal (name, body,
8768 uentry_getParams (name), alist, TRUE, ret);
8771 cstring_free (iname);
8773 return ret;
8776 exprNode
8777 exprNode_iterNewId (/*@only@*/ cstring s)
8779 exprNode e = exprNode_new ();
8780 uentry ue = uentryList_getN (uentry_getParams (getCurrentIter ()), iterParamNo ());
8782 llassert (processingIterVars ());
8784 e->loc = context_getSaveLocation ();
8786 if (fileloc_isUndefined (e->loc))
8788 fileloc_free (e->loc);
8789 e->loc = fileloc_copy (g_currentloc);
8792 e->uses = sRefSet_new ();
8793 e->sets = sRefSet_new ();
8794 e->msets = sRefSet_new ();
8795 e->kind = XPR_VAR;
8796 e->val = multiVal_unknown ();
8797 e->guards = guardSet_new ();
8798 e->sref = sRef_undefined;
8799 e->isJumpPoint = FALSE;
8800 e->exitCode = XK_NEVERESCAPE;
8802 /*> missing fields, detected by splint <*/
8803 e->canBreak = FALSE;
8804 e->mustBreak = FALSE;
8805 e->etext = cstring_undefined;
8807 if (uentry_isYield (ue))
8809 uentry uue = uentry_makeVariable (s, uentry_getType (ue),
8810 fileloc_copy (e->loc),
8811 FALSE);
8812 sRef sr;
8814 uue = usymtab_supEntrySrefReturn (uue);
8816 sr = uentry_getSref (uue);
8817 sRef_mergeStateQuiet (sr, uentry_getSref (ue));
8818 sr = uentry_getSref (uue);
8819 sRef_setDefined (sr, e->loc);
8821 e->typ = uentry_getType (uue);
8822 e->sref = sr;
8823 e->edata = exprData_makeId (uue);
8824 uentry_setUsed (uue, g_currentloc);
8826 else
8828 uentry uue;
8830 sRef_setGlobalScope ();
8831 uue = uentry_makeVariableLoc (s, ctype_unknown);
8833 e->typ = ctype_unknown;
8834 e->edata = exprData_makeId (uue);
8836 uentry_setUsed (uue, e->loc);
8837 uentry_setHasNameError (uue);
8839 if (context_getFlag (FLG_REPEATUNRECOG))
8841 uentry_markOwned (uue);
8843 else
8845 usymtab_supGlobalEntry (uue);
8848 sRef_clearGlobalScope ();
8850 voptgenerror (FLG_UNRECOG, message ("Unrecognized identifier: %s", s),
8851 e->loc);
8855 cstring_free (s);
8857 exprNode_defineConstraints(e);
8858 return (e);
8861 exprNode
8862 exprNode_iterExpr (/*@returned@*/ exprNode e)
8864 if (!processingIterVars ())
8866 llcontbuglit ("checkIterParam: not in iter");
8867 return e;
8870 if (uentry_isYield (uentryList_getN (uentry_getParams (getCurrentIter ()),
8871 iterParamNo ())))
8873 if (exprNode_isDefined (e))
8875 if (fileloc_isDefined (e->loc))
8877 voptgenerror
8878 (FLG_ITERYIELD,
8879 message ("Yield parameter is not simple identifier: %s",
8880 exprNode_unparse (e)),
8881 e->loc);
8883 else
8885 voptgenerror
8886 (FLG_ITERYIELD,
8887 message ("Yield parameter is not simple identifier: %s",
8888 exprNode_unparse (e)),
8889 g_currentloc);
8894 return e;
8897 exprNode
8898 exprNode_iterId (/*@observer@*/ uentry c)
8900 uentry ue;
8902 llassert (processingIterVars ());
8904 ue = uentryList_getN (uentry_getParams (getCurrentIter ()),
8905 iterParamNo ());
8907 if (uentry_isYield (ue))
8909 ctype ct = uentry_getType (ue);
8910 exprNode e = exprNode_createPlain (ct);
8911 cstring name = uentry_getName (c);
8912 uentry le = uentry_makeVariable (name, ct, fileloc_undefined, FALSE);
8914 uentry_setUsed (ue, g_currentloc);
8915 uentry_setHasNameError (ue);
8917 cstring_free (name);
8919 e->kind = XPR_VAR;
8920 e->edata = exprData_makeId (le);
8921 e->loc = context_getSaveLocation ();
8922 e->sref = uentry_getSref (le);
8924 usymtab_supEntrySref (le);
8926 if (!context_inHeader ())
8928 if (optgenerror
8929 (FLG_ITERYIELD,
8930 message ("Yield parameter shadows local declaration: %q",
8931 uentry_getName (c)),
8932 fileloc_isDefined (e->loc) ? e->loc : g_currentloc))
8934 uentry_showWhereDeclared (c);
8938 return e;
8941 return (exprNode_fromIdentifierAux (c));
8944 exprNode exprNode_iterStart (/*@observer@*/ uentry name, /*@only@*/ exprNodeList alist)
8946 exprNode ret = exprNode_create (ctype_unknown);
8948 ret->kind = XPR_ITERCALL;
8949 ret->edata = exprData_makeIterCall (name, alist);
8951 if (uentry_isIter (name))
8953 uentryList params = uentry_getParams (name);
8955 if (context_inIterDef ()
8956 && uentryList_size (params) == exprNodeList_size (alist))
8958 int i = 0;
8960 exprNodeList_elements (alist, arg)
8962 uentry parg = uentryList_getN (params, i);
8964 if (uentry_isYield (parg))
8966 uentry ue = exprNode_getUentry (arg);
8968 if (uentry_isValid (ue))
8974 i++;
8975 } end_exprNodeList_elements;
8978 (void) checkArgsReal (name, ret, params, alist, TRUE, ret);
8979 checkUnspecCall (ret, params, alist);
8982 return ret;
8985 /*@exposed@*/ sRef exprNode_getSref (exprNode e)
8987 if (exprNode_isDefined (e))
8989 if (sRef_isInvalid (e->sref))
8991 /*@-mods@*/
8992 e->sref = sRef_makeUnknown ();
8993 sRef_setAliasKind (e->sref, AK_ERROR, fileloc_undefined);
8994 /*@=mods@*/
8995 return e->sref;
8997 else
8999 return e->sref;
9002 else
9004 return sRef_undefined;
9008 /*@observer@*/ cstring
9009 exprNode_unparseFirst (exprNode e)
9011 if (exprNode_isDefined (e))
9013 cstring ret;
9015 if (e->kind == XPR_STMTLIST
9016 || e->kind == XPR_COMMA || e->kind == XPR_COND)
9018 exprNode first = exprData_getPairA (e->edata);
9020 if (exprNode_isDefined (first))
9022 return (exprNode_unparseFirst (exprData_getPairA (e->edata)));
9024 else
9026 return (cstring_makeLiteralTemp ("..."));
9030 ret = cstring_elide (exprNode_unparse (e), 20);
9031 cstring_markOwned (ret);
9033 return (ret);
9035 else
9037 return cstring_makeLiteralTemp ("<error>");
9041 /*@observer@*/ cstring
9042 exprNode_unparse (/*@temp@*/ exprNode e)
9044 if (exprNode_isError (e))
9046 return cstring_makeLiteralTemp ("<error>");
9049 if (cstring_isDefined (e->etext))
9051 return e->etext;
9053 else
9055 cstring ret = exprNode_doUnparse (e);
9057 /*@-modifies@*/ /* benevolent */
9058 e->etext = ret;
9059 /*@=modifies@*/
9060 return ret;
9064 /*@observer@*/ fileloc
9065 exprNode_loc (exprNode e)
9067 if (exprNode_isError (e))
9069 return (g_currentloc);
9071 else
9073 return (e->loc);
9078 ** executes exprNode e
9079 ** recursively rexecutes as though in original parse using
9080 ** information in e->edata
9083 static /*@only@*/ exprNodeList exprNodeList_effect (exprNodeList e)
9085 exprNodeList ret = exprNodeList_new ();
9087 exprNodeList_elements (e, current)
9089 exprNodeList_addh (ret, exprNode_effect (current));
9090 } end_exprNodeList_elements;
9092 return ret;
9095 static /*@only@*/ exprNode exprNode_effect (exprNode e)
9096 /*@globals internalState@*/
9098 bool innerEffect = inEffect;
9099 exprNode ret;
9100 exprData data;
9102 inEffect = TRUE;
9104 context_clearJustPopped ();
9106 if (exprNode_isError (e))
9108 ret = exprNode_undefined;
9110 else
9113 ** Turn off expose and dependent transfer checking.
9114 ** Need to pass exposed internal nodes,
9115 ** [ copying would be a waste! ]
9116 ** [ Actually, I think I wasted a lot more time than its worth ]
9117 ** [ trying to do this. ]
9120 /*@-exposetrans@*/
9121 /*@-observertrans@*/
9122 /*@-dependenttrans@*/
9124 data = e->edata;
9126 switch (e->kind)
9128 case XPR_PARENS:
9129 ret = exprNode_addParens (exprData_getUopTok (data),
9130 exprNode_effect (exprData_getUopNode (data)));
9131 break;
9132 case XPR_ASSIGN:
9133 ret = exprNode_assign (exprNode_effect (exprData_getOpA (data)),
9134 exprNode_effect (exprData_getOpB (data)),
9135 exprData_getOpTok (data));
9136 break;
9137 case XPR_INITBLOCK:
9138 ret = exprNode_undefined;
9139 break;
9140 case XPR_CALL:
9141 ret = exprNode_functionCall (exprNode_effect (exprData_getFcn (data)),
9142 exprNodeList_effect (exprData_getArgs (data)));
9143 break;
9144 case XPR_EMPTY:
9145 ret = e;
9146 break;
9148 case XPR_LABEL:
9149 ret = e;
9150 break;
9152 case XPR_CONST:
9153 case XPR_VAR:
9155 cstring id = exprData_getId (data);
9156 uentry ue = usymtab_lookupSafe (id);
9158 ret = exprNode_fromIdentifierAux (ue);
9159 ret->loc = fileloc_update (ret->loc, e->loc);
9160 break;
9162 case XPR_BODY:
9163 ret = e;
9164 break;
9165 case XPR_FETCH:
9166 ret = exprNode_arrayFetch (exprNode_effect (exprData_getPairA (data)),
9167 exprNode_effect (exprData_getPairB (data)));
9168 break;
9169 case XPR_OP:
9171 ** evans 2002-03-15: for && and ||, need to do the guards also
9172 ** this is what cgrammar.y does - should be
9173 ** able to avoid duplication, but need to
9174 ** time with grammar productions.
9177 DPRINTF (("Effect: %s", exprNode_unparse (e)));
9179 if (lltok_getTok (exprData_getOpTok (data)) == AND_OP)
9181 exprNode e1 = exprNode_effect (exprData_getOpA (data));
9182 exprNode e2;
9183 exprNode_produceGuards (e1);
9184 context_enterAndClause (e1);
9185 e2 = exprNode_effect (exprData_getOpB (data));
9187 ret = exprNode_op (e1, e2,
9188 exprData_getOpTok (data));
9190 context_exitAndClause (ret, e2);
9192 else if (lltok_getTok (exprData_getOpTok (data)) == OR_OP)
9194 exprNode e1 = exprNode_effect (exprData_getOpA (data));
9195 exprNode e2;
9196 exprNode_produceGuards (e1);
9197 context_enterOrClause (e1);
9198 e2 = exprNode_effect (exprData_getOpB (data));
9200 ret = exprNode_op (e1, e2,
9201 exprData_getOpTok (data));
9203 context_exitOrClause (ret, e2);
9205 else
9207 ret = exprNode_op (exprNode_effect (exprData_getOpA (data)),
9208 exprNode_effect (exprData_getOpB (data)),
9209 exprData_getOpTok (data));
9211 break;
9213 case XPR_POSTOP:
9214 ret = exprNode_postOp (exprNode_effect (exprData_getUopNode (data)),
9215 exprData_getUopTok (data));
9216 break;
9217 case XPR_PREOP:
9218 ret = exprNode_preOp (exprNode_effect (exprData_getUopNode (data)),
9219 exprData_getUopTok (data));
9220 break;
9222 case XPR_OFFSETOF:
9223 case XPR_SIZEOFT:
9224 case XPR_SIZEOF:
9225 case XPR_ALIGNOFT:
9226 case XPR_ALIGNOF:
9227 ret = e;
9228 break;
9230 case XPR_VAARG:
9231 ret = exprNode_vaArg (exprData_getCastTok (data),
9232 exprNode_effect (exprData_getCastNode (data)),
9233 exprData_getCastType (data));
9234 break;
9236 case XPR_CAST:
9237 ret = exprNode_cast (exprData_getCastTok (data),
9238 exprNode_effect (exprData_getCastNode (data)),
9239 exprData_getCastType (data));
9240 break;
9241 case XPR_ITERCALL:
9242 ret = exprNode_iterStart (exprData_getIterCallIter (data),
9243 exprNodeList_effect
9244 (exprData_getIterCallArgs (data)));
9245 break;
9247 case XPR_ITER:
9248 ret = exprNode_iter (exprData_getIterSname (data),
9249 exprNodeList_effect (exprData_getIterAlist (data)),
9250 exprNode_effect (exprData_getIterBody (data)),
9251 exprData_getIterEname (data));
9252 break;
9254 case XPR_FOR:
9255 ret = exprNode_for (exprNode_effect (exprData_getPairA (data)),
9256 exprNode_effect (exprData_getPairB (data)));
9257 break;
9259 case XPR_FORPRED:
9260 ret = exprNode_forPred (exprNode_effect (exprData_getTripleInit (data)),
9261 exprNode_effect (exprData_getTripleTest (data)),
9262 exprNode_effect (exprData_getTripleInc (data)));
9263 break;
9265 case XPR_TOK:
9266 ret = exprNode_createTok (exprData_getTok (data));
9267 break;
9269 case XPR_GOTO:
9270 ret = exprNode_goto (exprData_getLiteral (data));
9271 ret->loc = fileloc_update (ret->loc, e->loc);
9272 break;
9274 case XPR_CONTINUE:
9275 ret = exprNode_continue (exprData_getTok (data), QSAFEBREAK);
9276 break;
9278 case XPR_BREAK:
9279 ret = exprNode_break (exprData_getTok (data), QSAFEBREAK);
9280 break;
9282 case XPR_RETURN:
9283 ret = exprNode_return (exprNode_effect (exprData_getSingle (data)));
9284 break;
9286 case XPR_NULLRETURN:
9287 ret = exprNode_nullReturn (exprData_getTok (data));
9288 break;
9290 case XPR_COMMA:
9291 ret = exprNode_comma (exprNode_effect (exprData_getPairA (data)),
9292 exprNode_effect (exprData_getPairB (data)));
9293 break;
9295 case XPR_COND:
9296 ret = exprNode_cond (exprNode_effect (exprData_getTriplePred (data)),
9297 exprNode_effect (exprData_getTripleTrue (data)),
9298 exprNode_effect (exprData_getTripleFalse (data)));
9299 break;
9300 case XPR_IF:
9301 ret = exprNode_if (exprNode_effect (exprData_getPairA (data)),
9302 exprNode_effect (exprData_getPairB (data)));
9303 break;
9305 case XPR_IFELSE:
9306 ret = exprNode_ifelse (exprNode_effect (exprData_getTriplePred (data)),
9307 exprNode_effect (exprData_getTripleTrue (data)),
9308 exprNode_effect (exprData_getTripleFalse (data)));
9309 break;
9310 case XPR_WHILEPRED:
9311 ret = exprNode_whilePred (exprData_getSingle (data));
9312 break;
9314 case XPR_WHILE:
9315 ret = exprNode_while (exprNode_effect (exprData_getPairA (data)),
9316 exprNode_effect (exprData_getPairB (data)));
9317 break;
9319 case XPR_DOWHILE:
9320 ret = exprNode_doWhile (exprNode_effect (exprData_getPairA (data)),
9321 exprNode_effect (exprData_getPairB (data)));
9322 break;
9324 case XPR_BLOCK:
9325 ret = exprNode_makeBlock (exprNode_effect (exprData_getSingle (data)));
9326 break;
9328 case XPR_STMT:
9329 ret = exprNode_statement (exprNode_effect (exprData_getUopNode (data)),
9330 exprData_getUopTok (data));
9331 break;
9333 case XPR_STMTLIST:
9334 ret = exprNode_concat (exprNode_effect (exprData_getPairA (data)),
9335 exprNode_effect (exprData_getPairB (data)));
9336 break;
9338 case XPR_FTCASE:
9339 case XPR_CASE:
9340 ret = exprNode_caseMarker
9341 (exprNode_effect (exprData_getSingle (data)),
9342 TRUE);
9343 break;
9345 case XPR_FTDEFAULT:
9346 case XPR_DEFAULT:
9347 ret = exprNode_createTok (exprData_getTok (data));
9348 break;
9350 case XPR_SWITCH:
9351 ret = exprNode_switch (exprNode_effect (exprData_getPairA (data)),
9352 exprNode_effect (exprData_getPairB (data)));
9353 break;
9355 case XPR_INIT:
9356 ret = exprNode_makeInitialization
9357 (exprData_getInitId (data),
9358 exprNode_effect (exprData_getInitNode (data)));
9359 break;
9361 case XPR_FACCESS:
9362 ret = exprNode_fieldAccessAux
9363 (exprNode_effect (exprData_getFieldNode (data)),
9364 exprNode_loc (exprData_getFieldNode (data)),
9365 cstring_copy (exprData_getFieldName (data)));
9366 break;
9368 case XPR_ARROW:
9369 ret = exprNode_arrowAccessAux
9370 (exprNode_effect (exprData_getFieldNode (data)),
9371 exprNode_loc (exprData_getFieldNode (data)),
9372 cstring_copy (exprData_getFieldName (data)));
9373 break;
9375 case XPR_STRINGLITERAL:
9376 ret = e;
9377 break;
9379 case XPR_NUMLIT:
9380 ret = e;
9381 break;
9383 case XPR_NODE:
9384 ret = e;
9385 break;
9386 /*@-branchstate@*/
9388 /*@=branchstate@*/
9389 /*@=observertrans@*/
9390 /*@=exposetrans@*/
9391 /*@=dependenttrans@*/
9394 if (!innerEffect)
9396 inEffect = FALSE;
9399 return ret;
9402 static /*@observer@*/ cstring exprNode_rootVarName (exprNode e)
9404 cstring ret;
9405 exprData data;
9407 if (exprNode_isError (e))
9409 return cstring_undefined;
9412 data = e->edata;
9414 switch (e->kind)
9416 case XPR_PARENS:
9417 ret = exprNode_rootVarName (exprData_getUopNode (data));
9418 break;
9419 case XPR_ASSIGN:
9420 ret = exprNode_rootVarName (exprData_getOpA (data));
9421 break;
9422 case XPR_CONST:
9423 case XPR_VAR:
9424 ret = exprData_getId (data);
9425 break;
9426 case XPR_INIT:
9427 ret = idDecl_getName (exprData_getInitId (data));
9428 break;
9429 default:
9430 ret = cstring_undefined;
9431 break;
9434 return ret;
9437 static /*@only@*/ cstring exprNode_doUnparse (exprNode e)
9439 cstring ret;
9440 exprData data;
9442 if (exprNode_isError (e))
9444 static /*@only@*/ cstring error = cstring_undefined;
9446 if (!cstring_isDefined (error))
9448 error = cstring_makeLiteral ("<error>");
9451 return error;
9454 data = e->edata;
9456 switch (e->kind)
9458 case XPR_PARENS:
9459 ret = message ("(%s)", exprNode_unparse (exprData_getUopNode (e->edata)));
9460 break;
9461 case XPR_ASSIGN:
9462 ret = message ("%s %s %s",
9463 exprNode_unparse (exprData_getOpA (data)),
9464 lltok_unparse (exprData_getOpTok (data)),
9465 exprNode_unparse (exprData_getOpB (data)));
9466 break;
9467 case XPR_CALL:
9468 ret = message ("%s(%q)",
9469 exprNode_unparse (exprData_getFcn (data)),
9470 exprNodeList_unparse (exprData_getArgs (data)));
9471 break;
9472 case XPR_INITBLOCK:
9473 ret = message ("{ %q }", exprNodeList_unparse (exprData_getArgs (data)));
9474 break;
9475 case XPR_EMPTY:
9476 ret = cstring_undefined;
9477 break;
9478 case XPR_LABEL:
9479 ret = message ("%s:", exprData_getId (data));
9480 break;
9481 case XPR_CONST:
9482 case XPR_VAR:
9483 ret = cstring_copy (exprData_getId (data));
9484 break;
9485 case XPR_FETCH:
9486 ret = message ("%s[%s]", exprNode_unparse (exprData_getPairA (data)),
9487 exprNode_unparse (exprData_getPairB (data)));
9488 break;
9489 case XPR_BODY:
9490 ret = message ("<body>");
9491 break;
9492 case XPR_OP:
9493 ret = message ("%s %s %s",
9494 exprNode_unparse (exprData_getOpA (data)),
9495 lltok_unparse (exprData_getOpTok (data)),
9496 exprNode_unparse (exprData_getOpB (data)));
9497 break;
9499 case XPR_PREOP:
9500 ret = message ("%s%s",
9501 lltok_unparse (exprData_getUopTok (data)),
9502 exprNode_unparse (exprData_getUopNode (data)));
9503 break;
9505 case XPR_POSTOP:
9506 ret = message ("%s%s",
9507 exprNode_unparse (exprData_getUopNode (data)),
9508 lltok_unparse (exprData_getUopTok (data)));
9509 break;
9511 case XPR_OFFSETOF:
9512 ret = message ("offsetof(%s,%q)",
9513 ctype_unparse (qtype_getType (exprData_getOffsetType (data))),
9514 cstringList_unparseSep (exprData_getOffsetName (data), cstring_makeLiteralTemp (".")));
9515 break;
9517 case XPR_SIZEOFT:
9518 ret = message ("sizeof(%s)", ctype_unparse (qtype_getType (exprData_getType (data))));
9519 break;
9521 case XPR_SIZEOF:
9522 ret = message ("sizeof(%s)", exprNode_unparse (exprData_getSingle (data)));
9523 break;
9525 case XPR_ALIGNOFT:
9526 ret = message ("alignof(%s)", ctype_unparse (qtype_getType (exprData_getType (data))));
9527 break;
9529 case XPR_ALIGNOF:
9530 ret = message ("alignof(%s)", exprNode_unparse (exprData_getSingle (data)));
9531 break;
9533 case XPR_VAARG:
9534 ret = message ("va_arg(%s, %q)",
9535 exprNode_unparse (exprData_getCastNode (data)),
9536 qtype_unparse (exprData_getCastType (data)));
9537 break;
9539 case XPR_ITERCALL:
9540 ret = message ("%q(%q)",
9541 uentry_getName (exprData_getIterCallIter (data)),
9542 exprNodeList_unparse (exprData_getIterCallArgs (data)));
9543 break;
9544 case XPR_ITER:
9545 ret = message ("%q(%q) %s %q",
9546 uentry_getName (exprData_getIterSname (data)),
9547 exprNodeList_unparse (exprData_getIterAlist (data)),
9548 exprNode_unparse (exprData_getIterBody (data)),
9549 uentry_getName (exprData_getIterEname (data)));
9550 break;
9551 case XPR_CAST:
9552 ret = message ("(%q)%s",
9553 qtype_unparse (exprData_getCastType (data)),
9554 exprNode_unparse (exprData_getCastNode (data)));
9555 break;
9557 case XPR_FOR:
9558 ret = message ("%s %s",
9559 exprNode_unparse (exprData_getPairA (data)),
9560 exprNode_unparse (exprData_getPairB (data)));
9561 break;
9563 case XPR_FORPRED:
9564 ret = message ("for (%s; %s; %s)",
9565 exprNode_unparse (exprData_getTripleInit (data)),
9566 exprNode_unparse (exprData_getTripleTest (data)),
9567 exprNode_unparse (exprData_getTripleInc (data)));
9568 break;
9570 case XPR_GOTO:
9571 ret = message ("goto %s", exprData_getLiteral (data));
9572 break;
9574 case XPR_CONTINUE:
9575 ret = cstring_makeLiteral ("continue");
9576 break;
9578 case XPR_BREAK:
9579 ret = cstring_makeLiteral ("break");
9580 break;
9582 case XPR_RETURN:
9583 ret = message ("return %s", exprNode_unparse (exprData_getSingle (data)));
9584 break;
9586 case XPR_NULLRETURN:
9587 ret = cstring_makeLiteral ("return");
9588 break;
9590 case XPR_COMMA:
9591 ret = message ("%s, %s",
9592 exprNode_unparse (exprData_getPairA (data)),
9593 exprNode_unparse (exprData_getPairB (data)));
9594 break;
9596 case XPR_COND:
9597 ret = message ("%s ? %s : %s",
9598 exprNode_unparse (exprData_getTriplePred (data)),
9599 exprNode_unparse (exprData_getTripleTrue (data)),
9600 exprNode_unparse (exprData_getTripleFalse (data)));
9601 break;
9602 case XPR_IF:
9603 ret = message ("if (%s) %s",
9604 exprNode_unparse (exprData_getPairA (data)),
9605 exprNode_unparse (exprData_getPairB (data)));
9606 break;
9608 case XPR_IFELSE:
9609 ret = message ("if (%s) %s else %s",
9610 exprNode_unparse (exprData_getTriplePred (data)),
9611 exprNode_unparse (exprData_getTripleTrue (data)),
9612 exprNode_unparse (exprData_getTripleFalse (data)));
9613 break;
9614 case XPR_WHILE:
9615 ret = message ("while (%s) %s",
9616 exprNode_unparse (exprData_getPairA (data)),
9617 exprNode_unparse (exprData_getPairB (data)));
9618 break;
9620 case XPR_WHILEPRED:
9621 ret = cstring_copy (exprNode_unparse (exprData_getSingle (data)));
9622 break;
9624 case XPR_TOK:
9625 ret = cstring_copy (lltok_unparse (exprData_getTok (data)));
9626 break;
9628 case XPR_DOWHILE:
9629 ret = message ("do { %s } while (%s)",
9630 exprNode_unparse (exprData_getPairB (data)),
9631 exprNode_unparse (exprData_getPairA (data)));
9632 break;
9634 case XPR_BLOCK:
9635 ret = message ("{ %s }", exprNode_unparse (exprData_getSingle (data)));
9636 /* evans 2002-02-20 was unparseFirst! */
9637 break;
9639 case XPR_STMT:
9640 ret = message ("%s;", exprNode_unparse (exprData_getUopNode (data)));
9641 break;
9643 case XPR_STMTLIST:
9644 if (exprNode_isStatement (exprData_getPairA (data)))
9647 ** statement expressions already print the ;
9650 ret = message ("%s %s",
9651 exprNode_unparse (exprData_getPairA (data)),
9652 exprNode_unparse (exprData_getPairB (data)));
9654 else
9656 ret = message ("%s; %s",
9657 exprNode_unparse (exprData_getPairA (data)),
9658 exprNode_unparse (exprData_getPairB (data)));
9660 break;
9662 case XPR_FTDEFAULT:
9663 case XPR_DEFAULT:
9664 ret = cstring_makeLiteral ("default:");
9665 break;
9667 case XPR_SWITCH:
9668 ret = message ("switch (%s) %s",
9669 exprNode_unparse (exprData_getPairA (data)),
9670 exprNode_unparse (exprData_getPairB (data)));
9671 break;
9673 case XPR_FTCASE:
9674 case XPR_CASE:
9675 ret = message ("case %s:",
9676 exprNode_unparse (exprData_getSingle (data)));
9677 break;
9679 case XPR_INIT:
9680 if (exprNode_isError (exprData_getInitNode (data)))
9682 ret = message ("%q", idDecl_unparseC (exprData_getInitId (data)));
9684 else
9686 ret = message ("%q = %s",
9687 idDecl_unparseC (exprData_getInitId (data)),
9688 exprNode_unparse (exprData_getInitNode (data)));
9690 break;
9692 case XPR_FACCESS:
9693 ret = message ("%s.%s",
9694 exprNode_unparse (exprData_getFieldNode (data)),
9695 exprData_getFieldName (data));
9696 break;
9698 case XPR_ARROW:
9699 ret = message ("%s->%s",
9700 exprNode_unparse (exprData_getFieldNode (data)),
9701 exprData_getFieldName (data));
9702 break;
9704 case XPR_STRINGLITERAL:
9705 if (ctype_isWideString (e->typ))
9707 ret = message ("L\"%s\"", exprData_getLiteral (data));
9709 else
9711 ret = message ("\"%s\"", exprData_getLiteral (data));
9713 break;
9715 case XPR_NUMLIT:
9716 ret = cstring_copy (exprData_getLiteral (data));
9717 break;
9719 case XPR_NODE:
9720 ret = cstring_makeLiteral ("<node>");
9721 break;
9724 return ret;
9727 bool
9728 exprNode_isInitializer (exprNode e)
9730 return (exprNode_isDefined (e)
9731 && e->kind == XPR_INIT);
9734 bool
9735 exprNode_isCharLiteral (exprNode e)
9737 if (exprNode_isDefined (e))
9739 return (multiVal_isChar (exprNode_getValue (e)));
9741 else
9743 return FALSE;
9747 bool
9748 exprNode_isNumLiteral (exprNode e)
9750 if (exprNode_isDefined (e))
9752 return (multiVal_isInt (exprNode_getValue (e)));
9754 else
9756 return FALSE;
9760 static bool
9761 exprNode_isFalseConstant (exprNode e)
9763 if (exprNode_isDefined (e))
9765 cstring s = exprNode_rootVarName (e);
9767 if (cstring_equal (s, context_getFalseName ()))
9769 return TRUE;
9773 return FALSE;
9776 bool
9777 exprNode_matchLiteral (ctype expected, exprNode e)
9779 if (exprNode_isDefined (e))
9781 multiVal m = exprNode_getValue (e);
9783 if (multiVal_isDefined (m))
9785 if (multiVal_isInt (m))
9787 long int val = multiVal_forceInt (m);
9789 if (ctype_isNumAbstract (expected)
9790 && context_flagOn (FLG_NUMABSTRACTLIT, exprNode_loc (e)))
9792 return TRUE;
9795 if (ctype_isDirectBool (ctype_realishType (expected)))
9797 if (val == 0)
9799 return FALSE; /* really?! return TRUE; allow use of 0 for FALSE */
9801 else
9803 return FALSE;
9807 if (ctype_isRealInt (expected))
9810 ** unsigned <- [ constant >= 0 is okay ]
9813 if (ctype_isUnsigned (expected))
9815 if (val < 0)
9817 return FALSE;
9822 ** No checks on sizes of integers...maybe add
9823 ** these later.
9826 DPRINTF (("Here: %s => %s", exprNode_unparse (e), ctype_unparse (expected)));
9827 DPRINTF (("Type: %s / %s", ctype_unparse (exprNode_getType (e)),
9828 bool_unparse (ctype_isInt (exprNode_getType (e)))));
9830 if (context_getFlag (FLG_NUMLITERAL)
9831 && (ctype_isRegularInt (exprNode_getType (e)) || val == 0)) {
9832 return TRUE;
9833 } else {
9834 if (val == 0) {
9835 return TRUE;
9836 } else {
9837 return FALSE; /* evs 2000-05-17: previously, always returned TRUE */
9841 else if (ctype_isChar (expected))
9843 return FALSE;
9845 else if (ctype_isArrayPtr (expected))
9848 ** evans 2001-10-14: We allow 0 to match any pointer, but only if the type matches or is void *.
9851 if (val == 0)
9853 if (ctype_match (exprNode_getType (e), expected)
9854 || ctype_isVoidPointer (exprNode_getType (e)))
9856 return TRUE;
9859 else
9861 return FALSE;
9864 else if (ctype_isAnyFloat (expected))
9866 return (context_getFlag (FLG_NUMLITERAL));
9868 else
9870 return FALSE;
9873 else if (multiVal_isDouble (m))
9875 if (ctype_isAnyFloat (expected))
9877 return TRUE;
9880 else if (multiVal_isChar (m))
9882 /*signed? */ char val = multiVal_forceChar (m);
9884 if (ctype_isChar (expected))
9886 if (ctype_isUnsigned (expected) && ((int) val) < 0)
9888 return FALSE;
9890 else
9892 return TRUE;
9896 else
9898 return FALSE;
9903 return FALSE;
9906 bool
9907 exprNode_matchType (ctype expected, exprNode e)
9909 ctype actual;
9911 if (!exprNode_isDefined (e)) return TRUE;
9913 actual = ctype_realishType (exprNode_getType (e));
9915 if (ctype_match (ctype_realishType (expected), actual))
9917 return TRUE;
9920 llassert (!exprNode_isError (e));
9921 return (exprNode_matchLiteral (expected, e));
9924 static bool
9925 exprNode_matchTypes (exprNode e1, exprNode e2)
9927 ctype t1;
9928 ctype t2;
9930 if (!exprNode_isDefined (e1)) return TRUE;
9931 if (!exprNode_isDefined (e2)) return TRUE;
9934 ** realish type --- keep bools, bools
9937 t1 = ctype_realishType (exprNode_getType (e1));
9938 t2 = ctype_realishType (exprNode_getType (e2));
9940 if (ctype_match (t1, t2))
9942 return TRUE;
9945 DPRINTF (("Matching literal! %s %s %s %s",
9946 ctype_unparse (t1), exprNode_unparse (e2),
9947 ctype_unparse (t2), exprNode_unparse (e1)));
9949 return (exprNode_matchLiteral (t1, e2) || exprNode_matchLiteral (t2, e1));
9953 ** pass e as ct
9956 static bool
9957 exprNode_matchArgType (ctype ct, exprNode e)
9959 ctype et;
9961 if (!exprNode_isDefined (e))
9963 return TRUE;
9966 et = ctype_realType (exprNode_getType (e));
9968 if (ctype_matchArg (ct, et)) return TRUE;
9970 llassert (!exprNode_isError (e));
9971 return (exprNode_matchLiteral (ct, e));
9974 static /*@only@*/ exprNodeSList
9975 exprNode_flatten (/*@dependent@*/ exprNode e) /*@*/
9977 if (exprNode_isDefined (e))
9979 if (e->kind == XPR_STMTLIST)
9981 return (exprNodeSList_append
9982 (exprNode_flatten (exprData_getPairA (e->edata)),
9983 exprNode_flatten (exprData_getPairB (e->edata))));
9985 else if (e->kind == XPR_BLOCK)
9987 return (exprNode_flatten (exprData_getSingle (e->edata)));
9989 else
9991 return (exprNodeSList_singleton (e));
9995 return exprNodeSList_new ();
9998 static /*@exposed@*/ exprNode
9999 exprNode_lastStatement (/*@returned@*/ exprNode e)
10001 if (exprNode_isDefined (e))
10003 if (e->kind == XPR_STMTLIST)
10005 exprNode b = exprData_getPairB (e->edata);
10007 if (exprNode_isDefined (b))
10009 return exprNode_lastStatement (b);
10011 else
10013 return exprNode_lastStatement (exprData_getPairA (e->edata));
10016 else if (e->kind == XPR_BLOCK)
10018 return (exprNode_lastStatement (exprData_getSingle (e->edata)));
10020 else
10022 return (e);
10026 return exprNode_undefined;
10029 static /*@exposed@*/ exprNode
10030 exprNode_firstStatement (/*@returned@*/ exprNode e)
10032 if (exprNode_isDefined (e))
10034 if (e->kind == XPR_STMTLIST)
10036 exprNode b = exprData_getPairA (e->edata);
10038 if (exprNode_isDefined (b))
10040 return exprNode_firstStatement (b);
10042 else
10044 return exprNode_firstStatement (exprData_getPairB (e->edata));
10047 else if (e->kind == XPR_BLOCK)
10049 return (exprNode_firstStatement (exprData_getSingle (e->edata)));
10051 else
10053 return (e);
10057 return exprNode_undefined;
10060 static void
10061 exprNode_mergeUSs (exprNode res, exprNode other)
10063 if (exprNode_isDefined (res) && exprNode_isDefined (other))
10065 res->msets = sRefSet_union (res->msets, other->msets);
10066 res->sets = sRefSet_union (res->sets, other->sets);
10067 res->uses = sRefSet_union (res->uses, other->uses);
10071 static void
10072 exprNode_mergeCondUSs (exprNode res, exprNode other1, exprNode other2)
10074 if (exprNode_isDefined (res))
10076 if (exprNode_isDefined (other1))
10078 res->sets = sRefSet_union (res->sets, other1->sets);
10079 res->msets = sRefSet_union (res->msets, other1->msets);
10080 res->uses = sRefSet_union (res->uses, other1->uses);
10082 if (exprNode_isDefined (other2))
10084 res->sets = sRefSet_union (res->sets, other2->sets);
10085 res->msets = sRefSet_union (res->msets, other2->msets);
10086 res->uses = sRefSet_union (res->uses, other2->uses);
10092 ** modifies e->uses
10094 ** Reports errors is s is not defined.
10097 static void
10098 exprNode_addUse (exprNode e, /*@exposed@*/ sRef s)
10100 if (exprNode_isDefined (e))
10102 e->uses = sRefSet_insert (e->uses, s);
10106 void
10107 exprNode_checkUse (exprNode e, /*@exposed@*/ sRef s, fileloc loc)
10109 if (sRef_isKnown (s) && !sRef_isConst (s))
10112 ** need to check all outer types are useable
10115 DPRINTF (("Check use: %s / %s",
10116 exprNode_unparse (e), sRef_unparse (s)));
10118 exprNode_addUse (e, s);
10120 if (!context_inProtectVars ())
10123 ** only report the deepest error
10126 sRef errorRef = sRef_undefined;
10127 sRef lastRef = sRef_undefined;
10128 bool deadRef = FALSE;
10129 bool unuseable = FALSE;
10130 bool errorMaybe = FALSE;
10132 while (sRef_isValid (s) && sRef_isKnown (s))
10134 ynm readable = sRef_isValidLvalue (s);
10136 DPRINTF (("Readable: %s / %s",
10137 sRef_unparseFull (s), ynm_unparse (readable)));
10139 if (!(ynm_toBoolStrict (readable)))
10141 if (ynm_isMaybe (readable))
10143 lastRef = errorRef;
10144 errorRef = s;
10145 DPRINTF (("Setting ERROR: %s", sRef_unparseFull (s)));
10146 deadRef = sRef_isPossiblyDead (errorRef);
10147 unuseable = sRef_isUnuseable (errorRef);
10148 errorMaybe = TRUE;
10150 else
10152 lastRef = errorRef;
10153 errorRef = s;
10154 DPRINTF (("Setting ERROR: %s", sRef_unparseFull (s)));
10155 deadRef = sRef_isDead (errorRef);
10156 unuseable = sRef_isUnuseable (errorRef);
10157 errorMaybe = FALSE;
10161 if (!sRef_isPartial (s))
10163 DPRINTF (("Defining! %s", sRef_unparseFull (s)));
10164 sRef_setDefined (s, loc);
10165 DPRINTF (("Defining! %s", sRef_unparseFull (s)));
10170 s = sRef_getBaseSafe (s);
10171 } /* end while */
10173 if (sRef_isValid (errorRef))
10175 if (sRef_isValid (lastRef) && sRef_isField (lastRef)
10176 && sRef_isPointer (errorRef))
10178 errorRef = lastRef;
10179 DPRINTF (("errorRef: %s", sRef_unparseFull (errorRef)));
10182 if (deadRef)
10184 if (sRef_isThroughArrayFetch (errorRef))
10186 if (optgenerror
10187 (FLG_STRICTUSERELEASED,
10188 message ("%q %q may be used after being released",
10189 sRef_unparseKindNamePlain (errorRef),
10190 sRef_unparse (errorRef)),
10191 loc))
10193 sRef_showRefKilled (errorRef);
10195 if (sRef_isKept (errorRef))
10197 sRef_clearAliasState (errorRef, loc);
10201 else
10203 DPRINTF (("HERE: %s", sRef_unparseFull (errorRef)));
10205 if (optgenerror
10206 (FLG_USERELEASED,
10207 message ("%q %q %qused after being released",
10208 sRef_unparseKindNamePlain (errorRef),
10209 sRef_unparse (errorRef),
10210 cstring_makeLiteral (errorMaybe
10211 ? "may be " : "")),
10212 loc))
10214 sRef_showRefKilled (errorRef);
10216 if (sRef_isKept (errorRef))
10218 sRef_clearAliasState (errorRef, loc);
10223 else if (unuseable)
10225 if (optgenerror
10226 (FLG_USEDEF,
10227 message ("%q %q%qused in inconsistent state",
10228 sRef_unparseKindName (errorRef),
10229 sRef_unparseOpt (errorRef),
10230 cstring_makeLiteral (errorMaybe ? "may be " : "")),
10231 loc))
10233 sRef_showStateInconsistent (errorRef);
10236 else
10238 DPRINTF (("HERE: %s", sRef_unparseFull (errorRef)));
10240 if (optgenerror
10241 (FLG_USEDEF,
10242 message ("%q %q%qused before definition",
10243 sRef_unparseKindName (errorRef),
10244 sRef_unparseOpt (errorRef),
10245 cstring_makeLiteral (errorMaybe ? "may be " : "")),
10246 loc))
10251 DPRINTF (("Error: %s", sRef_unparseFull (errorRef)));
10254 sRef_setDefined (errorRef, loc);
10256 if (sRef_isAddress (errorRef))
10258 sRef_setDefined (sRef_getRootBase (errorRef), loc);
10260 } /* end is error */
10264 setCodePoint ();
10267 static void
10268 checkSafeUse (exprNode e, /*@exposed@*/ sRef s)
10270 if (exprNode_isDefined (e) && sRef_isKnown (s))
10272 e->uses = sRefSet_insert (e->uses, s);
10276 static void
10277 exprNode_checkSetAny (exprNode e, /*@dependent@*/ cstring name)
10279 if (exprNode_isDefined (e))
10281 e->sets = sRefSet_insert (e->sets, sRef_makeUnconstrained (name));
10285 void
10286 exprNode_checkSet (exprNode e, /*@exposed@*/ sRef s)
10288 sRef defines = sRef_undefined;
10290 if (sRef_isValid (s) && !sRef_isNothing (s))
10292 uentry ue = sRef_getBaseUentry (s);
10294 if (uentry_isValid (ue))
10296 uentry_setLset (ue);
10299 if (!ynm_toBoolStrict (sRef_isWriteable (s)))
10301 voptgenerror (FLG_USEDEF,
10302 message ("Attempt to set unuseable storage: %q",
10303 sRef_unparse (s)),
10304 exprNode_loc (e));
10307 if (sRef_isMeaningful (s))
10309 if (sRef_isDead (s))
10311 sRef base = sRef_getBaseSafe (s);
10313 if (sRef_isValid (base)
10314 && sRef_isDead (base))
10316 sRef_setPartial (s, exprNode_loc (e));
10319 defines = s; /* okay - modifies for only param */
10321 else if (sRef_isPartial (s))
10323 sRef eref = exprNode_getSref (e);
10325 if (!sRef_isPartial (eref))
10328 ** should do something different here???
10331 sRef_setDefinedComplete (eref, exprNode_loc (e));
10333 else
10335 sRef_setPartialDefinedComplete (eref, exprNode_loc (e));
10338 if (sRef_isMeaningful (eref))
10340 defines = eref;
10342 else
10344 defines = s;
10347 else if (sRef_isAllocated (s))
10349 sRef eref = exprNode_getSref (e);
10352 if (!sRef_isAllocated (eref))
10354 sRef_setDefinedComplete (eref, exprNode_loc (e));
10356 else
10358 sRef base = sRef_getBaseSafe (eref);
10360 if (sRef_isValid (base))
10362 sRef_setPdefined (base, exprNode_loc (e));
10366 defines = s;
10368 else
10370 sRef_setDefinedNCComplete (s, exprNode_loc (e));
10371 defines = s;
10375 else /* not meaningful...but still need to insert it */
10377 defines = s;
10381 if (exprNode_isDefined (e) && sRef_isValid (defines))
10383 e->sets = sRefSet_insert (e->sets, defines);
10387 void
10388 exprNode_checkMSet (exprNode e, /*@exposed@*/ sRef s)
10390 if (sRef_isValid (s) && !sRef_isNothing (s))
10392 uentry ue = sRef_getBaseUentry (s);
10394 if (uentry_isValid (ue))
10396 uentry_setLset (ue);
10399 if (!ynm_toBoolStrict (sRef_isWriteable (s)))
10401 voptgenerror (FLG_USEDEF,
10402 message ("Attempt to set unuseable storage: %q", sRef_unparse (s)),
10403 exprNode_loc (e));
10406 if (sRef_isMeaningful (s))
10408 sRef_setDefinedComplete (s, exprNode_loc (e));
10411 if (exprNode_isDefined (e))
10413 e->msets = sRefSet_insert (e->msets, s);
10418 static void
10419 checkUnspecCall (/*@notnull@*/ /*@dependent@*/ exprNode fcn, uentryList params, exprNodeList args)
10421 checkAnyCall (fcn, cstring_undefined, params, args,
10422 FALSE, sRefSet_undefined, FALSE, 0);
10425 static void
10426 checkOneArg (uentry ucurrent, /*@notnull@*/ exprNode current,
10427 /*@dependent@*/ exprNode fcn, bool isSpec, int argno, int totargs)
10429 setCodePoint ();
10431 if (uentry_isYield (ucurrent))
10433 sRef_setDefined (exprNode_getSref (current), exprNode_loc (current));
10434 exprNode_checkSet (current, current->sref);
10436 else
10438 if (uentry_isSefParam (ucurrent))
10440 sRefSet sets = current->sets;
10441 sRef ref = exprNode_getSref (current);
10443 if (sRef_isMacroParamRef (ref))
10445 uentry ue = sRef_getUentry (ref);
10447 if (!uentry_isSefParam (ue))
10449 voptgenerror
10450 (FLG_SEFPARAMS,
10451 message
10452 ("Parameter %d to %s is declared sef, but "
10453 "the argument is a macro parameter declared "
10454 "without sef: %s",
10455 argno, exprNode_unparse (fcn),
10456 exprNode_unparse (current)),
10457 exprNode_loc (current));
10461 if (!sRefSet_isEmpty (sets))
10463 sRefSet reported = sRefSet_undefined;
10465 sRefSet_realElements (current->sets, el)
10467 if (sRefSet_isSameNameMember (reported, el))
10469 ; /* don't report again */
10471 else
10473 if (sRef_isUnconstrained (el))
10475 voptgenerror
10476 (FLG_SEFUNSPEC,
10477 message
10478 ("Parameter %d to %s is declared sef, but "
10479 "the argument calls unconstrained function %s "
10480 "(no guarantee it will not modify something): %s",
10481 argno, exprNode_unparse (fcn),
10482 sRef_unconstrainedName (el),
10483 exprNode_unparse (current)),
10484 exprNode_loc (current));
10486 else
10488 voptgenerror
10489 (FLG_SEFPARAMS,
10490 message
10491 ("Parameter %d to %s is declared sef, but "
10492 "the argument may modify %q: %s",
10493 argno, exprNode_unparse (fcn),
10494 sRef_unparse (el),
10495 exprNode_unparse (current)),
10496 exprNode_loc (current));
10499 } end_sRefSet_realElements;
10503 transferChecks_passParam (current, ucurrent, isSpec, fcn, argno, totargs);
10504 exprNode_mergeUSs (fcn, current);
10508 static void
10509 checkAnyCall (/*@dependent@*/ exprNode fcn,
10510 /*@dependent@*/ cstring fname,
10511 uentryList pn,
10512 exprNodeList args,
10513 bool hasMods, sRefSet mods,
10514 bool isSpec,
10515 int specialArgs)
10517 int paramno = 0;
10518 int nargs = exprNodeList_size (args);
10520 setCodePoint ();
10523 ** concat all args ud's to f, add each arg sref as a use unless
10524 ** it was specified as "out", in which case it is a def.
10527 uentryList_reset (pn);
10530 ** aliasing checks:
10532 ** if paramn is only or unique, no other arg may alias argn
10535 exprNodeList_elements (args, current)
10537 paramno++;
10539 if (exprNode_isDefined (current))
10541 if ((!uentryList_isUndefined (pn) && !uentryList_isFinished (pn)))
10543 uentry ucurrent = uentryList_current (pn);
10545 if (specialArgs == 0
10546 || (paramno < specialArgs))
10548 checkOneArg (ucurrent, current, fcn, isSpec, paramno, nargs);
10550 if (context_maybeSet (FLG_ALIASUNIQUE))
10552 if (uentry_isOnly (ucurrent)
10553 || uentry_isUnique (ucurrent))
10555 checkUniqueParams (fcn, current, args,
10556 paramno, ucurrent);
10561 else /* uentry is undefined */
10563 if (specialArgs == 0)
10565 exprNode_checkUseParam (current);
10568 exprNode_mergeUSs (fcn, current);
10571 uentryList_advanceSafe (pn);
10572 } end_exprNodeList_elements;
10574 if (hasMods)
10576 setCodePoint ();
10578 sRefSet_allElements (mods, s)
10580 sRef fb;
10581 sRef rb = sRef_getRootBase (s);
10583 if (sRef_isFileOrGlobalScope (rb))
10585 context_usedGlobal (rb);
10588 fb = sRef_fixBaseParam (s, args);
10590 if (!sRef_isMacroParamRef (fb))
10592 if (sRef_isNothing (fb))
10596 else
10598 if (sRef_isValid (fb))
10600 uentry ue = sRef_getBaseUentry (s);
10602 if (uentry_isValid (ue))
10604 uentry_setLset (ue);
10608 fcn->sets = sRefSet_insert (fcn->sets, fb);
10611 sRef_clearDerivedComplete (s);
10612 } end_sRefSet_allElements;
10614 setCodePoint ();
10616 else
10618 if (context_hasMods ())
10620 if (context_maybeSet (FLG_MODUNCON))
10622 voptgenerror
10623 (FLG_MODUNCON,
10624 message ("Undetected modification possible "
10625 "from call to unconstrained function %s: %s",
10626 fname,
10627 exprNode_unparse (fcn)),
10628 exprNode_loc (fcn));
10631 else
10633 if (context_maybeSet (FLG_MODUNCONNOMODS)
10634 && !(context_inIterDef () || context_inIterEnd ()))
10636 voptgenerror
10637 (FLG_MODUNCONNOMODS,
10638 message ("Undetected modification possible "
10639 "from call to unconstrained function %s: %s",
10640 fname,
10641 exprNode_unparse (fcn)),
10642 exprNode_loc (fcn));
10646 exprNode_checkSetAny (fcn, fname);
10650 void exprNode_checkUseParam (exprNode current)
10652 if (exprNode_isDefined (current))
10654 exprNode_checkUse (current, current->sref, current->loc);
10658 static ctype
10659 checkNumerics (ctype tr1, ctype tr2, ctype te1, ctype te2,
10660 /*@notnull@*/ exprNode e1, /*@notnull@*/ exprNode e2,
10661 lltok op)
10663 ctype ret = tr1;
10665 if (!ctype_match (tr1, tr2))
10667 if ((ctype_isRealInt (tr1) || ctype_isReal (tr1)) &&
10668 (ctype_isRealInt (tr2) || ctype_isReal (tr2)))
10670 DPRINTF (("No error: [%s] %s / [%s] %s",
10671 exprNode_unparse (e1), ctype_unparse (tr1),
10672 exprNode_unparse (e2), ctype_unparse (tr2)));
10675 ** evans 2003-06-15: changed this so if either type is a literal,
10676 ** the other type is used.
10677 ** (Need to look at the ISO C99 rules on this...)
10680 if (exprNode_isNumLiteral (e1)) {
10681 ret = tr2;
10682 } else if (exprNode_isNumLiteral (e2)) {
10683 ret = tr1;
10684 } else {
10685 ret = ctype_biggerType (tr1, tr2);
10688 else
10690 if (ctype_isNumAbstract (tr1)
10691 && exprNode_isNumLiteral (e2)
10692 && context_flagOn (FLG_NUMABSTRACTLIT, e1->loc))
10694 ret = tr1; /* No error */
10696 else if (ctype_isNumAbstract (tr2)
10697 && exprNode_isNumLiteral (e1)
10698 && context_flagOn (FLG_NUMABSTRACTLIT, e1->loc))
10700 ret = tr2;
10702 else
10704 if (gentypeerror
10705 (tr1, e1, tr2, e2,
10706 message ("Incompatible types for %s (%s, %s): %s %s %s",
10707 lltok_unparse (op),
10708 ctype_unparse (te1),
10709 ctype_unparse (te2),
10710 exprNode_unparse (e1), lltok_unparse (op),
10711 exprNode_unparse (e2)),
10712 e1->loc))
10714 ret = ctype_unknown;
10716 else
10718 ret = ctype_biggerType (tr1, tr2);
10723 else
10725 if (ctype_isNumAbstract (tr1))
10727 ret = tr1;
10729 else if (ctype_isForceRealNumeric (&tr1)
10730 && ctype_isForceRealNumeric (&tr2))
10732 ret = ctype_resolveNumerics (tr1, tr2);
10734 else if (!context_msgStrictOps ())
10736 if (ctype_isPointer (tr1))
10738 if (ctype_isPointer (tr2) && !exprNode_isNullValue (e2))
10740 ret = ctype_int;
10742 else if (ctype_isInt (tr2))
10744 ret = te1;
10746 else
10748 ret = ctype_unknown;
10751 else if (ctype_isPointer (tr2))
10753 if (ctype_isPointer (tr1))
10755 ret = ctype_int;
10757 else if (ctype_isInt (tr1))
10759 ret = te2;
10761 else
10763 ret = ctype_unknown;
10766 else
10768 ret = ctype_resolveNumerics (tr1, tr2);
10771 else
10773 int opid = lltok_getTok (op);
10774 bool comparop = (opid == EQ_OP || opid == NE_OP
10775 || opid == TLT || opid == TGT
10776 || opid == LE_OP || opid == GE_OP);
10778 if (!ctype_isNumeric (tr1) && !ctype_isNumeric (tr2))
10780 if (comparop
10781 && ((ctype_isEnum (tr1) && ctype_isEnum (tr2))
10782 || (ctype_isBool (tr1) && ctype_isBool (tr2))
10783 || (ctype_isChar (tr1) && ctype_isChar (tr2))))
10785 ; /* no error */
10787 else
10789 if (ctype_sameName (te1, te2))
10791 voptgenerror
10792 (FLG_STRICTOPS,
10793 message ("Operands of %s are non-numeric (%t): %s %s %s",
10794 lltok_unparse (op), te1,
10795 exprNode_unparse (e1), lltok_unparse (op),
10796 exprNode_unparse (e2)),
10797 e1->loc);
10799 else
10801 voptgenerror
10802 (FLG_STRICTOPS,
10803 message ("Operands of %s are non-numerics (%t, %t): %s %s %s",
10804 lltok_unparse (op), te1, te2,
10805 exprNode_unparse (e1), lltok_unparse (op),
10806 exprNode_unparse (e2)),
10807 e1->loc);
10811 else if (!ctype_isNumeric (tr1))
10813 voptgenerror
10814 (FLG_STRICTOPS,
10815 message ("Right operand of %s is non-numeric (%t): %s %s %s",
10816 lltok_unparse (op), te1,
10817 exprNode_unparse (e1), lltok_unparse (op),
10818 exprNode_unparse (e2)),
10819 e1->loc);
10821 else
10823 if (!ctype_isNumeric (tr2))
10825 voptgenerror
10826 (FLG_STRICTOPS,
10827 message ("Left operand of %s is non-numeric (%t): %s %s %s",
10828 lltok_unparse (op), te2,
10829 exprNode_unparse (e1), lltok_unparse (op),
10830 exprNode_unparse (e2)),
10831 e2->loc);
10835 ret = ctype_unknown;
10839 return ret;
10842 static bool
10843 abstractOpError (ctype tr1, ctype tr2, lltok op,
10844 /*@notnull@*/ exprNode e1, /*@notnull@*/ exprNode e2,
10845 fileloc loc1, fileloc loc2)
10847 if (ctype_isRealAbstract (tr1) && ctype_isRealAbstract (tr2))
10849 if (ctype_match (tr1, tr2))
10851 if (ctype_isRealNumAbstract (tr1))
10853 ; /* No warning for numabstract types */
10855 else
10857 if (lltok_isEqOp (op) || lltok_isNotEqOp (op))
10859 return optgenerror
10860 (FLG_ABSTRACTCOMPARE,
10861 message ("Object equality comparison (%s) on objects of abstract type (%t): %s %s %s",
10862 lltok_unparse (op), tr1,
10863 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
10864 loc1);
10866 else
10868 return optgenerror
10869 (FLG_ABSTRACT,
10870 message ("Operands of %s are abstract type (%t): %s %s %s",
10871 lltok_unparse (op), tr1,
10872 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
10873 loc1);
10877 else
10879 if (ctype_isRealNumAbstract (tr1) && ctype_isRealNumAbstract (tr2))
10881 return optgenerror
10882 (FLG_NUMABSTRACT,
10883 message
10884 ("Operands of %s are different numabstract types (%t, %t): %s %s %s",
10885 lltok_unparse (op), tr1, tr2,
10886 exprNode_unparse (e1),
10887 lltok_unparse (op), exprNode_unparse (e2)),
10888 loc1);
10890 else
10892 return optgenerror
10893 (FLG_ABSTRACT,
10894 message ("Operands of %s are abstract types (%t, %t): %s %s %s",
10895 lltok_unparse (op), tr1, tr2,
10896 exprNode_unparse (e1), lltok_unparse (op),
10897 exprNode_unparse (e2)),
10898 loc1);
10902 else if (ctype_isRealAbstract (tr1) && !ctype_isRealNumAbstract (tr1))
10904 return optgenerror
10905 (FLG_ABSTRACT,
10906 message ("Left operand of %s is abstract type (%t): %s %s %s",
10907 lltok_unparse (op), tr1,
10908 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
10909 loc1);
10911 else
10913 if (ctype_isRealAbstract (tr2) && !ctype_isRealNumAbstract (tr2))
10915 return optgenerror
10916 (FLG_ABSTRACT,
10917 message ("Right operand of %s is abstract type (%t): %s %s %s",
10918 lltok_unparse (op), tr2,
10919 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
10920 loc2);
10924 return FALSE;
10928 ** e1 <= e2
10930 ** requies e1 and e2 and not error exprNode's.
10932 ** Checks:
10934 ** If e1 is a component of an abstract type, and e2 is mutable and client-visible,
10935 ** the rep of the abstract type is exposed.
10937 ** The order is very important:
10939 ** check rep expose (move into check transfer)
10940 ** check transfer
10941 ** setup aliases
10945 ** This isn't really a sensible procedure, but the indententation
10946 ** was getting too deep.
10949 static void
10950 checkOneRepExpose (sRef ysr, sRef base,
10951 /*@notnull@*/ exprNode e1,
10952 /*@notnull@*/ exprNode e2, ctype ct,
10953 sRef s2b)
10955 if (!(sRef_isOnly (ysr) || sRef_isKeep (ysr)
10956 || sRef_isOwned (ysr)
10957 || sRef_isExposed (ysr)))
10959 if (sRef_isAnyParam (base) && !sRef_isExposed (base)
10960 && !sRef_isObserver (base)) /* evans 2001-07-11: added isObserver */
10963 if (sRef_isIReference (ysr))
10965 if (sRef_sameName (base, sRef_getRootBase (e2->sref)))
10967 voptgenerror
10968 (FLG_ASSIGNEXPOSE,
10969 message
10970 ("Assignment of mutable component of parameter %q "
10971 "to component of abstract "
10972 "type %s exposes rep: %s = %s",
10973 sRef_unparse (base),
10974 ctype_unparse (ct),
10975 exprNode_unparse (e1), exprNode_unparse (e2)),
10976 e1->loc);
10978 else
10980 voptgenerror
10981 (FLG_ASSIGNEXPOSE,
10982 message
10983 ("Assignment of mutable component of parameter %q "
10984 "(through alias %q) to component of abstract "
10985 "type %s exposes rep: %s = %s",
10986 sRef_unparse (base),
10987 sRef_unparse (e2->sref),
10988 ctype_unparse (ct),
10989 exprNode_unparse (e1), exprNode_unparse (e2)),
10990 e1->loc);
10993 else
10995 if (sRef_sameName (base, sRef_getRootBase (e2->sref)))
10997 voptgenerror
10998 (FLG_ASSIGNEXPOSE,
10999 message ("Assignment of mutable parameter %q "
11000 "to component of abstract type %s "
11001 "exposes rep: %s = %s",
11002 sRef_unparse (base),
11003 ctype_unparse (ct),
11004 exprNode_unparse (e1),
11005 exprNode_unparse (e2)),
11006 e1->loc);
11008 else
11010 voptgenerror
11011 (FLG_ASSIGNEXPOSE,
11012 message ("Assignment of mutable parameter %q "
11013 "(through alias %q) to "
11014 "component of abstract type %s exposes "
11015 "rep: %s = %s",
11016 sRef_unparse (base),
11017 sRef_unparse (e2->sref),
11018 ctype_unparse (ct),
11019 exprNode_unparse (e1),
11020 exprNode_unparse (e2)),
11021 e1->loc);
11026 if (sRef_isFileOrGlobalScope (s2b))
11028 if (sRef_sameName (base, sRef_getRootBase (e2->sref)))
11030 voptgenerror
11031 (FLG_REPEXPOSE,
11032 message ("Assignment of global %q "
11033 "to component of "
11034 "abstract type %s exposes rep: %s = %s",
11035 sRef_unparse (base),
11036 ctype_unparse (ct),
11037 exprNode_unparse (e1), exprNode_unparse (e2)),
11038 e1->loc);
11040 else
11042 voptgenerror
11043 (FLG_REPEXPOSE,
11044 message ("Assignment of global %q (through alias %q) "
11045 "to component of "
11046 "abstract type %s exposes rep: %s = %s",
11047 sRef_unparse (base),
11048 sRef_unparse (e2->sref),
11049 ctype_unparse (ct),
11050 exprNode_unparse (e1), exprNode_unparse (e2)),
11051 e1->loc);
11057 static void
11058 doAssign (/*@notnull@*/ exprNode e1, /*@notnull@*/ exprNode e2, bool isInit)
11060 DPRINTF (("Do assign: %s <- %s",
11061 exprNode_unparse (e1), exprNode_unparse (e2)));
11062 DPRINTF (("Ctype: %s", ctype_unparse (exprNode_getType (e1))));
11064 if (ctype_isRealFunction (exprNode_getType (e1))
11065 && !ctype_isRealPointer (exprNode_getType (e1)))
11067 voptgenerror
11068 (FLG_TYPE,
11069 message ("Invalid left-hand side of assignment (function type %s): %s",
11070 ctype_unparse (exprNode_getType (e1)),
11071 exprNode_unparse (e1)),
11072 e1->loc);
11075 if (context_getFlag (FLG_ASSIGNEXPOSE) && ctype_isMutable (e2->typ))
11077 ctype t2 = exprNode_getType (e2);
11078 sRef sr = sRef_getRootBase (e1->sref);
11079 ctype ct = sRef_getType (sr);
11081 if (ctype_isAbstract (t2)
11082 && !ctype_isNumAbstract (t2)
11083 && !(uentry_isMutableDatatype (usymtab_getTypeEntry (ctype_typeId (t2)))))
11085 /* it is immutable, okay to reference */
11086 goto donerepexpose;
11089 if (ctype_isAbstract (ct) && sRef_isIReference (e1->sref))
11091 sRef s2b = sRef_getRootBase (e2->sref);
11092 sRef s1 = e1->sref;
11093 sRef s1b = sRef_getRootBase (s1);
11094 sRefSet aliases;
11096 aliases = usymtab_canAlias (e2->sref);
11098 if (!sRef_similar (s2b, s1b)
11099 && !sRef_isExposed (s1)
11100 && !(sRef_isOnly (s2b) || sRef_isKeep (s2b) || sRef_isExposed (s2b)))
11102 if (sRef_isAnyParam (s2b) && !sRef_isOnly (s2b)
11103 && !sRef_isOwned (s2b) && !sRef_isKeep (s2b)
11104 && !sRef_isExposed (s2b))
11106 if (sRef_isIReference (e2->sref))
11108 voptgenerror
11109 (FLG_ASSIGNEXPOSE,
11110 message
11111 ("Assignment of mutable component of parameter %q "
11112 "to component of abstract type %s exposes rep: %s = %s",
11113 sRef_unparse (s2b),
11114 ctype_unparse (ct),
11115 exprNode_unparse (e1), exprNode_unparse (e2)),
11116 e1->loc);
11118 else
11120 voptgenerror
11121 (FLG_ASSIGNEXPOSE,
11122 message ("Assignment of mutable parameter %q to "
11123 "component of abstract type %s exposes rep: %s = %s",
11124 sRef_unparse (s2b),
11125 ctype_unparse (ct),
11126 exprNode_unparse (e1), exprNode_unparse (e2)),
11127 e1->loc);
11131 if (sRef_isFileOrGlobalScope (s2b))
11133 voptgenerror
11134 (FLG_ASSIGNEXPOSE,
11135 message ("Assignment of global %q to component of "
11136 "abstract type %s exposes rep: %s = %s",
11137 sRef_unparse (s2b),
11138 ctype_unparse (ct),
11139 exprNode_unparse (e1), exprNode_unparse (e2)),
11140 e1->loc);
11143 sRefSet_realElements (aliases, ysr)
11145 sRef base = sRef_getRootBase (ysr);
11147 if (sRef_similar (ysr, s2b) || sRef_similar (s1b, base)
11148 || sRef_sameName (base, s1b))
11150 ; /* error already reported or same sref */
11152 else
11154 checkOneRepExpose (ysr, base, e1, e2, ct, s2b);
11156 } end_sRefSet_realElements;
11158 sRefSet_free (aliases);
11162 donerepexpose:
11165 ** function variables don't really work...
11168 if (!ctype_isFunction (ctype_realType (e2->typ)))
11170 if (isInit)
11172 DPRINTF (("Check init: %s / %s",
11173 exprNode_unparse (e1), exprNode_unparse (e2)));
11174 transferChecks_initialization (e1, e2);
11176 else
11178 transferChecks_assign (e1, e2);
11181 else
11183 sRef fref = e2->sref;
11185 sRef_setDefState (e1->sref, sRef_getDefState (fref), e1->loc);
11186 sRef_setNullState (e1->sref, sRef_getNullState (fref), e1->loc);
11188 /* Need to typecheck the annotation on the parameters */
11190 if (ctype_isRealFunction (e1->typ)) {
11191 uentryList e1p = ctype_argsFunction (ctype_realType (e1->typ));
11192 uentryList e2p = ctype_argsFunction (ctype_realType (e2->typ));
11194 if (!uentryList_isMissingParams (e1p)
11195 && !uentryList_isMissingParams (e2p)
11196 && uentryList_size (e1p) > 0) {
11197 if (uentryList_size (e1p) == uentryList_size (e2p)) {
11198 int n = 0;
11200 uentryList_elements (e1p, el1) {
11201 uentry el2;
11203 el2 = uentryList_getN (e2p, n);
11204 n++;
11205 uentry_checkMatchParam (el1, el2, n, e2);
11206 } end_uentryList_elements;
11212 if (exprNode_isStringLiteral (e2))
11214 exprNode_checkStringLiteralLength (exprNode_getType (e1), e2);
11217 if (isInit && sRef_isFileOrGlobalScope (e1->sref))
11221 else
11223 DPRINTF (("Update aliases: %s / %s", exprNode_unparse (e1), exprNode_unparse (e2)));
11224 updateAliases (e1, e2);
11228 static void
11229 checkMacroParen (exprNode e)
11231 if (exprNode_isError (e) || e->kind == XPR_CAST)
11235 else
11237 if (sRef_isUnsafe (e->sref) && !exprNode_isInParens (e))
11239 voptgenerror
11240 (FLG_MACROPARENS,
11241 message ("Macro parameter used without parentheses: %s",
11242 exprNode_unparse (e)),
11243 e->loc);
11248 static void
11249 reflectNullTest (/*@notnull@*/ exprNode e, bool isnull)
11251 if (isnull)
11253 e->guards = guardSet_addTrueGuard (e->guards, e->sref);
11255 else
11257 e->guards = guardSet_addFalseGuard (e->guards, e->sref);
11262 ** e1 <= e2
11264 ** if e2 is a parameter or global derived location which
11265 ** can be modified (that is, e2 is a mutable abstract type,
11266 ** or a derived pointer), then e1 can alias e2.
11268 ** e1 can alias everything which e2 can alias.
11270 ** Also, if e1 is guarded, remove from guard sets!
11273 static void updateAliases (/*@notnull@*/ exprNode e1, /*@notnull@*/ exprNode e2)
11275 if (!context_inProtectVars ())
11278 ** depends on types of e1 and e2
11281 sRef s1 = e1->sref;
11282 sRef s2 = e2->sref;
11283 ctype t1 = exprNode_getType (e1);
11285 /* handle pointer sRefs, record fields, arrays, etc... */
11287 if (!ctype_isRealSU (t1))
11289 DPRINTF (("Copying real! %s", ctype_unparse (t1)));
11290 sRef_copyRealDerivedComplete (s1, s2);
11292 else
11295 ** Fields should alias
11298 DPRINTF (("Not COPYING!: %s", ctype_unparse (t1)));
11301 if (ctype_isMutable (t1) && sRef_isKnown (s1))
11303 usymtab_clearAlias (s1);
11304 usymtab_addMustAlias (s1, s2);
11305 DPRINTF (("Add must alias: %s / %s", sRef_unparse (s1), sRef_unparse (s2)));
11307 else
11309 DPRINTF (("Not mutable: %s", ctype_unparse (t1)));
11312 if (sRef_possiblyNull (s1) && usymtab_isGuarded (s1))
11314 usymtab_unguard (s1);
11319 exprNode exprNode_updateLocation (/*@returned@*/ exprNode e, /*@temp@*/ fileloc loc)
11321 if (exprNode_isDefined (e))
11323 e->loc = fileloc_update (e->loc, loc);
11325 else
11327 e = exprNode_createLoc (ctype_unknown, fileloc_copy (loc));
11330 return (e);
11333 static void checkUniqueParams (exprNode fcn,
11334 /*@notnull@*/ exprNode current,
11335 exprNodeList args,
11336 int paramno, uentry ucurrent)
11338 int iparamno = 0;
11339 sRef thisref = exprNode_getSref (current);
11342 ** Check if any argument could match this argument.
11345 exprNodeList_elements (args, icurrent)
11347 iparamno++;
11349 if (iparamno != paramno)
11351 sRef sr = exprNode_getSref (icurrent);
11353 if (sRef_similarRelaxed (thisref, sr))
11355 if (!sRef_isConst (thisref) && !sRef_isConst (sr))
11357 voptgenerror
11358 (FLG_ALIASUNIQUE,
11359 message
11360 ("Parameter %d (%s) to function %s is declared %s but "
11361 "is aliased by parameter %d (%s)",
11362 paramno,
11363 exprNode_unparse (current),
11364 exprNode_unparse (fcn),
11365 alkind_unparse (uentry_getAliasKind (ucurrent)),
11366 iparamno, exprNode_unparse (icurrent)),
11367 current->loc);
11370 else
11372 sRefSet aliases = usymtab_canAlias (sr);
11374 sRefSet_allElements (aliases, asr)
11376 if (ctype_isUnknown (sRef_getType (thisref)))
11378 sRef_setType (thisref, uentry_getType (ucurrent));
11381 if (sRef_similarRelaxed (thisref, asr))
11383 if (sRef_isExternal (asr))
11385 if (sRef_isLocalState (thisref))
11387 ; /* okay */
11389 else
11391 sRef base = sRef_getRootBase (asr);
11393 if (!sRef_similar (sRef_getBase (asr), thisref))
11395 if (sRef_isUnique (base) || sRef_isOnly (base)
11396 || sRef_isKept (base)
11397 || (sRef_isAddress (asr) && sRef_isLocalVar (base))
11398 || (sRef_isAddress (thisref)
11399 && sRef_isLocalVar (sRef_getRootBase (thisref))))
11401 ; /* okay, no error */
11403 else
11405 voptgenerror
11406 (FLG_MAYALIASUNIQUE,
11407 message
11408 ("Parameter %d (%s) to function %s is declared %s but "
11409 "may be aliased externally by parameter %d (%s)",
11410 paramno,
11411 exprNode_unparse (current),
11412 exprNode_unparse (fcn),
11413 alkind_unparse (uentry_getAliasKind (ucurrent)),
11414 iparamno, exprNode_unparse (icurrent)),
11415 current->loc);
11420 else
11422 voptgenerror
11423 (FLG_ALIASUNIQUE,
11424 message
11425 ("Parameter %d (%s) to function %s is declared %s but "
11426 "is aliased externally by parameter %d (%s) through "
11427 "alias %q",
11428 paramno,
11429 exprNode_unparse (current),
11430 exprNode_unparse (fcn),
11431 alkind_unparse (uentry_getAliasKind (ucurrent)),
11432 iparamno, exprNode_unparse (icurrent),
11433 sRef_unparse (asr)),
11434 current->loc);
11437 } end_sRefSet_allElements;
11438 sRefSet_free (aliases);
11441 } end_exprNodeList_elements;
11444 long exprNode_getLongValue (exprNode e)
11446 long value;
11448 if (exprNode_hasValue (e) && multiVal_isInt (exprNode_getValue (e)))
11450 value = multiVal_forceInt (exprNode_getValue (e));
11452 else
11454 value = 0; /* Unknown value */
11457 return value;
11460 /*@only@*/ fileloc exprNode_getNextSequencePoint (exprNode e)
11463 ** Returns the location of the sequence point following e.
11465 ** Only works for statements (for now).
11468 if (exprNode_isDefined (e) && e->kind == XPR_STMT) {
11469 lltok t = exprData_getUopTok (e->edata);
11470 return fileloc_copy(lltok_getLoc (t));
11471 } else {
11472 /* drl possible problem : warning fix
11473 llcontbug (message ("Cannot get next sequence point: %s", exprNode_unparse (e)));
11475 return fileloc_undefined;
11479 exprNode exprNode_createNew(ctype c)
11481 exprNode ret;
11483 ret = exprNode_createPlain (c);
11485 return ret;
11488 bool exprNode_isInitBlock (exprNode e)
11490 return (exprNode_isDefined(e) && e->kind == XPR_INITBLOCK);
11493 /*drl 3/2/2003 moved this function out of constraint.c */
11494 exprNode exprNode_copyConstraints (/*@returned@*/ exprNode dst, exprNode src)
11497 llassert (exprNode_isDefined (dst) );
11498 llassert (exprNode_isDefined (src) );
11500 constraintList_free (dst->ensuresConstraints);
11501 constraintList_free (dst->requiresConstraints);
11502 constraintList_free (dst->trueEnsuresConstraints);
11503 constraintList_free (dst->falseEnsuresConstraints);
11505 dst->ensuresConstraints = constraintList_copy (src->ensuresConstraints);
11506 dst->requiresConstraints = constraintList_copy (src->requiresConstraints);
11507 dst->trueEnsuresConstraints = constraintList_copy (src->trueEnsuresConstraints);
11508 dst->falseEnsuresConstraints = constraintList_copy (src->falseEnsuresConstraints);
11509 return dst;
11512 void exprNode_revealState (exprNode e)
11514 if (exprNode_isDefined (e)) {
11515 llmsg (message ("%s: State of %s: %s", fileloc_unparse (exprNode_loc (e)),
11516 exprNode_unparse (e), sRef_unparseFull (e->sref)));
11517 } else {
11518 llmsg (message ("%s: Reveal state undefined", fileloc_unparse (g_currentloc)));