2 ** LCLint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2000 University of Virginia,
4 ** Massachusetts Institute of Technology
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.
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.
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 lclint: lclint-request@cs.virginia.edu
21 ** To report a bug: lclint-bug@cs.virginia.edu
22 ** For more information: http://lclint.cs.virginia.edu
28 # include <ctype.h> /* for isdigit */
29 # include "lclintMacros.nf"
31 # include "cgrammar.h"
32 # include "cgrammar_tokens.h"
34 # include "exprChecks.h"
35 # include "aliasChecks.h"
36 # include "exprNodeSList.h"
37 # include "exprData.i"
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_isBlock (exprNode p_e);
43 static void checkGlobUse (uentry p_glob, bool p_isCall, /*@notnull@*/ exprNode p_e);
44 static void exprNode_addUse (exprNode p_e, sRef p_s);
45 static bool exprNode_matchArgType (ctype p_ct, exprNode p_e);
46 static exprNode exprNode_fakeCopy (exprNode p_e) /*@*/ ;
47 static exprNode exprNode_statementError (/*@only@*/ exprNode p_e);
48 static bool exprNode_matchTypes (exprNode p_e1, exprNode p_e2);
49 static void checkUniqueParams (exprNode p_fcn,
50 /*@notnull@*/ exprNode p_current, exprNodeList p_args,
51 int p_paramno, uentry p_ucurrent);
52 static void updateAliases (/*@notnull@*/ exprNode p_e1, /*@notnull@*/ exprNode p_e2);
53 static void abstractOpError (ctype p_tr1, ctype p_tr2, lltok p_op,
54 /*@notnull@*/ exprNode p_e1, /*@notnull@*/ exprNode p_e2,
55 fileloc p_loc1, fileloc p_loc2);
56 static ctype checkNumerics (ctype p_tr1, ctype p_tr2, ctype p_te1, ctype p_te2,
57 /*@notnull@*/ exprNode p_e1, /*@notnull@*/ exprNode p_e2, lltok p_op);
58 static void doAssign (/*@notnull@*/ exprNode p_e1, /*@notnull@*/ exprNode p_e2, bool p_isInit);
59 static void checkSafeUse (exprNode p_e, sRef p_s);
60 static void reflectNullTest (/*@notnull@*/ exprNode p_e, bool p_isnull);
61 static void checkMacroParen (exprNode p_e);
62 static exprNodeSList exprNode_flatten (/*@dependent@*/ exprNode p_e);
63 static void exprNode_checkSetAny (exprNode p_e, /*@dependent@*/ cstring p_name);
64 static void exprNode_checkUse (exprNode p_e, sRef p_s, fileloc p_loc);
65 static void exprNode_mergeUSs (exprNode p_res, exprNode p_other);
66 static void exprNode_mergeCondUSs (exprNode p_res, exprNode p_other1, exprNode p_other2);
67 static /*@only@*/ /*@notnull@*/ exprNode exprNode_fromIdentifierAux (/*@observer@*/ uentry p_c);
68 static void checkAnyCall (/*@notnull@*/ /*@dependent@*/ exprNode p_fcn,
69 /*@dependent@*/ cstring p_fname,
70 uentryList p_pn, exprNodeList p_args,
71 bool p_hasMods, sRefSet p_mods, bool p_isSpec,
73 static void checkOneArg (uentry p_ucurrent, /*@notnull@*/ exprNode p_current,
74 /*@dependent@*/ exprNode p_fcn, bool p_isSpec, int p_argno, int p_totargs);
76 checkUnspecCall (/*@notnull@*/ /*@dependent@*/ exprNode p_fcn, uentryList p_params, exprNodeList p_args);
78 static /*@only@*/ exprNode exprNode_effect (exprNode p_e)
79 /*@globals internalState@*/ ;
80 static /*@only@*/ cstring exprNode_doUnparse (exprNode p_e);
81 static /*@observer@*/ cstring exprNode_rootVarName (exprNode p_e);
82 static /*@exposed@*/ exprNode
83 exprNode_lastStatement (/*@returned@*/ exprNode p_e);
85 static /*@null@*/ sRef defref = sRef_undefined;
86 static /*@only@*/ exprNode mustExitNode = exprNode_undefined;
88 static int checkArgsReal (uentry p_fcn, /*@dependent@*/ exprNode p_f,
90 exprNodeList p_args, bool p_isIter, exprNode p_ret);
92 static bool inEffect = FALSE;
93 static int nowalloc = 0;
94 static int totalloc = 0;
95 static int maxalloc = 0;
97 static /*@only@*/ uentry regArg;
98 static /*@only@*/ uentry outArg;
99 static /*@only@*/ uentry outStringArg;
100 static /*@exposed@*/ sRef stdinRef;
101 static /*@exposed@*/ sRef stdoutRef;
102 static /*@only@*/ uentry csArg;
103 static /*@only@*/ uentry csOnlyArg;
104 static ctype cstringType;
105 static ctype ctypeType;
106 static ctype filelocType;
107 static bool initMod = FALSE;
110 ** must occur after library has been read
113 void exprNode_initMod (void)
114 /*@globals undef regArg, undef outArg, undef outStringArg,
115 undef csOnlyArg, undef csArg;
122 cstringType = ctype_unknown;
123 ctypeType = ctype_unknown;
124 filelocType = ctype_unknown;
126 defref = sRef_undefined;
128 if (usymtab_existsType (cstring_makeLiteralTemp ("cstring")))
130 cstringType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("cstring"));
133 if (usymtab_existsType (cstring_makeLiteralTemp ("ctype")))
135 ctypeType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("ctype"));
138 if (usymtab_existsType (cstring_makeLiteralTemp ("fileloc")))
140 filelocType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("fileloc"));
143 if (usymtab_existsGlob (cstring_makeLiteralTemp ("stdin")))
145 ue = usymtab_lookupGlob (cstring_makeLiteralTemp ("stdin"));
147 else /* define stdin */
149 ue = uentry_makeVariable (cstring_makeLiteralTemp ("stdin"),
151 fileloc_getBuiltin (),
153 uentry_setHasNameError (ue);
154 ue = usymtab_supGlobalEntryReturn (ue);
157 stdinRef = sRef_makePointer (uentry_getSref (ue));
159 if (usymtab_existsGlob (cstring_makeLiteralTemp ("stdout")))
161 ue = usymtab_lookupGlob (cstring_makeLiteralTemp ("stdout"));
165 ue = uentry_makeVariable (cstring_makeLiteralTemp ("stdout"),
167 fileloc_getBuiltin (),
169 uentry_setHasNameError (ue);
170 ue = usymtab_supGlobalEntryReturn (ue);
173 stdoutRef = sRef_makePointer (uentry_getSref (ue));
175 tmp = idDecl_create (cstring_undefined, qtype_create (ctype_unknown));
177 regArg = uentry_makeParam (tmp, PARAMUNKNOWN);
180 qtype_addQual (qtype_create (ctype_makePointer (ctype_unknown)),
183 outArg = uentry_makeParam (tmp, PARAMUNKNOWN);
185 idDecl_setTyp (tmp, qtype_addQual (qtype_create (ctype_string),
188 outStringArg = uentry_makeParam (tmp, PARAMUNKNOWN);
190 idDecl_setTyp (tmp, qtype_addQual (qtype_addQual (qtype_create (cstringType),
192 qual_createNull ()));
194 csOnlyArg = uentry_makeParam (tmp, PARAMUNKNOWN);
196 idDecl_setTyp (tmp, qtype_addQual (qtype_create (cstringType), qual_createNull ()));
197 csArg = uentry_makeParam (tmp, PARAMUNKNOWN);
203 exprNode_destroyMod (void)
204 /*@globals killed regArg, killed outArg, killed outStringArg,
205 killed mustExitNode, initMod @*/
209 uentry_free (regArg);
210 uentry_free (outArg);
211 uentry_free (outStringArg);
213 exprNode_free (mustExitNode);
220 static void exprNode_resetSref (/*@notnull@*/ exprNode e)
225 static exprNode exprNode_fakeCopy (exprNode e)
227 /*@-temptrans@*/ /*@-retalias@*/
229 /*@=temptrans@*/ /*@=retalias@*/
232 static bool isFlagKey (char key)
234 return (key == '-' || key == '+' || key == ' ' || key == '#');
237 static void exprNode_combineControl (/*@notnull@*/ exprNode ret,
238 /*@notnull@*/ exprNode ifclause,
239 /*@notnull@*/ exprNode elseclause)
241 ret->canBreak = ifclause->canBreak || elseclause->canBreak;
244 (ifclause->mustBreak || exprNode_mustEscape (ifclause))
245 && (elseclause->mustBreak || exprNode_mustEscape (elseclause));
247 ret->exitCode = exitkind_combine (ifclause->exitCode,
248 elseclause->exitCode);
253 ** For exprNode's returned by exprNode_effect.
256 static bool shallowKind (exprKind kind)
258 return (kind == XPR_STRINGLITERAL
259 || kind == XPR_NUMLIT
262 || kind == XPR_NODE);
266 exprNode_freeIniter (/*@only@*/ exprNode e)
268 if (!exprNode_isError (e))
273 sfree (e->edata->field);
277 exprNode_free (e->edata->op->b);
278 /*@-compdestroy@*/ sfree (e->edata->op); /*@=compdestroy@*/
282 llbug (message ("other: %s", exprNode_unparse (e)));
285 multiVal_free (e->val);
286 cstring_free (e->etext);
287 fileloc_free (e->loc);
288 sRefSet_free (e->uses);
289 sRefSet_free (e->sets);
290 sRefSet_free (e->msets);
291 guardSet_free (e->guards);
297 exprNode_freeShallow (/*@only@*/ exprNode e)
299 if (!exprNode_isError (e))
301 if (shallowKind (e->kind))
308 if (e->kind == XPR_EMPTY
309 || e->kind == XPR_BODY
310 || e->kind == XPR_STRINGLITERAL
311 || e->kind == XPR_NUMLIT
312 || e->kind == XPR_NODE
313 || e->kind == XPR_OFFSETOF
314 || e->kind == XPR_ALIGNOFT
315 || e->kind == XPR_ALIGNOF
316 || e->kind == XPR_SIZEOFT
317 || e->kind == XPR_SIZEOF)
319 /* don't free anything */
323 /* multiVal_free (e->val); */
324 cstring_free (e->etext);
325 fileloc_free (e->loc);
326 sRefSet_free (e->uses);
327 sRefSet_free (e->sets);
328 sRefSet_free (e->msets);
329 guardSet_free (e->guards);
330 exprData_freeShallow (e->edata, e->kind);
332 /*@-compdestroy@*/ sfree (e); /*@=compdestroy@*/
341 exprNode_free (exprNode e)
343 if (!exprNode_isError (e))
347 multiVal_free (e->val);
348 cstring_free (e->etext);
349 fileloc_free (e->loc);
350 sRefSet_free (e->uses);
351 sRefSet_free (e->sets);
352 sRefSet_free (e->msets);
353 guardSet_free (e->guards);
354 exprData_free (e->edata, e->kind);
364 exprNode_makeError ()
366 return exprNode_undefined;
369 static /*@out@*/ /*@only@*/ /*@notnull@*/ exprNode
372 exprNode ret = (exprNode) dmalloc (sizeof (*ret));
373 /* static int lastexpnodes = 0; */
378 if (nowalloc > maxalloc)
386 static /*@notnull@*/ /*@special@*/ exprNode
387 exprNode_createPlain (ctype c)
389 /*@post:isnull result->edata, result->loc, result->val, result->guards,
390 result->uses, result->sets, result->msets, result->etext @*/
393 exprNode e = exprNode_new ();
397 e->val = multiVal_undefined;
399 e->etext = cstring_undefined;
400 e->loc = fileloc_undefined;
401 e->guards = guardSet_undefined;
402 e->uses = sRefSet_undefined;
403 e->sets = sRefSet_undefined;
404 e->msets = sRefSet_undefined;
405 e->edata = exprData_undefined;
406 e->exitCode = XK_NEVERESCAPE;
408 e->mustBreak = FALSE;
409 e->isJumpPoint = FALSE;
413 /*@observer@*/ exprNode exprNode_makeMustExit (void)
415 if (exprNode_isUndefined (mustExitNode))
417 mustExitNode = exprNode_createPlain (ctype_unknown);
418 mustExitNode->exitCode = XK_MUSTEXIT;
425 static /*@notnull@*/ /*@special@*/ exprNode exprNode_create (ctype c)
427 /*@post:isnull result->edata, result->guards, result->val,
428 result->uses, result->sets, result->msets@*/
431 exprNode e = exprNode_createPlain (c);
432 e->loc = fileloc_copy (g_currentloc);
436 static /*@notnull@*/ /*@special@*/ exprNode exprNode_createUnknown (void)
438 /*@post:isnull result->edata, result->guards,
439 result->uses, result->sets, result->msets@*/
442 return (exprNode_create (ctype_unknown));
445 static /*@notnull@*/ /*@special@*/ exprNode
446 exprNode_createLoc (ctype c, /*@keep@*/ fileloc loc)
448 /*@post:isnull result->edata, result->guards, result->val,
449 result->uses, result->sets, result->msets@*/
452 exprNode e = exprNode_createPlain (c);
458 exprNode_copySets (/*@special@*/ /*@notnull@*/ exprNode ret, exprNode e)
459 /*@defines ret->guards, ret->uses, ret->sets, ret->msets@*/
461 if (exprNode_isDefined (e))
463 ret->guards = guardSet_copy (e->guards);
464 ret->uses = sRefSet_newCopy (e->uses);
465 ret->sets = sRefSet_newCopy (e->sets);
466 ret->msets = sRefSet_newCopy (e->msets);
470 ret->guards = guardSet_undefined;
471 ret->uses = sRefSet_undefined;
472 ret->sets = sRefSet_undefined;
473 ret->msets = sRefSet_undefined;
477 static /*@notnull@*/ /*@special@*/ exprNode
478 exprNode_createPartialLocCopy (exprNode e, /*@only@*/ fileloc loc)
480 /*@post:isnull result->edata, result->etext@*/
483 exprNode ret = exprNode_new ();
485 if (exprNode_isError (e))
487 ret->typ = ctype_unknown;
488 ret->val = multiVal_undefined;
490 ret->guards = guardSet_undefined;
491 ret->uses = sRefSet_undefined;
492 ret->sets = sRefSet_undefined;
493 ret->msets = sRefSet_undefined;
498 ret->val = multiVal_copy (e->val);
500 ret->guards = guardSet_copy (e->guards);
501 ret->uses = sRefSet_newCopy (e->uses);
502 ret->sets = sRefSet_newCopy (e->sets);
503 ret->msets = sRefSet_newCopy (e->msets);
506 ret->kind = XPR_EMPTY;
508 ret->etext = cstring_undefined;
509 ret->exitCode = XK_NEVERESCAPE;
510 ret->canBreak = FALSE;
511 ret->mustBreak = FALSE;
512 ret->isJumpPoint = FALSE;
513 ret->edata = exprData_undefined;
519 static /*@notnull@*/ /*@special@*/ exprNode
520 exprNode_createPartialCopy (exprNode e)
522 /*@post:isnull result->edata, result->etext@*/
525 return (exprNode_createPartialLocCopy (e, fileloc_copy (exprNode_loc (e))));
528 static /*@notnull@*/ /*@special@*/ exprNode
529 exprNode_createPartialNVCopy (exprNode e)
531 /*@post:isnull result->edata, result->etext, result->val @*/
534 exprNode ret = exprNode_new ();
536 if (exprNode_isError (e))
538 ret->typ = ctype_unknown;
539 ret->loc = fileloc_undefined;
540 ret->guards = guardSet_undefined;
541 ret->uses = sRefSet_undefined;
542 ret->sets = sRefSet_undefined;
543 ret->msets = sRefSet_undefined;
548 ret->loc = fileloc_copy (e->loc);
549 ret->guards = guardSet_copy (e->guards);
550 ret->uses = sRefSet_newCopy (e->uses);
551 ret->sets = sRefSet_newCopy (e->sets);
552 ret->msets = sRefSet_newCopy (e->msets);
555 ret->val = multiVal_undefined;
556 ret->kind = XPR_EMPTY;
558 ret->etext = cstring_undefined;
559 ret->exitCode = XK_NEVERESCAPE;
560 ret->canBreak = FALSE;
561 ret->mustBreak = FALSE;
562 ret->isJumpPoint = FALSE;
563 ret->edata = exprData_undefined;
568 static /*@notnull@*/ /*@special@*/ exprNode
569 exprNode_createSemiCopy (exprNode e)
571 /*@post:isnull result->edata, result->etext, result->sets,
572 result->msets, result->uses, result->guards@*/
575 if (exprNode_isError (e))
577 return exprNode_createPlain (ctype_unknown);
581 exprNode ret = exprNode_new ();
584 ret->val = multiVal_copy (e->val);
585 ret->loc = fileloc_copy (e->loc);
586 ret->guards = guardSet_undefined;
587 ret->uses = sRefSet_undefined;
588 ret->sets = sRefSet_undefined;
589 ret->msets = sRefSet_undefined;
591 ret->kind = XPR_EMPTY;
593 ret->etext = cstring_undefined;
594 ret->exitCode = XK_NEVERESCAPE;
595 ret->canBreak = FALSE;
596 ret->mustBreak = FALSE;
597 ret->isJumpPoint = FALSE;
598 ret->edata = exprData_undefined;
605 exprNode_isNullValue (exprNode e)
607 if (exprNode_isDefined (e))
609 multiVal m = exprNode_getValue (e);
611 if (multiVal_isInt (m))
613 return (multiVal_forceInt (m) == 0);
621 exprNode_isUnknownConstant (/*@notnull@*/ exprNode e)
623 while (e->kind == XPR_PARENS)
625 e = exprData_getUopNode (e->edata);
626 llassert (exprNode_isDefined (e));
629 if (e->kind == XPR_CONST)
631 multiVal m = exprNode_getValue (e);
633 if (multiVal_isUnknown (m))
643 exprNode_numLiteral (ctype c, /*@temp@*/ cstring t,
644 /*@only@*/ fileloc loc, long val)
646 exprNode e = exprNode_createLoc (c, loc);
648 e->kind = XPR_NUMLIT;
650 llassert (multiVal_isUndefined (e->val));
651 e->val = multiVal_makeInt (val);
652 e->edata = exprData_makeLiteral (cstring_copy (t));
656 e->sref = sRef_makeUnknown ();
657 sRef_setDefNull (e->sref, e->loc);
660 DPRINTF (("Num lit: %s / %s", exprNode_unparse (e), ctype_unparse (exprNode_getType (e))));
665 exprNode_charLiteral (char c, cstring text, /*@only@*/ fileloc loc)
667 exprNode e = exprNode_createLoc (ctype_char, loc);
669 if (context_getFlag (FLG_CHARINTLITERAL))
671 e->typ = ctype_makeConj (ctype_char, ctype_int);
674 e->kind = XPR_NUMLIT;
675 e->val = multiVal_makeChar (c);
677 e->edata = exprData_makeLiteral (cstring_copy (text));
682 exprNode_floatLiteral (double d, ctype ct, cstring text, /*@only@*/ fileloc loc)
684 exprNode e = exprNode_createLoc (ct, loc);
686 e->kind = XPR_NUMLIT;
687 e->val = multiVal_makeDouble (d);
688 e->edata = exprData_makeLiteral (cstring_copy (text));
692 multiVal exprNode_getValue (exprNode e)
694 while (exprNode_isInParens (e)) {
695 if (e->edata != NULL) {
696 e = exprData_getUopNode (e->edata);
702 if (exprNode_isDefined (e)) {
705 return multiVal_undefined;
710 exprNode_stringLiteral (/*@only@*/ cstring t, /*@only@*/ fileloc loc)
712 exprNode e = exprNode_createLoc (ctype_string, loc);
713 int len = cstring_length (t) - 2;
714 char *ts = cstring_toCharsSafe (t);
715 char *s = cstring_toCharsSafe (cstring_create (len + 1));
717 if (context_getFlag (FLG_STRINGLITERALLEN))
719 if (len > context_getValue (FLG_STRINGLITERALLEN))
721 voptgenerror (FLG_STRINGLITERALLEN,
723 ("String literal length (%d) exceeds maximum "
726 context_getValue (FLG_STRINGLITERALLEN),
732 strncpy (s, ts+1, size_fromInt (len));
736 e->kind = XPR_STRINGLITERAL;
737 e->val = multiVal_makeString (cstring_fromCharsO (s));
738 e->edata = exprData_makeLiteral (t);
739 e->sref = sRef_makeType (ctype_string);
740 /* Start modifications */
741 /* This expr is null terminated, so we set the len and size */
742 sRef_setNullTerminatedState(e->sref);
744 TPRINTF("Len is set to : %d\n\n", strlen((char *)multiVal_forceString(e->val)));
745 TPRINTF("Size is set to : %d\n\n", strlen((char *)multiVal_forceString(e->val)));
746 TPRINTF("State is set to: %d\n\n", e->sref->bufinfo.bufstate);
748 sRef_setLen(e->sref, strlen((char *)multiVal_forceString(e->val)));
749 sRef_setSize(e->sref, strlen((char *)multiVal_forceString(e->val)));
751 if (context_getFlag (FLG_READONLYSTRINGS))
753 sRef_setAliasKind (e->sref, AK_STATIC, fileloc_undefined);
754 sRef_setExKind (e->sref, XO_OBSERVER, loc);
758 sRef_setAliasKind (e->sref, AK_ERROR, fileloc_undefined);
761 return (e); /* s released */
764 exprNode exprNode_fromUIO (cstring c)
766 fileloc loc = context_getSaveLocation ();
767 exprNode e = exprNode_createPlain (ctype_unknown);
771 if (fileloc_isUndefined (loc))
773 loc = fileloc_copy (g_currentloc);
776 e->loc = loc; /* save loc was mangled */
779 if (usymtab_exists (c))
781 uentry ue = usymtab_lookupEither (c);
783 if (uentry_isDatatype (ue)
784 && uentry_isSpecified (ue))
787 (message ("%q: Specified datatype %s used in code, but not defined. "
788 "(Cannot continue reasonably from this error.)",
789 fileloc_unparse (e->loc), c));
797 llassertprint (!usymtab_exists (c), ("Entry exists: %s", c));
800 ** was supercedeGlobalEntry...is this better?
803 if (!context_inIterEnd ())
805 if (context_inMacro ())
807 if (context_getFlag (FLG_UNRECOG))
811 message ("Unrecognized identifier in macro definition: %s", c), e->loc);
815 flagcode_recordSuppressed (FLG_UNRECOG);
821 (FLG_UNRECOG, message ("Unrecognized identifier: %s", c),
826 e->edata = exprData_makeId (uentry_makeUnrecognized (c, fileloc_copy (loc)));
828 /* No alias errors for unrecognized identifiers */
829 sRef_setAliasKind (e->sref, AK_ERROR, loc);
834 exprNode exprNode_createId (/*@observer@*/ uentry c)
836 if (uentry_isValid (c))
838 exprNode e = exprNode_new ();
840 e->typ = uentry_getType (c);
842 if (uentry_isFunction (c)
843 && !sRef_isLocalVar (uentry_getSref (c)))
845 e->sref = sRef_undefined;
849 e->sref = uentry_getSref (c);
852 if (sRef_isStateUnknown (e->sref) && uentry_isNonLocal (c))
854 sRef_setDefined (e->sref, fileloc_undefined);
858 ** yoikes! leaving this out was a heinous bug...that would have been
859 ** caught if i had lclint working first. gag!
862 e->etext = cstring_undefined;
864 if (uentry_isEitherConstant (c))
867 e->val = multiVal_copy (uentry_getConstantValue (c));
872 e->val = multiVal_unknown ();
875 e->edata = exprData_makeId (c);
876 e->loc = context_getSaveLocation ();
878 if (fileloc_isUndefined (e->loc))
880 fileloc_free (e->loc);
881 e->loc = fileloc_copy (g_currentloc);
884 e->guards = guardSet_new ();
885 e->sets = sRefSet_new ();
886 e->msets = sRefSet_new ();
887 e->uses = sRefSet_new ();
889 /*> missing fields, detected by lclint <*/
890 e->exitCode = XK_NEVERESCAPE;
891 e->isJumpPoint = FALSE;
893 e->mustBreak = FALSE;
899 return exprNode_createUnknown ();
903 /*@notnull@*/ exprNode
904 exprNode_fromIdentifier (/*@observer@*/ uentry c)
908 if (context_justPopped ()) /* watch out! c could be dead */
910 uentry ce = usymtab_lookupSafe (LastIdentifier ());
912 if (uentry_isValid (ce))
918 llbuglit ("Looks like Aunt Millie forgot to walk to dog again.");
922 ret = exprNode_fromIdentifierAux (c);
928 static /*@only@*/ /*@notnull@*/ exprNode
929 exprNode_fromIdentifierAux (/*@observer@*/ uentry c)
931 exprNode e = exprNode_createId (c);
934 uentry_setUsed (c, e->loc);
936 if (uentry_isVar (c) && sRef_isGlobal (sr))
938 checkGlobUse (c, FALSE, e);
945 exprNode_isZero (exprNode e)
947 if (exprNode_isDefined (e))
949 multiVal m = exprNode_getValue (e);
951 if (multiVal_isInt (m))
953 return (multiVal_forceInt (m) == 0);
961 exprNode_isNonNegative (exprNode e)
963 if (exprNode_isDefined (e))
965 multiVal m = exprNode_getValue (e);
967 if (multiVal_isInt (m))
969 return (multiVal_forceInt (m) >= 0);
977 ** a[x] - uses a but NOT a[]
978 ** result sref = a[] (set/use in assignment)
980 ** The syntax x[a] is also legal in C, and has the same
981 ** semantics. If ind is an array, and arr is an int, flip
986 exprNode_arrayFetch (/*@only@*/ exprNode e1, /*@only@*/ exprNode e2)
989 ** error in arr, error propagates (no new messages)
990 ** error in ind, assume valid and continue
993 if (exprNode_isError (e1))
996 return (exprNode_makeError ());
1002 ctype carr = exprNode_getType (e1);
1003 ctype crarr = ctype_realType (carr);
1006 ** this sets up funny aliasing, that leads to spurious
1007 ** lclint errors. Hence, the i2 comments.
1010 if (!ctype_isRealArray (crarr)
1011 && ctype_isRealNumeric (crarr)
1012 && !exprNode_isError (e2)
1013 && ctype_isRealAP (exprNode_getType (e2))) /* fetch like 3[a] */
1018 carr = exprNode_getType (arr);
1019 crarr = ctype_realType (carr);
1027 if (sRef_possiblyNull (arr->sref))
1029 if (!usymtab_isGuarded (arr->sref))
1031 if (optgenerror (FLG_NULLDEREF,
1032 message ("Index of %s pointer %q: %s",
1033 sRef_nullMessage (arr->sref),
1034 sRef_unparse (arr->sref),
1035 exprNode_unparse (arr)),
1038 sRef_showNullInfo (arr->sref);
1040 /* suppress future messages */
1041 sRef_setNullError (arr->sref);
1046 if (exprNode_isError (ind))
1048 if ((ctype_isArrayPtr (crarr)
1049 && !ctype_isFunction (crarr))
1050 || ctype_isUnknown (carr))
1052 exprNode ret = exprNode_createPartialCopy (arr);
1054 if (ctype_isKnown (carr))
1056 ret->typ = ctype_baseArrayPtr (crarr);
1060 ret->typ = ctype_unknown;
1063 ret->sref = sRef_makeArrayFetch (arr->sref);
1065 ret->kind = XPR_FETCH;
1068 ** Because of funny aliasing (when arr and ind are
1069 ** flipped) spurious errors would be reported here.
1072 /*@i2@*/ ret->edata = exprData_makePair (arr, ind);
1073 checkSafeUse (ret, arr->sref);
1078 voptgenerror (FLG_TYPE,
1079 message ("Array fetch from non-array (%t): %s[%s]", carr,
1080 exprNode_unparse (e1), exprNode_unparse (e2)),
1082 exprNode_free (arr);
1083 return (exprNode_makeError ());
1088 if (!ctype_isForceRealInt (&(ind->typ)))
1090 ctype rt = ctype_realType (ind->typ);
1092 if (ctype_isChar (rt))
1096 message ("Array fetch using non-integer, %t: %s[%s]",
1098 exprNode_unparse (e1), exprNode_unparse (e2)),
1101 else if (ctype_isEnum (rt))
1105 message ("Array fetch using non-integer, %t: %s[%s]",
1107 exprNode_unparse (e1), exprNode_unparse (e2)),
1114 message ("Array fetch using non-integer, %t: %s[%s]",
1116 exprNode_unparse (e1), exprNode_unparse (e2)),
1120 multiVal_free (ind->val);
1121 ind->val = multiVal_unknown ();
1124 if (ctype_isArrayPtr (crarr) && !ctype_isFunction (crarr))
1126 exprNode ret = exprNode_createSemiCopy (arr);
1127 multiVal m = exprNode_getValue (ind);
1129 ret->typ = ctype_baseArrayPtr (crarr);
1130 ret->kind = XPR_FETCH;
1132 if (multiVal_isInt (m))
1134 int i = (int) multiVal_forceInt (m);
1136 if (sRef_isValid (arr->sref)) {
1137 ret->sref = sRef_makeArrayFetchKnown (arr->sref, i);
1139 ret->sref = sRef_undefined;
1144 ret->sref = sRef_makeArrayFetch (arr->sref);
1147 ret->sets = sRefSet_realNewUnion (arr->sets, ind->sets);
1148 ret->msets = sRefSet_realNewUnion (arr->msets, ind->msets);
1149 ret->uses = sRefSet_realNewUnion (arr->uses, ind->uses);
1151 /* (see comment on spurious errors above) */
1152 /*@i2@*/ ret->edata = exprData_makePair (arr, ind);
1154 exprNode_checkUse (ret, ind->sref, ind->loc);
1155 exprNode_checkUse (ret, arr->sref, arr->loc);
1161 if (ctype_isUnknown (carr))
1163 exprNode ret = exprNode_createPartialCopy (arr);
1165 ret->kind = XPR_FETCH;
1166 ret->typ = ctype_unknown;
1167 ret->sets = sRefSet_union (ret->sets, ind->sets);
1168 ret->msets = sRefSet_union (ret->msets, ind->msets);
1169 ret->uses = sRefSet_union (ret->uses, ind->uses);
1171 /* (see comment on spurious errors above) */
1172 /*@i2@*/ ret->edata = exprData_makePair (arr, ind);
1174 exprNode_checkUse (ret, ind->sref, ind->loc);
1175 exprNode_checkUse (ret, arr->sref, arr->loc);
1182 message ("Array fetch from non-array (%t): %s[%s]", carr,
1183 exprNode_unparse (e1), exprNode_unparse (e2)),
1186 exprNode_free (arr);
1187 exprNode_free (ind);
1189 return (exprNode_makeError ());
1199 checkArgs (uentry fcn, /*@dependent@*/ exprNode f, ctype t,
1200 exprNodeList args, exprNode ret)
1202 return (checkArgsReal (fcn, f, ctype_argsFunction (t), args, FALSE, ret));
1206 ** checkPrintfArgs --- checks arguments for printf-like functions
1207 ** Arguments before ... have already been checked.
1208 ** The argument before the ... is a char *.
1209 ** argno is the format string argument.
1213 checkPrintfArgs (/*@notnull@*/ /*@dependent@*/ exprNode f, uentry fcn,
1214 exprNodeList args, exprNode ret, int argno)
1217 ** the last argument before the elips is the format string
1222 int nargs = exprNodeList_size (args);
1223 uentryList params = uentry_getParams (fcn);
1227 ** These should be ensured by checkSpecialFunction
1230 llassert (uentryList_size (params) == argno + 1);
1231 llassert (uentry_isElipsisMarker (uentryList_getN (params, argno)));
1233 a = exprNodeList_getN (args, argno - 1);
1234 formatloc = fileloc_copy (exprNode_loc (a));
1236 if (exprNode_isDefined (a) && exprNode_isStringLiteral (a)
1237 && exprNode_knownStringValue (a))
1239 char *format = cstring_toCharsSafe (multiVal_forceString (exprNode_getValue (a)));
1240 char *code = format;
1243 nargs = exprNodeList_size (args);
1245 while ((code = strchr (code, '%')) != NULL)
1247 char *origcode = code;
1248 char key = *(++code);
1249 ctype modtype = ctype_int;
1250 bool modified = FALSE;
1252 fileloc_addColumn (formatloc, code - ocode);
1255 while (isFlagKey (key))
1258 fileloc_incColumn (formatloc);
1261 if (key == 'm') /* skipped in syslog */
1266 /* ignore field width */
1267 while (isdigit ((int) key) != 0)
1270 fileloc_incColumn (formatloc);
1273 /* ignore precision */
1277 fileloc_incColumn (formatloc);
1280 ** In printf, '*' means: read the next arg as an int for the
1281 ** field width. This seems to be missing from my copy of the
1282 ** standard x3.159-1989. Setion 4.9.6.1 refers to * (described
1283 ** later) but never does.
1288 ; /* don't do anything --- handle later */
1292 while (isdigit ((int) key) != 0)
1295 fileloc_incColumn (formatloc);
1302 modtype = ctype_sint; /* short */
1304 fileloc_incColumn (formatloc);
1306 else if (key == 'l' || key == 'L')
1308 modtype = ctype_lint; /* long */
1310 fileloc_incColumn (formatloc);
1317 /* now, key = type of conversion to apply */
1319 fileloc_incColumn (formatloc);
1327 message ("No argument corresponding to %q format "
1328 "code %d (%%%h): \"%s\"",
1329 uentry_getName (fcn),
1331 cstring_fromChars (format)),
1334 if (fileloc_isDefined (formatloc)
1335 && context_getFlag (FLG_SHOWCOL))
1337 llgenindentmsg (cstring_makeLiteral ("Corresponding format code"),
1345 a = exprNodeList_getN (args, i);
1348 if (!exprNode_isError (a))
1354 case '*': /* int argument for fieldwidth */
1355 expecttype = ctype_int;
1356 *(--code) = '%'; /* convert it for next code */
1357 fileloc_subColumn (formatloc, 1);
1358 /*@switchbreak@*/ break;
1361 expecttype = ctype_combine (ctype_uint, modtype);
1362 /*@switchbreak@*/ break;
1364 case 'i': /* int argument */
1366 expecttype = ctype_combine (ctype_int, modtype);
1367 /*@switchbreak@*/ break;
1369 case 'x': /* unsigned int */
1371 expecttype = ctype_combine (ctype_uint, modtype);
1372 /*@switchbreak@*/ break;
1378 case 'f': /* double */
1379 expecttype = ctype_combine (ctype_double, modtype);
1380 /*@switchbreak@*/ break;
1382 case 'c': /* int converted to char (check its a char?) */
1383 expecttype = ctype_makeConj (ctype_char, ctype_uchar);
1384 /*@switchbreak@*/ break;
1386 case 's': /* string */
1387 expecttype = ctype_string;
1388 /*@switchbreak@*/ break;
1391 while (((key = *(++code)) != ']')
1394 fileloc_incColumn (formatloc);
1400 (message ("Bad character set format: %s",
1401 cstring_fromChars (origcode)));
1404 expecttype = ctype_string;
1405 /*@switchbreak@*/ break;
1407 case 'p': /* pointer */
1408 expecttype = ctype_makePointer (ctype_void);
1410 /*@switchbreak@*/ break;
1412 case 'n': /* pointer to int, modified by call! */
1413 expecttype = ctype_combine (ctype_makePointer (ctype_int), modtype);
1415 uentry_setDefState (regArg, SS_ALLOCATED); /* corresponds to out */
1416 /*@switchbreak@*/ break;
1418 case 'm': /* in a syslog, it doesn't consume an argument */
1419 /* should check we're really doing syslog */
1421 /*@switchbreak@*/ break;
1425 expecttype = ctype_unknown;
1429 message ("Unrecognized format code: %s",
1430 cstring_fromChars (origcode)),
1431 fileloc_isDefined (formatloc)
1432 ? formatloc : g_currentloc);
1434 /*@switchbreak@*/ break;
1437 if (!(exprNode_matchArgType (expecttype, a)))
1439 if (ctype_isVoidPointer (expecttype)
1440 && ctype_isRealAbstract (a->typ)
1441 && (context_getFlag (FLG_ABSTVOIDP)))
1447 if (llgenformattypeerror
1448 (expecttype, exprNode_undefined,
1450 message ("Format argument %d to %q (%%%h) expects "
1453 uentry_getName (fcn),
1455 a->typ, exprNode_unparse (a)),
1458 if (fileloc_isDefined (formatloc)
1459 && context_getFlag (FLG_SHOWCOL))
1462 (cstring_makeLiteral
1463 ("Corresponding format code"),
1470 uentry_setType (regArg, expecttype);
1471 checkOneArg (regArg, a, f, FALSE, i+1, nargs);
1473 if (ctype_equal (expecttype, ctype_string))
1475 exprNode_checkUse (a, sRef_makePointer (a->sref), a->loc);
1478 uentry_setType (regArg, ctype_unknown);
1479 uentry_fixupSref (regArg);
1483 exprNode_checkCallModifyVal (a->sref, args, f, ret);
1497 voptgenerror (FLG_TYPE,
1498 message ("Format string for %q has %d arg%p, given %d",
1499 uentry_getName (fcn), i - argno, nargs - argno),
1505 /* no checking possible for compile-time unknown format strings */
1508 fileloc_free (formatloc);
1512 checkScanfArgs (/*@notnull@*/ /*@dependent@*/ exprNode f, uentry fcn,
1513 exprNodeList args, exprNode ret, int argno)
1517 int nargs = exprNodeList_size (args);
1518 uentryList params = uentry_getParams (fcn);
1522 ** These should be ensured by checkSpecialFunction
1525 llassert (uentryList_size (params) == argno + 1);
1526 llassert (uentry_isElipsisMarker (uentryList_getN (params, argno)));
1528 a = exprNodeList_getN (args, argno - 1);
1529 formatloc = fileloc_copy (exprNode_loc (a));
1531 if (exprNode_isDefined (a) && exprNode_isStringLiteral (a)
1532 && exprNode_knownStringValue (a))
1534 char *format = cstring_toCharsSafe (multiVal_forceString (exprNode_getValue (a)));
1535 char *code = format;
1538 nargs = exprNodeList_size (args);
1540 while ((code = strchr (code, '%')) != NULL)
1542 char *origcode = code;
1543 char key = *(++code);
1544 ctype modtype = ctype_int;
1545 char modifier = '\0';
1546 bool modified = TRUE;
1547 bool ignore = FALSE;
1549 fileloc_addColumn (formatloc, code - ocode);
1552 ** this is based on ANSI standard library description of fscanf
1553 ** (from ANSI standard X3.159-1989, 4.9.6.1)
1556 /* '*' suppresses assignment (does not need match argument) */
1563 fileloc_incColumn (formatloc);
1566 /* ignore field width */
1567 while (isdigit ((int) key) != 0)
1570 fileloc_incColumn (formatloc);
1575 modtype = ctype_sint; /* short */
1577 fileloc_incColumn (formatloc);
1579 else if (key == 'l' || key == 'L')
1581 modtype = ctype_lint; /* long */
1585 fileloc_incColumn (formatloc);
1592 /* now, key = type of conversion to apply */
1594 fileloc_incColumn (formatloc);
1608 message ("No argument corresponding to %q format "
1609 "code %d (%%%h): \"%s\"",
1610 uentry_getName (fcn),
1612 cstring_fromChars (format)),
1615 if (fileloc_isDefined (formatloc)
1616 && context_getFlag (FLG_SHOWCOL))
1619 (cstring_makeLiteral ("Corresponding format code"),
1627 a = exprNodeList_getN (args, i);
1630 if (!exprNode_isError (a))
1636 case '*': /* int argument for fieldwidth */
1637 expecttype = ctype_makePointer (ctype_int);
1638 *(--code) = '%'; /* convert it for next code */
1639 fileloc_subColumn (formatloc, 1);
1640 /*@switchbreak@*/ break;
1643 expecttype = ctype_makePointer (ctype_combine (ctype_uint, modtype));
1644 /*@switchbreak@*/ break;
1649 case 'X': /* unsigned int */
1650 expecttype = ctype_makePointer (ctype_combine (ctype_int, modtype));
1651 /*@switchbreak@*/ break;
1658 /* printf is double, scanf is float! */
1660 if (modifier == 'l')
1662 expecttype = ctype_makePointer (ctype_double);
1664 else if (modifier == 'L')
1666 expecttype = ctype_makePointer (ctype_ldouble);
1670 llassert (modifier == '\0');
1671 expecttype = ctype_makePointer (ctype_float);
1673 /*@switchbreak@*/ break;
1675 case 'c': /* int converted to char (check its a char?) */
1676 expecttype = ctype_makePointer (ctype_makeConj (ctype_char, ctype_uchar));
1677 /*@switchbreak@*/ break;
1679 case 's': /* string */
1680 expecttype = ctype_string;
1681 /*@switchbreak@*/ break;
1685 while (((key = *(++code)) != ']')
1688 fileloc_incColumn (formatloc);
1694 (message ("Bad character set format: %s",
1695 cstring_fromChars (origcode)));
1698 expecttype = ctype_string;
1699 /*@switchbreak@*/ break;
1701 case 'p': /* pointer */
1702 expecttype = ctype_unknown;
1704 /*@switchbreak@*/ break;
1706 case 'n': /* pointer to int, modified by call! */
1707 expecttype = ctype_makePointer (ctype_int);
1708 /*@switchbreak@*/ break;
1711 expecttype = ctype_unknown;
1715 message ("Unrecognized format code: %s",
1716 cstring_fromChars (origcode)),
1717 fileloc_isDefined (formatloc)
1718 ? formatloc : g_currentloc);
1720 /*@switchbreak@*/ break;
1723 if (!(exprNode_matchArgType (expecttype, a)))
1725 if (ctype_isVoidPointer (expecttype)
1726 && ctype_isRealAbstract (a->typ)
1727 && (context_getFlag (FLG_ABSTVOIDP)))
1733 if (modifier != '\0')
1735 if (llgenformattypeerror
1736 (expecttype, exprNode_undefined,
1738 message ("Format argument %d to %q (%%%h%h) expects "
1741 uentry_getName (fcn),
1744 a->typ, exprNode_unparse (a)),
1747 if (fileloc_isDefined (formatloc)
1748 && context_getFlag (FLG_SHOWCOL))
1751 (cstring_makeLiteral
1752 ("Corresponding format code"),
1760 if (llgenformattypeerror
1761 (expecttype, exprNode_undefined,
1763 message ("Format argument %d to %q (%%%h) expects "
1766 uentry_getName (fcn),
1768 a->typ, exprNode_unparse (a)),
1771 if (fileloc_isDefined (formatloc)
1772 && context_getFlag (FLG_SHOWCOL))
1775 (cstring_makeLiteral
1776 ("Corresponding format code"),
1784 uentry_setType (outArg, expecttype);
1785 checkOneArg (outArg, a, f, FALSE, i+1, nargs);
1786 uentry_setType (outArg, ctype_unknown);
1787 uentry_fixupSref (outArg);
1791 exprNode_checkCallModifyVal (a->sref, args, f, ret);
1796 /* a->sref = defref; */
1806 voptgenerror (FLG_TYPE,
1807 message ("Format string for %q has %d arg%p, given %d",
1808 uentry_getName (fcn), i - argno, nargs - argno),
1814 /* no checking possible for compile-time unknown format strings */
1817 fileloc_free (formatloc);
1821 checkMessageArgs (/*@notnull@*/ /*@dependent@*/ exprNode f,
1824 /*@unused@*/ int argno)
1827 ** the last argument before the elips is the format string
1830 int nargs = exprNodeList_size (args);
1835 a = exprNodeList_getN (args, argno - 1);
1836 formatloc = fileloc_copy (exprNode_loc (a));
1838 if (ctype_isUnknown (cstringType)) {
1839 if (usymtab_existsType (cstring_makeLiteralTemp ("cstring")))
1841 cstringType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("cstring"));
1845 if (ctype_isUnknown (ctypeType)) {
1846 if (usymtab_existsType (cstring_makeLiteralTemp ("ctype")))
1848 ctypeType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("ctype"));
1852 if (ctype_isUnknown (filelocType)) {
1853 if (usymtab_existsType (cstring_makeLiteralTemp ("fileloc")))
1855 filelocType = usymtab_lookupAbstractType (cstring_makeLiteralTemp ("fileloc"));
1859 if (exprNode_isDefined (a) && exprNode_isStringLiteral (a)
1860 && exprNode_knownStringValue (a))
1862 cstring format = multiVal_forceString (exprNode_getValue (a));
1863 char *code = cstring_toCharsSafe (format);
1866 nargs = exprNodeList_size (args);
1868 while ((code = strchr (code, '%')) != NULL)
1870 char *origcode = code;
1871 char key = *(++code);
1872 bool isOnly = FALSE;
1874 fileloc_addColumn (formatloc, code - ocode);
1876 while (key >= '0' && key <= '9')
1879 fileloc_incColumn (formatloc);
1883 fileloc_incColumn (formatloc);
1896 message ("Message missing format arg %d (%%%h): \"%s\"",
1897 i + 1, key, format),
1903 a = exprNodeList_getN (args, i);
1907 if (!exprNode_isError (a))
1911 /*@-loopswitchbreak@*/
1917 expecttype = ctype_char; break;
1919 expecttype = cstringType; break;
1921 expecttype = cstringType; isOnly = TRUE; break;
1923 expecttype = cstringType; isOnly = TRUE; break;
1924 case 'd': expecttype = ctype_int; break;
1925 case 'u': expecttype = ctype_uint; break;
1926 case 'w': expecttype = ctype_ulint; break;
1927 case 'f': expecttype = ctype_float; break;
1928 case 'b': expecttype = ctype_bool; break;
1929 case 't': expecttype = ctypeType; break;
1930 case 'l': expecttype = filelocType; break;
1931 case 'p': /* a wee bit of a hack methinks */
1932 expecttype = ctype_int;
1934 case 'r': expecttype = ctype_bool; break;
1936 expecttype = ctype_unknown;
1939 message ("Unrecognized format code: %s",
1940 cstring_fromChars (origcode)),
1941 fileloc_isDefined (formatloc)
1942 ? formatloc : g_currentloc);
1945 /*@=loopswitchbreak@*/
1947 if (!(exprNode_matchArgType (expecttype, a)))
1949 if (ctype_isVoidPointer (expecttype)
1950 && ctype_isRealAbstract (a->typ)
1951 && (context_getFlag (FLG_ABSTVOIDP)))
1957 if (llgenformattypeerror
1958 (expecttype, exprNode_undefined,
1960 message ("Format argument %d to %q (%%%h) expects "
1963 uentry_getName (fcn),
1965 a->typ, exprNode_unparse (a)),
1968 if (fileloc_isDefined (formatloc)
1969 && context_getFlag (FLG_SHOWCOL))
1972 (cstring_makeLiteral
1973 ("Corresponding format code"),
1980 if (ctype_equal (expecttype, cstringType))
1984 checkOneArg (csOnlyArg, a, f, FALSE, i+1, nargs);
1985 uentry_fixupSref (csOnlyArg);
1989 checkOneArg (csArg, a, f, FALSE, i+1, nargs);
1990 uentry_fixupSref (csArg);
1995 checkOneArg (regArg, a, f, FALSE, i+1, nargs);
1996 uentry_fixupSref (regArg);
2005 voptgenerror (FLG_TYPE,
2006 message ("Format string for %q has %d arg%p, given %d",
2007 uentry_getName (fcn), i - argno, nargs -argno),
2013 /* no checking possible for compile-time unknown format strings */
2016 fileloc_free (formatloc);
2020 checkExpressionDefinedAux (/*@notnull@*/ exprNode e1,
2021 /*@notnull@*/ exprNode e2,
2027 bool hadUncon = FALSE;
2029 if (sRef_isGlobal (sRef_getRootBase (e1->sref)) &&
2030 sRefSet_hasUnconstrained (sets2))
2033 (FLG_EVALORDERUNCON,
2035 ("Expression may have undefined behavior (%q used in right operand "
2036 "may set global variable %q used in left operand): %s %s %s",
2037 sRefSet_unparseUnconstrained (sets2),
2038 sRef_unparse (sRef_getRootBase (e1->sref)),
2039 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
2043 if (sRef_isGlobal (sRef_getRootBase (e2->sref)) &&
2044 sRefSet_hasUnconstrained (sets1))
2047 (FLG_EVALORDERUNCON,
2049 ("Expression has undefined behavior (%q used in left operand "
2050 "may set global variable %q used in right operand): %s %s %s",
2051 sRefSet_unparseUnconstrained (sets1),
2052 sRef_unparse (e2->sref),
2053 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
2057 sRefSet_realElements (e1->uses, sr)
2059 if (sRef_isMeaningful (sr) && sRefSet_member (sets2, sr))
2064 ("Expression has undefined behavior (left operand uses %q, "
2065 "modified by right operand): %s %s %s",
2067 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
2070 } end_sRefSet_realElements;
2072 sRefSet_realElements (sets1, sr)
2074 if (sRef_isMeaningful (sr))
2076 if (sRef_same (sr, e2->sref))
2081 ("Expression has undefined behavior (value of right operand "
2082 "modified by left operand): %s %s %s",
2083 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
2086 else if (sRefSet_member (e2->uses, sr))
2091 ("Expression has undefined behavior (left operand modifies %q, "
2092 "used by right operand): %s %s %s",
2094 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
2099 if (sRefSet_member (sets2, sr))
2101 if (sRef_isUnconstrained (sr))
2109 hadUncon = optgenerror
2110 (FLG_EVALORDERUNCON,
2112 ("Expression may have undefined behavior. Left operand "
2113 "calls %q; right operand calls %q. The unconstrained "
2114 "functions may modify global state used by "
2115 "the other operand): %s %s %s",
2116 sRefSet_unparseUnconstrained (sets1),
2117 sRefSet_unparseUnconstrained (sets2),
2118 exprNode_unparse (e1), lltok_unparse (op),
2119 exprNode_unparse (e2)),
2128 ("Expression has undefined behavior (both "
2129 "operands modify %q): %s %s %s",
2131 exprNode_unparse (e1),
2132 lltok_unparse (op), exprNode_unparse (e2)),
2138 } end_sRefSet_realElements;
2141 static void checkExpressionDefined (exprNode e1, exprNode e2, lltok op)
2143 bool hasError = FALSE;
2145 if (exprNode_isError (e1) || exprNode_isError (e2))
2150 if (sRefSet_member (e2->sets, e1->sref))
2152 if (e2->kind == XPR_CALL)
2158 hasError = optgenerror
2160 message ("Expression has undefined behavior "
2161 "(value of left operand is modified "
2162 "by right operand): %s %s %s",
2163 exprNode_unparse (e1), lltok_unparse (op),
2164 exprNode_unparse (e2)),
2169 if (context_getFlag (FLG_EVALORDERUNCON))
2171 if (sRefSet_member (e2->msets, e1->sref))
2173 if (e2->kind == XPR_CALL)
2179 hasError = optgenerror
2182 ("Expression has undefined behavior (value of left "
2183 "operand may be modified by right operand): %s %s %s",
2184 exprNode_unparse (e1), lltok_unparse (op),
2185 exprNode_unparse (e2)),
2193 checkExpressionDefinedAux (e1, e2, e1->sets, e2->sets, op, FLG_EVALORDER);
2195 if (context_maybeSet (FLG_EVALORDERUNCON))
2197 checkExpressionDefinedAux (e1, e2, e1->msets,
2198 e2->msets, op, FLG_EVALORDERUNCON);
2203 static void checkSequencing (exprNode p_f, exprNodeList p_args);
2206 checkArgsReal (uentry fcn, /*@dependent@*/ exprNode f, uentryList cl,
2207 exprNodeList args, bool isIter, exprNode ret)
2211 if (!exprNode_isError (f))
2213 if (!uentryList_isMissingParams (cl))
2215 int nargs = exprNodeList_size (args);
2216 int expectargs = uentryList_size (cl);
2220 if (expectargs == 0)
2228 message ("Iter %q invoked with %d args, "
2230 uentry_getName (fcn),
2238 message ("Function %s called with %d args, "
2240 exprNode_unparse (f), nargs),
2247 last = uentry_getType (uentryList_getN (cl, expectargs - 1));
2249 exprNodeList_reset (args);
2251 uentryList_elements (cl, current)
2253 ctype ct = uentry_getType (current);
2256 if (ctype_isElips (ct))
2259 ** do special checking for printf/scanf library functions
2261 ** this is kludgey code, just for handling the special case
2265 if (uentry_isPrintfLike (fcn))
2267 checkPrintfArgs (f, fcn, args, ret, i);
2270 else if (uentry_isScanfLike (fcn))
2272 checkScanfArgs (f, fcn, args, ret, i);
2275 else if (uentry_isMessageLike (fcn))
2277 checkMessageArgs (f, fcn, args, i);
2282 llassert (!uentry_isSpecialFunction (fcn));
2285 nargs = expectargs; /* avoid errors */
2290 if (i >= nargs) break;
2292 a = exprNodeList_current (args);
2293 exprNodeList_advance (args);
2297 if (exprNode_isError (a))
2304 probably necessary? I'm not sure about this one
2305 checkMacroParen (a);
2308 f->guards = guardSet_union (f->guards, a->guards);
2310 if (!(exprNode_matchArgType (ct, a)))
2312 if (ctype_isVoidPointer (ct)
2313 && (ctype_isPointer (a->typ)
2314 && (ctype_isRealAbstract (ctype_baseArrayPtr (a->typ)))))
2319 ("Pointer to abstract type (%t) used "
2321 "(arg %d to %q): %s",
2323 uentry_getName (fcn),
2324 exprNode_unparse (a)),
2332 (ct, exprNode_undefined,
2335 ("Iter %q expects arg %d to "
2336 "be %t gets %t: %s",
2337 uentry_getName (fcn),
2338 i, ct, a->typ, exprNode_unparse (a)),
2349 ("Function %q expects arg %d to be %t gets %t: %s",
2350 uentry_getName (fcn),
2351 i, ct, a->typ, exprNode_unparse (a)),
2354 DPRINTF (("Types: %s / %s",
2356 ctype_unparse (a->typ)));
2360 ** Clear null marker for abstract types.
2361 ** (It is not revealed, so suppress future messages.)
2364 if (ctype_isAbstract (a->typ))
2366 sRef_setNullUnknown (exprNode_getSref (a), a->loc);
2373 } end_uentryList_elements ;
2376 if (expectargs != nargs) /* note: not != since we may have ... */
2378 if (ctype_isElips (last))
2382 message ("Function %s called with %d args, expects at least %d",
2383 exprNode_unparse (f),
2384 nargs, expectargs - 1),
2393 message ("Iter %q invoked with %d args, expects %d",
2394 uentry_getName (fcn), nargs, expectargs),
2401 message ("Function %s called with %d args, expects %d",
2402 exprNode_unparse (f),
2415 ** Check for undefined code sequences in function arguments:
2417 ** one parameter sets something used by another parameter
2418 ** one parameter sets something set by another parameter
2422 checkSequencingOne (exprNode f, exprNodeList args,
2423 /*@notnull@*/ exprNode el, int argno)
2426 ** Do second loop, iff +undefunspec
2430 int numloops = context_maybeSet (FLG_EVALORDERUNCON) ? 2 : 1;
2432 for (checkloop = 0; checkloop < numloops; checkloop++)
2438 thissets = el->sets;
2442 llassert (checkloop == 1);
2443 thissets = el->msets;
2446 sRefSet_realElements (thissets, thisset)
2450 /*@access exprNodeList@*/
2451 for (j = 0; j < args->nelements; j++)
2453 exprNode jl = args->elements[j];
2454 int thisargno = j + 1;
2456 if (thisargno != argno && exprNode_isDefined (jl))
2458 sRefSet otheruses = jl->uses;
2460 if (sRef_isGlobal (sRef_getRootBase (jl->sref)) &&
2461 sRefSet_hasUnconstrained (thissets))
2464 (FLG_EVALORDERUNCON,
2467 ("%q used in argument %d may set "
2468 "global variable %q used by argument %d: %s(%q)",
2469 cstring_capitalizeFree (sRefSet_unparseUnconstrained (thissets)),
2472 sRef_unparse (sRef_getRootBase (jl->sref)),
2474 exprNode_unparse (f), exprNodeList_unparse (args)),
2478 if (sRefSet_member (otheruses, thisset))
2480 if (sRef_isUnconstrained (thisset))
2483 (FLG_EVALORDERUNCON,
2485 ("Unconstrained functions used in arguments %d (%q) "
2486 "and %d (%s) may modify "
2487 "or use global state in undefined way: %s(%q)",
2489 sRefSet_unparseUnconstrainedPlain (otheruses),
2491 sRef_unconstrainedName (thisset),
2492 exprNode_unparse (f),
2493 exprNodeList_unparse (args)),
2501 ("Argument %d modifies %q, used by argument %d "
2502 "(order of evaluation of actual parameters is "
2503 "undefined): %s(%q)",
2504 argno, sRef_unparse (thisset), thisargno,
2505 exprNode_unparse (f), exprNodeList_unparse (args)),
2511 sRefSet othersets = jl->sets;
2513 if (sRefSet_member (othersets, thisset))
2515 if (sRef_isUnconstrained (thisset))
2518 (FLG_EVALORDERUNCON,
2520 ("Unconstrained functions used in "
2521 "arguments %d (%q) and %d (%s) may modify "
2522 "or use global state in undefined way: %s(%q)",
2524 sRefSet_unparseUnconstrainedPlain (othersets),
2526 sRef_unconstrainedName (thisset),
2527 exprNode_unparse (f), exprNodeList_unparse (args)),
2535 ("Argument %d modifies %q, set by argument %d (order of"
2536 " evaluation of actual parameters is undefined): %s(%q)",
2537 argno, sRef_unparse (thisset), thisargno,
2538 exprNode_unparse (f), exprNodeList_unparse (args)),
2545 /*@noaccess exprNodeList@*/
2546 } end_sRefSet_realElements;
2551 checkSequencing (exprNode f, exprNodeList args)
2553 if (exprNodeList_size (args) > 1)
2558 /*@access exprNodeList*/
2560 for (i = 0; i < args->nelements; i++)
2562 el = args->elements[i];
2564 if (!exprNode_isError (el))
2566 checkSequencingOne (f, args, el, i + 1);
2569 /*@noaccess exprNodeList*/
2574 ** requires le = exprNode_getUentry (f)
2578 checkGlobMods (/*@notnull@*/ /*@dependent@*/ exprNode f,
2579 uentry le, exprNodeList args,
2580 /*@notnull@*/ exprNode ret, int specialArgs)
2582 bool isSpec = FALSE;
2583 bool hasMods = FALSE;
2585 globSet usesGlobs = globSet_undefined;
2586 sRefSet mods = sRefSet_undefined;
2587 bool freshMods = FALSE;
2588 uentryList params = uentryList_undefined;
2591 ** check globals and modifies
2596 if (!uentry_isValid (le))
2598 ctype fr = ctype_realType (f->typ);
2600 if (ctype_isFunction (fr))
2602 params = ctype_argsFunction (fr);
2606 params = uentryList_missingParams;
2609 if (!context_getFlag (FLG_MODNOMODS)
2610 && !context_getFlag (FLG_GLOBUNSPEC))
2612 checkUnspecCall (f, params, args);
2618 fname = uentry_rawName (le);
2622 if (uentry_isFunction (le))
2624 params = uentry_getParams (le);
2625 mods = uentry_getMods (le);
2626 hasMods = uentry_hasMods (le);
2627 usesGlobs = uentry_getGlobs (le);
2628 isSpec = uentry_isSpecified (le);
2630 else /* not a function */
2632 ctype ct = ctype_realType (uentry_getType (le));
2634 llassertprint (uentry_isVar (le) && ctype_isFunction (ct),
2635 ("checkModGlobs: uentry not a function: %s",
2636 uentry_unparse (le)));
2638 params = ctype_argsFunction (ct);
2648 globSet_allElements (usesGlobs, el)
2650 if (sRef_isValid (el))
2652 if (sRef_isInternalState (el) || sRef_isSystemState (el))
2654 context_usedGlobal (el);
2655 exprNode_checkUse (f, el, f->loc);
2657 if (context_checkInternalUse ())
2659 if (!context_globAccess (el))
2661 if (sRef_isSystemState (el)
2662 && !context_getFlag (FLG_MODFILESYSTEM))
2671 ("Called procedure %s may access %q, but "
2672 "globals list does not include globals %s",
2673 exprNode_unparse (f),
2675 cstring_makeLiteralTemp (sRef_isInternalState (el)
2683 else if (sRef_isNothing (el) || sRef_isSpecState (el))
2689 uentry gle = sRef_getUentry (el);
2690 sRef sr = sRef_updateSref (el);
2692 if (sRef_isUndefGlob (el))
2694 sRef_setDefined (sr, f->loc);
2695 exprNode_checkSet (f, sr);
2703 if (sRef_isAllocated (el))
2705 exprNode_checkSet (f, sr);
2709 if (sRef_isStateUndefined (sr))
2714 ("%s %q used by function undefined before call: %s",
2715 sRef_getScopeName (sr),
2717 exprNode_unparse (f)),
2719 sRef_setDefined (sr, f->loc);
2721 exprNode_checkUse (f, sr, f->loc);
2724 checkGlobUse (gle, TRUE, f);
2727 if (sRef_isKilledGlob (el))
2729 sRef_kill (sr, f->loc);
2730 context_usedGlobal (sr);
2734 } end_globSet_allElements;
2740 if (context_hasMods () || context_getFlag (FLG_MODNOMODS))
2742 sRefSet smods = sRefSet_undefined;
2745 ** NEED to check for modifies anything
2749 ** check each sRef that called function modifies (ml), is
2755 sRefSet_allElements (mods, s) /* s is something which may be modified */
2757 if (sRef_isKindSpecial (s))
2759 if (sRef_isSpecInternalState (s))
2761 if (context_getFlag (FLG_MODINTERNALSTRICT))
2763 exprNode_checkCallModifyVal (s, args, f, ret);
2767 sRefSet mmods = context_modList ();
2769 sRefSet_allElements (mmods, el)
2771 if (sRef_isInternalState (el))
2773 sRef_setModified (el);
2775 } end_sRefSet_allElements ;
2780 exprNode_checkCallModifyVal (s, args, f, ret);
2785 sRef rb = sRef_getRootBase (s);
2787 if (sRef_isGlobal (rb))
2789 context_usedGlobal (rb);
2792 if (sRef_isFileStatic (s)
2793 && !fileId_equal (fileloc_fileId (f->loc),
2794 fileloc_fileId (uentry_whereDefined (le))))
2796 smods = sRefSet_insert (smods, s);
2800 exprNode_checkCallModifyVal (s, args, f, ret);
2803 } end_sRefSet_allElements;
2808 ** Static elements in modifies set can have nasty consequences.
2809 ** (I think...have not been able to reproduce a possible bug.)
2812 if (!sRefSet_isDefined (smods))
2814 mods = sRefSet_newCopy (mods);
2817 sRefSet_allElements (smods, el)
2819 bool res = sRefSet_delete (mods, el);
2822 } end_sRefSet_allElements;
2824 sRefSet_free (smods);
2829 else if (sRefSet_isDefined (mods))
2830 { /* just check observers */
2833 sRefSet_allElements (mods, s) /* s is something which may be modified */
2835 sRef rb = sRef_getRootBase (s);
2839 if (sRef_isParam (rb))
2841 sRef b = sRef_fixBaseParam (s, args);
2843 if (sRef_isObserver (b))
2845 exprNode e = exprNodeList_nth (args, sRef_getParam (rb));
2849 message ("Function call may modify observer%q: %s",
2850 sRef_unparsePreOpt (b), exprNode_unparse (e)),
2853 sRef_showExpInfo (b);
2857 } end_sRefSet_allElements;
2861 if (!hasMods) /* no specified modifications */
2863 if (context_getFlag (FLG_MODOBSERVERUNCON))
2865 exprNodeList_elements (args, e)
2867 if (exprNode_isDefined (e))
2869 sRef s = exprNode_getSref (e);
2871 if (sRef_isObserver (s)
2872 && ctype_isMutable (sRef_getType (s)))
2875 (FLG_MODOBSERVERUNCON,
2877 ("Call to unconstrained function %s may modify observer%q: %s",
2878 exprNode_unparse (f),
2879 sRef_unparsePreOpt (s), exprNode_unparse (e)),
2882 sRef_showExpInfo (s);
2886 } end_exprNodeList_elements;
2891 checkAnyCall (f, fname, params, args, hasMods, mods, isSpec, specialArgs);
2893 ret->uses = sRefSet_union (ret->uses, f->uses);
2894 ret->sets = sRefSet_union (ret->sets, f->sets);
2895 ret->msets = sRefSet_union (ret->msets, f->msets);
2900 ** Spurious errors reported, because lclint can't tell
2901 ** mods must be fresh if freshMods is true.
2904 /*@i@*/ sRefSet_free (mods);
2910 void checkGlobUse (uentry glob, bool isCall, /*@notnull@*/ exprNode e)
2912 if (uentry_isVar (glob))
2914 if (context_inFunctionLike ())
2916 sRef sr = uentry_getSref (glob);
2918 context_usedGlobal (sr);
2920 if (context_checkGlobUse (glob))
2922 if (!context_globAccess (sr))
2928 message ("Called procedure %s may access %s %q",
2929 exprNode_unparse (e),
2930 sRef_unparseScope (sr),
2931 uentry_getName (glob)),
2938 message ("Undocumented use of %s %s",
2939 sRef_unparseScope (sr),
2940 exprNode_unparse (e)),
2949 llbug (message ("Global not variable: %q", uentry_unparse (glob)));
2953 static /*@only@*/ exprNode
2954 functionCallSafe (/*@only@*/ /*@notnull@*/ exprNode f,
2955 ctype t, /*@keep@*/ exprNodeList args)
2957 /* requires f is a non-error exprNode, with type function */
2958 cstring fname = exprNode_unparse (f);
2959 uentry le = exprNode_getUentry (f);
2960 exprNode ret = exprNode_createPartialCopy (f);
2965 ret->typ = ctype_returnValue (t);
2966 ret->kind = XPR_CALL;
2968 ret->edata = exprData_makeCall (f, args);
2971 ** Order of these steps is very important!
2973 ** Must check for argument dependencies before messing up uses and sets.
2976 if (context_getFlag (FLG_EVALORDER))
2978 exprNodeList_elements (args, current)
2980 if (exprNode_isDefined (current))
2982 exprNode_addUse (current, current->sref);
2984 } end_exprNodeList_elements;
2986 if (context_maybeSet (FLG_EVALORDER) || context_maybeSet (FLG_EVALORDERUNCON))
2988 checkSequencing (f, args);
2991 exprNodeList_elements (args, current)
2993 if (exprNode_isDefined (current) && sRef_isMeaningful (current->sref))
2995 exprNode_addUse (ret, sRef_makeDerived (current->sref));
2997 } end_exprNodeList_elements ;
3000 special = checkArgs (le, f, t, args, ret);
3001 checkGlobMods (f, le, args, ret, special);
3005 if (uentry_isValid (le)
3006 && (uentry_isFunction (le)
3007 || (uentry_isVariable (le)
3008 && ctype_isFunction (uentry_getType (le)))))
3010 exitkind exk = uentry_getExitCode (le);
3012 /* f->typ is already set to the return type */
3014 ret->sref = uentry_returnedRef (le, args);
3016 if (uentry_isFunction (le) && exprNodeList_size (args) >= 1)
3018 qual nullPred = uentry_nullPred (le);
3020 if (qual_isTrueNull (nullPred))
3022 exprNode arg = exprNodeList_head (args);
3024 if (exprNode_isDefined (arg))
3026 ret->guards = guardSet_addFalseGuard (ret->guards, arg->sref);
3029 else if (qual_isFalseNull (nullPred))
3031 exprNode arg = exprNodeList_head (args);
3033 if (exprNode_isDefined (arg))
3035 ret->guards = guardSet_addTrueGuard (ret->guards, arg->sref);
3040 llassert (qual_isUnknown (nullPred));
3044 if (exitkind_isConditionalExit (exk))
3048 ** if (arg0) then { exit! } else { ; }
3050 ** if (arg0) then { ; } else { exit! }
3055 llassert (!exprNodeList_isEmpty (args));
3056 firstArg = exprNodeList_head (args);
3058 if (exprNode_isDefined (firstArg)
3059 && !guardSet_isEmpty (firstArg->guards))
3061 usymtab_trueBranch (guardSet_undefined);
3062 usymtab_altBranch (guardSet_undefined);
3064 if (exitkind_isTrueExit (exk))
3066 usymtab_popBranches (firstArg,
3067 exprNode_makeMustExit (),
3069 TRUE, TRUEEXITCLAUSE);
3073 usymtab_popBranches (firstArg,
3075 exprNode_makeMustExit (),
3076 TRUE, FALSEEXITCLAUSE);
3080 ret->exitCode = XK_MAYEXIT;
3082 else if (exitkind_mustExit (exk))
3084 ret->exitCode = XK_MUSTEXIT;
3086 else if (exitkind_couldExit (exk))
3088 ret->exitCode = XK_MAYEXIT;
3095 if (cstring_equalLit (fname, "exit"))
3097 if (exprNodeList_size (args) == 1)
3099 exprNode arg = exprNodeList_head (args);
3101 if (exprNode_isDefined (arg) && exprNode_knownIntValue (arg))
3103 long int val = multiVal_forceInt (exprNode_getValue (arg));
3110 ("Argument to exit has implementation defined behavior: %s",
3111 exprNode_unparse (arg)),
3112 exprNode_loc (arg));
3121 exprNode_checkSetAny (ret, uentry_rawName (le));
3128 ** this is yucky! should keep the uentry as part of exprNode!
3131 /*@observer@*/ uentry
3132 exprNode_getUentry (exprNode e)
3134 if (exprNode_isError (e))
3136 return uentry_undefined;
3140 cstring s = exprNode_rootVarName (e);
3141 uentry ue = usymtab_lookupSafe (s);
3148 exprNode_makeInitBlock (lltok brace, /*@only@*/ exprNodeList inits)
3150 exprNode ret = exprNode_createPlain (ctype_unknown);
3152 ret->kind = XPR_INITBLOCK;
3153 ret->edata = exprData_makeCall (exprNode_undefined, inits);
3154 ret->loc = fileloc_update (ret->loc, lltok_getLoc (brace));
3160 exprNode_functionCall (/*@only@*/ exprNode f, /*@only@*/ exprNodeList args)
3166 if (exprNode_isUndefined (f))
3169 exprNodeList_free (args);
3170 return exprNode_undefined;
3173 t = exprNode_getType (f);
3175 if (sRef_isLocalVar (f->sref))
3177 exprNode_checkUse (f, f->sref, f->loc);
3179 if (sRef_possiblyNull (f->sref))
3181 if (!usymtab_isGuarded (f->sref))
3183 if (optgenerror (FLG_NULLDEREF,
3184 message ("Function call using %s pointer %q",
3185 sRef_nullMessage (f->sref),
3186 sRef_unparse (f->sref)),
3189 sRef_showNullInfo (f->sref);
3190 sRef_setNullError (f->sref);
3198 if (ctype_isRealFunction (t))
3200 exprNode ret = functionCallSafe (f, t, args);
3204 else if (ctype_isUnknown (t))
3206 exprNode ret = exprNode_createPartialCopy (f);
3212 exprNodeList_elements (args, current)
3214 if (exprNode_isDefined (current))
3216 exprNode_checkUse (ret, current->sref, ret->loc);
3219 ** also, anything derivable from current->sref may be used
3222 exprNode_addUse (ret, sRef_makeDerived (current->sref));
3223 exprNode_mergeUSs (ret, current);
3225 } end_exprNodeList_elements;
3227 ret->edata = exprData_makeCall (f, args);
3228 ret->kind = XPR_CALL;
3230 tstring = cstring_copy (exprNode_unparse (f));
3232 cstring_markOwned (tstring);
3233 exprNode_checkSetAny (ret, tstring);
3239 voptgenerror (FLG_TYPE,
3240 message ("Call to non-function (type %t): %s", t,
3241 exprNode_unparse (f)),
3244 exprNodeList_free (args);
3246 return (exprNode_makeError ());
3251 exprNode_fieldAccess (/*@only@*/ exprNode s, /*@only@*/ cstring f)
3253 exprNode ret = exprNode_createPartialCopy (s);
3255 ret->kind = XPR_FACCESS;
3257 if (exprNode_isError (s))
3259 ret->edata = exprData_makeField (s, f);
3264 ctype t = exprNode_getType (s);
3265 ctype tr = ctype_realType (t);
3267 checkMacroParen (s);
3269 ret->edata = exprData_makeField (s, f);
3271 if (ctype_isStructorUnion (tr))
3273 uentry tf = uentryList_lookupField (ctype_getFields (tr), f);
3275 if (uentry_isUndefined (tf))
3277 voptgenerror (FLG_TYPE,
3278 message ("Access non-existent field %s of %t: %s", f, t,
3279 exprNode_unparse (ret)),
3286 uentry_setUsed (tf, exprNode_loc (ret));
3288 ret->typ = uentry_getType (tf);
3289 checkSafeUse (ret, s->sref);
3291 ret->sref = sRef_makeField (s->sref, uentry_rawName (tf));
3295 else /* isStructorUnion */
3297 if (ctype_isRealAbstract (tr))
3301 message ("Access field of abstract type (%t): %s.%s",
3302 t, exprNode_unparse (s), f),
3304 ret->typ = ctype_unknown;
3308 if (ctype_isKnown (tr))
3313 ("Access field of non-struct or union (%t): %s.%s",
3314 t, exprNode_unparse (s), f),
3317 ret->typ = ctype_unknown;
3321 cstring sn = cstring_copy (f);
3323 checkSafeUse (ret, s->sref);
3324 cstring_markOwned (sn);
3325 ret->sref = sRef_makeField (s->sref, sn);
3337 exprNode_addParens (/*@only@*/ lltok lpar, /*@only@*/ exprNode e)
3339 exprNode ret = exprNode_createPartialCopy (e);
3341 ret->loc = fileloc_update (ret->loc, lltok_getLoc (lpar));
3342 ret->kind = XPR_PARENS;
3343 ret->edata = exprData_makeUop (e, lpar);
3345 if (!exprNode_isError (e))
3347 ret->exitCode = e->exitCode;
3348 ret->canBreak = e->canBreak;
3349 ret->mustBreak = e->mustBreak;
3350 ret->isJumpPoint = e->isJumpPoint;
3351 ret->sref = e->sref;
3358 exprNode_arrowAccess (/*@only@*/ exprNode s, /*@only@*/ cstring f)
3360 exprNode ret = exprNode_createPartialCopy (s);
3362 ret->edata = exprData_makeField (s, f);
3363 ret->kind = XPR_ARROW;
3365 if (exprNode_isError (s))
3371 ctype t = exprNode_getType (s);
3372 ctype tr = ctype_realType (t);
3374 checkMacroParen (s);
3376 (void) ctype_fixArrayPtr (tr); /* REWRITE THIS */
3378 if (ctype_isRealPointer (tr))
3380 ctype b = ctype_realType (ctype_baseArrayPtr (tr));
3382 if (ctype_isStructorUnion (b))
3384 uentry fentry = uentryList_lookupField (ctype_getFields (b), f);
3386 if (sRef_isKnown (s->sref) && sRef_possiblyNull (s->sref))
3388 if (!usymtab_isGuarded (s->sref) && !context_inProtectVars ())
3392 message ("Arrow access from %s pointer%q: %s",
3393 sRef_nullMessage (s->sref),
3394 sRef_unparsePreOpt (s->sref),
3395 exprNode_unparse (ret)),
3398 sRef_showNullInfo (s->sref);
3399 sRef_setNullError (s->sref);
3404 if (uentry_isUndefined (fentry))
3408 message ("Access non-existent field %s of %t: %s",
3409 f, t, exprNode_unparse (ret)),
3411 ret->typ = ctype_unknown;
3418 ** was safeUse: shouldn't be safe!
3421 ** rec must be defined,
3422 ** *rec must be allocated
3423 ** rec->field need only be defined it if is an rvalue
3426 uentry_setUsed (fentry, exprNode_loc (ret));
3427 ret->typ = uentry_getType (fentry);
3429 exprNode_checkUse (ret, s->sref, s->loc);
3431 /* exprNode_checkUse (ret, sRef_makePointer (s->sref), s->loc); */
3432 ret->sref = sRef_makeArrow (s->sref, uentry_rawName (fentry));
3436 else /* Pointer to something that is not a struct or union*/
3438 if (ctype_isRealAbstract (tr))
3440 ctype xrt = ctype_forceRealType (tr);
3444 message ("Arrow access field of abstract type (%t): %s->%s",
3445 t, exprNode_unparse (s), f),
3449 ** Set the state correctly, as if the abstraction is broken.
3452 if (ctype_isRealPointer (xrt) &&
3453 (b = ctype_realType (ctype_baseArrayPtr (xrt)),
3454 ctype_isStructorUnion (b)))
3456 uentry fentry = uentryList_lookupField (ctype_getFields (b), f);
3457 ret->typ = uentry_getType (fentry);
3458 ret->sref = sRef_makeArrow (s->sref, uentry_rawName (fentry));
3462 ret->typ = ctype_unknown;
3463 ret->sref = sRef_undefined;
3466 else /* not a struct, union or abstract */
3468 if (ctype_isUnknown (tr)) {
3469 cstring sn = cstring_copy (f);
3471 DPRINTF (("Here: %s", exprNode_unparse (s)));
3473 exprNode_checkUse (ret, s->sref, s->loc);
3474 exprNode_checkUse (ret, sRef_makePointer (s->sref), s->loc);
3476 cstring_markOwned (sn);
3477 ret->sref = sRef_makeArrow (s->sref, sn);
3479 ret->kind = XPR_ARROW;
3484 message ("Arrow access field of non-struct or union "
3485 "pointer (%t): %s->%s",
3486 t, exprNode_unparse (s), f),
3489 ret->typ = ctype_unknown;
3490 ret->sref = sRef_undefined;
3495 else /* its not a pointer */
3497 if (!ctype_isUnknown (tr))
3501 message ("Arrow access of non-pointer (%t): %s->%s",
3502 t, exprNode_unparse (s), f),
3505 ret->typ = ctype_unknown;
3506 ret->sref = sRef_undefined;
3510 cstring sn = cstring_copy (f);
3512 DPRINTF (("Here: %s", exprNode_unparse (s)));
3514 exprNode_checkUse (ret, s->sref, s->loc);
3515 exprNode_checkUse (ret, sRef_makePointer (s->sref), s->loc);
3517 cstring_markOwned (sn);
3518 ret->sref = sRef_makeArrow (s->sref, sn);
3520 ret->kind = XPR_ARROW;
3531 ** only postOp's in C: i++ and i--
3535 exprNode_postOp (/*@only@*/ exprNode e, /*@only@*/ lltok op)
3537 /* check modification also */
3538 /* cstring opname = lltok_unparse (op);*/
3540 exprNode ret = exprNode_createPartialCopy (e);
3542 ret->loc = fileloc_update (ret->loc, lltok_getLoc (op));
3543 ret->kind = XPR_POSTOP;
3544 ret->edata = exprData_makeUop (e, op);
3546 if (!exprNode_isDefined (e))
3551 checkMacroParen (e);
3553 exprNode_checkUse (ret, e->sref, e->loc);
3554 exprNode_checkSet (ret, e->sref);
3556 t = exprNode_getType (e);
3558 if (sRef_isUnsafe (e->sref))
3560 voptgenerror (FLG_MACROPARAMS,
3561 message ("Operand of %s is macro parameter (non-functional): %s%s",
3562 lltok_unparse (op), exprNode_unparse (e), lltok_unparse (op)),
3564 sRef_makeSafe (e->sref);
3565 sRef_makeSafe (ret->sref);
3568 if (ctype_isForceRealNumeric (&t) || ctype_isRealAP (t))
3574 if (ctype_isRealAbstract (t))
3578 message ("Operand of %s is abstract type (%t): %s",
3579 lltok_unparse (op), t, exprNode_unparse (e)),
3586 message ("Operand of %s is non-numeric (%t): %s",
3587 lltok_unparse (op), t, exprNode_unparse (e)),
3590 ret->typ = ctype_unknown;
3593 /* if (ctype_isZero (t)) e->typ = ctype_int; */
3595 exprNode_checkModify (e, ret);
3597 /* start modifications */
3598 /* added by Seejo on 4/16/2000 */
3600 /* Arithmetic operations on pointers wil modify the size/len/null terminated
3602 if ((sRef_isPossiblyNullTerminated (e->sref)) || (sRef_isNullTerminated(e->sref))) {
3604 ret->sref = sRef_copy (e->sref);
3607 if (lltok_getTok (op) == INC_OP) {
3608 if (sRef_getSize(e->sref) > 0) {
3610 sRef_setSize (ret->sref, sRef_getSize(e->sref) - 1);
3612 if (sRef_getLen(e->sref) == 1) { /* i.e. the first character is \0 */
3613 /* Assumption: there is only 1 \0 in the buffer */
3614 /* This will not be correct if there are 2 \0's in the buffer */
3615 sRef_setNotNullTerminatedState(ret->sref);
3616 sRef_resetLen(ret->sref);
3618 sRef_setNullTerminatedState(ret->sref);
3619 sRef_setLen (ret->sref, sRef_getLen(e->sref) - 1);
3621 if (sRef_isNullTerminated (ret->sref))
3622 printf ("ret->sref is Null Terminated\n");
3623 else if (sRef_isPossiblyNullTerminated (ret->sref))
3624 printf ("ret->sref is Possibly Null Terminated\n");
3625 else if (sRef_isNotNullTerminated (ret->sref))
3626 printf ("ret->sref is Not Null Terminated\n");
3631 if (lltok_getTok (op) == DEC_OP) {
3632 if (sRef_getSize(e->sref) >= 0) {
3633 sRef_setSize (ret->sref, sRef_getSize(e->sref) + 1);
3634 sRef_setLen (ret->sref, sRef_getLen(e->sref) + 1);
3639 /* end modifications */
3645 exprNode_preOp (/*@only@*/ exprNode e, /*@only@*/ lltok op)
3647 bool checkMod = FALSE;
3649 int opid = lltok_getTok (op);
3650 exprNode ret = exprNode_createSemiCopy (e);
3652 exprNode_copySets (ret, e);
3654 multiVal_free (ret->val);
3655 ret->val = multiVal_undefined;
3656 ret->loc = fileloc_update (ret->loc, lltok_getLoc (op));
3657 ret->kind = XPR_PREOP;
3658 ret->edata = exprData_makeUop (e, op);
3660 if (exprNode_isError (e))
3665 checkMacroParen (e);
3667 te = exprNode_getType (e);
3668 tr = ctype_realType (te);
3670 if (opid != TAMPERSAND)
3672 exprNode_checkUse (ret, e->sref, e->loc);
3674 if (ctype_isRealAbstract (tr)
3675 && (!(ctype_isRealBool (te) && (opid == TEXCL))))
3677 if (optgenerror (FLG_ABSTRACT,
3678 message ("Operand of %s is abstract type (%t): %s",
3679 lltok_unparse (op), tr,
3680 exprNode_unparse (ret)),
3683 tr = te = ctype_unknown;
3684 ret->typ = ctype_unknown;
3685 sRef_setNullError (e->sref);
3693 case DEC_OP: /* should also check modification! */
3695 if (sRef_isMacroParamRef (e->sref))
3699 message ("Operand of %s is macro parameter (non-functional): %s",
3700 lltok_unparse (op), exprNode_unparse (ret)),
3705 exprNode_checkSet (ret, e->sref);
3708 if (ctype_isForceRealNumeric (&tr) || ctype_isRealAP (tr))
3713 if (context_msgStrictOps ())
3717 message ("Operand of %s is non-numeric (%t): %s",
3718 lltok_unparse (op), te, exprNode_unparse (ret)),
3721 ret->typ = ctype_int;
3724 /* start modifications */
3725 /* added by Seejo on 4/16/2000 */
3727 /* Arithmetic operations on pointers wil modify the size/len/null terminated
3729 if ((sRef_isPossiblyNullTerminated (e->sref)) || (sRef_isNullTerminated(e->sref))) {
3731 ret->sref = sRef_copy (e->sref);
3734 if (lltok_getTok (op) == INC_OP) {
3735 if (sRef_getSize(e->sref) > 0) {
3737 sRef_setSize (ret->sref, sRef_getSize(e->sref) - 1);
3739 if (sRef_getLen(e->sref) == 1) { /* i.e. the first character is \0 */
3740 /* Assumption: there is only 1 \0 in the buffer */
3741 /* This will not be correct if there are 2 \0's in the buffer */
3742 sRef_setNotNullTerminatedState(ret->sref);
3743 sRef_resetLen (ret->sref);
3745 sRef_setNullTerminatedState(ret->sref);
3746 sRef_setLen (ret->sref, sRef_getLen(e->sref) - 1);
3752 if (lltok_getTok (op) == DEC_OP) {
3753 if (sRef_getSize(e->sref) >= 0) {
3754 sRef_setSize (ret->sref, sRef_getSize(e->sref) + 1);
3755 sRef_setLen (ret->sref, sRef_getLen(e->sref) + 1);
3760 /* end modifications */
3767 if (ctype_isForceRealNumeric (&tr))
3771 ret->val = multiVal_invert (exprNode_getValue (e));
3775 ret->val = multiVal_copy (exprNode_getValue (e));
3780 if (context_msgStrictOps ())
3784 message ("Operand of %s is non-numeric (%t): %s",
3785 lltok_unparse (op), te, exprNode_unparse (ret)),
3789 ret->typ = ctype_int;
3793 case TEXCL: /* maybe this should be restricted */
3794 guardSet_flip (ret->guards);
3796 if (ctype_isRealBool (te))
3802 if (ctype_isRealPointer (tr))
3804 if (sRef_isKnown (e->sref))
3806 ret->guards = guardSet_addFalseGuard (ret->guards, e->sref);
3810 (FLG_BOOLOPS, FLG_PTRNEGATE,
3811 message ("Operand of %s is non-boolean (%t): %s",
3812 lltok_unparse (op), te, exprNode_unparse (ret)),
3819 message ("Operand of %s is non-boolean (%t): %s",
3820 lltok_unparse (op), te, exprNode_unparse (ret)),
3824 ret->typ = ctype_bool;
3829 if (ctype_isForceRealInt (&tr))
3834 if (context_msgStrictOps ())
3838 message ("Operand of %s is non-integer (%t): %s",
3839 lltok_unparse (op), te, exprNode_unparse (ret)),
3843 if (ctype_isInt (e->typ))
3849 ret->typ = ctype_int;
3855 ret->typ = ctype_makePointer (e->typ);
3857 if (sRef_isKnown (e->sref))
3859 ret->sref = sRef_makeAddress (e->sref);
3866 if (ctype_isAP (tr))
3868 ret->typ = ctype_baseArrayPtr (e->typ);
3872 if (ctype_isKnown (te))
3874 if (ctype_isFunction (te))
3880 message ("Dereference of function type (%t): %s",
3881 te, exprNode_unparse (ret)),
3886 voptgenerror (FLG_TYPE,
3887 message ("Dereference of non-pointer (%t): %s",
3888 te, exprNode_unparse (ret)),
3890 ret->typ = ctype_unknown;
3895 ret->typ = ctype_unknown;
3900 if (sRef_isKnown (e->sref))
3902 if (sRef_possiblyNull (e->sref))
3904 if (!usymtab_isGuarded (e->sref) && !context_inProtectVars ())
3908 message ("Dereference of %s pointer %q: %s",
3909 sRef_nullMessage (e->sref),
3910 sRef_unparse (e->sref),
3911 exprNode_unparse (ret)),
3914 sRef_showNullInfo (e->sref);
3915 sRef_setNotNull (e->sref, e->loc); /* suppress future messages */
3920 ret->sref = sRef_makePointer (e->sref);
3925 llbug (message ("exprNode_preOp: unhandled op: %s", lltok_unparse (op)));
3930 exprNode_checkModify (e, ret);
3937 ** any reason to disallow sizeof (abstract type) ?
3941 ** used by both sizeof
3945 ctype sizeof_resultType (void)
3947 static ctype sizet = ctype_unknown;
3949 if (ctype_isUnknown (sizet))
3951 if (usymtab_existsType (cstring_makeLiteralTemp ("size_t")))
3953 sizet = uentry_getAbstractType (usymtab_lookup (cstring_makeLiteralTemp ("size_t")));
3957 sizet = ctype_ulint;
3964 exprNode_sizeofType (/*@only@*/ qtype qt)
3966 exprNode ret = exprNode_create (sizeof_resultType ());
3967 ctype ct = qtype_getType (qt);
3969 ret->kind = XPR_SIZEOFT;
3970 ret->edata = exprData_makeSizeofType (qt);
3972 voptgenerror (FLG_SIZEOFTYPE,
3973 message ("Parameter to sizeof is type %s: %s",
3975 exprNode_unparse (ret)),
3982 exprNode_alignofType (/*@only@*/ qtype qt)
3984 exprNode ret = exprNode_create (sizeof_resultType ());
3985 ctype ct = qtype_getType (qt);
3987 ret->kind = XPR_ALIGNOFT;
3988 ret->edata = exprData_makeSizeofType (qt);
3990 voptgenerror (FLG_SIZEOFTYPE,
3991 message ("Parameter to alignof is type %s: %s",
3993 exprNode_unparse (ret)),
3999 exprNode exprNode_offsetof (qtype qt, cstringList s)
4001 exprNode ret = exprNode_create (sizeof_resultType ());
4002 ctype ct = qtype_getType (qt);
4004 ret->kind = XPR_OFFSETOF;
4005 ret->edata = exprData_makeOffsetof (qt, s);
4007 if (!ctype_isRealSU (ct))
4009 voptgenerror (FLG_TYPE,
4010 message ("First parameter to offsetof is not a "
4011 "struct or union type (type %s): %s",
4013 exprNode_unparse (ret)),
4020 cstringList_elements (s, el) {
4024 if (ctype_isUndefined (lt))
4028 else if (!ctype_isRealSU (lt))
4030 voptgenerror (FLG_TYPE,
4031 message ("Inner offsetof type is not a "
4032 "struct or union type (type %s before field %s): %s",
4033 ctype_unparse (lt), el,
4034 exprNode_unparse (ret)),
4040 fields = ctype_getFields (ctype_realType (lt));
4041 fld = uentryList_lookupField (fields, el);
4042 DPRINTF (("Try: %s / %s", ctype_unparse (lt), el));
4044 if (uentry_isUndefined (fld))
4046 if (ctype_equal (lt, ct)) {
4047 voptgenerror (FLG_TYPE,
4048 message ("Field %s in offsetof is not the "
4049 "name of a field of %s: %s",
4052 exprNode_unparse (ret)),
4055 voptgenerror (FLG_TYPE,
4056 message ("Deep field %s in offsetof is not the "
4057 "name of a field of %s: %s",
4060 exprNode_unparse (ret)),
4066 lt = uentry_getType (fld);
4069 } end_cstringList_elements;
4071 /* Should report error if its a bit field - behavior is undefined! */
4078 exprNode_sizeofExpr (/*@only@*/ exprNode e)
4082 if (exprNode_isUndefined (e))
4084 ret = exprNode_createLoc (ctype_unknown, fileloc_copy (g_currentloc));
4085 ret->edata = exprData_makeSingle (e);
4086 ret->typ = sizeof_resultType ();
4087 ret->kind = XPR_SIZEOF;
4091 uentry u = exprNode_getUentry (e);
4093 ret = exprNode_createPartialCopy (e);
4094 ret->edata = exprData_makeSingle (e);
4096 ret->typ = sizeof_resultType ();
4097 ret->kind = XPR_SIZEOF;
4099 if (uentry_isValid (u)
4100 && uentry_isRefParam (u)
4101 && ctype_isRealArray (uentry_getType (u)))
4104 (FLG_SIZEOFFORMALARRAY,
4105 message ("Parameter to sizeof is an array-type function parameter: %s",
4106 exprNode_unparse (ret)),
4112 ** sizeof (x) doesn't "really" use x
4119 exprNode_alignofExpr (/*@only@*/ exprNode e)
4123 if (exprNode_isUndefined (e))
4125 ret = exprNode_createLoc (ctype_unknown, fileloc_copy (g_currentloc));
4129 ret = exprNode_createPartialCopy (e);
4132 ret->edata = exprData_makeSingle (e);
4133 ret->typ = sizeof_resultType ();
4134 ret->kind = XPR_ALIGNOF;
4137 ** sizeof (x) doesn't "really" use x
4144 exprNode_cast (/*@only@*/ lltok tok, /*@only@*/ exprNode e, /*@only@*/ qtype q)
4150 if (exprNode_isError (e))
4153 lltok_release (tok);
4154 return exprNode_undefined;
4157 checkMacroParen (e);
4159 c = qtype_getType (q);
4160 t = exprNode_getType (e);
4162 ret = exprNode_createPartialCopy (e);
4164 ret->loc = fileloc_update (ret->loc, lltok_getLoc (tok));
4166 ret->kind = XPR_CAST;
4167 ret->edata = exprData_makeCast (tok, e, q);
4169 if (ctype_isRealSU (ctype_getBaseType (sRef_getType (e->sref))))
4172 ** This is a bit of a hack to avoid a problem
4173 ** when the code does,
4174 ** (some other struct) x
4179 ret->sref = sRef_copy (e->sref);
4180 usymtab_addForceMustAlias (ret->sref, e->sref);
4181 sRef_setTypeFull (ret->sref, c);
4182 DPRINTF (("Cast: %s -> %s", sRef_unparseFull (e->sref),
4183 sRef_unparseFull (ret->sref)));
4187 ret->sref = e->sref;
4188 sRef_setTypeFull (ret->sref, c);
4189 DPRINTF (("Cast 2: -> %s", sRef_unparseFull (ret->sref)));
4196 ** void * <-> abstract * (if FLG_ABSTVOIDP)
4197 ** abstract * <-> void * (if FLG_ABSTVOIDP)
4200 if (ctype_isVoid (c)) /* cast to void is always okay --- discard value */
4204 else if (ctype_isRealAP (c)) /* casting to array or pointer */
4206 ctype bc = ctype_getBaseType (c);
4207 ctype bt = ctype_getBaseType (t);
4208 ctype rt = ctype_realType (t);
4210 if (ctype_isFunction (ctype_baseArrayPtr (ctype_realType (c)))
4211 && (ctype_isArrayPtr (rt)
4212 && !ctype_isFunction (ctype_realType (ctype_baseArrayPtr (rt)))))
4216 message ("Cast from function pointer type (%t) to "
4217 "non-function pointer (%t): %s",
4218 c, t, exprNode_unparse (ret)),
4222 if (!ctype_isFunction (ctype_baseArrayPtr (c))
4223 && (ctype_isArrayPtr (rt)
4224 && ctype_isFunction (ctype_realType (ctype_baseArrayPtr (rt)))))
4228 message ("Cast from non-function pointer type (%t) to "
4229 "function pointer (%t): %s",
4230 c, t, exprNode_unparse (ret)),
4234 if (exprNode_isZero (e) && context_getFlag (FLG_ZEROPTR) &&
4235 !(ctype_isRealAbstract (bc)
4236 && context_hasAccess (ctype_typeId (bc))))
4238 ; /* okay to cast zero */
4242 if (ctype_isRealAbstract (bc)
4243 && !context_hasAccess (ctype_typeId (bc)))
4245 if (ctype_isVoidPointer (t) || ctype_isUnknown (t))
4249 message ("Cast to underlying abstract type %t: %s",
4250 c, exprNode_unparse (ret)),
4257 message ("Cast to underlying abstract type %t: %s",
4258 c, exprNode_unparse (ret)),
4263 if (ctype_isRealAbstract (bt)
4264 && !context_hasAccess (ctype_typeId (bt)))
4266 if (ctype_isUnknown (c) || ctype_isVoidPointer (c))
4270 message ("Cast from underlying abstract type %t: %s",
4271 t, exprNode_unparse (ret)),
4278 message ("Cast from underlying abstract type %t: %s",
4279 t, exprNode_unparse (ret)),
4287 ctype bt = ctype_realType (ctype_getBaseType (t));
4288 ctype bc = ctype_realType (ctype_getBaseType (c));
4290 if (ctype_isAbstract (bt) && !context_hasAccess (ctype_typeId (bt)))
4292 if (ctype_match (c, t))
4294 if (ctype_equal (c, t))
4298 message ("Redundant cast involving abstract type %t: %s",
4299 bt, exprNode_unparse (ret)),
4307 message ("Cast from abstract type %t: %s",
4308 bt, exprNode_unparse (ret)),
4313 if (ctype_isAbstract (bc)
4314 && !context_hasAccess (ctype_typeId (bc)))
4316 if (ctype_match (c, t))
4324 message ("Cast to abstract type %t: %s", bc,
4325 exprNode_unparse (ret)),
4331 if (ctype_isAbstract (c))
4333 if (sRef_isExposed (e->sref) || sRef_isOnly (e->sref))
4335 /* okay, cast exposed to abstract */
4336 sRef_clearExKindComplete (ret->sref, fileloc_undefined);
4340 if (ctype_isVisiblySharable (t)
4341 && sRef_isExternallyVisible (e->sref)
4342 && !(ctype_isAbstract (t)
4343 && context_hasAccess (ctype_typeId (t))))
4347 message ("Cast to abstract type from externally visible "
4348 "mutable storage exposes rep of %s: %s",
4350 exprNode_unparse (e)),
4360 evaluationOrderUndefined (lltok op)
4362 int opid = lltok_getTok (op);
4364 return (opid != AND_OP && opid != OR_OP);
4367 static bool checkIntegral (/*@notnull@*/ exprNode e1,
4368 /*@notnull@*/ exprNode e2,
4369 /*@notnull@*/ exprNode ret,
4374 ctype te1 = exprNode_getType (e1);
4375 ctype te2 = exprNode_getType (e2);
4377 ctype tr1 = ctype_realishType (te1);
4378 ctype tr2 = ctype_realishType (te2);
4380 if (ctype_isForceRealInt (&tr1) && ctype_isForceRealInt (&tr2))
4386 if (context_msgStrictOps ())
4388 if (!ctype_isInt (tr1) && !ctype_isInt (tr2))
4390 if (ctype_sameName (te1, te2))
4394 message ("Operands of %s are non-integer (%t): %s",
4395 lltok_unparse (op), te1,
4396 exprNode_unparse (ret)),
4403 message ("Operands of %s are non-integers (%t, %t): %s",
4404 lltok_unparse (op), te1, te2,
4405 exprNode_unparse (ret)),
4409 else if (!ctype_isInt (tr1))
4413 message ("Left operand of %s is non-integer (%t): %s",
4414 lltok_unparse (op), te1, exprNode_unparse (ret)),
4418 /* !ctype_isInt (te2) */
4422 message ("Right operand of %s is non-integer (%t): %s",
4423 lltok_unparse (op), te2, exprNode_unparse (ret)),
4433 ** returns exprNode representing e1 op e2
4435 ** uses msg if there are errors
4436 ** can be used for both assignment ops and regular ops
4441 static /*@only@*/ /*@notnull@*/ exprNode
4442 exprNode_makeOp (/*@keep@*/ exprNode e1, /*@keep@*/ exprNode e2,
4443 /*@keep@*/ lltok op)
4445 ctype te1, te2, tr1, tr2, tret;
4446 int opid = lltok_getTok (op);
4447 bool hasError = FALSE;
4450 if (exprNode_isError (e1))
4452 ret = exprNode_createPartialNVCopy (e2);
4456 ret = exprNode_createPartialNVCopy (e1);
4459 ret->val = multiVal_undefined;
4461 ret->edata = exprData_makeOp (e1, e2, op);
4463 if (exprNode_isError (e1) || exprNode_isError (e2))
4465 if (opid == TLT || opid == TGT || opid == LE_OP || opid == GE_OP
4466 || opid == EQ_OP || opid == NE_OP
4467 || opid == AND_OP || opid == OR_OP)
4469 ret->typ = ctype_bool;
4472 if (exprNode_isDefined (e1))
4474 exprNode_checkUse (ret, e1->sref, e1->loc);
4477 if (exprNode_isDefined (e2))
4479 exprNode_mergeUSs (ret, e2);
4480 exprNode_checkUse (ret, e2->sref, e2->loc);
4486 tret = ctype_unknown;
4487 te1 = exprNode_getType (e1);
4488 DPRINTF (("te1 = %s / %s", exprNode_unparse (e1), ctype_unparse (te1)));
4490 te2 = exprNode_getType (e2);
4492 tr1 = ctype_realishType (te1);
4493 tr2 = ctype_realishType (te2);
4497 ret->guards = guardSet_or (ret->guards, e2->guards);
4499 else if (opid == AND_OP)
4501 ret->guards = guardSet_and (ret->guards, e2->guards);
4508 if (opid == EQ_OP || opid == NE_OP)
4510 exprNode temp1 = e1, temp2 = e2;
4512 /* could do NULL == x */
4514 if (exprNode_isNullValue (e1) || exprNode_isUnknownConstant (e1))
4516 temp1 = e2; temp2 = e1;
4519 if (exprNode_isNullValue (temp2) || exprNode_isUnknownConstant (temp2))
4521 reflectNullTest (temp1, (opid == NE_OP));
4522 guardSet_free (ret->guards);
4523 ret->guards = guardSet_copy (temp1->guards);
4527 if (opid == TLT || opid == TGT || opid == LE_OP || opid == GE_OP
4528 || opid == EQ_OP || opid == NE_OP || opid == AND_OP || opid == OR_OP)
4533 if (anyAbstract (tr1, tr2) &&
4534 (!((ctype_isRealBool (te1) || ctype_isRealBool (te2)) &&
4535 (opid == AND_OP || opid == OR_OP
4536 || opid == EQ_OP || opid == NE_OP))))
4538 abstractOpError (tr1, tr2, op, e1, e2, e1->loc, e2->loc);
4540 else if (ctype_isUnknown (te1) || ctype_isUnknown (te2))
4542 /* unknown types, no comparisons possible */
4548 case TMULT: /* multiplication and division: */
4550 case MUL_ASSIGN: /* numeric, numeric -> numeric */
4551 case DIV_ASSIGN: /* */
4553 tret = checkNumerics (tr1, tr2, te1, te2, e1, e2, op);
4556 case TPLUS: /* addition and subtraction: */
4557 case TMINUS: /* pointer, int -> pointer */
4558 case SUB_ASSIGN: /* int, pointer -> pointer */
4559 case ADD_ASSIGN: /* numeric, numeric -> numeric */
4561 tr1 = ctype_fixArrayPtr (tr1);
4563 if ((ctype_isRealPointer (tr1) && !exprNode_isNullValue (e1))
4564 && (!ctype_isRealPointer (tr2) && ctype_isRealInt (tr2)))
4568 if (context_msgPointerArith ())
4572 message ("Pointer arithmetic (%t, %t): %s",
4573 te1, te2, exprNode_unparse (ret)),
4577 if (sRef_possiblyNull (e1->sref)
4578 && !usymtab_isGuarded (e1->sref))
4581 (FLG_NULLPOINTERARITH,
4582 message ("Pointer arithmetic involving possibly "
4583 "null pointer %s: %s",
4584 exprNode_unparse (e1),
4585 exprNode_unparse (ret)),
4589 ret->sref = sRef_copy (e1->sref);
4591 /* start modifications */
4592 /* added by Seejo on 4/16/2000 */
4594 /* Arithmetic operations on pointers wil modify the size/len/null terminated
4596 if ((sRef_isPossiblyNullTerminated (e1->sref)) || (sRef_isNullTerminated(e1->sref))) {
4597 //if (sRef_isKnown (e->sref)) {
4598 //ret->sref = sRef_makeAddress (e->sref);
4601 int val = (int) multiVal_forceInt (e2->val);
4603 /* Operator : + or += */
4604 if ((lltok_getTok (op) == TPLUS) || (lltok_getTok(op) == ADD_ASSIGN)) {
4605 if (sRef_getSize(e1->sref) >= val) {/* Incrementing the pointer by
4606 val should not result in a
4607 size < 0 (size = 0 is ok !) */
4609 sRef_setSize (ret->sref, sRef_getSize(e1->sref) - val);
4611 if (sRef_getLen(e1->sref) == val) { /* i.e. the character at posn val is \0 */
4612 sRef_setNotNullTerminatedState(ret->sref);
4613 sRef_resetLen (ret->sref);
4615 sRef_setNullTerminatedState(ret->sref);
4616 sRef_setLen (ret->sref, sRef_getLen(e1->sref) - val);
4621 /* Operator : - or -= */
4622 if ((lltok_getTok (op) == TMINUS) || (lltok_getTok (op) == SUB_ASSIGN)) {
4623 if (sRef_getSize(e1->sref) >= 0) {
4624 sRef_setSize (ret->sref, sRef_getSize(e1->sref) + val);
4625 sRef_setLen (ret->sref, sRef_getLen(e1->sref) + val);
4630 /* end modifications */
4632 sRef_setNullError (ret->sref);
4635 ** Fixed for 2.2c: the alias state of ptr + int is dependent,
4636 ** since is points to storage that should not be deallocated
4637 ** through this pointer.
4640 if (sRef_isOnly (ret->sref)
4641 || sRef_isFresh (ret->sref))
4643 sRef_setAliasKind (ret->sref, AK_DEPENDENT, exprNode_loc (ret));
4648 else if ((!ctype_isRealPointer(tr1) && ctype_isRealInt (tr1))
4649 && (ctype_isRealPointer (tr2) && !exprNode_isNullValue (e2)))
4651 if (context_msgPointerArith ())
4655 message ("Pointer arithmetic (%t, %t): %s",
4656 te1, te2, exprNode_unparse (ret)),
4660 if (sRef_possiblyNull (e1->sref)
4661 && !usymtab_isGuarded (e1->sref))
4664 (FLG_NULLPOINTERARITH,
4665 message ("Pointer arithmetic involving possibly "
4666 "null pointer %s: %s",
4667 exprNode_unparse (e2),
4668 exprNode_unparse (ret)),
4672 ret->sref = sRef_copy (e2->sref);
4674 /* start modifications */
4675 /* added by Seejo on 4/16/2000 */
4677 /* Arithmetic operations on pointers wil modify the size/len/null terminated
4680 if ((sRef_isPossiblyNullTerminated (e2->sref)) || (sRef_isNullTerminated(e2->sref))) {
4681 //if (sRef_isKnown (e->sref)) {
4682 //ret->sref = sRef_makeAddress (e->sref);
4685 int val = (int) multiVal_forceInt (e1->val);
4687 /* Operator : + or += */
4688 if ((lltok_getTok (op) == TPLUS) || (lltok_getTok(op) == ADD_ASSIGN)) {
4689 if (sRef_getSize(e2->sref) >= val) {/* Incrementing the pointer by
4690 val should not result in a
4691 size < 0 (size = 0 is ok !) */
4693 sRef_setSize (ret->sref, sRef_getSize(e2->sref) - val);
4695 if (sRef_getLen(e2->sref) == val) { /* i.e. the character at posn val is \0 */
4696 sRef_setNotNullTerminatedState(ret->sref);
4697 sRef_resetLen (ret->sref);
4699 sRef_setNullTerminatedState(ret->sref);
4700 sRef_setLen (ret->sref, sRef_getLen(e2->sref) - val);
4705 /* Operator : - or -= */
4706 if ((lltok_getTok (op) == TMINUS) || (lltok_getTok (op) == SUB_ASSIGN)) {
4707 if (sRef_getSize(e2->sref) >= 0) {
4708 sRef_setSize (ret->sref, sRef_getSize(e2->sref) + val);
4709 sRef_setLen (ret->sref, sRef_getLen(e2->sref) + val);
4714 /* end modifications */
4716 sRef_setNullError (ret->sref);
4719 ** Fixed for 2.2c: the alias state of ptr + int is dependent,
4720 ** since is points to storage that should not be deallocated
4721 ** through this pointer.
4724 if (sRef_isOnly (ret->sref)
4725 || sRef_isFresh (ret->sref)) {
4726 sRef_setAliasKind (ret->sref, AK_DEPENDENT, exprNode_loc (ret));
4730 ret->sref = e2->sref;
4734 tret = checkNumerics (tr1, tr2, te1, te2, e1, e2, op);
4739 case LEFT_ASSIGN: /* Shifts: should be unsigned values */
4743 case TAMPERSAND: /* bitwise & */
4745 case TCIRC: /* ^ (XOR) */
4750 bool reported = FALSE;
4751 flagcode code = FLG_BITWISEOPS;
4753 if (opid == LEFT_OP || opid == LEFT_ASSIGN
4754 || opid == RIGHT_OP || opid == RIGHT_ASSIGN) {
4755 code = FLG_SHIFTSIGNED;
4758 if (!ctype_isUnsigned (tr1))
4760 if (exprNode_isNonNegative (e1)) {
4763 reported = optgenerror
4765 message ("Left operand of %s is not unsigned value (%t): %s",
4766 lltok_unparse (op), te1,
4767 exprNode_unparse (ret)),
4777 /* right need not be signed for shifts */
4778 if (code != FLG_SHIFTSIGNED
4779 && !ctype_isUnsigned (tr2))
4781 if (!exprNode_isNonNegative (e2)) {
4782 reported = optgenerror
4784 message ("Right operand of %s is not unsigned value (%t): %s",
4785 lltok_unparse (op), te2,
4786 exprNode_unparse (ret)),
4794 if (!checkIntegral (e1, e2, ret, op)) {
4795 te1 = ctype_unknown;
4799 DPRINTF (("Set: %s", ctype_unparse (te1)));
4802 ** tret is the widest type of te1 and te2
4805 tret = ctype_widest (te1, te2);
4810 if (checkIntegral (e1, e2, ret, op)) {
4813 tret = ctype_unknown;
4818 case TLT: /* comparisons */
4819 case TGT: /* numeric, numeric -> bool */
4820 if ((ctype_isReal (tr1) && !ctype_isInt (tr1))
4821 || (ctype_isReal (tr2) && !ctype_isInt (tr2)))
4824 bool fepsilon = FALSE;
4826 if (!ctype_isReal (rtype) || ctype_isInt (rtype))
4831 if (opid == TLT || opid == TGT)
4833 uentry ue1 = exprNode_getUentry (e1);
4834 uentry ue2 = exprNode_getUentry (e2);
4837 ** FLT_EPSILON, etc. really is a variable, not
4841 if (uentry_isVariable (ue1))
4843 cstring uname = uentry_rawName (ue1);
4845 if (cstring_equalLit (uname, "FLT_EPSILON")
4846 || cstring_equalLit (uname, "DBL_EPSILON")
4847 || cstring_equalLit (uname, "LDBL_EPSILON"))
4853 if (uentry_isVariable (ue2))
4855 cstring uname = uentry_rawName (ue2);
4857 if (cstring_equalLit (uname, "FLT_EPSILON")
4858 || cstring_equalLit (uname, "DBL_EPSILON")
4859 || cstring_equalLit (uname, "LDBL_EPSILON"))
4868 ; /* Don't complain. */
4874 message ("Dangerous comparison involving %s types: %s",
4875 ctype_unparse (rtype),
4876 exprNode_unparse (ret)),
4885 ** Types should match.
4888 if (!exprNode_matchTypes (e1, e2))
4890 hasError = gentypeerror
4892 message ("Operands of %s have incompatible types (%t, %t): %s",
4893 lltok_unparse (op), te1, te2, exprNode_unparse (ret)),
4899 || (ctype_isForceRealNumeric (&tr1)
4900 && ctype_isForceRealNumeric (&tr2)) ||
4901 (ctype_isRealPointer (tr1) && ctype_isRealPointer (tr2)))
4907 if ((ctype_isRealNumeric (tr1) && ctype_isRealPointer (tr2)) ||
4908 (ctype_isRealPointer (tr1) && ctype_isRealNumeric (tr2)))
4912 message ("Comparison of pointer and numeric (%t, %t): %s",
4913 te1, te2, exprNode_unparse (ret)),
4918 (void) checkNumerics (tr1, tr2, te1, te2, e1, e2, op);
4923 /* EQ_OP should NOT be used with booleans (unless one is FALSE) */
4925 if ((opid == EQ_OP || opid == NE_OP) &&
4926 ctype_isDirectBool (tr1) && ctype_isDirectBool (tr2))
4929 ** is one a variable?
4932 if (uentry_isVariable (exprNode_getUentry (e1))
4933 || uentry_isVariable (exprNode_getUentry (e2)))
4936 ** comparisons with FALSE are okay
4939 if (exprNode_isFalseConstant (e1)
4940 || exprNode_isFalseConstant (e2))
4949 ("Use of %q with %s variables (risks inconsistency because "
4950 "of multiple true values): %s",
4951 cstring_makeLiteral ((opid == EQ_OP) ? "==" : "!="),
4952 context_printBoolName (), exprNode_unparse (ret)),
4959 case AND_OP: /* bool, bool -> bool */
4962 if (ctype_isForceRealBool (&tr1) && ctype_isForceRealBool (&tr2))
4968 if (context_maybeSet (FLG_BOOLOPS))
4970 if (!ctype_isRealBool (te1) && !ctype_isRealBool (te2))
4972 if (ctype_sameName (te1, te2))
4976 message ("Operands of %s are non-boolean (%t): %s",
4977 lltok_unparse (op), te1,
4978 exprNode_unparse (ret)),
4986 ("Operands of %s are non-booleans (%t, %t): %s",
4987 lltok_unparse (op), te1, te2, exprNode_unparse (ret)),
4991 else if (!ctype_isRealBool (te1))
4995 message ("Left operand of %s is non-boolean (%t): %s",
4996 lltok_unparse (op), te1, exprNode_unparse (ret)),
4999 else if (!ctype_isRealBool (te2))
5003 message ("Right operand of %s is non-boolean (%t): %s",
5004 lltok_unparse (op), te2, exprNode_unparse (ret)),
5017 (cstring_makeLiteral
5018 ("There has been a problem in the parser. This usually results "
5019 "from using an old version of bison (1.25) to build LCLint. "
5020 "Please upgrade your bison implementation to version 1.28."));
5025 DPRINTF (("Return type: %s", ctype_unparse (tret)));
5028 exprNode_checkUse (ret, e1->sref, e1->loc);
5029 exprNode_mergeUSs (ret, e2);
5030 exprNode_checkUse (ret, e2->sref, e2->loc);
5036 exprNode_op (/*@only@*/ exprNode e1, /*@keep@*/ exprNode e2,
5037 /*@only@*/ lltok op)
5041 checkMacroParen (e1);
5042 checkMacroParen (e2);
5044 if (evaluationOrderUndefined (op) && context_maybeSet (FLG_EVALORDER))
5046 checkExpressionDefined (e1, e2, op);
5049 ret = exprNode_makeOp (e1, e2, op);
5054 void exprNode_checkAssignMod (exprNode e1, exprNode ret)
5057 ** This is somewhat bogus!
5059 ** Assigning to a nested observer in a non-observer datatype
5060 ** should not produce an error.
5063 sRef ref = exprNode_getSref (e1);
5065 DPRINTF (("Check assign mod: %s",
5066 sRef_unparseFull (ref)));
5068 if (sRef_isObserver (ref)
5069 || ((sRef_isFileStatic (ref) || sRef_isGlobal (ref))
5070 && ctype_isArray (ctype_realType (sRef_getType (ref)))))
5072 sRef base = sRef_getBase (ref);
5074 if (sRef_isValid (base) && sRef_isObserver (base))
5076 exprNode_checkModify (e1, ret);
5080 exprNode_checkModifyVal (e1, ret);
5085 exprNode_checkModify (e1, ret);
5090 exprNode_assign (/*@only@*/ exprNode e1,
5091 /*@only@*/ exprNode e2, /*@only@*/ lltok op)
5093 bool isalloc = FALSE;
5094 bool isjustalloc = FALSE;
5097 DPRINTF (("%s [%s] <- %s [%s]",
5098 exprNode_unparse (e1),
5099 ctype_unparse (e1->typ),
5100 exprNode_unparse (e2),
5101 ctype_unparse (e2->typ)));
5103 if (lltok_getTok (op) != TASSIGN)
5105 ret = exprNode_makeOp (e1, e2, op);
5109 ret = exprNode_createPartialCopy (e1);
5110 ret->kind = XPR_ASSIGN;
5111 ret->edata = exprData_makeOp (e1, e2, op);
5113 if (!exprNode_isError (e2))
5115 ret->sets = sRefSet_union (ret->sets, e2->sets);
5116 ret->msets = sRefSet_union (ret->msets, e2->msets);
5117 ret->uses = sRefSet_union (ret->uses, e2->uses);
5121 checkExpressionDefined (e1, e2, op);
5123 if (exprNode_isError (e1))
5125 if (!exprNode_isError (e2))
5127 ret->loc = fileloc_update (ret->loc, e2->loc);
5131 ret->loc = fileloc_update (ret->loc, g_currentloc);
5135 if (!exprNode_isError (e2))
5137 checkMacroParen (e2);
5140 if (exprNode_isDefined (e1))
5142 if (sRef_isMacroParamRef (e1->sref))
5144 if (context_inIterDef ())
5146 uentry ue = sRef_getUentry (e1->sref);
5148 if (uentry_isYield (ue))
5154 if (fileloc_isDefined (e1->loc))
5158 message ("Assignment to non-yield iter parameter: %q",
5159 sRef_unparse (e1->sref)),
5166 message ("Assignment to non-yield iter parameter: %q",
5167 sRef_unparse (e1->sref)),
5174 if (fileloc_isDefined (e1->loc))
5178 message ("Assignment to macro parameter: %q",
5179 sRef_unparse (e1->sref)),
5186 message ("Assignment to macro parameter: %q",
5187 sRef_unparse (e1->sref)),
5194 exprNode_checkAssignMod (e1, ret);
5197 if (exprNode_isDefined (e2))
5199 if (lltok_getTok (op) == TASSIGN)
5201 ctype te1 = exprNode_getType (e1);
5202 ctype te2 = exprNode_getType (e2);
5204 if (!ctype_forceMatch (te1, te2))
5206 if (exprNode_matchLiteral (te1, e2))
5214 message ("Assignment of %t to %t: %s %s %s",
5215 te2, te1, exprNode_unparse (e1),
5217 exprNode_unparse (e2)),
5223 exprNode_mergeUSs (ret, e2);
5224 exprNode_checkUse (ret, e2->sref, e2->loc);
5226 doAssign (e1, e2, FALSE);
5227 ret->sref = e1->sref;
5231 if (exprNode_isDefined (e2))
5233 exprNode_mergeUSs (ret, e2);
5234 exprNode_checkUse (ret, e2->sref, e2->loc);
5238 if (sRef_isPointer (e1->sref) && !sRef_isMacroParamRef (e1->sref))
5240 exprNode_checkUse (ret, sRef_getBase (e1->sref), e1->loc);
5243 isjustalloc = sRef_isJustAllocated (e1->sref);
5244 isalloc = sRef_isAllocated (e1->sref);
5246 if (sRef_isField (e1->sref))
5248 sRef root = sRef_getRootBase (sRef_getBase (e1->sref));
5250 if (!sRef_isAllocated (root) && !sRef_isMacroParamRef (root))
5252 exprNode_checkUse (ret, root, e1->loc);
5258 ** be careful! this defines e1->sref.
5261 if (!sRef_isMacroParamRef (e1->sref))
5263 exprNode_checkSet (ret, e1->sref);
5268 sRef_setAllocatedComplete (e1->sref, exprNode_isDefined (e2)
5269 ? e2->loc : e1->loc);
5275 sRef_setAllocatedShallowComplete (e1->sref, exprNode_loc (e2));
5284 exprNode_cond (/*@keep@*/ exprNode pred, /*@keep@*/ exprNode ifclause,
5285 /*@keep@*/ exprNode elseclause)
5289 if (!exprNode_isError (pred))
5291 ret = exprNode_createPartialCopy (pred);
5292 checkMacroParen (pred);
5293 exprNode_checkPred (cstring_makeLiteralTemp ("conditional"), pred);
5295 if (!exprNode_isError (ifclause))
5297 checkMacroParen (ifclause); /* update macro counts! */
5299 if (!exprNode_isError (elseclause))
5301 checkMacroParen (elseclause);
5303 if (!exprNode_matchTypes (ifclause, elseclause))
5306 (exprNode_getType (ifclause),
5308 exprNode_getType (elseclause),
5310 message ("Conditional clauses are not of same type: "
5312 exprNode_unparse (ifclause),
5313 exprNode_getType (ifclause),
5314 exprNode_unparse (elseclause),
5315 exprNode_getType (elseclause)),
5318 ret->sref = sRef_undefined;
5319 ret->typ = ctype_unknown;
5324 /* for now...should merge the states */
5325 ret->sref = ifclause->sref;
5326 ret->typ = ifclause->typ;
5328 if (exprNode_isNullValue (ifclause))
5330 ret->typ = elseclause->typ;
5334 exprNode_checkUse (ret, pred->sref, pred->loc);
5335 exprNode_checkUse (ifclause, ifclause->sref, ifclause->loc);
5336 exprNode_checkUse (elseclause, elseclause->sref, elseclause->loc);
5338 exprNode_mergeCondUSs (ret, ifclause, elseclause);
5343 ret->typ = ifclause->typ;
5345 exprNode_checkUse (pred, pred->sref, pred->loc);
5346 exprNode_checkUse (ifclause, ifclause->sref, ifclause->loc);
5348 exprNode_mergeCondUSs (ret, ifclause, exprNode_undefined);
5353 if (!exprNode_isError (elseclause))
5355 ret->typ = elseclause->typ;
5357 exprNode_checkUse (pred, pred->sref, pred->loc);
5358 exprNode_checkUse (elseclause, elseclause->sref, elseclause->loc);
5360 exprNode_mergeCondUSs (ret, exprNode_undefined, elseclause);
5364 else /* pred is error */
5366 if (!exprNode_isError (ifclause))
5368 ret = exprNode_createSemiCopy (ifclause);
5370 checkMacroParen (ifclause); /* update macro counts! */
5372 if (!exprNode_isError (elseclause))
5374 checkMacroParen (elseclause);
5376 ret->typ = ifclause->typ;
5378 if (!ctype_forceMatch (ifclause->typ, elseclause->typ))
5381 (exprNode_getType (ifclause),
5383 exprNode_getType (elseclause),
5385 message ("Conditional clauses are not of same type: "
5387 exprNode_unparse (ifclause),
5388 exprNode_getType (ifclause),
5389 exprNode_unparse (elseclause),
5390 exprNode_getType (elseclause)),
5393 ret->typ = ctype_unknown;
5397 exprNode_checkUse (ifclause, ifclause->sref, ifclause->loc);
5398 exprNode_checkUse (elseclause, elseclause->sref, elseclause->loc);
5400 exprNode_mergeCondUSs (ret, ifclause, elseclause);
5403 else if (!exprNode_isError (elseclause)) /* pred, if errors */
5405 ret = exprNode_createSemiCopy (ifclause);
5407 ret->typ = elseclause->typ;
5408 checkMacroParen (elseclause);
5410 exprNode_checkUse (elseclause, elseclause->sref, elseclause->loc);
5411 exprNode_mergeCondUSs (ret, exprNode_undefined, elseclause);
5413 else /* all errors! */
5415 ret = exprNode_createLoc (ctype_unknown, g_currentloc);
5419 ret->kind = XPR_COND;
5420 ret->edata = exprData_makeCond (pred, ifclause, elseclause);
5422 if (exprNode_isDefined (ifclause) && exprNode_isDefined (elseclause))
5424 exprNode_combineControl (ret, ifclause, elseclause);
5431 exprNode_vaArg (/*@only@*/ lltok tok, /*@only@*/ exprNode arg, /*@only@*/ qtype qt)
5433 ctype totype = qtype_getType (qt);
5435 exprNode_createPartialLocCopy (arg, fileloc_copy (lltok_getLoc (tok)));
5439 ** check use of va_arg : <valist>, type -> type
5442 if (exprNode_isError (arg))
5447 targ = exprNode_getType (arg);
5450 ** arg should have be a pointer
5453 if (!ctype_isUA (targ) ||
5454 (!usymId_equal (ctype_typeId (targ),
5455 usymtab_getTypeId (cstring_makeLiteralTemp ("va_list")))))
5459 message ("First argument to va_arg is not a va_list (type %t): %s",
5460 targ, exprNode_unparse (arg)),
5464 exprNode_checkSet (ret, arg->sref);
5468 ** return type is totype
5472 ret->kind = XPR_VAARG;
5473 ret->edata = exprData_makeCast (tok, arg, qt);
5478 exprNode exprNode_labelMarker (/*@only@*/ cstring label)
5480 exprNode ret = exprNode_createPlain (ctype_undefined);
5481 ret->kind = XPR_LABEL;
5482 ret->edata = exprData_makeLiteral (label);
5483 ret->isJumpPoint = TRUE;
5485 return (ret); /* for now, ignore label */
5488 exprNode exprNode_notReached (/*@returned@*/ exprNode stmt)
5490 if (exprNode_isDefined (stmt))
5492 stmt->isJumpPoint = TRUE;
5494 /* This prevent stray no return path errors, etc. */
5495 stmt->exitCode = XK_MUSTEXIT;
5501 bool exprNode_isDefaultMarker (exprNode e)
5503 if (exprNode_isDefined (e))
5505 return (e->kind == XPR_DEFAULT || e->kind == XPR_FTDEFAULT);
5511 bool exprNode_isCaseMarker (exprNode e)
5513 if (exprNode_isDefined (e))
5515 return (e->kind == XPR_FTCASE || e->kind == XPR_CASE);
5521 bool exprNode_isLabelMarker (exprNode e)
5523 if (exprNode_isDefined (e))
5525 return (e->kind == XPR_LABEL);
5531 exprNode exprNode_caseMarker (/*@only@*/ exprNode test, bool fallThrough)
5533 exprNode ret = exprNode_createPartialCopy (test);
5535 ret->kind = fallThrough ? XPR_FTCASE : XPR_CASE;
5537 if (exprNode_isError (test)) {
5541 exprNode_checkUse (ret, test->sref, test->loc);
5543 usymtab_setExitCode (ret->exitCode);
5547 usymtab_setMustBreak ();
5550 ret->edata = exprData_makeSingle (test);
5551 ret->isJumpPoint = TRUE;
5557 exprNode exprNode_caseStatement (/*@only@*/ exprNode test, /*@only@*/ exprNode stmt, bool fallThrough)
5559 exprNode ret = exprNode_createPartialCopy (test);
5561 ret->kind = fallThrough ? XPR_FTCASE : XPR_CASE;
5562 ret->edata = exprData_makePair (test, stmt);
5563 ret->isJumpPoint = TRUE;
5565 if (exprNode_isError (test))
5570 exprNode_checkUse (ret, test->sref, test->loc);
5572 if (exprNode_isError (stmt))
5577 exprNode_mergeUSs (ret, stmt);
5579 ret->exitCode = stmt->exitCode;
5580 ret->mustBreak = stmt->mustBreak;
5581 ret->canBreak = stmt->canBreak;
5583 usymtab_setExitCode (ret->exitCode);
5587 usymtab_setMustBreak ();
5594 /*@notnull@*/ /*@only@*/ exprNode
5595 exprNode_defaultMarker (/*@only@*/ lltok def, bool fallThrough)
5597 exprNode ret = exprNode_createTok (def);
5599 ret->isJumpPoint = TRUE;
5600 ret->kind = fallThrough ? XPR_FTDEFAULT : XPR_DEFAULT;
5605 exprNode_mayEscape (exprNode e)
5607 if (exprNode_isDefined (e))
5609 return exitkind_couldEscape (e->exitCode);
5615 exprNode_mustBreak (exprNode e)
5617 if (exprNode_isDefined (e))
5619 return e->mustBreak;
5625 exprNode_mustEscape (exprNode e)
5627 if (exprNode_isDefined (e))
5629 return exitkind_mustEscape (e->exitCode) || exprNode_mustBreak (e);
5636 exprNode_errorEscape (exprNode e)
5638 if (exprNode_isDefined (e))
5640 return exitkind_isError (e->exitCode);
5646 exprNode exprNode_concat (/*@only@*/ exprNode e1, /*@only@*/ exprNode e2)
5648 exprNode ret = exprNode_createPartialCopy (e1);
5650 ret->edata = exprData_makePair (e1, e2);
5651 ret->kind = XPR_STMTLIST;
5653 if (exprNode_isDefined (e1))
5655 ret->isJumpPoint = e1->isJumpPoint;
5656 ret->canBreak = e1->canBreak;
5660 if (exprNode_isDefined (e2))
5662 ret->loc = fileloc_update (ret->loc, e2->loc);
5666 if (exprNode_isDefined (e2))
5668 ret->exitCode = e2->exitCode;
5669 ret->mustBreak = e2->mustBreak;
5670 if (e2->canBreak) ret->canBreak = TRUE;
5674 ** if e1 must return, then e2 is unreachable!
5677 if (exprNode_isDefined (e1) && exprNode_isDefined (e2))
5679 if ((exprNode_mustEscape (e1) || exprNode_mustBreak (e1))
5680 && !(e2->isJumpPoint))
5682 if (context_getFlag (FLG_UNREACHABLE))
5686 if (e2->kind == XPR_STMT)
5688 nr = exprData_getSingle (e2->edata);
5691 if ((nr->kind == XPR_TOK
5692 && lltok_isSemi (exprData_getTok (nr->edata))))
5694 /* okay to have unreachable ";" */
5695 ret->exitCode = XK_MUSTEXIT;
5696 ret->canBreak = TRUE;
5700 if (optgenerror (FLG_UNREACHABLE,
5701 message ("Unreachable code: %s",
5702 exprNode_unparseFirst (nr)),
5705 ret->isJumpPoint = TRUE;
5706 ret->mustBreak = FALSE;
5707 ret->exitCode = XK_ERROR;
5708 DPRINTF (("Jump point: %s", exprNode_unparse (ret)));
5712 ret->exitCode = XK_MUSTEXIT;
5713 ret->canBreak = TRUE;
5721 if ((e2->kind == XPR_CASE || e2->kind == XPR_DEFAULT))
5724 ** We want a warning anytime we have:
5726 ** yyy; <<<- no break or return
5730 exprNode lastStmt = exprNode_lastStatement (e1);
5732 if (exprNode_isDefined (lastStmt)
5733 && !exprNode_mustEscape (lastStmt)
5734 && !exprNode_mustBreak (lastStmt)
5735 && !exprNode_isCaseMarker (lastStmt)
5736 && !exprNode_isDefaultMarker (lastStmt)
5737 && !exprNode_isLabelMarker (lastStmt))
5739 voptgenerror (FLG_CASEBREAK,
5741 ("Fall through case (no preceeding break)"),
5748 exprNode_mergeUSs (ret, e2);
5750 usymtab_setExitCode (ret->exitCode);
5754 usymtab_setMustBreak ();
5760 exprNode exprNode_createTok (/*@only@*/ lltok t)
5762 exprNode ret = exprNode_create (ctype_unknown);
5763 ret->kind = XPR_TOK;
5764 ret->edata = exprData_makeTok (t);
5768 exprNode exprNode_statement (/*@only@*/ exprNode e)
5770 if (!exprNode_isError (e))
5772 exprNode_checkStatement(e);
5775 return (exprNode_statementError (e));
5778 static exprNode exprNode_statementError (/*@only@*/ exprNode e)
5780 exprNode ret = exprNode_createPartialCopy (e);
5782 if (!exprNode_isError (e))
5784 if (e->kind != XPR_ASSIGN)
5786 exprNode_checkUse (ret, e->sref, e->loc);
5789 ret->exitCode = e->exitCode;
5790 ret->canBreak = e->canBreak;
5791 ret->mustBreak = e->mustBreak;
5794 ret->edata = exprData_makeSingle (e);
5795 ret->kind = XPR_STMT;
5800 exprNode exprNode_checkExpr (/*@returned@*/ exprNode e)
5802 if (!exprNode_isError (e))
5804 if (e->kind != XPR_ASSIGN)
5806 exprNode_checkUse (e, e->sref, e->loc);
5813 void exprNode_produceGuards (exprNode pred)
5815 if (!exprNode_isError (pred))
5817 if (ctype_isRealPointer (pred->typ))
5819 pred->guards = guardSet_addTrueGuard (pred->guards, pred->sref);
5822 exprNode_checkUse (pred, pred->sref, pred->loc);
5823 exprNode_resetSref (pred);
5827 exprNode exprNode_makeBlock (/*@only@*/ exprNode e)
5829 exprNode ret = exprNode_createPartialCopy (e);
5831 if (!exprNode_isError (e))
5833 ret->exitCode = e->exitCode;
5834 ret->canBreak = e->canBreak;
5835 ret->mustBreak = e->mustBreak;
5838 ret->edata = exprData_makeSingle (e);
5839 ret->kind = XPR_BLOCK;
5843 bool exprNode_isBlock (exprNode e)
5845 return (exprNode_isDefined (e)
5846 && ((e)->kind == XPR_BLOCK));
5849 bool exprNode_isAssign (exprNode e)
5851 if (exprNode_isDefined (e))
5853 return (e->kind == XPR_ASSIGN);
5859 bool exprNode_isEmptyStatement (exprNode e)
5861 return (exprNode_isDefined (e)
5862 && (e->kind == XPR_TOK)
5863 && (lltok_isSemi (exprData_getTok (e->edata))));
5866 exprNode exprNode_if (/*@only@*/ exprNode pred, /*@only@*/ exprNode tclause)
5869 bool emptyErr = FALSE;
5871 if (context_maybeSet (FLG_IFEMPTY))
5873 if (exprNode_isEmptyStatement (tclause))
5875 emptyErr = optgenerror (FLG_IFEMPTY,
5877 ("Body of if statement is empty"),
5878 exprNode_loc (tclause));
5882 if (!emptyErr && context_maybeSet (FLG_IFBLOCK))
5884 if (exprNode_isDefined (tclause)
5885 && !exprNode_isBlock (tclause))
5887 voptgenerror (FLG_IFBLOCK,
5889 ("Body of if statement is not a block: %s",
5890 exprNode_unparse (tclause)),
5891 exprNode_loc (tclause));
5895 if (exprNode_isError (pred))
5897 if (exprNode_isError (tclause))
5899 ret = exprNode_createLoc (ctype_unknown, g_currentloc);
5903 ret = exprNode_createPartialCopy (tclause);
5908 if (exprNode_mustEscape (pred))
5912 message ("Predicate always exits: %s", exprNode_unparse (pred)),
5913 exprNode_loc (pred));
5916 exprNode_checkPred (cstring_makeLiteralTemp ("if"), pred);
5917 exprNode_checkUse (pred, pred->sref, pred->loc);
5919 if (!exprNode_isError (tclause))
5921 exprNode_mergeCondUSs (pred, tclause, exprNode_undefined);
5924 ret = exprNode_createPartialCopy (pred);
5928 ret->edata = exprData_makePair (pred, tclause);
5930 ret->exitCode = XK_UNKNOWN;
5932 if (exprNode_isDefined (tclause))
5934 ret->exitCode = exitkind_makeConditional (tclause->exitCode);
5935 ret->canBreak = tclause->canBreak;
5936 ret->sets = sRefSet_union (ret->sets, tclause->sets);
5937 ret->msets = sRefSet_union (ret->msets, tclause->msets);
5938 ret->uses = sRefSet_union (ret->uses, tclause->uses);
5941 ret->mustBreak = FALSE;
5946 exprNode exprNode_ifelse (/*@only@*/ exprNode pred,
5947 /*@only@*/ exprNode tclause,
5948 /*@only@*/ exprNode eclause)
5951 bool tEmptyErr = FALSE;
5952 bool eEmptyErr = FALSE;
5954 if (context_maybeSet (FLG_IFEMPTY))
5956 if (exprNode_isEmptyStatement (tclause))
5958 tEmptyErr = optgenerror
5961 ("Body of if clause of if statement is empty"),
5962 exprNode_loc (tclause));
5965 if (exprNode_isEmptyStatement (eclause))
5967 eEmptyErr = optgenerror
5970 ("Body of else clause of if statement is empty"),
5971 exprNode_loc (eclause));
5975 if (context_maybeSet (FLG_IFBLOCK))
5978 && exprNode_isDefined (tclause)
5979 && !exprNode_isBlock (tclause))
5981 voptgenerror (FLG_IFBLOCK,
5983 ("Body of if clause of if statement is not a block: %s",
5984 exprNode_unparse (tclause)),
5985 exprNode_loc (tclause));
5989 && exprNode_isDefined (eclause)
5990 && !exprNode_isBlock (eclause)
5991 && !(eclause->kind == XPR_IF)
5992 && !(eclause->kind == XPR_IFELSE))
5997 ("Body of else clause of if statement is not a block: %s",
5998 exprNode_unparse (eclause)),
5999 exprNode_loc (eclause));
6003 if (context_maybeSet (FLG_ELSEIFCOMPLETE))
6005 if (exprNode_isDefined (eclause)
6006 && (eclause->kind == XPR_IF))
6008 voptgenerror (FLG_ELSEIFCOMPLETE,
6009 message ("Incomplete else if logic (no final else): %s",
6010 exprNode_unparse (eclause)),
6011 exprNode_loc (eclause));
6015 if (exprNode_isError (pred))
6017 if (exprNode_isError (tclause))
6019 if (exprNode_isError (eclause))
6021 ret = exprNode_createLoc (ctype_unknown, g_currentloc);
6025 ret = exprNode_createPartialCopy (eclause);
6030 ret = exprNode_createPartialCopy (tclause);
6033 else /* pred is okay */
6035 ret = exprNode_createPartialCopy (pred);
6037 if (exprNode_mustEscape (pred))
6041 message ("Predicate always exits: %s", exprNode_unparse (pred)),
6042 exprNode_loc (pred));
6045 exprNode_checkPred (cstring_makeLiteralTemp ("if"), pred);
6046 exprNode_checkUse (ret, pred->sref, pred->loc);
6048 exprNode_mergeCondUSs (ret, tclause, eclause);
6051 ret->kind = XPR_IFELSE;
6052 ret->edata = exprData_makeCond (pred, tclause, eclause);
6054 if (exprNode_isDefined (tclause) && exprNode_isDefined (eclause))
6056 exprNode_combineControl (ret, tclause, eclause);
6057 ret->loc = fileloc_update (ret->loc, eclause->loc);
6064 ** *allpaths <- TRUE iff all executions paths must go through the switch
6068 checkSwitchExpr (exprNode test, /*@dependent@*/ exprNode e, /*@out@*/ bool *allpaths)
6070 exprNodeSList el = exprNode_flatten (e);
6071 bool mustReturn = TRUE; /* find a branch that doesn't */
6072 bool thisReturn = FALSE;
6073 bool hasDefault = FALSE;
6074 bool hasAllMembers = FALSE;
6075 bool inSwitch = FALSE;
6076 bool isEnumSwitch = FALSE;
6077 bool canBreak = FALSE;
6078 bool fallThrough = FALSE;
6079 ctype ct = ctype_unknown;
6080 enumNameSList usedEnums;
6083 if (exprNode_isDefined (test))
6088 ttype = ctype_realType (ct);
6090 if (ctype_isEnum (ttype))
6092 isEnumSwitch = TRUE;
6093 enums = ctype_elist (ttype);
6094 usedEnums = enumNameSList_new ();
6098 exprNodeSList_elements (el, current)
6100 if (exprNode_isDefined (current))
6102 switch (current->kind)
6110 message ("Duplicate default cases in switch"),
6111 exprNode_loc (current));
6116 if (current->kind == XPR_DEFAULT || current->kind == XPR_FTDEFAULT)
6124 exprNode st = exprData_getSingle (current->edata);
6125 uentry ue = exprNode_getUentry (st);
6127 if (uentry_isValid (ue))
6129 cstring cname = uentry_rawName (ue);
6131 if (enumNameList_member (/*@-usedef@*/enums/*@=usedef@*/, cname))
6133 if (enumNameSList_member
6134 (/*@-usedef@*/usedEnums/*@=usedef@*/, cname))
6138 message ("Duplicate case in switch: %s",
6144 enumNameSList_addh (usedEnums, cname);
6151 message ("Case in switch not %s member: %s",
6152 ctype_unparse (ct), cname),
6159 if (inSwitch && !fallThrough)
6161 if (!thisReturn || canBreak)
6171 /*@switchbreak@*/ break;
6173 thisReturn = thisReturn || exprNode_mustEscape (current);
6174 canBreak = canBreak || current->canBreak;
6175 if (canBreak) fallThrough = FALSE;
6178 } end_exprNodeSList_elements;
6180 if (inSwitch) /* check the last one! */
6182 if (!thisReturn || canBreak)
6191 && (enumNameSList_size (/*@-usedef@*/usedEnums/*@=usedef@*/) !=
6192 enumNameList_size (/*@-usedef@*/enums/*@=usedef@*/)))
6194 enumNameSList unused = enumNameSList_subtract (enums, usedEnums);
6196 voptgenerror (FLG_MISSCASE,
6197 message ("Missing case%s in switch: %q",
6198 cstring_makeLiteralTemp
6199 ((enumNameSList_size (unused) > 1) ? "s" : ""),
6200 enumNameSList_unparse (unused)),
6203 enumNameSList_free (unused);
6207 hasAllMembers = TRUE;
6211 enumNameSList_free (usedEnums);
6215 *allpaths = hasDefault;
6218 exprNodeSList_free (el);
6219 return ((hasDefault || hasAllMembers) && mustReturn);
6222 exprNode exprNode_switch (/*@only@*/ exprNode e, /*@only@*/ exprNode s)
6224 exprNode ret = exprNode_createPartialCopy (e);
6227 DPRINTF (("Switch: %s", exprNode_unparse (s)));
6229 ret->kind = XPR_SWITCH;
6230 ret->edata = exprData_makePair (e, s);
6232 if (!exprNode_isError (s))
6234 exprNode fs = exprNode_firstStatement (s);
6235 ret->loc = fileloc_update (ret->loc, s->loc);
6237 if (exprNode_isUndefined (fs)
6238 || exprNode_isCaseMarker (fs) || exprNode_isLabelMarker (fs)
6239 || exprNode_isDefaultMarker (fs)) {
6242 voptgenerror (FLG_FIRSTCASE,
6244 ("Statement after switch is not a case: %s", exprNode_unparse (fs)),
6249 if (!exprNode_isError (e))
6251 if (checkSwitchExpr (e, s, &allpaths))
6253 ret->exitCode = XK_MUSTRETURN;
6257 ret->exitCode = e->exitCode;
6260 ret->canBreak = e->canBreak;
6261 ret->mustBreak = e->mustBreak;
6265 ** exprNode.c:3883,32: Variable allpaths used before definition
6272 DPRINTF (("Context exit switch!"));
6273 context_exitSwitch (ret, allpaths);
6274 DPRINTF (("Context exit switch done!"));
6279 static void checkInfiniteLoop (/*@notnull@*/ exprNode test,
6280 /*@notnull@*/ exprNode body)
6282 sRefSet tuses = test->uses;
6284 if (!sRefSet_isEmpty (test->uses))
6286 sRefSet sets = sRefSet_newCopy (body->sets);
6287 bool hasError = TRUE;
6288 bool innerState = FALSE;
6289 sRefSet tuncon = sRefSet_undefined;
6291 sets = sRefSet_union (sets, test->sets);
6292 sets = sRefSet_union (sets, body->msets);
6293 sets = sRefSet_union (sets, test->msets);
6295 sRefSet_allElements (tuses, el)
6297 if (sRef_isUnconstrained (el))
6299 tuncon = sRefSet_insert (tuncon, el);
6303 if (sRefSet_member (sets, el))
6310 if (sRef_isInternalState (el)
6311 || sRef_isFileStatic (sRef_getRootBase (el)))
6315 } end_sRefSet_allElements ;
6319 sRefSet suncon = sRefSet_undefined;
6320 bool sinner = FALSE;
6322 sRefSet_allElements (sets, el)
6324 if (sRef_isUnconstrained (el))
6326 suncon = sRefSet_insert (suncon, el);
6328 else if (sRef_isInternalState (el))
6336 } end_sRefSet_allElements ;
6338 if (sinner && innerState)
6342 else if (sRefSet_isEmpty (tuncon)
6343 && sRefSet_isEmpty (suncon))
6348 ("Suspected infinite loop. No value used in loop test (%q) "
6349 "is modified by test or loop body.",
6350 sRefSet_unparsePlain (tuses)),
6355 if (sRefSet_isEmpty (tuncon))
6359 message ("Suspected infinite loop. No condition values "
6360 "modified. Modification possible through "
6361 "unconstrained calls: %q",
6362 sRefSet_unparsePlain (suncon)),
6369 message ("Suspected infinite loop. No condition values "
6370 "modified. Possible undetected dependency through "
6371 "unconstrained calls in loop test: %q",
6372 sRefSet_unparsePlain (tuncon)),
6378 sRefSet_free (sets);
6382 exprNode exprNode_while (/*@keep@*/ exprNode t, /*@keep@*/ exprNode b)
6385 bool emptyErr = FALSE;
6387 if (context_maybeSet (FLG_WHILEEMPTY))
6389 if (exprNode_isEmptyStatement (b))
6391 emptyErr = optgenerror
6394 ("Body of while statement is empty"),
6399 if (!emptyErr && context_maybeSet (FLG_WHILEBLOCK))
6401 if (exprNode_isDefined (b)
6402 && !exprNode_isBlock (b))
6404 if (context_inIterDef ()
6405 && (b->kind == XPR_STMTLIST
6406 || b->kind == XPR_TOK))
6412 voptgenerror (FLG_WHILEBLOCK,
6414 ("Body of while statement is not a block: %s",
6415 exprNode_unparse (b)),
6421 if (exprNode_isError (t))
6423 if (exprNode_isError (b))
6425 ret = exprNode_createLoc (ctype_unknown, g_currentloc);
6429 ret = exprNode_createPartialCopy (b);
6436 ret = exprNode_createPartialCopy (t);
6438 llassert (t->kind == XPR_WHILEPRED);
6440 test = exprData_getSingle (t->edata);
6442 if (!exprNode_isError (b) && exprNode_isDefined (test))
6444 if (context_maybeSet (FLG_INFLOOPS)
6445 || context_maybeSet (FLG_INFLOOPSUNCON))
6448 ** check that some variable in the predicate is set by the body
6449 ** if the predicate uses any variables
6452 checkInfiniteLoop (test, b);
6455 exprNode_mergeUSs (ret, b);
6457 if (exprNode_isDefined (b))
6459 ret->exitCode = exitkind_makeConditional (b->exitCode);
6464 ret->edata = exprData_makePair (t, b);
6465 ret->kind = XPR_WHILE;
6467 if (exprNode_isDefined (t) && exprNode_mustEscape (t))
6471 message ("Predicate always exits: %s", exprNode_unparse (t)),
6475 ret->exitCode = XK_NEVERESCAPE;
6478 ** If loop is infinite, and there is no break inside,
6479 ** exit code is never reach.
6482 if (exprNode_knownIntValue (t))
6484 if (!exprNode_isZero (t))
6486 if (exprNode_isDefined (b))
6490 /* Really, it means never reached. */
6491 ret->exitCode = XK_MUSTEXIT;
6501 ret->canBreak = FALSE;
6502 ret->mustBreak = FALSE;
6508 ** do { b } while (t);
6510 ** note: body passed as first argument
6513 exprNode exprNode_doWhile (/*@only@*/ exprNode b, /*@only@*/ exprNode t)
6517 if (exprNode_isError (t))
6519 if (exprNode_isError (b))
6521 ret = exprNode_createLoc (ctype_unknown, g_currentloc);
6525 ret = exprNode_createPartialCopy (b);
6527 ret->exitCode = exitkind_makeConditional (b->exitCode);
6528 exprNode_checkUse (ret, b->sref, b->loc);
6529 ret->exitCode = b->exitCode;
6530 ret->canBreak = b->canBreak;
6531 ret->mustBreak = b->mustBreak;
6536 ret = exprNode_createPartialCopy (t);
6537 exprNode_checkPred (cstring_makeLiteralTemp ("while"), t);
6539 if (!exprNode_isError (b))
6542 ** forgot the copy's --- why wasn't this detected??
6545 ret->sets = sRefSet_copy (ret->sets, b->sets);
6546 ret->msets = sRefSet_copy (ret->msets, b->msets);
6547 ret->uses = sRefSet_copy (ret->uses, b->uses);
6549 /* left this out --- causes and aliasing bug (infinite loop)
6550 should be detected?? */
6552 exprNode_checkUse (ret, b->sref, b->loc);
6553 exprNode_mergeUSs (ret, t);
6554 exprNode_checkUse (ret, t->sref, t->loc);
6556 ret->exitCode = b->exitCode;
6557 ret->canBreak = b->canBreak;
6558 ret->mustBreak = b->mustBreak;
6562 context_exitDoWhileClause (t);
6564 ret->kind = XPR_DOWHILE;
6565 ret->edata = exprData_makePair (t, b);
6569 exprNode exprNode_for (/*@keep@*/ exprNode inc, /*@keep@*/ exprNode body)
6572 bool emptyErr = FALSE;
6574 if (context_maybeSet (FLG_FOREMPTY))
6576 if (exprNode_isEmptyStatement (body))
6578 emptyErr = optgenerror
6581 ("Body of for statement is empty"),
6582 exprNode_loc (body));
6586 if (!emptyErr && context_maybeSet (FLG_FORBLOCK))
6588 if (exprNode_isDefined (body)
6589 && !exprNode_isBlock (body))
6591 if (context_inIterDef ()
6592 && (body->kind == XPR_STMTLIST
6593 || body->kind == XPR_TOK))
6599 voptgenerror (FLG_FORBLOCK,
6601 ("Body of for statement is not a block: %s",
6602 exprNode_unparse (body)),
6603 exprNode_loc (body));
6609 ** for ud purposes: (alreadly) init -> test -> (now) LOOP: body + inc + test
6612 if (exprNode_isError (body))
6614 ret = exprNode_createPartialCopy (inc);
6618 ret = exprNode_createPartialCopy (body);
6620 ret->exitCode = exitkind_makeConditional (body->exitCode);
6622 exprNode_mergeUSs (inc, body);
6624 if (exprNode_isDefined (inc))
6628 context_setMessageAnnote (cstring_makeLiteral ("in post loop increment"));
6631 tmp = exprNode_effect (exprData_getTripleInc (inc->edata));
6632 exprNode_freeShallow (tmp);
6634 context_clearMessageAnnote ();
6635 context_setMessageAnnote (cstring_makeLiteral ("in post loop test"));
6637 tmp = exprNode_effect (exprData_getTripleTest (inc->edata));
6638 exprNode_freeShallow (tmp);
6640 context_clearMessageAnnote ();
6642 ret->uses = sRefSet_copy (ret->uses, inc->uses);
6643 ret->sets = sRefSet_copy (ret->sets, inc->sets);
6644 ret->msets = sRefSet_copy (ret->msets, inc->msets);
6648 ret->kind = XPR_FOR;
6649 ret->edata = exprData_makePair (inc, body);
6651 if (exprNode_isDefined (inc)) {
6652 exprNode test = exprData_getTripleTest (inc->edata);
6654 if (exprNode_isUndefined (test)) {
6655 if (exprNode_isDefined (body)) {
6656 if (!body->canBreak) {
6657 /* Really, it means never reached. */
6658 ret->exitCode = XK_MUSTEXIT;
6668 ** for (init; test; inc)
6671 ** while (test) { body; inc; }
6673 ** Now: check use of init (may set vars for test)
6674 ** check use of test
6678 /*@observer@*/ guardSet exprNode_getForGuards (exprNode pred)
6682 if (exprNode_isError (pred)) return guardSet_undefined;
6684 llassert (pred->kind == XPR_FORPRED);
6686 test = exprData_getTripleTest (pred->edata);
6688 if (!exprNode_isError (test))
6690 return (test->guards);
6693 return guardSet_undefined;
6696 exprNode exprNode_whilePred (/*@only@*/ exprNode test)
6698 exprNode ret = exprNode_createSemiCopy (test);
6700 if (exprNode_isDefined (test))
6702 exprNode_copySets (ret, test);
6703 exprNode_checkPred (cstring_makeLiteralTemp ("while"), test);
6704 exprNode_checkUse (ret, test->sref, test->loc);
6706 exprNode_produceGuards (test);
6708 ret->guards = guardSet_copy (test->guards);
6711 ret->edata = exprData_makeSingle (test);
6712 ret->kind = XPR_WHILEPRED;
6716 exprNode exprNode_forPred (/*@only@*/ exprNode init, /*@only@*/ exprNode test,
6717 /*@only@*/ exprNode inc)
6722 ** for ud purposes: init -> test -> LOOP: [ body, inc ]
6725 exprNode_checkPred (cstring_makeLiteralTemp ("for"), test);
6727 if (!exprNode_isError (inc))
6729 ret = exprNode_createPartialCopy (inc);
6733 if (!exprNode_isError (init))
6735 ret = exprNode_createPartialCopy (init);
6737 else if (!exprNode_isError (test))
6739 ret = exprNode_createPartialCopy (test);
6743 ret = exprNode_createUnknown ();
6747 exprNode_mergeUSs (ret, init);
6749 if (exprNode_isDefined (init))
6751 exprNode_checkUse (ret, init->sref, init->loc);
6754 exprNode_mergeUSs (ret, test);
6756 if (exprNode_isDefined (test))
6758 exprNode_checkUse (ret, test->sref, test->loc);
6761 ret->kind = XPR_FORPRED;
6762 ret->edata = exprData_makeFor (init, test, inc);
6766 /*@notnull@*/ /*@only@*/ exprNode exprNode_goto (/*@only@*/ cstring label)
6768 exprNode ret = exprNode_createUnknown ();
6770 if (context_inMacro ())
6772 voptgenerror (FLG_MACROSTMT,
6773 message ("Macro %s uses goto (not functional)",
6774 context_inFunctionName ()),
6778 ret->kind = XPR_GOTO;
6779 ret->edata = exprData_makeLiteral (label);
6780 ret->mustBreak = TRUE;
6781 ret->exitCode = XK_GOTO;
6782 ret->canBreak = TRUE;
6786 exprNode exprNode_continue (/*@only@*/ lltok l, int qcontinue)
6788 exprNode ret = exprNode_createLoc (ctype_unknown, fileloc_copy (lltok_getLoc (l)));
6790 ret->kind = XPR_CONTINUE;
6791 ret->edata = exprData_makeTok (l);
6792 ret->canBreak = TRUE;
6793 ret->mustBreak = TRUE;
6795 if (qcontinue == QSAFEBREAK)
6799 else if (qcontinue == QINNERCONTINUE)
6801 if (!context_inDeepLoop ())
6804 (FLG_LOOPLOOPCONTINUE,
6805 cstring_makeLiteral ("Continue statement marked with innercontinue "
6806 "is not inside a nested loop"),
6807 exprNode_loc (ret));
6810 else if (qcontinue == BADTOK)
6812 if (context_inDeepLoop ())
6815 (FLG_LOOPLOOPCONTINUE,
6816 cstring_makeLiteral ("Continue statement in nested loop"),
6817 exprNode_loc (ret));
6822 llbuglit ("exprNode_continue: bad qcontinue");
6828 exprNode exprNode_break (/*@only@*/ lltok l, int bqual)
6830 exprNode ret = exprNode_createLoc (ctype_unknown, fileloc_copy (lltok_getLoc (l)));
6831 clause breakClause = context_breakClause ();
6833 ret->kind = XPR_BREAK;
6834 ret->edata = exprData_makeTok (l);
6835 ret->canBreak = TRUE;
6836 ret->mustBreak = TRUE;
6838 if (breakClause == NOCLAUSE)
6842 cstring_makeLiteral ("Break not inside while, for or switch statement"),
6843 exprNode_loc (ret));
6847 if (bqual != BADTOK)
6854 if (breakClause == SWITCHCLAUSE)
6856 if (!context_inDeepSwitch ())
6858 voptgenerror (FLG_SYNTAX,
6860 ("Break preceded by innerbreak is not in a deep switch"),
6861 exprNode_loc (ret));
6866 if (!context_inDeepLoop ())
6868 voptgenerror (FLG_SYNTAX,
6870 ("Break preceded by innerbreak is not in a deep loop"),
6871 exprNode_loc (ret));
6876 if (breakClause == SWITCHCLAUSE)
6878 voptgenerror (FLG_SYNTAX,
6880 ("Break preceded by loopbreak is breaking a switch"),
6881 exprNode_loc (ret));
6885 if (breakClause != SWITCHCLAUSE)
6889 message ("Break preceded by switchbreak is breaking %s",
6890 cstring_makeLiteralTemp
6891 ((breakClause == WHILECLAUSE
6892 || breakClause == DOWHILECLAUSE) ? "a while loop"
6893 : (breakClause == FORCLAUSE) ? "a for loop"
6894 : (breakClause == ITERCLAUSE) ? "an iterator"
6896 exprNode_loc (ret));
6904 if (breakClause == SWITCHCLAUSE)
6906 clause nextBreakClause = context_nextBreakClause ();
6908 switch (nextBreakClause)
6910 case NOCLAUSE: break;
6916 (FLG_LOOPSWITCHBREAK,
6917 cstring_makeLiteral ("Break statement in switch inside loop"),
6918 exprNode_loc (ret));
6922 (FLG_SWITCHSWITCHBREAK,
6923 cstring_makeLiteral ("Break statement in switch inside switch"),
6924 exprNode_loc (ret));
6931 if (context_inDeepLoop ())
6935 cstring_makeLiteral ("Break statement in nested loop"),
6936 exprNode_loc (ret));
6940 if (context_inDeepLoopSwitch ())
6943 (FLG_SWITCHLOOPBREAK,
6944 cstring_makeLiteral ("Break statement in loop inside switch"),
6945 exprNode_loc (ret));
6955 exprNode exprNode_nullReturn (/*@only@*/ lltok t)
6957 fileloc loc = lltok_getLoc (t);
6958 exprNode ret = exprNode_createLoc (ctype_unknown, fileloc_copy (loc));
6960 context_returnFunction ();
6961 exprChecks_checkNullReturn (loc);
6963 ret->kind = XPR_NULLRETURN;
6964 ret->edata = exprData_makeTok (t);
6965 ret->exitCode = XK_MUSTRETURN;
6969 exprNode exprNode_return (/*@only@*/ exprNode e)
6973 if (exprNode_isError (e))
6975 ret = exprNode_createUnknown ();
6979 ret = exprNode_createLoc (ctype_unknown, fileloc_copy (e->loc));
6981 exprNode_checkUse (ret, e->sref, e->loc);
6982 exprNode_checkReturn (e);
6985 context_returnFunction ();
6986 ret->kind = XPR_RETURN;
6987 ret->edata = exprData_makeSingle (e);
6988 ret->exitCode = XK_MUSTRETURN;
6993 exprNode exprNode_comma (/*@only@*/ exprNode e1, /*@only@*/ exprNode e2)
6997 if (exprNode_isError (e1))
6999 if (exprNode_isError (e2))
7001 ret = exprNode_createLoc (ctype_unknown, g_currentloc);
7005 ret = exprNode_createPartialCopy (e2);
7006 exprNode_checkUse (ret, e2->sref, e2->loc);
7007 ret->sref = e2->sref;
7012 ret = exprNode_createPartialCopy (e1);
7014 exprNode_checkUse (ret, e1->sref, e1->loc);
7016 if (!exprNode_isError (e2))
7018 exprNode_mergeUSs (ret, e2);
7019 exprNode_checkUse (ret, e2->sref, e2->loc);
7020 ret->sref = e2->sref;
7024 ret->kind = XPR_COMMA;
7025 ret->edata = exprData_makePair (e1, e2);
7027 if (exprNode_isDefined (e1))
7029 if (exprNode_isDefined (e2))
7033 if (exprNode_mustEscape (e1) || e1->mustBreak)
7037 message ("Second clause of comma expression is unreachable: %s",
7038 exprNode_unparse (e2)),
7042 ret->exitCode = exitkind_combine (e1->exitCode, e2->exitCode);
7043 ret->mustBreak = e1->mustBreak || e2->mustBreak;
7044 ret->canBreak = e1->canBreak || e2->canBreak;
7048 if (exprNode_mustEscape (e1) || e1->mustBreak)
7052 message ("Second clause of comma expression is unreachable: %s",
7053 exprNode_unparse (e2)),
7057 ret->exitCode = e1->exitCode;
7058 ret->canBreak = e1->canBreak;
7063 if (exprNode_isDefined (e2))
7065 ret->exitCode = e2->exitCode;
7066 ret->mustBreak = e2->mustBreak;
7067 ret->canBreak = e2->canBreak;
7074 static bool exprNode_checkOneInit (/*@notnull@*/ exprNode el, exprNode val)
7076 ctype t1 = exprNode_getType (el);
7077 ctype t2 = exprNode_getType (val);
7078 bool hasError = FALSE;
7080 if (ctype_isUnknown (t1))
7082 voptgenerror (FLG_IMPTYPE,
7083 message ("Variable has unknown (implicitly int) type: %s",
7084 exprNode_unparse (el)),
7088 el->typ = ctype_int;
7091 if (exprNode_isDefined (val) && val->kind == XPR_INITBLOCK)
7093 exprNodeList vals = exprData_getArgs (val->edata);
7095 if (ctype_isRealAP (t1))
7100 exprNodeList_elements (vals, oneval)
7102 cstring istring = message ("%d", i);
7105 (exprNode_fakeCopy (el),
7106 exprNode_numLiteral (ctype_int, istring,
7107 fileloc_copy (el->loc), i));
7109 if (exprNode_isDefined (newel))
7111 if (exprNodeList_size (vals) == 1
7112 && ctype_isString (exprNode_getType (oneval))
7113 && ctype_isChar (exprNode_getType (newel)))
7115 exprNode_freeIniter (newel);
7119 if (exprNode_checkOneInit (newel, oneval))
7124 if (nerrors > 3 && exprNodeList_size (vals) > 6)
7127 (message ("Additional initialization errors "
7128 "for %s not reported",
7129 exprNode_unparse (el)),
7131 exprNode_freeIniter (newel);
7136 exprNode_freeIniter (newel);
7141 exprNode_freeIniter (newel);
7146 cstring_free (istring);
7149 } end_exprNodeList_elements;
7152 else if (ctype_isStruct (ctype_realType (t1)))
7154 uentryList fields = ctype_getFields (t1);
7157 if (uentryList_size (fields) != exprNodeList_size (vals))
7159 if (uentryList_size (fields) > exprNodeList_size (vals))
7161 hasError = optgenerror
7163 message ("Initializer block for "
7164 "%s has %d field%p, but %s has %d field%p: %q",
7165 exprNode_unparse (el),
7166 exprNodeList_size (vals),
7168 uentryList_size (fields),
7169 exprNodeList_unparse (vals)),
7174 hasError = optgenerror
7176 message ("Initializer block for "
7177 "%s has %d field%p, but %s has %d field%p: %q",
7178 exprNode_unparse (el),
7179 exprNodeList_size (vals),
7181 uentryList_size (fields),
7182 exprNodeList_unparse (vals)),
7188 exprNodeList_elements (vals, oneval)
7190 uentry thisfield = uentryList_getN (fields, i);
7192 exprNode_fieldAccess (exprNode_fakeCopy (el),
7193 uentry_getName (thisfield));
7195 if (exprNode_isDefined (newel))
7197 if (exprNode_checkOneInit (newel, oneval))
7202 exprNode_freeIniter (newel);
7206 } end_exprNodeList_elements;
7211 hasError = optgenerror
7213 message ("Initializer block used for "
7214 "%s where %t is expected: %s",
7215 exprNode_unparse (el), t1, exprNode_unparse (val)),
7221 if (exprNode_isDefined (val))
7223 doAssign (el, val, TRUE);
7225 if (!exprNode_matchType (t1, val))
7227 hasError = gentypeerror
7229 message ("Initial value of %s is type %t, "
7231 exprNode_unparse (el),
7232 t2, t1, exprNode_unparse (val)),
7241 exprNode exprNode_makeInitialization (/*@only@*/ idDecl t,
7242 /*@only@*/ exprNode e)
7244 uentry ue = usymtab_lookup (idDecl_observeId (t));
7245 bool isUsed = uentry_isUsed (ue);
7246 exprNode ret = exprNode_fromIdentifierAux (ue);
7247 ctype ct = ctype_realishType (ret->typ);
7250 if (ctype_isUnknown (ct))
7252 voptgenerror (FLG_IMPTYPE,
7253 message ("Variable has unknown (implicitly int) type: %s",
7254 idDecl_getName (t)),
7255 exprNode_isDefined (e) ? exprNode_loc (e) : g_currentloc);
7260 if (exprNode_isError (e))
7262 e = exprNode_createUnknown ();
7265 /* error: assume initializer is defined */
7266 sRef_setDefined (ret->sref, loc);
7270 loc = exprNode_loc (e);
7275 ** was addSafeUse --- what's the problem?
7277 ** int x = 3, y = x ?
7280 exprNode_checkUse (ret, e->sref, e->loc);
7282 if (ctype_isUnknown (e->typ) && uentry_isValid (ue))
7284 exprNode lhs = exprNode_createId (ue);
7287 ** static storage should be undefined before initializing
7290 if (uentry_isStatic (ue))
7292 sRef_setDefState (lhs->sref, SS_PARTIAL, fileloc_undefined);
7295 (void) exprNode_checkOneInit (lhs, e);
7297 if (uentry_isStatic (ue))
7299 sRef_setDefState (lhs->sref, SS_DEFINED, fileloc_undefined);
7302 exprNode_free (lhs);
7306 if (!exprNode_matchType (ct, e))
7308 if (exprNode_isZero (e) && ctype_isArrayPtr (ct))
7315 (exprNode_getType (e), e, exprNode_getType (ret), ret,
7317 ("Variable %s initialized to type %t, expects %t: %s",
7318 exprNode_unparse (ret), exprNode_getType (e),
7319 exprNode_getType (ret),
7320 exprNode_unparse (e)),
7326 if (uentry_isStatic (ue))
7328 sRef_setDefState (ret->sref, SS_PARTIAL, fileloc_undefined);
7331 doAssign (ret, e, TRUE);
7333 if (uentry_isStatic (ue))
7335 sRef_setDefState (ret->sref, SS_DEFINED, fileloc_undefined);
7339 if (context_inIterDef ())
7341 /* should check if it is yield */
7342 uentry_setUsed (ue, loc);
7346 if (!isUsed) /* could be @unused@-qualified variable */
7348 uentry_setNotUsed (ue);
7352 ret->exitCode = XK_NEVERESCAPE;
7353 ret->mustBreak = FALSE;
7356 ** Must be before new kind is assigned!
7359 exprData_free (ret->edata, ret->kind);
7361 ret->kind = XPR_INIT;
7362 ret->edata = exprData_makeInit (t, e);
7363 exprNode_mergeUSs (ret, e);
7367 exprNode exprNode_iter (/*@observer@*/ uentry name,
7368 /*@only@*/ exprNodeList alist,
7369 /*@only@*/ exprNode body,
7370 /*@observer@*/ uentry end)
7375 llassert (uentry_isValid (name));
7377 uentry_setUsed (name, exprNode_loc (body));
7379 ret = exprNode_createPartialCopy (body);
7380 iname = uentry_getName (name);
7382 if (uentry_isInvalid (end))
7385 message ("Iter %s not balanced with end_%s", iname, iname));
7389 cstring ename = uentry_getName (end);
7391 if (!cstring_equalPrefix (ename, "end_"))
7393 llerror (FLG_ITER, message ("Iter %s not balanced with end_%s: %s",
7394 iname, iname, ename));
7398 if (!cstring_equal (iname, cstring_suffix (ename, 4)))
7401 message ("Iter %s not balanced with end_%s: %s",
7402 iname, iname, ename));
7406 cstring_free (ename);
7409 context_exitIterClause (body);
7411 ret->kind = XPR_ITER;
7412 ret->edata = exprData_makeIter (name, alist, body, end);
7414 if (uentry_isIter (name))
7416 (void) checkArgsReal (name, body,
7417 uentry_getParams (name), alist, TRUE, ret);
7420 cstring_free (iname);
7426 exprNode_iterNewId (/*@only@*/ cstring s)
7428 exprNode e = exprNode_new ();
7429 uentry ue = uentryList_getN (uentry_getParams (getCurrentIter ()), iterParamNo ());
7431 llassert (processingIterVars ());
7433 e->loc = context_getSaveLocation ();
7435 if (fileloc_isUndefined (e->loc))
7437 fileloc_free (e->loc);
7438 e->loc = fileloc_copy (g_currentloc);
7441 e->uses = sRefSet_new ();
7442 e->sets = sRefSet_new ();
7443 e->msets = sRefSet_new ();
7445 e->val = multiVal_unknown ();
7446 e->guards = guardSet_new ();
7448 e->isJumpPoint = FALSE;
7449 e->exitCode = XK_NEVERESCAPE;
7451 /*> missing fields, detected by lclint <*/
7452 e->canBreak = FALSE;
7453 e->mustBreak = FALSE;
7454 e->etext = cstring_undefined;
7456 if (uentry_isYield (ue))
7458 uentry uue = uentry_makeVariable (s, uentry_getType (ue),
7459 fileloc_copy (e->loc),
7463 uue = usymtab_supEntrySrefReturn (uue);
7465 sr = uentry_getSref (uue);
7466 sRef_mergeStateQuiet (sr, uentry_getSref (ue));
7467 sr = uentry_getSref (uue);
7468 sRef_setDefined (sr, e->loc);
7470 e->typ = uentry_getType (uue);
7472 e->edata = exprData_makeId (uue);
7473 uentry_setUsed (uue, g_currentloc);
7479 sRef_setGlobalScope ();
7480 uue = uentry_makeVariableLoc (s, ctype_unknown);
7482 e->typ = ctype_unknown;
7483 e->edata = exprData_makeId (uue);
7485 uentry_setUsed (uue, e->loc);
7486 uentry_setHasNameError (uue);
7488 if (context_getFlag (FLG_REPEATUNRECOG))
7490 uentry_markOwned (uue);
7494 usymtab_supGlobalEntry (uue);
7497 sRef_clearGlobalScope ();
7499 voptgenerror (FLG_UNRECOG, message ("Unrecognized identifier: %s", s),
7509 exprNode_iterExpr (/*@returned@*/ exprNode e)
7511 if (!processingIterVars ())
7513 llcontbuglit ("checkIterParam: not in iter");
7517 if (uentry_isYield (uentryList_getN (uentry_getParams (getCurrentIter ()),
7520 if (exprNode_isDefined (e))
7522 if (fileloc_isDefined (e->loc))
7526 message ("Yield parameter is not simple identifier: %s",
7527 exprNode_unparse (e)),
7534 message ("Yield parameter is not simple identifier: %s",
7535 exprNode_unparse (e)),
7545 exprNode_iterId (/*@observer@*/ uentry c)
7549 llassert (processingIterVars ());
7551 ue = uentryList_getN (uentry_getParams (getCurrentIter ()),
7554 if (uentry_isYield (ue))
7556 ctype ct = uentry_getType (ue);
7557 exprNode e = exprNode_createPlain (ct);
7558 cstring name = uentry_getName (c);
7559 uentry le = uentry_makeVariable (name, ct, fileloc_undefined, FALSE);
7561 uentry_setUsed (ue, g_currentloc);
7562 uentry_setHasNameError (ue);
7564 cstring_free (name);
7567 e->edata = exprData_makeId (le);
7568 e->loc = context_getSaveLocation ();
7569 e->sref = uentry_getSref (le);
7571 usymtab_supEntrySref (le);
7573 if (!context_inHeader ())
7577 message ("Yield parameter shadows local declaration: %q",
7578 uentry_getName (c)),
7579 fileloc_isDefined (e->loc) ? e->loc : g_currentloc))
7581 uentry_showWhereDeclared (c);
7588 return (exprNode_fromIdentifierAux (c));
7591 exprNode exprNode_iterStart (/*@observer@*/ uentry name, /*@only@*/ exprNodeList alist)
7593 exprNode ret = exprNode_create (ctype_unknown);
7595 ret->kind = XPR_ITERCALL;
7596 ret->edata = exprData_makeIterCall (name, alist);
7598 if (uentry_isIter (name))
7600 uentryList params = uentry_getParams (name);
7602 if (context_inIterDef ()
7603 && uentryList_size (params) == exprNodeList_size (alist))
7607 exprNodeList_elements (alist, arg)
7609 uentry parg = uentryList_getN (params, i);
7611 if (uentry_isYield (parg))
7613 uentry ue = exprNode_getUentry (arg);
7615 if (uentry_isValid (ue))
7622 } end_exprNodeList_elements;
7625 (void) checkArgsReal (name, ret, params, alist, TRUE, ret);
7626 checkUnspecCall (ret, params, alist);
7632 /*@exposed@*/ sRef exprNode_getSref (exprNode e)
7634 if (exprNode_isDefined (e))
7637 if (e->sref == defref) /*@noaccess sRef@*/
7640 e->sref = sRef_makeUnknown ();
7641 sRef_setAliasKind (e->sref, AK_ERROR, fileloc_undefined);
7652 return sRef_undefined;
7656 /*@observer@*/ cstring
7657 exprNode_unparseFirst (exprNode e)
7659 if (exprNode_isDefined (e))
7663 if (e->kind == XPR_STMTLIST
7664 || e->kind == XPR_COMMA || e->kind == XPR_COND)
7666 exprNode first = exprData_getPairA (e->edata);
7668 if (exprNode_isDefined (first))
7670 return (exprNode_unparseFirst (exprData_getPairA (e->edata)));
7674 return (cstring_makeLiteralTemp ("..."));
7678 ret = cstring_elide (exprNode_unparse (e), 20);
7679 cstring_markOwned (ret);
7685 return cstring_makeLiteralTemp ("<error>");
7689 /*@observer@*/ cstring
7690 exprNode_unparse (exprNode e)
7692 if (exprNode_isError (e))
7694 return cstring_makeLiteralTemp ("<error>");
7697 if (cstring_isDefined (e->etext))
7703 cstring ret = exprNode_doUnparse (e);
7705 /*@-modifies@*/ /* benevolent */
7712 /*@observer@*/ fileloc
7713 exprNode_loc (exprNode e)
7715 if (exprNode_isError (e))
7717 return (g_currentloc);
7726 ** executes exprNode e
7727 ** recursively rexecutes as though in original parse using
7728 ** information in e->edata
7731 static /*@only@*/ exprNodeList exprNodeList_effect (exprNodeList e)
7733 exprNodeList ret = exprNodeList_new ();
7735 exprNodeList_elements (e, current)
7737 exprNodeList_addh (ret, exprNode_effect (current));
7738 } end_exprNodeList_elements;
7743 static /*@only@*/ exprNode exprNode_effect (exprNode e)
7744 /*@globals internalState@*/
7746 bool innerEffect = inEffect;
7752 context_clearJustPopped ();
7754 if (exprNode_isError (e))
7756 ret = exprNode_undefined;
7761 ** Turn off expose and dependent transfer checking.
7762 ** Need to pass exposed internal nodes,
7763 ** [ copying would be a waste! ]
7764 ** [ Actually, I think I wasted a lot more time than its worth ]
7765 ** [ trying to do this. ]
7769 /*@-observertrans@*/
7770 /*@-dependenttrans@*/
7777 ret = exprNode_addParens (exprData_getUopTok (data),
7778 exprNode_effect (exprData_getUopNode (data)));
7781 ret = exprNode_assign (exprNode_effect (exprData_getOpA (data)),
7782 exprNode_effect (exprData_getOpB (data)),
7783 exprData_getOpTok (data));
7786 ret = exprNode_undefined;
7789 ret = exprNode_functionCall (exprNode_effect (exprData_getFcn (data)),
7790 exprNodeList_effect (exprData_getArgs (data)));
7803 cstring id = exprData_getId (data);
7804 uentry ue = usymtab_lookupSafe (id);
7806 ret = exprNode_fromIdentifierAux (ue);
7807 ret->loc = fileloc_update (ret->loc, e->loc);
7814 ret = exprNode_arrayFetch (exprNode_effect (exprData_getPairA (data)),
7815 exprNode_effect (exprData_getPairB (data)));
7818 ret = exprNode_op (exprNode_effect (exprData_getOpA (data)),
7819 exprNode_effect (exprData_getOpB (data)),
7820 exprData_getOpTok (data));
7824 ret = exprNode_postOp (exprNode_effect (exprData_getUopNode (data)),
7825 exprData_getUopTok (data));
7828 ret = exprNode_preOp (exprNode_effect (exprData_getUopNode (data)),
7829 exprData_getUopTok (data));
7841 ret = exprNode_vaArg (exprData_getCastTok (data),
7842 exprNode_effect (exprData_getCastNode (data)),
7843 exprData_getCastType (data));
7847 ret = exprNode_cast (exprData_getCastTok (data),
7848 exprNode_effect (exprData_getCastNode (data)),
7849 exprData_getCastType (data));
7852 ret = exprNode_iterStart (exprData_getIterCallIter (data),
7854 (exprData_getIterCallArgs (data)));
7858 ret = exprNode_iter (exprData_getIterSname (data),
7859 exprNodeList_effect (exprData_getIterAlist (data)),
7860 exprNode_effect (exprData_getIterBody (data)),
7861 exprData_getIterEname (data));
7865 ret = exprNode_for (exprNode_effect (exprData_getPairA (data)),
7866 exprNode_effect (exprData_getPairB (data)));
7870 ret = exprNode_forPred (exprNode_effect (exprData_getTripleInit (data)),
7871 exprNode_effect (exprData_getTripleTest (data)),
7872 exprNode_effect (exprData_getTripleInc (data)));
7876 ret = exprNode_createTok (exprData_getTok (data));
7880 ret = exprNode_goto (exprData_getLiteral (data));
7881 ret->loc = fileloc_update (ret->loc, e->loc);
7885 ret = exprNode_continue (exprData_getTok (data), QSAFEBREAK);
7889 ret = exprNode_break (exprData_getTok (data), QSAFEBREAK);
7893 ret = exprNode_return (exprNode_effect (exprData_getSingle (data)));
7896 case XPR_NULLRETURN:
7897 ret = exprNode_nullReturn (exprData_getTok (data));
7901 ret = exprNode_comma (exprNode_effect (exprData_getPairA (data)),
7902 exprNode_effect (exprData_getPairB (data)));
7906 ret = exprNode_cond (exprNode_effect (exprData_getTriplePred (data)),
7907 exprNode_effect (exprData_getTripleTrue (data)),
7908 exprNode_effect (exprData_getTripleFalse (data)));
7911 ret = exprNode_if (exprNode_effect (exprData_getPairA (data)),
7912 exprNode_effect (exprData_getPairB (data)));
7916 ret = exprNode_ifelse (exprNode_effect (exprData_getTriplePred (data)),
7917 exprNode_effect (exprData_getTripleTrue (data)),
7918 exprNode_effect (exprData_getTripleFalse (data)));
7921 ret = exprNode_whilePred (exprData_getSingle (data));
7925 ret = exprNode_while (exprNode_effect (exprData_getPairA (data)),
7926 exprNode_effect (exprData_getPairB (data)));
7930 ret = exprNode_doWhile (exprNode_effect (exprData_getPairA (data)),
7931 exprNode_effect (exprData_getPairB (data)));
7935 ret = exprNode_makeBlock (exprNode_effect (exprData_getSingle (data)));
7939 ret = exprNode_statement (exprNode_effect (exprData_getSingle (data)));
7943 ret = exprNode_concat (exprNode_effect (exprData_getPairA (data)),
7944 exprNode_effect (exprData_getPairB (data)));
7949 ret = exprNode_caseMarker
7950 (exprNode_effect (exprData_getSingle (data)),
7956 ret = exprNode_createTok (exprData_getTok (data));
7960 ret = exprNode_switch (exprNode_effect (exprData_getPairA (data)),
7961 exprNode_effect (exprData_getPairB (data)));
7965 ret = exprNode_makeInitialization
7966 (exprData_getInitId (data),
7967 exprNode_effect (exprData_getInitNode (data)));
7971 ret = exprNode_fieldAccess (exprNode_effect (exprData_getFieldNode (data)),
7972 cstring_copy (exprData_getFieldName (data)));
7976 ret = exprNode_arrowAccess (exprNode_effect (exprData_getFieldNode (data)),
7977 cstring_copy (exprData_getFieldName (data)));
7980 case XPR_STRINGLITERAL:
7994 /*@=observertrans@*/
7996 /*@=dependenttrans@*/
8007 static /*@observer@*/ cstring exprNode_rootVarName (exprNode e)
8012 if (exprNode_isError (e))
8014 return cstring_undefined;
8022 ret = exprNode_rootVarName (exprData_getUopNode (data));
8025 ret = exprNode_rootVarName (exprData_getOpA (data));
8029 ret = exprData_getId (data);
8054 case XPR_NULLRETURN:
8077 case XPR_STRINGLITERAL:
8078 ret = cstring_undefined;
8085 static /*@only@*/ cstring exprNode_doUnparse (exprNode e)
8090 if (exprNode_isError (e))
8092 static /*@only@*/ cstring error = cstring_undefined;
8094 if (!cstring_isDefined (error))
8096 error = cstring_makeLiteral ("<error>");
8107 ret = message ("(%s)", exprNode_unparse (exprData_getUopNode (e->edata)));
8110 ret = message ("%s %s %s",
8111 exprNode_unparse (exprData_getOpA (data)),
8112 lltok_unparse (exprData_getOpTok (data)),
8113 exprNode_unparse (exprData_getOpB (data)));
8116 ret = message ("%s(%q)",
8117 exprNode_unparse (exprData_getFcn (data)),
8118 exprNodeList_unparse (exprData_getArgs (data)));
8121 ret = message ("{ %q }", exprNodeList_unparse (exprData_getArgs (data)));
8124 ret = cstring_undefined;
8127 ret = message ("%s:", exprData_getId (data));
8131 ret = cstring_copy (exprData_getId (data));
8134 ret = message ("%s[%s]", exprNode_unparse (exprData_getPairA (data)),
8135 exprNode_unparse (exprData_getPairB (data)));
8138 ret = message ("<body>");
8141 ret = message ("%s %s %s",
8142 exprNode_unparse (exprData_getOpA (data)),
8143 lltok_unparse (exprData_getOpTok (data)),
8144 exprNode_unparse (exprData_getOpB (data)));
8148 ret = message ("%s%s",
8149 lltok_unparse (exprData_getUopTok (data)),
8150 exprNode_unparse (exprData_getUopNode (data)));
8154 ret = message ("%s%s",
8155 exprNode_unparse (exprData_getUopNode (data)),
8156 lltok_unparse (exprData_getUopTok (data)));
8160 ret = message ("offsetof(%s,%q)",
8161 ctype_unparse (qtype_getType (exprData_getOffsetType (data))),
8162 cstringList_unparseSep (exprData_getOffsetName (data), cstring_makeLiteralTemp (".")));
8166 ret = message ("sizeof(%s)", ctype_unparse (qtype_getType (exprData_getType (data))));
8170 ret = message ("sizeof(%s)", exprNode_unparse (exprData_getSingle (data)));
8174 ret = message ("alignof(%s)", ctype_unparse (qtype_getType (exprData_getType (data))));
8178 ret = message ("alignof(%s)", exprNode_unparse (exprData_getSingle (data)));
8182 ret = message ("va_arg(%s, %q)",
8183 exprNode_unparse (exprData_getCastNode (data)),
8184 qtype_unparse (exprData_getCastType (data)));
8188 ret = message ("%q(%q)",
8189 uentry_getName (exprData_getIterCallIter (data)),
8190 exprNodeList_unparse (exprData_getIterCallArgs (data)));
8193 ret = message ("%q(%q) %s %q",
8194 uentry_getName (exprData_getIterSname (data)),
8195 exprNodeList_unparse (exprData_getIterAlist (data)),
8196 exprNode_unparse (exprData_getIterBody (data)),
8197 uentry_getName (exprData_getIterEname (data)));
8200 ret = message ("(%q)%s",
8201 qtype_unparse (exprData_getCastType (data)),
8202 exprNode_unparse (exprData_getCastNode (data)));
8206 ret = message ("%s %s",
8207 exprNode_unparse (exprData_getPairA (data)),
8208 exprNode_unparse (exprData_getPairB (data)));
8212 ret = message ("for (%s; %s; %s)",
8213 exprNode_unparse (exprData_getTripleInit (data)),
8214 exprNode_unparse (exprData_getTripleTest (data)),
8215 exprNode_unparse (exprData_getTripleInc (data)));
8219 ret = message ("goto %s", exprData_getLiteral (data));
8223 ret = cstring_makeLiteral ("continue");
8227 ret = cstring_makeLiteral ("break");
8231 ret = message ("return %s", exprNode_unparse (exprData_getSingle (data)));
8234 case XPR_NULLRETURN:
8235 ret = cstring_makeLiteral ("return");
8239 ret = message ("%s, %s",
8240 exprNode_unparse (exprData_getPairA (data)),
8241 exprNode_unparse (exprData_getPairB (data)));
8245 ret = message ("%s ? %s : %s",
8246 exprNode_unparse (exprData_getTriplePred (data)),
8247 exprNode_unparse (exprData_getTripleTrue (data)),
8248 exprNode_unparse (exprData_getTripleFalse (data)));
8251 ret = message ("if (%s) %s",
8252 exprNode_unparse (exprData_getPairA (data)),
8253 exprNode_unparse (exprData_getPairB (data)));
8257 ret = message ("if (%s) %s else %s",
8258 exprNode_unparse (exprData_getTriplePred (data)),
8259 exprNode_unparse (exprData_getTripleTrue (data)),
8260 exprNode_unparse (exprData_getTripleFalse (data)));
8263 ret = message ("while (%s) %s",
8264 exprNode_unparse (exprData_getPairA (data)),
8265 exprNode_unparse (exprData_getPairB (data)));
8269 ret = cstring_copy (exprNode_unparse (exprData_getSingle (data)));
8273 ret = cstring_copy (lltok_unparse (exprData_getTok (data)));
8277 ret = message ("do { %s } while (%s)",
8278 exprNode_unparse (exprData_getPairB (data)),
8279 exprNode_unparse (exprData_getPairA (data)));
8283 ret = message ("{ %s }", exprNode_unparseFirst (exprData_getSingle (data)));
8287 ret = cstring_copy (exprNode_unparse (exprData_getSingle (data)));
8291 ret = message ("%s; %s",
8292 exprNode_unparse (exprData_getPairA (data)),
8293 exprNode_unparse (exprData_getPairB (data)));
8298 ret = cstring_makeLiteral ("default:");
8302 ret = message ("switch (%s) %s",
8303 exprNode_unparse (exprData_getPairA (data)),
8304 exprNode_unparse (exprData_getPairB (data)));
8309 ret = message ("case %s:",
8310 exprNode_unparse (exprData_getSingle (data)));
8314 ret = message ("%s = %s",
8315 idDecl_getName (exprData_getInitId (data)),
8316 exprNode_unparse (exprData_getInitNode (data)));
8320 ret = message ("%s.%s",
8321 exprNode_unparse (exprData_getFieldNode (data)),
8322 exprData_getFieldName (data));
8326 ret = message ("%s->%s",
8327 exprNode_unparse (exprData_getFieldNode (data)),
8328 exprData_getFieldName (data));
8331 case XPR_STRINGLITERAL:
8332 ret = cstring_copy (exprData_getLiteral (data));
8336 ret = cstring_copy (exprData_getLiteral (data));
8340 ret = cstring_makeLiteral ("<node>");
8348 exprNode_isCharLit (exprNode e)
8350 if (exprNode_isDefined (e))
8352 return (multiVal_isChar (exprNode_getValue (e)));
8361 exprNode_isNumLit (exprNode e)
8363 if (exprNode_isDefined (e))
8365 return (multiVal_isInt (exprNode_getValue (e)));
8374 exprNode_isFalseConstant (exprNode e)
8376 if (exprNode_isDefined (e))
8378 cstring s = exprNode_rootVarName (e);
8380 if (cstring_equal (s, context_getFalseName ()))
8390 exprNode_matchLiteral (ctype expected, exprNode e)
8392 if (exprNode_isDefined (e))
8394 multiVal m = exprNode_getValue (e);
8396 if (multiVal_isDefined (m))
8398 if (multiVal_isInt (m))
8400 long int val = multiVal_forceInt (m);
8402 if (ctype_isDirectBool (ctype_realishType (expected)))
8406 return FALSE; /* really?! return TRUE; allow use of 0 for FALSE */
8414 if (ctype_isRealInt (expected))
8417 ** unsigned <- [ constant >= 0 is okay ]
8420 if (ctype_isUnsigned (expected))
8429 ** No checks on sizes of integers...maybe add
8433 DPRINTF (("Here: %s => %s", exprNode_unparse (e), ctype_unparse (expected)));
8434 DPRINTF (("Type: %s / %s", ctype_unparse (exprNode_getType (e)),
8435 bool_unparse (ctype_isInt (exprNode_getType (e)))));
8437 if (context_getFlag (FLG_NUMLITERAL)
8438 && (ctype_isRegularInt (exprNode_getType (e)) || val == 0)) {
8444 return FALSE; /* evs 2000-05-17: previously, always returned TRUE */
8448 else if (ctype_isChar (expected))
8452 else if (ctype_isArrayPtr (expected))
8456 else if (ctype_isAnyFloat (expected))
8458 return (context_getFlag (FLG_NUMLITERAL));
8465 else if (multiVal_isDouble (m))
8467 if (ctype_isAnyFloat (expected))
8472 else if (multiVal_isChar (m))
8474 char val = multiVal_forceChar (m);
8476 if (ctype_isChar (expected))
8478 if (ctype_isUnsigned (expected) && ((int)val) < 0)
8499 exprNode_matchType (ctype expected, exprNode e)
8503 if (!exprNode_isDefined (e)) return TRUE;
8505 actual = ctype_realishType (exprNode_getType (e));
8507 if (ctype_match (ctype_realishType (expected), actual))
8512 llassert (!exprNode_isError (e));
8513 return (exprNode_matchLiteral (expected, e));
8517 exprNode_matchTypes (exprNode e1, exprNode e2)
8522 if (!exprNode_isDefined (e1)) return TRUE;
8523 if (!exprNode_isDefined (e2)) return TRUE;
8526 ** realish type --- keep bools, bools
8529 t1 = ctype_realishType (exprNode_getType (e1));
8530 t2 = ctype_realishType (exprNode_getType (e2));
8532 if (ctype_match (t1, t2))
8537 return (exprNode_matchLiteral (t1, e2) || exprNode_matchLiteral (t2, e1));
8545 exprNode_matchArgType (ctype ct, exprNode e)
8549 if (!exprNode_isDefined (e))
8554 et = ctype_realType (exprNode_getType (e));
8556 if (ctype_matchArg (ct, et)) return TRUE;
8558 llassert (!exprNode_isError (e));
8559 return (exprNode_matchLiteral (ct, e));
8562 static /*@only@*/ exprNodeSList
8563 exprNode_flatten (/*@dependent@*/ exprNode e) /*@*/
8565 if (exprNode_isDefined (e))
8567 if (e->kind == XPR_STMTLIST)
8569 return (exprNodeSList_append
8570 (exprNode_flatten (exprData_getPairA (e->edata)),
8571 exprNode_flatten (exprData_getPairB (e->edata))));
8573 else if (e->kind == XPR_BLOCK)
8575 return (exprNode_flatten (exprData_getSingle (e->edata)));
8579 return (exprNodeSList_singleton (e));
8583 return exprNodeSList_new ();
8586 static /*@exposed@*/ exprNode
8587 exprNode_lastStatement (/*@returned@*/ exprNode e)
8589 if (exprNode_isDefined (e))
8591 if (e->kind == XPR_STMTLIST)
8593 exprNode b = exprData_getPairB (e->edata);
8595 if (exprNode_isDefined (b))
8597 return exprNode_lastStatement (b);
8601 return exprNode_lastStatement (exprData_getPairA (e->edata));
8604 else if (e->kind == XPR_BLOCK)
8606 return (exprNode_lastStatement (exprData_getSingle (e->edata)));
8614 return exprNode_undefined;
8617 static /*@exposed@*/ exprNode
8618 exprNode_firstStatement (/*@returned@*/ exprNode e)
8620 if (exprNode_isDefined (e))
8622 if (e->kind == XPR_STMTLIST)
8624 exprNode b = exprData_getPairA (e->edata);
8626 if (exprNode_isDefined (b))
8628 return exprNode_firstStatement (b);
8632 return exprNode_firstStatement (exprData_getPairB (e->edata));
8635 else if (e->kind == XPR_BLOCK)
8637 return (exprNode_firstStatement (exprData_getSingle (e->edata)));
8645 return exprNode_undefined;
8649 exprNode_mergeUSs (exprNode res, exprNode other)
8651 if (exprNode_isDefined (res) && exprNode_isDefined (other))
8653 res->msets = sRefSet_union (res->msets, other->msets);
8654 res->sets = sRefSet_union (res->sets, other->sets);
8655 res->uses = sRefSet_union (res->uses, other->uses);
8660 exprNode_mergeCondUSs (exprNode res, exprNode other1, exprNode other2)
8662 if (exprNode_isDefined (res))
8664 if (exprNode_isDefined (other1))
8666 res->sets = sRefSet_union (res->sets, other1->sets);
8667 res->msets = sRefSet_union (res->msets, other1->msets);
8668 res->uses = sRefSet_union (res->uses, other1->uses);
8670 if (exprNode_isDefined (other2))
8672 res->sets = sRefSet_union (res->sets, other2->sets);
8673 res->msets = sRefSet_union (res->msets, other2->msets);
8674 res->uses = sRefSet_union (res->uses, other2->uses);
8682 ** Reports errors is s is not defined.
8686 exprNode_addUse (exprNode e, sRef s)
8688 if (exprNode_isDefined (e))
8690 e->uses = sRefSet_insert (e->uses, s);
8695 exprNode_checkUse (exprNode e, sRef s, fileloc loc)
8697 if (sRef_isKnown (s) && !sRef_isConst (s))
8700 ** need to check all outer types are useable
8703 DPRINTF (("Check use: %s / %s",
8704 exprNode_unparse (e), sRef_unparse (s)));
8706 exprNode_addUse (e, s);
8708 if (!context_inProtectVars ())
8711 ** only report the deepest error
8714 sRef errorRef = sRef_undefined;
8715 sRef lastRef = sRef_undefined;
8716 bool deadRef = FALSE;
8717 bool unuseable = FALSE;
8718 bool errorMaybe = FALSE;
8720 while (sRef_isValid (s) && sRef_isKnown (s))
8722 ynm readable = sRef_isReadable (s);
8724 if (!(ynm_toBoolStrict (readable)))
8726 if (ynm_isMaybe (readable))
8730 deadRef = sRef_isPossiblyDead (errorRef);
8731 unuseable = sRef_isUnuseable (errorRef);
8738 deadRef = sRef_isDead (errorRef);
8739 unuseable = sRef_isUnuseable (errorRef);
8743 if (!sRef_isPartial (s))
8745 sRef_setDefined (s, fileloc_undefined);
8749 s = sRef_getBaseSafe (s);
8752 if (sRef_isValid (errorRef))
8754 if (sRef_isValid (lastRef) && sRef_isField (lastRef)
8755 && sRef_isPointer (errorRef))
8762 if (sRef_isThroughArrayFetch (errorRef))
8765 (FLG_STRICTUSERELEASED,
8766 message ("%q %q may be used after being released",
8767 sRef_unparseKindNamePlain (errorRef),
8768 sRef_unparse (errorRef)),
8771 sRef_showRefKilled (errorRef);
8773 if (sRef_isKept (errorRef))
8775 sRef_clearAliasState (errorRef, loc);
8781 DPRINTF (("HERE: %s", sRef_unparse (errorRef)));
8785 message ("%q %q %qused after being released",
8786 sRef_unparseKindNamePlain (errorRef),
8787 sRef_unparse (errorRef),
8788 cstring_makeLiteral (errorMaybe
8792 sRef_showRefKilled (errorRef);
8794 if (sRef_isKept (errorRef))
8796 sRef_clearAliasState (errorRef, loc);
8805 message ("%q %q%qused in inconsistent state",
8806 sRef_unparseKindName (errorRef),
8807 sRef_unparseOpt (errorRef),
8808 cstring_makeLiteral (errorMaybe ? "may be " : "")),
8811 sRef_showStateInconsistent (errorRef);
8816 DPRINTF (("HERE: %s", sRef_unparse (errorRef)));
8820 message ("%q %q%qused before definition",
8821 sRef_unparseKindName (errorRef),
8822 sRef_unparseOpt (errorRef),
8823 cstring_makeLiteral (errorMaybe ? "may be " : "")),
8827 sRef_setDefined (errorRef, loc);
8829 if (sRef_isAddress (errorRef))
8831 sRef_setDefined (sRef_getRootBase (errorRef), loc);
8833 } /* end is error */
8841 checkSafeUse (exprNode e, sRef s)
8843 if (exprNode_isDefined (e) && sRef_isKnown (s))
8845 e->uses = sRefSet_insert (e->uses, s);
8850 exprNode_checkSetAny (exprNode e, /*@dependent@*/ cstring name)
8852 if (exprNode_isDefined (e))
8854 e->sets = sRefSet_insert (e->sets, sRef_makeUnconstrained (name));
8859 exprNode_checkSet (exprNode e, sRef s)
8861 sRef defines = sRef_undefined;
8863 if (sRef_isValid (s) && !sRef_isNothing (s))
8865 uentry ue = sRef_getBaseUentry (s);
8867 if (uentry_isValid (ue))
8869 uentry_setLset (ue);
8872 if (!ynm_toBoolStrict (sRef_isWriteable (s)))
8874 voptgenerror (FLG_USEDEF,
8875 message ("Attempt to set unuseable storage: %q",
8880 if (sRef_isMeaningful (s))
8883 if (sRef_isDead (s))
8885 sRef base = sRef_getBaseSafe (s);
8887 if (sRef_isValid (base)
8888 && sRef_isDead (base))
8890 sRef_setPartial (s, exprNode_loc (e));
8893 defines = s; /* okay - modifies for only param */
8895 else if (sRef_isPartial (s))
8897 sRef eref = exprNode_getSref (e);
8899 if (!sRef_isPartial (eref))
8902 ** should do something different here???
8905 sRef_setDefinedComplete (eref, exprNode_loc (e));
8909 sRef_setPartialDefinedComplete (eref, exprNode_loc (e));
8912 if (sRef_isMeaningful (eref))
8921 else if (sRef_isAllocated (s))
8923 sRef eref = exprNode_getSref (e);
8926 if (!sRef_isAllocated (eref))
8928 sRef_setDefinedComplete (eref, exprNode_loc (e));
8932 sRef base = sRef_getBaseSafe (eref);
8934 if (sRef_isValid (base))
8936 sRef_setPdefined (base, exprNode_loc (e));
8944 sRef_setDefinedNCComplete (s, exprNode_loc (e));
8949 else /* not meaningful...but still need to insert it */
8955 if (exprNode_isDefined (e) && sRef_isValid (defines))
8957 e->sets = sRefSet_insert (e->sets, defines);
8962 exprNode_checkMSet (exprNode e, sRef s)
8964 if (sRef_isValid (s) && !sRef_isNothing (s))
8966 uentry ue = sRef_getBaseUentry (s);
8968 if (uentry_isValid (ue))
8970 uentry_setLset (ue);
8973 if (!ynm_toBoolStrict (sRef_isWriteable (s)))
8975 voptgenerror (FLG_USEDEF,
8976 message ("Attempt to set unuseable storage: %q", sRef_unparse (s)),
8980 if (sRef_isMeaningful (s))
8982 sRef_setDefinedComplete (s, exprNode_loc (e));
8985 if (exprNode_isDefined (e))
8987 e->msets = sRefSet_insert (e->msets, s);
8993 checkUnspecCall (/*@notnull@*/ /*@dependent@*/ exprNode fcn, uentryList params, exprNodeList args)
8995 checkAnyCall (fcn, cstring_undefined, params, args,
8996 FALSE, sRefSet_undefined, FALSE, 0);
9000 checkOneArg (uentry ucurrent, /*@notnull@*/ exprNode current,
9001 /*@dependent@*/ exprNode fcn, bool isSpec, int argno, int totargs)
9005 if (uentry_isYield (ucurrent))
9007 sRef_setDefined (exprNode_getSref (current), exprNode_loc (current));
9008 exprNode_checkSet (current, current->sref);
9012 if (uentry_isSefParam (ucurrent))
9014 sRefSet sets = current->sets;
9015 sRef ref = exprNode_getSref (current);
9017 if (sRef_isMacroParamRef (ref))
9019 uentry ue = sRef_getUentry (ref);
9021 if (!uentry_isSefParam (ue))
9026 ("Parameter %d to %s is declared sef, but "
9027 "the argument is a macro parameter declared "
9029 argno, exprNode_unparse (fcn),
9030 exprNode_unparse (current)),
9031 exprNode_loc (current));
9035 if (!sRefSet_isEmpty (sets))
9037 sRefSet reported = sRefSet_undefined;
9039 sRefSet_realElements (current->sets, el)
9041 if (sRefSet_isSameNameMember (reported, el))
9043 ; /* don't report again */
9047 if (sRef_isUnconstrained (el))
9052 ("Parameter %d to %s is declared sef, but "
9053 "the argument calls unconstrained function %s "
9054 "(no guarantee it will not modify something): %s",
9055 argno, exprNode_unparse (fcn),
9056 sRef_unconstrainedName (el),
9057 exprNode_unparse (current)),
9058 exprNode_loc (current));
9065 ("Parameter %d to %s is declared sef, but "
9066 "the argument may modify %q: %s",
9067 argno, exprNode_unparse (fcn),
9069 exprNode_unparse (current)),
9070 exprNode_loc (current));
9073 } end_sRefSet_realElements;
9077 checkPassTransfer (current, ucurrent, isSpec, fcn, argno, totargs);
9078 exprNode_mergeUSs (fcn, current);
9083 checkAnyCall (/*@dependent@*/ exprNode fcn,
9084 /*@dependent@*/ cstring fname,
9087 bool hasMods, sRefSet mods,
9092 int nargs = exprNodeList_size (args);
9097 ** concat all args ud's to f, add each arg sref as a use unless
9098 ** it was specified as "out", in which case it is a def.
9101 uentryList_reset (pn);
9106 ** if paramn is only or unique, no other arg may alias argn
9109 exprNodeList_elements (args, current)
9113 if (exprNode_isDefined (current))
9115 if ((!uentryList_isUndefined (pn) && !uentryList_isFinished (pn)))
9117 uentry ucurrent = uentryList_current (pn);
9119 if (specialArgs == 0
9120 || (paramno < specialArgs))
9122 checkOneArg (ucurrent, current, fcn, isSpec, paramno, nargs);
9124 if (context_maybeSet (FLG_ALIASUNIQUE))
9126 if (uentry_isOnly (ucurrent)
9127 || uentry_isUnique (ucurrent))
9129 checkUniqueParams (fcn, current, args,
9135 else /* uentry is undefined */
9137 if (specialArgs == 0)
9139 exprNode_checkUseParam (current);
9142 exprNode_mergeUSs (fcn, current);
9145 uentryList_advanceSafe (pn);
9146 } end_exprNodeList_elements;
9152 sRefSet_allElements (mods, s)
9155 sRef rb = sRef_getRootBase (s);
9157 if (sRef_isGlobal (rb))
9159 context_usedGlobal (rb);
9162 fb = sRef_fixBaseParam (s, args);
9164 if (!sRef_isMacroParamRef (fb))
9166 if (sRef_isNothing (fb))
9172 if (sRef_isValid (fb))
9174 uentry ue = sRef_getBaseUentry (s);
9176 if (uentry_isValid (ue))
9178 uentry_setLset (ue);
9182 fcn->sets = sRefSet_insert (fcn->sets, fb);
9185 sRef_clearDerivedComplete (s);
9186 } end_sRefSet_allElements;
9192 if (context_hasMods ())
9194 if (context_maybeSet (FLG_MODUNCON))
9198 message ("Undetected modification possible "
9199 "from call to unconstrained function %s: %s",
9201 exprNode_unparse (fcn)),
9202 exprNode_loc (fcn));
9207 if (context_maybeSet (FLG_MODUNCONNOMODS)
9208 && !(context_inIterDef () || context_inIterEnd ()))
9211 (FLG_MODUNCONNOMODS,
9212 message ("Undetected modification possible "
9213 "from call to unconstrained function %s: %s",
9215 exprNode_unparse (fcn)),
9216 exprNode_loc (fcn));
9220 exprNode_checkSetAny (fcn, fname);
9224 void exprNode_checkUseParam (exprNode current)
9226 if (exprNode_isDefined (current))
9228 exprNode_checkUse (current, current->sref, current->loc);
9233 checkNumerics (ctype tr1, ctype tr2, ctype te1, ctype te2,
9234 /*@notnull@*/ exprNode e1, /*@notnull@*/ exprNode e2,
9239 if (!ctype_match (tr1, tr2))
9241 if ((ctype_isRealInt (tr1) || ctype_isReal (tr1)) &&
9242 (ctype_isRealInt (tr2) || ctype_isReal (tr2)))
9250 message ("Incompatible types for %s (%s, %s): %s %s %s",
9252 ctype_unparse (te1),
9253 ctype_unparse (te2),
9254 exprNode_unparse (e1), lltok_unparse (op),
9255 exprNode_unparse (e2)),
9258 ret = ctype_unknown;
9262 if (ctype_isForceRealNumeric (&tr1) && ctype_isForceRealNumeric (&tr2))
9264 ret = ctype_resolveNumerics (tr1, tr2);
9266 else if (!context_msgStrictOps ())
9268 if (ctype_isPointer (tr1))
9270 if (ctype_isPointer (tr2) && !exprNode_isNullValue (e2))
9274 else if (ctype_isInt (tr2))
9280 ret = ctype_unknown;
9283 else if (ctype_isPointer (tr2))
9285 if (ctype_isPointer (tr1))
9289 else if (ctype_isInt (tr1))
9295 ret = ctype_unknown;
9300 ret = ctype_resolveNumerics (tr1, tr2);
9305 int opid = lltok_getTok (op);
9306 bool comparop = (opid == EQ_OP || opid == NE_OP
9307 || opid == TLT || opid == TGT
9308 || opid == LE_OP || opid == GE_OP);
9310 if (!ctype_isNumeric (tr1) && !ctype_isNumeric (tr2))
9313 && ((ctype_isEnum (tr1) && ctype_isEnum (tr2))
9314 || (ctype_isBool (tr1) && ctype_isBool (tr2))
9315 || (ctype_isChar (tr1) && ctype_isChar (tr2))))
9321 if (ctype_sameName (te1, te2))
9325 message ("Operands of %s are non-numeric (%t): %s %s %s",
9326 lltok_unparse (op), te1,
9327 exprNode_unparse (e1), lltok_unparse (op),
9328 exprNode_unparse (e2)),
9335 message ("Operands of %s are non-numerics (%t, %t): %s %s %s",
9336 lltok_unparse (op), te1, te2,
9337 exprNode_unparse (e1), lltok_unparse (op),
9338 exprNode_unparse (e2)),
9343 else if (!ctype_isNumeric (tr1))
9347 message ("Right operand of %s is non-numeric (%t): %s %s %s",
9348 lltok_unparse (op), te1,
9349 exprNode_unparse (e1), lltok_unparse (op),
9350 exprNode_unparse (e2)),
9355 if (!ctype_isNumeric (tr2))
9359 message ("Left operand of %s is non-numeric (%t): %s %s %s",
9360 lltok_unparse (op), te2,
9361 exprNode_unparse (e1), lltok_unparse (op),
9362 exprNode_unparse (e2)),
9367 ret = ctype_unknown;
9375 abstractOpError (ctype tr1, ctype tr2, lltok op,
9376 /*@notnull@*/ exprNode e1, /*@notnull@*/ exprNode e2,
9377 fileloc loc1, fileloc loc2)
9379 if (ctype_isRealAbstract (tr1) && ctype_isRealAbstract (tr2))
9381 if (ctype_match (tr1, tr2))
9385 message ("Operands of %s are abstract type (%t): %s %s %s",
9386 lltok_unparse (op), tr1,
9387 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
9394 message ("Operands of %s are abstract types (%t, %t): %s %s %s",
9395 lltok_unparse (op), tr1, tr2,
9396 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
9400 else if (ctype_isRealAbstract (tr1))
9404 message ("Left operand of %s is abstract type (%t): %s %s %s",
9405 lltok_unparse (op), tr1,
9406 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
9411 if (ctype_isRealAbstract (tr2))
9415 message ("Right operand of %s is abstract type (%t): %s %s %s",
9416 lltok_unparse (op), tr2,
9417 exprNode_unparse (e1), lltok_unparse (op), exprNode_unparse (e2)),
9426 ** requies e1 and e2 and not error exprNode's.
9430 ** If e1 is a component of an abstract type, and e2 is mutable and client-visible,
9431 ** the rep of the abstract type is exposed.
9433 ** The order is very important:
9435 ** check rep expose (move into check transfer)
9441 ** This isn't really a sensible procedure, but the indententation
9442 ** was getting too deep.
9446 checkOneRepExpose (sRef ysr, sRef base,
9447 /*@notnull@*/ exprNode e1,
9448 /*@notnull@*/ exprNode e2, ctype ct,
9451 if (!(sRef_isOnly (ysr) || sRef_isKeep (ysr)
9452 || sRef_isOwned (ysr) || sRef_isExposed (ysr)))
9454 if (sRef_isAnyParam (base) && !sRef_isExposed (base))
9456 if (sRef_isIReference (ysr))
9458 if (sRef_sameName (base, sRef_getRootBase (e2->sref)))
9463 ("Assignment of mutable component of parameter %q "
9464 "to component of abstract "
9465 "type %s exposes rep: %s = %s",
9466 sRef_unparse (base),
9468 exprNode_unparse (e1), exprNode_unparse (e2)),
9476 ("Assignment of mutable component of parameter %q "
9477 "(through alias %q) to component of abstract "
9478 "type %s exposes rep: %s = %s",
9479 sRef_unparse (base),
9480 sRef_unparse (e2->sref),
9482 exprNode_unparse (e1), exprNode_unparse (e2)),
9488 if (sRef_sameName (base, sRef_getRootBase (e2->sref)))
9492 message ("Assignment of mutable parameter %q "
9493 "to component of abstract type %s "
9494 "exposes rep: %s = %s",
9495 sRef_unparse (base),
9497 exprNode_unparse (e1),
9498 exprNode_unparse (e2)),
9505 message ("Assignment of mutable parameter %q "
9506 "(through alias %q) to "
9507 "component of abstract type %s exposes "
9509 sRef_unparse (base),
9510 sRef_unparse (e2->sref),
9512 exprNode_unparse (e1),
9513 exprNode_unparse (e2)),
9519 if (sRef_isGlobal (s2b))
9521 if (sRef_sameName (base, sRef_getRootBase (e2->sref)))
9525 message ("Assignment of global %q "
9527 "abstract type %s exposes rep: %s = %s",
9528 sRef_unparse (base),
9530 exprNode_unparse (e1), exprNode_unparse (e2)),
9537 message ("Assignment of global %q (through alias %q) "
9539 "abstract type %s exposes rep: %s = %s",
9540 sRef_unparse (base),
9541 sRef_unparse (e2->sref),
9543 exprNode_unparse (e1), exprNode_unparse (e2)),
9551 doAssign (/*@notnull@*/ exprNode e1, /*@notnull@*/ exprNode e2, bool isInit)
9553 if (ctype_isRealFunction (exprNode_getType (e1))
9554 && !ctype_isRealPointer (exprNode_getType (e1)))
9558 message ("Invalid left-hand side of assignment (function type %s): %s",
9559 ctype_unparse (exprNode_getType (e1)),
9560 exprNode_unparse (e1)),
9564 if (context_getFlag (FLG_ASSIGNEXPOSE) && ctype_isMutable (e2->typ))
9566 ctype t2 = exprNode_getType (e2);
9567 sRef sr = sRef_getRootBase (e1->sref);
9568 ctype ct = sRef_getType (sr);
9570 if (ctype_isAbstract (t2)
9571 && !(uentry_isMutableDatatype (usymtab_getTypeEntry (ctype_typeId (t2)))))
9573 /* it is immutable, okay to reference */
9577 if (ctype_isAbstract (ct) && sRef_isIReference (e1->sref))
9579 sRef s2b = sRef_getRootBase (e2->sref);
9581 sRef s1b = sRef_getRootBase (s1);
9584 aliases = usymtab_canAlias (e2->sref);
9586 if (!sRef_similar (s2b, s1b)
9587 && !sRef_isExposed (s1)
9588 && !(sRef_isOnly (s2b) || sRef_isKeep (s2b) || sRef_isExposed (s2b)))
9590 if (sRef_isAnyParam (s2b) && !sRef_isOnly (s2b)
9591 && !sRef_isOwned (s2b) && !sRef_isKeep (s2b)
9592 && !sRef_isExposed (s2b))
9594 if (sRef_isIReference (e2->sref))
9599 ("Assignment of mutable component of parameter %q "
9600 "to component of abstract type %s exposes rep: %s = %s",
9603 exprNode_unparse (e1), exprNode_unparse (e2)),
9610 message ("Assignment of mutable parameter %q to "
9611 "component of abstract type %s exposes rep: %s = %s",
9614 exprNode_unparse (e1), exprNode_unparse (e2)),
9619 if (sRef_isGlobal (s2b))
9623 message ("Assignment of global %q to component of "
9624 "abstract type %s exposes rep: %s = %s",
9627 exprNode_unparse (e1), exprNode_unparse (e2)),
9631 sRefSet_realElements (aliases, ysr)
9633 sRef base = sRef_getRootBase (ysr);
9635 if (sRef_similar (ysr, s2b) || sRef_similar (s1b, base)
9636 || sRef_sameName (base, s1b))
9638 ; /* error already reported or same sref */
9642 checkOneRepExpose (ysr, base, e1, e2, ct, s2b);
9644 } end_sRefSet_realElements;
9646 sRefSet_free (aliases);
9653 ** function variables don't really work...
9656 if (!ctype_isFunction (ctype_realType (e2->typ)))
9660 checkInitTransfer (e1, e2);
9664 checkAssignTransfer (e1, e2);
9669 sRef fref = e2->sref;
9671 sRef_setDefState (e1->sref, sRef_getDefState (fref), e1->loc);
9672 sRef_setNullState (e1->sref, sRef_getNullState (fref), e1->loc);
9674 /* Need to typecheck the annotation on the parameters */
9676 if (ctype_isRealFunction (e1->typ)) {
9677 uentryList e1p = ctype_argsFunction (ctype_realType (e1->typ));
9678 uentryList e2p = ctype_argsFunction (ctype_realType (e2->typ));
9680 if (!uentryList_isMissingParams (e1p)
9681 && !uentryList_isMissingParams (e2p)
9682 && uentryList_size (e1p) > 0) {
9683 if (uentryList_size (e1p) == uentryList_size (e2p)) {
9686 uentryList_elements (e1p, el1) {
9689 el2 = uentryList_getN (e2p, n);
9691 uentry_checkMatchParam (el1, el2, n, e2);
9692 } end_uentryList_elements;
9698 if (isInit && sRef_isGlobal (e1->sref))
9704 updateAliases (e1, e2);
9709 checkMacroParen (exprNode e)
9711 if (exprNode_isError (e) || e->kind == XPR_CAST)
9717 if (sRef_isUnsafe (e->sref) && !exprNode_isInParens (e))
9721 message ("Macro parameter used without parentheses: %s",
9722 exprNode_unparse (e)),
9729 reflectNullTest (/*@notnull@*/ exprNode e, bool isnull)
9733 e->guards = guardSet_addTrueGuard (e->guards, e->sref);
9737 e->guards = guardSet_addFalseGuard (e->guards, e->sref);
9744 ** if e2 is a parameter or global derived location which
9745 ** can be modified (that is, e2 is a mutable abstract type,
9746 ** or a derived pointer), then e1 can alias e2.
9748 ** e1 can alias everything which e2 can alias.
9750 ** Also, if e1 is guarded, remove from guard sets!
9753 static void updateAliases (/*@notnull@*/ exprNode e1, /*@notnull@*/ exprNode e2)
9755 if (!context_inProtectVars ())
9758 ** depends on types of e1 and e2
9763 ctype t1 = exprNode_getType (e1);
9765 /* handle pointer sRefs, record fields, arrays, etc... */
9767 if (!ctype_isRealSU (t1))
9769 sRef_copyRealDerivedComplete (s1, s2);
9772 if (ctype_isMutable (t1) && sRef_isKnown (s1))
9774 usymtab_clearAlias (s1);
9775 usymtab_addMustAlias (s1, s2);
9778 if (sRef_possiblyNull (s1) && usymtab_isGuarded (s1))
9780 usymtab_unguard (s1);
9785 exprNode exprNode_updateLocation (/*@returned@*/ exprNode e, /*@temp@*/ fileloc loc)
9787 if (exprNode_isDefined (e))
9789 e->loc = fileloc_update (e->loc, loc);
9793 e = exprNode_createLoc (ctype_unknown, fileloc_copy (loc));
9799 static void checkUniqueParams (exprNode fcn,
9800 /*@notnull@*/ exprNode current,
9802 int paramno, uentry ucurrent)
9805 sRef thisref = exprNode_getSref (current);
9808 ** Check if any argument could match this argument.
9811 exprNodeList_elements (args, icurrent)
9815 if (iparamno != paramno)
9817 sRef sr = exprNode_getSref (icurrent);
9819 if (sRef_similarRelaxed (thisref, sr))
9821 if (!sRef_isConst (thisref) && !sRef_isConst (sr))
9826 ("Parameter %d (%s) to function %s is declared %s but "
9827 "is aliased by parameter %d (%s)",
9829 exprNode_unparse (current),
9830 exprNode_unparse (fcn),
9831 alkind_unparse (uentry_getAliasKind (ucurrent)),
9832 iparamno, exprNode_unparse (icurrent)),
9838 sRefSet aliases = usymtab_canAlias (sr);
9840 sRefSet_allElements (aliases, asr)
9842 if (ctype_isUnknown (sRef_getType (thisref)))
9844 sRef_setType (thisref, uentry_getType (ucurrent));
9847 if (sRef_similarRelaxed (thisref, asr))
9849 if (sRef_isExternal (asr))
9851 if (sRef_isLocalState (thisref))
9857 sRef base = sRef_getRootBase (asr);
9859 if (!sRef_similar (sRef_getBase (asr), thisref))
9861 if (sRef_isUnique (base) || sRef_isOnly (base)
9862 || sRef_isKept (base)
9863 || (sRef_isAddress (asr) && sRef_isLocalVar (base))
9864 || (sRef_isAddress (thisref)
9865 && sRef_isLocalVar (sRef_getRootBase (thisref))))
9867 ; /* okay, no error */
9872 (FLG_MAYALIASUNIQUE,
9874 ("Parameter %d (%s) to function %s is declared %s but "
9875 "may be aliased externally by parameter %d (%s)",
9877 exprNode_unparse (current),
9878 exprNode_unparse (fcn),
9879 alkind_unparse (uentry_getAliasKind (ucurrent)),
9880 iparamno, exprNode_unparse (icurrent)),
9891 ("Parameter %d (%s) to function %s is declared %s but "
9892 "is aliased externally by parameter %d (%s) through "
9895 exprNode_unparse (current),
9896 exprNode_unparse (fcn),
9897 alkind_unparse (uentry_getAliasKind (ucurrent)),
9898 iparamno, exprNode_unparse (icurrent),
9899 sRef_unparse (asr)),
9903 } end_sRefSet_allElements;
9904 sRefSet_free (aliases);
9907 } end_exprNodeList_elements;